应使用 mb_strlen()、mb_substr()、mb_convert_encoding() 等多字节函数处理中文:mb_strlen("你好", "utf-8") 返回 2;mb_substr("你好世界", 0, 2, "utf-8") 返回"你好";mb_convert_encoding($str, "utf-8", "gbk") 显式指定编码;json_encode() 前必须确保字符串为 utf-8。

mb_strlen() 代替 strlen() 计算中文字符数
直接用 strlen() 算含中文的字符串,结果是字节数不是字符数。比如 "你好" 在 UTF-8 下占 6 字节,strlen() 返回 6,但你真正需要的是“2个字符”。
必须改用 mb_strlen(),且显式传入编码:
-
mb_strlen("你好", "UTF-8")→ 返回2 -
mb_strlen("Hello你好", "UTF-8")→ 返回7 - 不传编码参数依赖
mb_internal_encoding(),但该值可能被其他代码或配置修改,不可靠 - 如果传错编码(比如把 UTF-8 字符串当 GBK 传),
mb_strlen()可能返回false或错误值
mb_substr() 截取中文不乱码
substr("你好世界", 0, 2) 极大概率输出乱码,因为它是按字节截的——UTF-8 中一个中文占 3 字节,“0,2”只拿了前 2 字节,半个汉字。
mb_substr() 按字符截,安全得多:
-
mb_substr("你好世界", 0, 2, "UTF-8")→"你好" -
mb_substr("a你好b", 1, 2, "UTF-8")→"你好"(跳过首字母 a,取两个中文) - 起始位置和长度单位都是“字符”,不是字节
- 负数索引也支持:
mb_substr("测试abc", -3, 2, "UTF-8")→"ab"(从末尾倒数第 3 个字符开始取 2 个)
mb_convert_encoding() 转码时别信默认值
从 GBK 页面抓数据、读取旧数据库、处理用户上传文件时,常遇到非 UTF-8 编码。用 mb_convert_encoding() 转成 UTF-8 是标准做法,但容易踩坑:
-
mb_convert_encoding($gbk_str, "UTF-8", "GBK")✅ 明确指定源编码 -
mb_convert_encoding($gbk_str, "UTF-8")❌ 源编码按mb_internal_encoding()推断,大概率错 - 如果源编码判断错误,转出来可能是全 ? 或乱码,且函数不报错
- 建议先用
mb_detect_encoding()粗略探测(注意它不 100% 可靠),再人工验证或结合上下文确认
json_encode() 强制要求输入为 UTF-8
PHP 的 json_encode() 函数内部不做编码转换。只要字符串里有非 UTF-8 字节序列,它就直接返回 false,且 json_last_error_msg() 提示 “Malformed UTF-8 characters”。
常见触发场景:
- 从 GBK 数据库读出未转码就直接
json_encode() - 用户 POST 提交的表单没声明
accept-charset="UTF-8",浏览器可能用本地编码(如 GBK)发送 - 用
utf8_encode()处理非 ISO-8859-1 数据(该函数自 PHP 8.2 起已弃用,且只认 Latin-1)
稳妥做法:所有进 json_encode() 的字符串,先过一遍 mb_convert_encoding($str, "UTF-8", $actual_encoding),确保万无一失。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











