php中文乱码需全链路utf-8统一:文件存为utf-8无bom,php开头设header(‘content-type: text/html; charset=utf-8’),mb_internal_encoding(‘utf-8’),数据库连接用charset=utf8mb4,模板引擎显式指定utf-8,web服务器禁用冲突charset指令。

PHP脚本本身没设UTF-8,echo中文就乱码
PHP文件保存为UTF-8无BOM格式只是基础,关键还得告诉PHP「我用的是UTF-8」。否则echo、print输出中文时,浏览器可能按ISO-8859-1解析,显示成或一堆问号。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在PHP文件最开头(任何输出之前)加
header('Content-Type: text/html; charset=utf-8'); - 如果用了
mb_internal_encoding(),统一设为mb_internal_encoding('UTF-8');,避免mb_substr等函数内部编码不一致 - 检查
php.ini里default_charset是否为"UTF-8"(不是utf8,注意连字符)
Twig/Smarty/Blade模板里中文变方块或问号
模板引擎本身不决定编码,它只是把变量插进HTML里——乱码根源通常是:PHP传给模板的数据已损坏,或模板输出未声明charset,或HTML meta缺失。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- Twig:确保
TwigEnvironment创建时charset选项设为'utf-8',例如:new Environment($loader, ['charset' => 'UTF-8']) - Smarty:调用
$smarty->setEncoding('UTF-8')(v3+),并确认$smarty->template_dir下所有.tpl文件都是UTF-8无BOM - Blade:laravel默认已配好UTF-8,但若手动
echo $content前做过iconv或mb_convert_encoding,要确认目标编码是UTF-8而非UTF8(少横线会失败)
数据库查出的中文在模板里显示乱码
这是最隐蔽的乱码链:mysql连接编码 ≠ 表字段编码 ≠ PHP处理编码。即使页面和模板都设了UTF-8,只要pdo/mysqli连接没指定charset=utf8mb4,查出来的字符串实际是latin1编码的二进制流。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- PDO连接DSN里必须显式加
;charset=utf8mb4,例如:mysql:host=localhost;dbname=test;charset=utf8mb4 - MySQLi连接后立即执行
$mysqli->set_charset('utf8mb4')(不能只靠SET NAMES utf8mb4) - 检查表结构:
SHOW CREATE table xxx中字段是否带CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 避免用
mysql_query("SET NAMES utf8")(已废弃且不等价于utf8mb4)
apache/nginx返回头里charset被覆盖
即使PHP写了header('Content-Type: text/html; charset=utf-8'),Web服务器可能在响应头里强行加了别的charset(比如Apache的AddDefaultCharset ISO-8859-1),导致浏览器忽略PHP的声明。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- Apache:检查
httpd.conf或.htaccess里有没有AddDefaultCharset,删掉或改为AddDefaultCharset UTF-8 - Nginx:确认
server或location块里没有charset GBK;这类配置;如有charset指令,设为charset utf-8; - 用浏览器开发者工具→Network→Response Headers,直接看最终返回的
Content-Type值,以这个为准
真正卡住人的往往不是某个单一设置,而是UTF-8在「文件保存→PHP运行时→数据库连接→模板渲染→HTTP响应头→浏览器解析」这条链上,任意一环写成utf8(无横线)、UTF8(大小写混)、utf8mb4(但前端没配)或漏掉no BOM,都会让中文突然变成乱码。逐段验证比盲目加mb_convert_encoding更有效。