改config.php的charset无效,因其仅控制HTML响应头,不影响数据库连接;真正起效的是database.php中charset=utf8mb4、DSN写死charset=utf8mb4、MySQL服务端character_set_server=utf8mb4,并需手动执行SET NAMES utf8mb4。

ThinkPHP字符乱码不是单一环节问题,而是文件、HTTP头、数据库、模板四者编码不一致导致的叠加故障。直接改 config.php 里的 'charset' => 'utf-8' 几乎没用。
为什么改 config.php 的 charset 不起作用
这个配置项只影响 ThinkPHP 自动渲染 HTML 模板时的 Content-Type 响应头(比如 fetch() 输出页面),它完全不控制数据库连接、SQL 执行、PDO 初始化或文件读取的编码。很多开发者卡在这里反复修改却无效,就是因为误以为它是“全局编码开关”。
-
'charset' => 'utf-8'在 TP5/6 中对数据库连接无任何影响;真正起作用的是database.php里的'charset' - 即使你写了
'charset' => 'utf8mb4',如果 MySQL 服务端character_set_server是latin1或utf8,连接后仍不会自动执行SET NAMES utf8mb4 - TP6 默认不触发
SET NAMES,必须显式配置或手动执行,否则 PDO 会沿用服务器默认字符集
database.php 必须设为 utf8mb4,且不能写 utf8
MySQL 的 utf8 是历史包袱,实际是 utf8mb3,不支持 emoji 和部分生僻中文(如「?」「?」)。一旦存入这类字符,会被静默截断或变问号,且无法通过后续转换恢复。
- 在
config/database.php中,把'charset' => 'utf8'改成'charset' => 'utf8mb4'(注意拼写,不能少mb4) - DSN 字符串里也得带
;charset=utf8mb4,例如:mysql:host=127.0.0.1;dbname=test;charset=utf8mb4 - 确认 MySQL 服务端已启用:
SHOW VARIABLES LIKE 'character_set_server';返回值必须是utf8mb4,否则改配置无效 - 连接建立后,检查日志或用
Db::connect()->getPdo()->getAttribute(PDO::ATTR_CLIENT_VERSION)验证是否真用了 utf8mb4
文件 BOM、HTML meta、header() 必须三者统一
乱码常出现在调试输出(如 dump())、错误页(halt())、或纯 PHP 脚本直出内容上,根源是 PHP 文件本身含 BOM 或未发送正确响应头。
立即学习“PHP免费学习笔记(深入)”;
- 用 VS Code 或 Notepad++ 打开所有 PHP 入口文件(
public/index.php、app/common.php等),保存为 UTF-8 无 BOM 格式(不是“UTF-8 with BOM”) - 入口文件顶部加:
header('Content-Type: text/html; charset=utf-8');—— 这能覆盖 IIS/Apache 的默认响应头,尤其对dump()和halt()生效 - 所有 HTML 模板头部必须有:
<meta charset="utf-8">;若用<meta http-equiv="Content-Type">,确保属性值与 header 一致 - 不要依赖框架自动输出 meta:TP 的模板引擎不会帮你补 meta,
fetch()只输出内容,不注入 head
GET/POST 中文参数乱码要单独处理
IIS 或某些 Nginx 配置下,URL 中的中文参数(如 ?name=张三)会被服务器按 GBK 解码再传给 PHP,而 PHP 默认以 UTF-8 处理,结果就是乱码。这不是 ThinkPHP 的 bug,是 Web 服务器层的编码错位。
- 最可靠方案:前端传参前用
urlencode()编码,后端接收后用urldecode()解码,例如:$name = urldecode(input('get.name')); - 若必须兼容旧链接,可在中间件或
app/common.php开头统一转码:$_GET = array_map(function($v) { return is_string($v) ? iconv('gbk', 'utf-8//IGNORE', $v) : $v; }, $_GET); - 避免用
mb_convert_encoding($_GET['name'], 'UTF-8', 'auto'),auto不可靠,容易误判 - POST 表单乱码同理,确保表单
<form accept-charset="utf-8">,且页面本身是 UTF-8 编码
真正棘手的不是某处漏配,而是多个环节都“看起来正常”——文件是 UTF-8、数据库设了 utf8mb4、meta 也写了,但只要 MySQL 服务端没切到 utf8mb4,或 PHP 文件带了 BOM,或 URL 参数未经 urlencode,乱码就会在某个具体场景突然冒出来。排查时得逐层验证,不能只看配置项有没有写。



















