根本原因是UTF-8汉字占3字节、GBK占2字节,substr按字节截取导致结果不同且易乱码;应统一用mb_substr并显式指定编码,配合编码检测与统一转码,确保输入、处理、输出全流程编码一致。

PHP7.4 中 UTF-8 和 GBK 字符串截取结果不同,根本原因不是“函数用错了”,而是两种编码下**同一个中文字符占用的字节数不同**:UTF-8 中汉字占 3 字节,GBK 中占 2 字节。而像 substr 这类函数只认字节位置,不识别字符边界,所以同样截 10 个字节,在 UTF-8 里可能切掉 3 个汉字加 1 个字节,在 GBK 里可能正好是 5 个完整汉字——结果自然不同,且极易乱码。
统一用 mb_substr 按字符截取
不管源字符串是 UTF-8 还是 GBK,只要明确知道它的编码,就该用 mb_substr 替代 substr:
-
mb_substr($str, 0, 10, 'UTF-8')—— 截前 10 个 Unicode 字符(如 10 个汉字) -
mb_substr($str, 0, 10, 'GBK')—— 同样截前 10 个字符,但按 GBK 编码解析 - 务必显式传入第 4 个参数
$encoding,不能依赖内部编码设置,避免隐式误判
不确定编码时先检测再处理
外部输入(如表单、API 响应、文件读取)常无法预知真实编码,需主动探测:
- 用
mb_detect_encoding($str, ['UTF-8', 'GBK', 'GB2312', 'BIG5'], true)获取最可能的编码 - 若返回 false 或结果不可靠,可结合
bin2hex(substr($str, 0, 4))查看前几个字节特征(如e4bda0是 UTF-8 的「你」,c4e3是 GBK 的「你」) - 检测后立即转为统一编码(推荐 UTF-8),再用
mb_substr处理:$utf8_str = mb_convert_encoding($str, 'UTF-8', $detected_enc);
避免 iconv + substr 组合
有人试图“先用 iconv 转成 GBK,再用 substr 截”,这仍是错的:
-
iconv只改编码,不改变substr的字节逻辑 - 例如 UTF-8 字符串
"你好"(6 字节)转 GBK 后变成 4 字节,substr(..., 0, 3)会截断第二个汉字,结果仍乱码 - 真正安全的做法是:转码后,继续用
mb_substr(..., 0, N, 'GBK')按字符操作
输出前确保环境一致
即使截取正确,显示仍乱码,往往卡在输出环节:
- PHP 文件本身保存为 UTF-8 无 BOM 格式
- 脚本开头加
header('Content-Type: text/html; charset=UTF-8'); - HTML 中写
- 数据库连接指定
charset=utf8mb4,避免从源头混入 GBK 数据
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











