PHP中文乱码需五处同步UTF-8无BOM:PHP文件编码、HTTP响应头、HTML meta、数据库(utf8mb4)及连接设置、外部文件读取与内部函数(如mb_strlen),缺一即乱码。

PHP文件必须保存为UTF-8无BOM
VS Code右下角显示“UTF-8 with BOM”或“GBK”,就直接导致header()报“headers already sent”,中文输出成问号或方块。BOM是三个不可见字节\xEF\xBB\xBF,会卡在<?php 之前,让PHP误以为已开始输出。
- 在VS Code中:右下角点击编码 → “通过编码重新打开” → 选“UTF-8” → 再点编码 → “另存为编码” → 勾选“UTF-8(不带BOM)”并覆盖
- Linux下验证:
file -i your.php,输出应含charset=utf-8且**无**with bom - Notepad++用户:编码 → 转为UTF-8无BOM格式 → 保存
header()必须放在所有输出之前
header('Content-Type: text/html; charset=utf-8')一旦被空格、tab、echo、HTML或关闭标签?>提前触发输出,就会失效,浏览器按ISO-8859-1解析UTF-8字节流,中文全变乱码。
- 该行必须是PHP文件的**第一行有效内容**,前面不能有任何字符(包括空白行)
- 检查是否引入了其他PHP文件(如
require 'config.php'),那些文件也必须是UTF-8无BOM,且自身也不含任何前置输出 - 临时调试可用
ob_start()垫底,但只是掩盖问题,不是修复 - 用
curl -I http://localhost/test.php确认响应头里真有Content-Type: text/html; charset=utf-8
MySQL必须用utf8mb4,且连接层显式设置
MySQL的utf8不是真正的UTF-8,它只支持最多3字节字符(不支持emoji和部分生僻汉字),而utf8mb4才是完整实现。仅改表字符集没用,PHP连接时若不声明,仍走默认latin1。
- 建库时:执行
CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 建表时:字段定义加
CHARACTER SET utf8mb4,例如VARCHAR(255) CHARACTER SET utf8mb4 - mysqli连接后立即调用:
mysqli_set_charset($conn, 'utf8mb4') - PDO连接时DSN中必须写:
mysql:host=localhost;dbname=test;charset=utf8mb4 - 避免用
SET NAMES utf8——它调的是MySQL的伪utf8,不是utf8mb4
读取外部中文文件时不能依赖file_get_contents自动识别
file_get_contents()只读二进制流,不做编码推断。若源文件是GBK,直接echo到UTF-8页面,浏览器就拿GBK字节当UTF-8解,必然乱码。
立即学习“PHP免费学习笔记(深入)”;
- 首选方案:把原始文本文件本身转成UTF-8无BOM再读,一劳永逸
- 次选方案:用
mb_convert_encoding()转换,例如$content = mb_convert_encoding(file_get_contents('data.txt'), 'UTF-8', 'GBK') - 流过滤方案(更底层):
$fp = fopen('data.txt', 'r'); stream_filter_append($fp, 'convert.iconv.GBK/UTF-8'); - 注意
iconv()需系统支持编码别名,且建议加//IGNORE容错,例如iconv('GBK', 'UTF-8//IGNORE', $str)
strlen vs mb_strlen)这五个点只要漏掉一个,乱码就一定会回来。没有“差不多”,只有全部对齐。



















