PHP乱码根源在于文件编码、HTTP响应头与HTML声明、数据库编码三者不一致;须统一为UTF-8无BOM、header声明charset=utf-8、MySQL用utf8mb4并同步连接与表结构编码。

PHP 文件本身不强制指定编码格式,乱码问题几乎都出在「文件保存编码」和「HTTP 响应头 / HTML meta 声明」不一致上。统一改 PHP 编码格式,核心是三件事:确保源文件存为 UTF-8 无 BOM,PHP 输出时声明 UTF-8,HTML 页面也声明 UTF-8。
用编辑器批量转存为 UTF-8 无 BOM
很多乱码根源是 PHP 文件被保存成了 GBK、GBK2312 或 UTF-8 with BOM。BOM(\xEF\xBB\xBF)会提前输出三个字节,导致 header() 报“headers already sent”错误,也干扰 JSON 输出。
- VS Code:右下角点击编码名称(如“GBK”或“UTF-8”),选
Save with Encoding→UTF-8(注意勾掉Include BOM) - Sublime Text:
File→Save with Encoding→UTF-8(不是 “UTF-8 with BOM”) - 命令行批量处理(Linux/macOS):
iconv -f GBK -t UTF-8//IGNORE file.php > file_utf8.php,再替换原文件;推荐用recode或uconv更稳妥 - Windows 记事本务必弃用——它默认保存为 ANSI(即本地编码),极易引入乱码
PHP 输出前强制设置 Content-Type 和字符集
即使文件是 UTF-8,若 PHP 没告诉浏览器“这是 UTF-8”,浏览器可能按 ISO-8859-1 或系统默认编码解析,中文就变问号或方块。
- 在所有输出内容前(最好在入口文件开头)加:
header('Content-Type: text/html; charset=utf-8'); - 如果用了框架(如 Laravel、ThinkPHP),检查配置中是否覆盖了默认 header;Laravel 的
App\Http\Kernel中中间件可能影响输出顺序 - 避免在
header()前有任何输出:包括空格、echo、BOM、甚至文件末尾多出的换行 - CLI 脚本不用设这个 header,但涉及数据库读写时,需单独设置连接编码(见下一条)
数据库连接与字段编码必须同步为 utf8mb4
PHP 文件和响应头都是 UTF-8,但 MySQL 连接或表字段仍是 latin1 或 utf8(MySQL 的 utf8 实为 utf8mb3,不支持 emoji 和部分生僻汉字),照样显示乱码。
立即学习“PHP免费学习笔记(深入)”;
- 连接时显式指定编码:
mysqli_set_charset($conn, 'utf8mb4')或 PDO DSN 加;charset=utf8mb4 - 建表语句中明确指定:
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - 检查现有表:用
SHOW CREATE TABLE table_name看CHARSET和COLLATION,不是utf8mb4就要ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - MySQL 配置文件(
my.cnf)中全局设collation-server = utf8mb4_unicode_ci和character-set-server = utf8mb4,避免新库/表继承旧编码
真正容易被忽略的是「三处编码必须同时对齐」:PHP 源文件编码、HTTP 响应头声明、MySQL 连接+表结构编码。少一处,就可能在某个环节(比如用户提交表单、读取旧数据、AJAX 返回 JSON)突然冒出乱码,而且现象不固定——有时正常有时错位,排查起来特别耗时间。











