PHP中文乱码必须文件、传输、存储、处理四环节同步统一UTF-8:①PHP文件用UTF-8无BOM保存;②开头设mb_internal_encoding("UTF-8")和header("Content-Type: text/html; charset=utf-8");③数据库用utf8mb4并PDO DSN加charset=utf8mb4;④字符串操作全用mb_*函数且显式传'UTF-8'参数。

PHP处理中文乱码不能靠单点修补,必须从文件、传输、存储、处理四个环节同步统一为UTF-8,缺一不可。任何一处漏掉(比如数据库设了utf8mb4但没在PDO DSN里加charset=utf8mb4),都会导致前端显示问号、方块或json_encode返回null。
确认PHP源文件是UTF-8无BOM
PHP解析器读取文件时,若开头有BOM(\xEF\xBB\xBF),会把它当作输出内容,直接触发Headers already sent错误,后续header()全部失效。
- 用VS Code打开PHP文件,右下角查看编码,如果不是
UTF-8,点击切换 → “Save with Encoding” → 选UTF-8(注意不是UTF-8 with BOM) - Linux下验证:
file -i your_script.php,输出应含charset=utf-8且不含with bom - 绝对避免用记事本保存PHP文件——它默认加BOM且无法关闭
强制PHP内部编码和HTTP响应头为UTF-8
mb_strlen()这类函数默认按系统locale(常为ISO-8859-1)处理字符串,不显式设内部编码,中文长度就全算错;而header()晚于任何输出就会失败。
- 在框架入口文件(如
public/index.php)最顶部第一行写:mb_internal_encoding("UTF-8"); - 紧接着写:
header("Content-Type: text/html; charset=utf-8");(HTML页面)或header("Content-Type: application/json; charset=utf-8");(API) - 如果担心前置输出,开头加
ob_start();,后面ob_clean();再发header,但治标不治本,优先清BOM和空格
数据库连接与字段必须全程utf8mb4
MySQL的utf8实际是utf8mb3,不支持emoji和部分生僻汉字;只设数据库字符集还不够,连接层和字段层都得对齐,否则SELECT出来的仍是乱码。
立即学习“PHP免费学习笔记(深入)”;
- 建库时用:
CREATE DATABASE mydb CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - PDO连接DSN中必须带
charset=utf8mb4:$pdo = new PDO("mysql:host=localhost;dbname=mydb;charset=utf8mb4", $u, $p); - 已有表字段要改:
ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 不要依赖
init_connect='SET NAMES utf8'——它设的是utf8,不是utf8mb4
字符串操作必须用mb_系列并传'UTF-8'参数
strpos()、substr()这些函数按字节切字符串,UTF-8中文占3字节,切在中间就成乱码;mb_strpos($text, $kw, 0, 'UTF-8')才是安全写法。
- 全局搜索项目中所有
strlen(、substr(、strpos(、strtolower(,替换成mb_strlen(、mb_substr(、mb_strpos(、mb_strtolower( - 每个
mb_函数调用都必须显式传第4参数'UTF-8',例如:mb_substr($str, 0, 10, 'UTF-8') - 正则匹配中文必须加
u修饰符:preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', $str) -
json_encode()必须加JSON_UNESCAPED_UNICODE选项,否则中文变\uXXXX
最容易被忽略的是:数据库字段字符集改了,但PHP连接没加charset=utf8mb4;或者mb_internal_encoding("UTF-8")写了,但mb_strpos()漏传'UTF-8'参数——这两处一错,前面所有努力都白费。



















