直接用substr()截中文大概率乱码,因其按字节截取,而UTF-8中汉字占3字节、GBK中占2字节,易切到字符中间;推荐优先使用mb_substr($str,0,10,'utf-8')按字符数安全截取,需确保php.ini启用mbstring扩展。

直接用 substr() 截中文,大概率会乱码,因为它按字节切,而 UTF-8 中一个汉字占 3 字节、GBK 中占 2 字节。切到中间,就变成非法字节序列,浏览器一渲染就显示为乱码或。
优先启用 mb_substr() 函数
这是最推荐、最简洁的解法,前提是 PHP 已开启 mbstring 扩展(检查 phpinfo() 是否有 mbstring support: enabled;若未启用,需在 php.ini 中取消 ;extension=mbstring 前的分号,重启服务)。
-
mb_substr($str, 0, 10, 'utf-8'):按字符数截取,10 表示 10 个字符(中英文各算 1 个),结果无乱码 -
mb_substr($str, 0, 10, 'gb2312'):适用于 GBK/GB2312 编码的老系统,同样按字符计数 - 不传第 4 个参数时,会使用 PHP 内部编码(可通过
mb_internal_encoding()查看)
区分 mb_substr 和 mb_strcut
两者都安全,但逻辑不同:
-
mb_substr:按“字符个数”截,适合标题、摘要等需要固定字数显示的场景 -
mb_strcut:按“字节数”截,但会自动避开多字节字符断点,避免半截汉字;例如mb_strcut($str, 0, 15, 'utf-8')最多返回 15 字节,且保证每个汉字完整 - 举例:
$s = "你好world";,mb_substr($s, 0, 5, 'utf-8')→ "你好wor"(5 个字符);mb_strcut($s, 0, 5, 'utf-8')→ "你好"(前 6 字节刚好两个汉字,第 5 字节无法单独成字,自动舍弃)
没有 mbstring 扩展时的手动处理
若无法启用扩展(如某些共享主机),可临时用自定义函数识别 UTF-8 字节结构:
立即学习“PHP免费学习笔记(深入)”;
- 逐字节读取,遇到
0xE0–0xEF开头的字节(UTF-8 三字节字符首字节),就跳过后续 2 字节 - 遇到
0xC0–0xDF开头的字节(两字节字符),就跳过后续 1 字节 - 其余视为单字节字符(ASCII)
- 累计有效字符数达目标后停止,拼接结果
编码声明必须一致
乱码常因前后编码不匹配放大:
- PHP 文件本身保存为 UTF-8 无 BOM 格式
- 输出前加
header('Content-Type: text/html; charset=utf-8'); - HTML 中写
<meta charset="utf-8"> - 数据库连接指定字符集,如 MySQL 使用
SET NAMES utf8mb4



















