php编码需分层控制:web服务器设默认字符集,php运行时用mb_internal_encoding()和ini_set()锁定编码,输出前用header()声明,数据库连接单独设置charset,关键函数显式传编码参数。

PHP加编码的常规做法:别只靠header()函数
PHP输出内容前必须明确告知浏览器用什么编码,否则中文会乱码。最直接的方式是用 header() 发送 Content-Type,但这个操作有严格前提:响应头必须在任何输出之前发送。
常见翻车点:echo、空格、BOM头、甚至文件开头的UTF-8 BOM都会导致 Cannot modify header information 错误。
- 确保PHP文件本身保存为「UTF-8 无BOM」格式(编辑器里要选对)
-
header('Content-Type: text/html; charset=utf-8');必须放在所有echo、print、HTML输出之前 - 如果用了模板引擎或框架(如Laravel、ThinkPHP),优先走框架的编码配置,而不是手写
header() - CLI模式下
header()无效,此时编码由终端环境决定,PHP内部字符串仍建议统一用UTF-8
多站点共用PHP时编码冲突的根本原因
不是PHP本身不支持多编码,而是Apache/Nginx + PHP-FPM的配置粒度不够细,容易让不同站点共用同一套PHP全局设置,比如 default_charset 或输出缓冲行为。
典型冲突场景:站点A要求UTF-8,站点B legacy系统用GBK,但PHP的 default_charset = "UTF-8" 在php.ini里全局生效,导致站点B的header被强行覆盖,或mbstring函数默认按UTF-8处理字节,造成截断。
立即学习“PHP免费学习笔记(深入)”;
- 检查
phpinfo()中default_charset值,它会影响htmlspecialchars()、htmlentities()等函数的默认编码 - 不要依赖
ini_set('default_charset', 'gbk')—— 它在某些SAPI(如CGI)下无效,且不能动态改写已发送的header - 各站点的入口文件(如
index.php)应主动调用mb_internal_encoding('UTF-8')或对应编码,而非仰赖php.ini
解决多站点编码隔离:从Web服务器到PHP层分段控制
关键思路是「分站配置,逐层兜底」:Nginx/Apache按server/vhost指定默认字符集,PHP层再用运行时函数锁定内部编码,最后输出前显式声明。
- Nginx中每个
server块加:charset utf-8;(仅影响静态资源和未设header的响应) - Apache中每个
<virtualhost></virtualhost>加:AddDefaultCharset UTF-8(同上,不覆盖PHP已发的header) - PHP-FPM池(
www.conf)可为不同站点配独立pool,通过php_admin_value[default_charset] = "UTF-8"隔离 - 业务代码里,入口处统一执行:
mb_internal_encoding('UTF-8'); ini_set('default_charset', 'UTF-8');,避免依赖全局配置
绕过编码冲突的务实策略:用mb_*函数代替原生函数
当无法完全控制环境(比如共享主机、老旧运维体系),最稳的方式是放弃对 default_charset 的依赖,所有涉及字符处理的地方显式传编码参数。
- 不用
strlen($str),改用mb_strlen($str, 'UTF-8') - 不用
substr($str, 0, 10),改用mb_substr($str, 0, 10, 'UTF-8') -
json_encode()默认只认UTF-8,若输入含GBK需先转码:json_encode(mb_convert_encoding($data, 'UTF-8', 'GBK')) - 数据库连接必须单独设编码:
$pdo->exec("SET NAMES utf8mb4");或在DSN里加;charset=utf8mb4
真正麻烦的从来不是“怎么加编码”,而是“哪一层该负责哪一段编码”——Web服务器管响应头,PHP运行时管字符串处理,数据库驱动管数据流,三者脱节时,光调一个 header() 没用。











