处理中文或utf-8多字节字符串必须用mb_substr()并显式传'utf-8';substr()按字节截取会导致中文乱码,因一个utf-8汉字占3字节,易截断字符中间;php无substring()函数,属常见误传。

直接说结论:处理中文或 UTF-8 多字节字符串,必须用 mb_substr() 并显式传 'UTF-8';纯英文/ASCII 场景可用 substr();别信 substring() —— PHP 根本没有这个内置函数,是常见误传。
为什么 substr() 截中文会乱码
substr() 按字节截取,而一个 UTF-8 中文占 3 字节。比如 "你好" 实际是 6 字节,substr($str, 0, 3) 只取前 3 字节,恰好卡在第一个汉字中间,输出就是乱码(如 好)。
常见错误现象:
- 页面显示 、、□ 等异常符号
- JSON 输出被截断导致解析失败
- 数据库写入时触发
Incorrect string value报错
解决办法只有两个条件同时满足:
- 启用
mbstring扩展(检查phpinfo()或运行extension_loaded('mbstring')) - 调用
mb_substr($str, $start, $length, 'UTF-8'),编码参数不能省略
mb_substr() 的 encoding 参数为什么不能省
省略第四个参数时,mb_substr() 依赖 mb_internal_encoding() 返回的值,而该值可能被其他代码临时修改,或未在 php.ini 中设为 UTF-8,导致行为不一致。
实操建议:
- 始终显式传
'UTF-8',哪怕本地测试正常 - 避免在函数外调用
mb_internal_encoding('UTF-8')来“一劳永逸”,它不是线程安全的 - 如果环境无法启用
mbstring(极少见),降级方案只能是先用iconv_strlen()判断长度,再用substr()配合字节偏移计算 —— 但强烈不推荐,复杂且易错
按分隔符截取时,别硬套 substr() + strpos()
例如想取邮箱 @ 前的部分,有人写 substr($email, 0, strpos($email, '@'))。这看似可行,但一旦 $email 不含 @,strpos() 返回 false,substr() 就会报 Warning 并返回空字符串。
更健壮的写法:
- 用
explode('@', $email)[0]——explode()对不存在的分隔符返回原字符串数组,不会崩溃 - 或加判断:
$pos = strpos($email, '@'); $user = $pos !== false ? substr($email, 0, $pos) : $email; - 若需兼容空格、换行等干扰,先
trim()再处理
生成摘要时加省略号的坑
很多人用 mb_substr($text, 0, 100, 'UTF-8') . '...',但这样可能在 HTML 标签中间截断,比如截出 <p>Hello...</p> 变成 <p>Hello...,破坏 DOM 结构。</p>
<p>真实项目中要注意:</p>
<ul>
<li>如果原文含 HTML,应先用 <code>strip_tags() 去标签再截取
mb_strrpos() 找最后一个空格位置做软截断,避免单词被劈开mb_strlen($text, 'UTF-8') 计算时要预留空间最麻烦的点其实不在函数选型,而在于你永远不知道上游数据是否真的 UTF-8 编码 —— 从数据库读、API 接、文件导入,都得先验码,否则 mb_substr() 也会失效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











