ThinkPHP部署乱码根源在于字符集未对齐或中途被污染,需四步排查:一、所有PHP文件须UTF-8无BOM;二、数据库连接DSN中硬写charset=utf8mb4并确保MySQL服务端配置一致;三、导出功能前执行ob_end_clean(),CSV加EFBBBF BOM;四、语言包与模板统一UTF-8无BOM,禁用mb_internal_encoding切换编码。

ThinkPHP部署后出现乱码,核心不是“编码没设”,而是多个环节的字符集未对齐或中途被污染。常见表现包括:网页中文显示为方块或问号、数据库读出是???、导出Excel乱码、语言包关键词不识别、上传文件名变成乱码。问题往往跨文件、跨协议、跨层级,需逐段排查。
一、确认 PHP 文件本身是 UTF-8 无 BOM
这是最容易被忽略的第一环。VS Code 或 Notepad++ 默认可能保存为「UTF-8 with BOM」,而 BOM(EF BB BF)会被 PHP 当作输出内容,导致 header 发送失败,浏览器 fallback 到 ISO-8859-1 解析,所有中文全乱。
- 用命令检查:
xxd app/lang/zh-cn.php | head -1,开头有ef bb bf就带 BOM - VS Code 右下角点击编码 → “Save with Encoding” → 选 UTF-8(不带 BOM)
- Notepad++:编码 → 转为 UTF-8 无 BOM 格式 → 保存
- 整个
app/和lang/目录下所有 .php 文件都需统一处理
二、数据库连接必须硬写 utf8mb4,不能只靠 config 配置
ThinkPHP 5/6 的 'charset' => 'utf8mb4' 在 database.php 中基本无效——尤其你手动写了 dsn 字段时,该配置直接被跳过;旧版 mysqlnd 驱动也不认它。
- 删掉
database.php中所有'charset' => ...行,避免干扰 - 在
'dsn'字段中显式写死:'dsn' => 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4' - MySQL 服务端也必须是 utf8mb4:
SHOW VARIABLES LIKE 'character_set_server';返回值应为utf8mb4,否则改my.cnf加character-set-server = utf8mb4并重启 - 连接建立后补执行:
Db::connect()->execute('SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci');(放在app/common.php或连接回调里)
三、导出类功能(Excel/CSV)要清缓冲 + 补 BOM
导出乱码几乎都源于输出缓冲区残留内容(空格、HTML、BOM、调试日志),它们会污染文件头,破坏 Excel 二进制结构或让 CSV 被 Excel 错当 GBK 解析。
立即学习“PHP免费学习笔记(深入)”;
- 导出方法第一行必须加:
ob_end_clean();(不是ob_clean(),也不是ob_flush()) - CSV 导出前需手动写入 UTF-8 BOM:
echo "\xEF\xBB\xBF";,再调fputcsv() - Excel(.xlsx)不用加 BOM,但确保 PhpSpreadsheet 生成的字符串是原生 UTF-8;若仍乱码,检查数据库查询结果是否已为乱码字节(可用
Db::query("SELECT CHARSET('你好')")验证) - 别写
header('Content-Type: text/html; charset=utf-8'),这对 Excel/CSV 完全无效,反而可能干扰解析
四、语言包与模板渲染需避免编码上下文污染
ThinkPHP 语言包是 PHP 数组文件,加载过程不走转码逻辑。一旦文件是 GBK 编码,或中间件中执行过 mb_internal_encoding('GBK'),Lang::get() 返回的就是错解字节。
- 批量检测语言文件编码:
find lang -name "*.php" -exec file -i {} \;,确保每行含charset=utf-8 - 批量转码(Linux/macOS):
find lang -name "*.php" -exec iconv -f gbk -t utf-8 {} -o {}.utf8 \; && rename 's/\.utf8$//' lang/**/*.php.utf8 - 检查是否有中间件或钩子调用了
mb_internal_encoding(),删掉或统一设为UTF-8 - 模板中若用
include引入非 UTF-8 文件,也会污染;建议全部模板统一为 UTF-8 无 BOM



















