加 JSON_UNESCAPED_UNICODE 仍乱码的根本原因是编码链路未全程 UTF-8:PHP 文件含 BOM、数据库连接未设 utf8mb4、响应头缺失 charset=utf-8、前端解析编码不匹配或 mbstring 未启用,任一环节断裂均导致中文坍缩。

直接用 json_encode($array, JSON_UNESCAPED_UNICODE),但前提是整个链路编码必须是 UTF-8 —— 否则光加这个选项没用,反而掩盖真正问题。
为什么加了 JSON_UNESCAPED_UNICODE 还是乱码
常见错误现象:加了 JSON_UNESCAPED_UNICODE,输出仍是 {"name":"\u5f20\u4e09"} 或更糟——变成问号、方块、空字符串。
- PHP 文件本身带 BOM(尤其 Windows 下用记事本保存过),
json_encode()会提前报错或静默失败 - 数据库连接没设 UTF-8,查出来的字段实际是 GBK 编码字节,但 PHP 当成 UTF-8 字符串处理
- 前端没声明
Content-Type: application/json; charset=utf-8,浏览器按 ISO-8859-1 解析,中文直接崩 -
mbstring扩展未启用,导致mb_detect_encoding()等函数不可用,后续转码逻辑失效
怎么确认 PHP 文件是否带 BOM
带 BOM 的 UTF-8 文件开头有不可见的 3 字节 EF BB BF,会干扰 header 输出和 JSON 生成。
- 用 VS Code 打开,右下角看编码显示 —— 如果是
UTF-8 with BOM,点它 → 选Save with Encoding→UTF-8 - 命令行快速检测:
head -c 3 your_file.php | xxd,输出含ef bb bf就是带 BOM - Sublime Text:菜单
File → Save with Encoding → UTF-8(注意不是 “UTF-8 with BOM”)
数据库查询结果含中文时怎么安全转 JSON
不能只靠 json_encode() 选项,得从数据源头控制编码一致性。
立即学习“PHP免费学习笔记(深入)”;
- MySQL 连接后立刻执行:
mysqli_set_charset($conn, 'utf8mb4')(别用utf8,那是 MySQL 的假 UTF-8) - 建表时字段显式指定:
VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 如果已有乱码数据(比如 GBK 存进 utf8mb4 字段),先用
mb_convert_encoding($str, 'UTF-8', 'GBK')转码再进json_encode() - 避免用
SET NAMES utf8—— 它不等价于mysqli_set_charset(),在某些 PDO 场景下无效
临时救急:对非 UTF-8 字符串做兼容性转码
当无法立刻统一编码环境(比如对接老系统、读取第三方 CSV),需手动识别并转换。
- 检测并转为 UTF-8:
$safe_str = mb_convert_encoding($str, 'UTF-8', mb_detect_encoding($str, ['UTF-8', 'GBK', 'BIG5'], true)) - 慎用
iconv('GBK', 'UTF-8//IGNORE', $str)——//IGNORE会丢字,//TRANSLIT可能引入问号 - 不要对整个数组用
urlencode()再json_encode()—— 这是上世纪的 hack,会导致 JSON 结构被破坏(比如"name":"%E5%BC%A0%E4%B8%89"),前端还得额外decodeURIComponent()
最常被忽略的一点:即使所有环节都设了 UTF-8,只要其中任意一环(文件、数据库连接、HTTP 响应头、前端 fetch 的 responseType)用了不同编码,中文就会在某个节点坍缩。排查时别只盯 json_encode() 参数,要像查电路一样逐段测电压。



















