相同编码与字符集配置下utf8_encode返回结果不同是什么原因
问题排查结论
乱码本质
生产环境返回的ção是典型的UTF-8二次编码现象:
正确UTF-8编码的ç对应字节为0xC3 0xA7,如果把这两个字节当作ISO-8859-1编码的单个字符,再次执行UTF-8转码,就会生成ç的乱码结果。
这说明两个环境中传入utf8_encode()的$str本身编码并不一致:
- 开发环境的
$str是ISO-8859-1编码,执行utf8_encode()转UTF-8后结果正常 - 生产环境的
$str已经是UTF-8编码,重复执行转码操作导致乱码
遗漏的配置项
你漏掉了PHP与MySQL连接层的默认字符集配置,对应php.ini中的两个参数:
mysqli.default_charset:mysqli扩展连接MySQL时的默认字符集pdo_mysql.default_charset:PDO扩展连接MySQL时的默认字符集
版本差异是问题根源
两个PHP版本的默认配置存在差异:
- PHP 7.1版本中,上述两个参数的默认值为
latin1,MySQL查询返回的字符串会以ISO-8859-1编码交给PHP,刚好匹配utf8_encode()的输入要求 - PHP 7.2版本中,上述两个参数的默认值调整为
UTF-8,MySQL查询返回的字符串本身就是UTF-8编码,不需要再执行转码
修复建议
- 不要依赖PHP默认的连接字符集,在代码中显式指定连接字符集:
- mysqli扩展:连接后执行
mysqli_set_charset($conn, 'utf8mb4') - PDO扩展:在DSN中添加
charset=utf8mb4参数
- mysqli扩展:连接后执行
- 弃用
utf8_encode()函数,改用mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1')显式指定编码转换规则,避免隐式转换带来的不可控问题。
内容的提问来源于stack exchange,提问作者Libania Paes
相关产品推荐
相关产品推荐

