根本原因是连接层字符集未对齐,必须在mysqli_connect()后立即调用mysqli_set_charset($link, 'utf8mb4'),且需验证@@character_set_client等三个变量均为utf8mb4,同时清除文件BOM。

PHP 8.5.5 连接 MySQL 时中文乱码,根本原因不是 PHP 版本变了,而是「连接层字符集没对齐」——哪怕你用的是 utf8mb4,只要没在连接建立后立刻设置,照样乱。
mysqli_connect 后必须立即调用 mysqli_set_charset()
PHP 8.5.5 不会自动继承 MySQL 服务端默认字符集。即使你在 my.cnf 里写了 default-character-set = utf8mb4,PHP 的 mysqli 扩展仍可能用 latin1 初始化连接。
-
mysqli_set_charset($link, 'utf8mb4')必须在mysqli_connect()成功之后、任何查询之前执行 - 不能只靠 DSN 里的
;charset=utf8mb4(PDO 可用,但 mysqli 不认这个参数) - 如果用了连接池或复用连接,每次重用前也得再 set 一次,避免上个请求残留影响
别用 utf8,坚持用 utf8mb4
MySQL 的 utf8 实际是阉割版(最多存 3 字节字符),微信昵称、emoji、生僻汉字全会截断或变问号。PHP 8.5.5 完全支持 utf8mb4,没理由退回去。
- 建库时用:
CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 建表时显式指定:
content TEXT CHARACTER SET utf8mb4 - 连接时传
'utf8mb4',不是'utf8'—— 后者在 mysqli 中等价于utf8mb3
检查连接是否真生效:查 character_set_client 和 character_set_results
光写 mysqli_set_charset() 不等于成功。有些环境(比如被某些中间件代理)会覆盖连接层设置,必须验证。
立即学习“PHP免费学习笔记(深入)”;
- 执行查询:
SELECT @@character_set_client, @@character_set_results, @@character_set_connection - 三个值都应为
utf8mb4;只要有一个是latin1或utf8,说明没生效 - 如果发现不一致,优先排查是否在
mysqli_connect()前就执行了其他查询(比如 session_start() 触发的写操作)
文件本身带 BOM 是隐形炸弹
PHP 8.5.5 对 BOM 更敏感——哪怕只是开头多了 \xEF\xBB\xBF,也会导致 headers already sent,进而让 header('Content-Type...') 失效,最终 HTML 渲染层也乱码。
- 用
file -i your_script.php检查是否含 BOM(输出含with bom就中招) - VS Code 中右下角编码显示如果是
UTF-8 with BOM,点它 → 选Save with Encoding→UTF-8 - Linux 下批量清理:
sed -i '1s/^\xEF\xBB\xBF//' *.php
真正麻烦的从来不是“设不设”,而是“设在哪”和“设完有没有被覆盖”。PHP 8.5.5 本身不制造乱码,但它放大了连接链路上任何一个环节的疏忽——尤其是 BOM 和连接复用场景下的字符集残留。



















