必须统一数据库、连接、脚本、输出四层字符集为utf8mb4;mysql库表需显式设utf8mb4,php连接须声明charset=utf8mb4,文件须存为utf-8无bom,http头与html meta须同步声明utf-8。

必须统一数据库、连接、脚本、输出四层的字符集,缺一不可;只改其中一层,乱码照旧。
MySQL数据库和表必须用 utf8mb4,不是 utf8
MySQL 的 utf8 是个历史坑——它实际只支持最多 3 字节的 UTF-8 字符(不支持 emoji、部分生僻汉字、数学符号等),而 utf8mb4 才是真正的 UTF-8 实现。
- 建库时显式指定:
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 查当前库字符集:
SHOW CREATE DATABASE mydb;,确认结果里是utf8mb4而非utf8 - 查某张表:
SHOW CREATE TABLE users;,若显示DEFAULT CHARSET=utf8,就立刻执行:ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 字段级也可单独设,比如
content TEXT CHARACTER SET utf8mb4,但整表转换更省事
PHP 连接 MySQL 时必须声明 utf8mb4 字符集
即使数据库本身是 utf8mb4,PHP 连接默认可能走 latin1 或 utf8 协议层,导致读写全程“翻译错位”。
- mysqli 方式:连接后**立即**调用
$mysqli->set_charset('utf8mb4');,不能漏、不能晚 - PDO 方式:DSN 中必须带
;charset=utf8mb4,例如:$dsn = "mysql:host=localhost;dbname=mydb;charset=utf8mb4"; - PDO 还建议加配置:
PDO::ATTR_EMULATE_PREPARES => false,否则预处理语句可能绕过字符集设置 - 验证是否生效:
var_dump($mysqli->character_set_name());应返回utf8mb4;PDO 可查$pdo->getAttribute(PDO::ATTR_CLIENT_VERSION)并结合实际查询测试
PHP 文件本身必须存为 UTF-8 without BOM
BOM(\xEF\xBB\xBF)是隐藏在文件开头的三个字节,PHP 解析时会把它当普通输出,导致 headers already sent 错误,进而让 header('Content-Type: text/html; charset=utf-8') 失效。
- VS Code:右下角点击编码名 → 选 “Save with Encoding” → 选 “UTF-8”(注意不是 “UTF-8 with BOM”)
- Notepad++:“编码”菜单 → “转为 UTF-8 无 BOM 格式”
- Linux 命令行批量去 BOM:
sed -i '1s/^\xEF\xBB\xBF//' *.php - 检查是否残留 BOM:
file -i your_script.php,输出含bom就还没清干净
HTTP 输出头和 HTML <meta> 必须同步声明 utf-8
浏览器靠响应头 Content-Type 主导解码,<meta charset="utf-8"> 是 fallback。两者不一致或缺失任一,都可能在 CDN、代理、旧浏览器下出问题。
-
header('Content-Type: text/html; charset=utf-8');必须出现在任何echo、print、HTML 输出之前,且前面不能有空格、空行、BOM -
<meta charset="utf-8">必须放在最开头,紧贴标签后,前面不能有注释或空格 - 用
curl -I http://yoursite.com/test.php检查响应头,确认Content-Type确实含charset=utf-8 - 如果用了
require引入其他 PHP 文件,要确保那些文件也全是UTF-8 without BOM,否则引入即触发 headers 已发送
最常被忽略的是「连接层字符集」和「文件 BOM」这两处:前者让数据进错管道,后者让 header 直接失效——它们不出错时一切正常,一出就是全链路乱码,排查起来特别费时间。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











