根本原因是substr等原生函数按字节操作,而UTF-8中文占3字节,截断会破坏字符边界导致乱码;必须用mb_substr()按字符截取,并显式指定'UTF-8'编码。

根本原因是 PHP 原生字符串函数(如 substr)按字节操作,而中文在 UTF-8 编码下占多个字节(通常是 3 字节),直接截断会切开多字节字符边界,导致残留非法字节序列,浏览器或终端无法识别,显示为问号或乱码符号。
UTF-8 中文不是“单个字符”,而是“字节组合”
UTF-8 是变长编码:英文字符占 1 字节,汉字占 3 字节。例如 “你好” 实际是 6 字节:0xE4 0xBD 0xA0 0xE5 0xA5 0xBD。若用 substr($str, 0, 4) 截取前 4 字节,得到的是 0xE4 0xBD 0xA0 0xE5 —— 这不是一个合法的 UTF-8 字符,解码失败,显示乱码。
substr 不知道你在处理中文
substr() 完全不感知字符编码,它只数字节位置。它没有内置逻辑去判断某个字节是 ASCII 还是 UTF-8 的起始字节或续字节。因此:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 你告诉它“从第 0 字节开始取 5 字节”,它就机械执行;
- 如果第 4、5 字节恰好是某个汉字的后半部分,结果必然损坏;
- 这种损坏不可逆,后续
echo或 JSON 输出时已无从修复。
环境不一致会放大问题
即使用了 mb_substr,仍可能乱码,常见于:
- 没显式传入编码参数,如
mb_substr($str, 0, 10)—— 它依赖内部默认编码(可能是ISO-8859-1),而非你文件/数据库实际用的UTF-8; - 服务器未启用
mbstring扩展,mb_substr函数根本不存在; - PHP 文件本身保存为 GBK,但声明了
charset=utf-8,源头数据已错。
不是 PHP 的 Bug,而是使用方式错位
这不是 PHP8.0 特有缺陷,而是所有版本共性。PHP 设计上把“字节操作”和“字符操作”做了明确分离:substr 负责字节,mb_substr 负责多字节字符。混淆二者用途,就会触发乱码。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










