mb_convert_variables 直接修改 $_POST 或模型数组更安全简洁,专为批量转码设计,避免手动递归漏洞;需确保 mbstring 启用,优先于 mb_convert_encoding 递归方案。

mb_convert_variables 直接改 $_POST 或模型数据数组,比手动遍历安全、简洁,且不依赖 eval。
用 mb_convert_variables 批量转模型或请求数组
ThinkPHP 中接收的 $_POST、$_GET 或控制器传入的关联数组,若原始编码是 GBK/GB2312,而项目统一用 UTF-8,最稳妥的方式不是逐层递归调用 mb_convert_encoding,而是用 PHP 原生的 mb_convert_variables ——它专为多变量批量转码设计,且直接修改原变量引用。
常见错误现象:mb_convert_encoding($arr, 'UTF-8', 'GBK') 对整个数组调用会失败(该函数只接受字符串),导致 Warning 或返回空;手动递归又容易漏掉深层嵌套或跳过 null/false 值。
实操建议:
- 确保
mbstring扩展已启用,且mb_internal_encoding()设为UTF-8(非必须但推荐) - 在控制器入口或中间件中尽早处理,例如:
mb_convert_variables('UTF-8', 'GBK', $_POST, $_GET) - 对 ThinkPHP 的模型数据(如
$data = input('post.')返回的数组),可直接传引用:mb_convert_variables('UTF-8', 'GBK', $data) - 该函数跳过对象、资源、闭包,不报错也不警告,所以别指望它处理 Eloquent 模型实例
mb_convert_encoding 递归处理需加类型防护
如果必须用 mb_convert_encoding(比如要兼容某些非标准编码或做条件过滤),就得自己写递归函数。但 ThinkPHP 的数组常含空值、数字、布尔、甚至 null 键,裸调 iconv 或 mb_convert_encoding 会触发 “Illegal character encoding” 警告。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 只对
is_string($value) && $value !== ''的值调用转换,跳过数字、布尔、null - 避免用
iconv:它对无效字节默认失败,而mb_convert_encoding支持//IGNORE和//TRANSLIT后缀,例如:mb_convert_encoding($v, 'UTF-8', 'GBK//IGNORE') - 检测源编码不可靠,别盲目用
mb_detect_encoding($v, ['UTF-8','GBK','BIG5'], true)—— 中文标点或纯 ASCII 内容常误判为 UTF-8 - ThinkPHP 的
input()已做过基础过滤,若已开启default_filter,重复转码可能造成二次乱码
文件级批量转码别在运行时做
有人把 ThinkPHP 控制器当脚本用,在 action 里遍历 ./app 下所有 PHP 文件调用 mb_convert_encoding 再 file_put_contents —— 这属于开发期任务,不该放线上运行时执行。
实操建议:
- 用命令行一次性完成:
find ./app -name "*.php" -exec iconv -f GBK -t UTF-8 {} -o {}.utf8 \;,再批量替换后缀并校验 BOM - 若必须用 PHP 脚本,单独写
convert-encoding.php放在think根目录下,通过php convert-encoding.php手动触发,而非走 HTTP 请求 - 大文件(>2MB)必须分块读取,
file_get_contents容易 OOM;小文件也建议加is_readable()和is_writable()检查,否则静默失败 - ThinkPHP 的模板文件(
.html)、语言包(.php数组)也要纳入转码范围,否则lang('xxx')取出仍是乱码
JSON 输出前的编码陷阱
ThinkPHP 常用 json() 方法返回响应,但若数组字段本身是 GBK 编码,json_encode() 会直接报错或输出空字符串 —— 它只接受 UTF-8 字符串。
实操建议:
- 不要等
json()报错才处理,应在组装返回数组前就完成转码,例如:$data = mb_convert_variables('UTF-8', 'GBK', $rawData) - 避免用
json_encode(..., JSON_UNESCAPED_UNICODE)掩盖问题:它只是让中文不转义,但解决不了源数据非 UTF-8 的根本矛盾 - 调试时用
mb_check_encoding($str, 'UTF-8')快速验证单个字段,比看json_last_error_msg()更早定位坏数据 - 数据库连接层(如
mysql.charset=utf8mb4)和 HTTP header(Content-Type: application/json; charset=utf-8)必须与 PHP 数组编码一致,三者错一个,前端就显示
var_dump(mb_detect_encoding($value)) 看一眼原始字节,比猜编码靠谱得多。



















