应使用 mb_substr() 并显式指定 'utf-8' 编码截取字符串,避免 substr() 按字节截取 UTF-8 中文导致乱码;同时确保响应头、文件编码、函数调用一致性。

直接用 mb_substr(),别碰 substr() —— 这是规避 ThinkPHP 截取字符串乱码最简单、最可靠的做法。前提是你的 PHP 环境已启用 mbstring 扩展(绝大多数现代环境默认开启)。
为什么 ThinkPHP 里 substr() 一截中文就乱码
ThinkPHP 本身不干预字符串函数行为,乱码根源在 PHP 底层:substr() 按字节切,而 UTF-8 中文占 3 字节。比如截取位置落在某个中文的第 2 个字节上,结果就是半个字符,浏览器渲染即乱码。
常见错误现象:
- 前端显示 、 或一堆问号
- 截取后字符串末尾多出异常符号(如
…前出现乱码) - 同一段代码在 CLI 下正常,Web 下乱码(往往因响应头或模板编码未对齐)
这不是 ThinkPHP 的 Bug,是误用单字节函数处理多字节文本的必然结果。
立即学习“PHP免费学习笔记(深入)”;
mb_substr() 的正确调用姿势
必须显式传入编码参数,不能依赖内部默认值。ThinkPHP 项目几乎全是 UTF-8,所以固定写 'utf-8':
// ✅ 正确:指定编码,按字符数截取 $short = mb_substr($title, 0, 15, 'utf-8'); // ❌ 错误:没指定编码,可能 fallback 到 latin1 或系统 locale $short = mb_substr($title, 0, 15); // ❌ 错误:用错函数,仍走字节逻辑 $short = substr($title, 0, 15);
注意事项:
-
mb_substr()第四个参数必须是字符串,如'utf-8',不能写成UTF8或UTF_8 - 若字符串实际是 GBK 编码(极少见),需改用
'gbk',但务必确认来源一致 - ThinkPHP 模板中慎用原生 PHP 函数,建议封装成助手函数或使用
Str::limit()(TP6+)
ThinkPHP 模板中输出截断的坑
即使 PHP 层用了 mb_substr(),模板里还可能翻车:
- HTML 响应头没设 charset:
header('Content-Type: text/html; charset=utf-8');必须存在(入口文件或中间件) - 模板文件本身保存为 ANSI/GBK 编码,却当 UTF-8 解析 —— 用编辑器确认并转存为 UTF-8 无 BOM
- 直接在模板里写
<?php echo mb_substr($str, 0, 10); ?>而没传编码,等于白做 - TP6 的
{{ $str|str_limit:10 }}默认用mb_substr,但底层仍依赖环境编码设置,不可盲目信任
最易被忽略的一点:mb_strlen() 和 mb_substr() 必须配对使用。如果你先用 mb_strlen($s, 'utf-8') 判断长度,再用 substr() 截取,前面的判断就白算了 —— 字符数和字节数永远对不上。



















