PHP脚本需显式设置Content-Type响应头charset参数并确保源文件UTF-8无BOM,同时统一mbstring内部编码与数据库连接编码(utf8mb4),HTML meta仅作备用。

PHP 脚本本身不自动声明或强制输出字符编码,必须显式设置 Content-Type 响应头 + 正确声明内部编码,否则浏览器很可能乱码,尤其在中文、日文等多字节场景下。
header() 中设置 Content-Type 的 charset 参数
这是最直接控制浏览器解码方式的手段。仅靠 mb_internal_encoding() 或文件保存格式无法让浏览器正确显示。
- 必须在任何输出(包括空白符)之前调用
header(),否则会触发Warning: Cannot modify header information - 推荐写法:
header('Content-Type: text/html; charset=utf-8');—— 注意charset小写,utf-8连字符不能省略 - 若输出 JSON,应改用:
header('Content-Type: application/json; charset=utf-8'); - 不要写成
UTF8或UTF-8(首字母大写),部分旧版 IE 对大小写敏感
确保 PHP 源文件本身是 UTF-8 无 BOM 编码
编辑器保存格式错误会导致开头隐式输出 BOM 字节,破坏 header() 调用,且不易排查。
- 用 VS Code、Sublime Text 或 Notepad++ 打开文件,检查右下角编码标识,选“UTF-8”而非“UTF-8 with BOM”
- Linux/macOS 下可用命令验证:
file -i your_script.php,输出含charset=utf-8即可 - 若已有 BOM,用
sed -i '1s/^\xEF\xBB\xBF//' your_script.php清除(仅限 Linux/macOS)
统一 mbstring 内部编码与数据库连接编码
PHP 处理字符串(如截取、查找)时,mb_* 函数依赖 mb_internal_encoding();而 MySQL 查询结果编码取决于连接层设置,两者不一致会引发隐性乱码。
立即学习“PHP免费学习笔记(深入)”;
- 在脚本开头统一设为 UTF-8:
mb_internal_encoding('UTF-8'); - MySQLi 连接后立即执行:
$mysqli->set_charset('utf8mb4');(注意是utf8mb4,不是utf8) - PDO 需在 DSN 中指定:
mysql:host=localhost;dbname=test;charset=utf8mb4,并禁用PDO::ATTR_EMULATE_PREPARES - 避免混用
iconv()和mb_convert_encoding()—— 同一项目只选一种多字节处理方案
HTML meta 标签只是 fallback,不可替代 header
当 HTTP 响应头缺失或错误时,浏览器才退而求其次读取 <meta charset="utf-8">。它不能修复已发生的输出中断或 header 冲突。
- 必须放在
<head>最前面,且只能出现一次 - 写法严格限定为:
<meta charset="utf-8">(小写、无引号也可,但双引号最稳妥) - 不要写成
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">—— 已被现代标准弃用,兼容性差
真正容易被忽略的是:数据库字段本身的字符集(如 utf8mb4_unicode_ci)和排序规则必须匹配连接设置,否则即便 PHP 层全对,SELECT 出来的数据仍是乱码。这个环节常被跳过,却直接决定最终呈现效果。



















