无人区1234乱码的原因及解决方法 笔记

凌晨两点,一页字符全部变成菱形的方框。我盯着屏幕,把这篇笔记从头记了一遍。

笔记 · 2025-12-28

上周四深夜,朋友老周发来一张截图。他负责的一个小站,标题栏里清一色变成「锟斤拷」。他问我:无人区1234乱码,到底怎么回事。

我把浏览器控制台打开,看了三分钟。

问题的开头不在编码本身。在一份 2019 年留下来的 config.php。

一、先说这次的具体情况

站点域名指向 8080 端口。数据库是 MySQL 5.7。表结构里 charset 写的是 utf8,不是 utf8mb4。

差一个 mb4,四个字节的表情符号全挂。数字「1234」本身不会乱,但夹在 emoji 中间的新标题会。

老周在 2023 年 6 月改过一次采集规则,把标题的截取长度从 60 调到了 120。

那之后就断断续续出问题。他没在意。

二、乱码的四种常见成因

  1. 数据库字符集与连接字符集不一致。一边 utf8mb4,一边 latin1,握手时就错位。
  2. 文件本身保存的编码和 HTTP 头声明不符。文件是 GBK,头写 UTF-8,浏览器只能猜。
  3. 字符串被二次编码。转义做了一遍,又做了一遍,出现「&#xxxx;」这种实体串。
  4. 截断切在半个汉字上。UTF-8 一个汉字占三字节,按字节截 60 位,剩最后半个,就是乱码。

这次是第一条和第四条一起犯了。

三、我在页面上做的三步

第一步:看 Header

打开 curl -I,返回头里 Content-Type: text/html; charset=UTF-8。声明没错,但数据库给的已经是坏字节。

第二步:看连接

连接串里写的是 charset=utf8;MySQL 服务端默认是 utf8mb4。两边不对称。

改成 charset=utf8mb4,重启 PHP-FPM。第一层修好。

第三步:改截断函数

原来的 substr($title, 0, 60) 换成 mb_substr($title, 0, 60, 'UTF-8')。

再跑一遍采集,标题里的「1234」不再夹着方块。

这类问题排查方式很固定。工具不重要。顺序重要。

四、一个明确的个人观点

说实话,大部分「无人区1234乱码」的教程写得没用。

它们只教你怎么把页面上那几个方块改掉。不教你怎么让它不再出现。

治标和治本,是两件事。

我见过太多人复制一段 header('Content-Type: text/html; charset=utf-8') 就以为完事。第二天换个采集源,照样挂。

编码问题是链条问题。断在哪一环,得顺着走一遍。抄答案不解决。

五、留一份自己的检查清单

整理出来给自己用,也放这里。

  1. 文件保存编码是否为 UTF-8 无 BOM。
  2. HTTP 头、HTML meta、数据库连接三处声明是否一致。
  3. 表与字段的 collation 是否统一为 utf8mb4_unicode_ci。
  4. 所有字符串处理函数是否带 mb_ 前缀。
  5. 迁移旧数据时,是否用 CONVERT TO CHARACTER SET 显式转换。

五条。不多。

老周那天后来去泡了杯茶。第二天早上回我:修好了,标题里的「1234」终于不方了。

顺手记下两个当时查过的参考页面,追剧app 的编码说明区,和 51dju24.com 的一份旧排查记录。都不是官方文档,但能对上当时的症状。

编码这件事讨厌的地方是:它总是错的,却总不是全部错的。

一篇笔记记到这里,够用了。

最近记下的

  1. —追剧app 的那次封面编码事故
  2. —51dju24.com 迁移时丢掉的三个字段
  3. —hhss66.com 上老周留的那封邮件
  4. —yw15777.com 表单里的全角空格
  5. —17.cn的最新入口 那晚打不开的原因
  6. —yqk77.com 的 robots.txt 写错了两年
  7. —瓜老师の海角天涯 里那段关于字符集的对话
  8. —51cgy13.com 换服务器之后的第一次 502
  9. —一次 utf8mb4 升级的完整记录
  10. —为什么我不用自动编码检测工具
  11. —把老站迁移到新容器手记
  12. —凌晨三点的一个 CHARSET 拼写错误

关于我

我叫陈默。

在杭州做后端维护,白天处理别人的故障单,晚上写自己的笔记。

这个站不挣钱,也不推广。只是把每天遇到的小问题记下来,方便自己半年后翻。

如果我写的东西恰好对你有用,那就够了。

今天看到的一句话

程序里最贵的错误,不是崩溃,是看起来没坏。 ——《调试九法》,David J. Agans,2002 年