PHP中文乱码需四层统一:文件存为UTF-8无BOM;PHP脚本顶部设header('Content-Type: text/html; charset=utf-8');HTML中加;数据库连接与表均用utf8mb4。

PHP中文乱码不是单一环节出错,而是文件编码、HTTP传输、数据库连接、HTML解析四层脱节导致的。只要其中一层是GBK、ISO-8859-1或utf8(非utf8mb4),中文就大概率显示为或一堆问号。
PHP文件必须存为UTF-8无BOM
BOM是三个不可见字节(\xEF\xBB\xBF),会卡在header()前面,直接触发“headers already sent”错误,后续所有字符集设置都失效。VS Code里右下角显示“UTF-8 with BOM”就是隐患;Notepad++里“编码→转为UTF-8”默认带BOM,要选“转为UTF-8-BOM”再手动去掉——不对,得选“转为UTF-8”且确认不勾选BOM选项。
- 用
file命令检查:file -i your_script.php,输出含charset=utf-8且无bom字样才算过关 - 批量修复旧文件:Linux下可用
sed -i '1s/^\xEF\xBB\xBF//' *.php清除BOM(仅限已知带BOM的文件) - IDE设置:VS Code中配置
"files.encoding": "utf8"和"files.autoGuessEncoding": false,避免自动识别误判
header()和必须同时设且一致
只写header('Content-Type: text/html; charset=utf-8')不够,浏览器在HTTP头缺失或被CDN缓存覆盖时,会退而求其次看HTML里的</meta charset="UTF-8">。两者不一致,Chrome可能按header,Firefox按meta,结果不稳定。
-
header()必须在任何输出前执行,包括空格、换行、echo ''、甚至PHP关闭标签?>后的空白 -
必须放在最开头,早于和外部CSS/JS链接 - 用curl验证真实响应头:
curl -I http://yoursite.com/test.php,确认返回中有Content-Type: text/html; charset=utf-8
mysqli或PDO连接必须显式设utf8mb4
MySQL的utf8其实是阉割版,最多存3字节字符,遇到emoji或某些生僻汉字就截断变乱码。utf8mb4才是真正的UTF-8实现。只改建表语句没用,PHP连接层不匹配照样乱。
- mysqli:连接后立刻调用
mysqli_set_charset($conn, 'utf8mb4'),别用mysqli_query($conn, 'SET NAMES utf8')——它不保证连接层编码生效 - PDO:DSN里必须带
;charset=utf8mb4,例如mysql:host=localhost;dbname=test;charset=utf8mb4,光靠setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4")不够可靠 - 验证是否真生效:
var_dump($conn->character_set_name());(mysqli)或var_dump($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));(PDO)
读取外部中文文件时不能依赖file_get_contents自动解码
file_get_contents()只是二进制读取,不会猜编码。如果读的是GBK编码的txt,直接echo出来就是乱码,哪怕页面本身是UTF-8。
- 明确知道源文件编码时,用
mb_convert_encoding(file_get_contents('data.txt'), 'UTF-8', 'GBK') - 不确定编码但文件内容较短,可用
mb_detect_encoding()试探(注意它不可靠,仅作参考) - 读取远程URL时,HTTP响应头里的
Content-Type可能带charset=gbk,此时应优先按响应头解码,而不是硬写UTF-8
最容易被忽略的是Web服务器配置:Apache的AddDefaultCharset或Nginx的charset指令,可能强行覆盖PHP的header()。上线前务必用curl -I确认最终发出的HTTP头,而不是只信PHP代码里的header()调用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











