为何json_encode返回空字符串?PHP嵌套数组转JSON遇UTF-8编码问题
解决PHP嵌套数组json_encode返回JSON_ERROR_UTF8的问题
问题描述
有一个3层嵌套的普通PHP数组,通过两层循环构建,未使用特殊对象,var_dump输出结构如下:
array (size=2) 'tram B' => array (size=2) 0 => array (size=3) 'name' => string 'Ile Verte' (length=9) 'distance' => int 298 'stationID' => int 762 1 => array (size=3) 'name' => string 'La Tronche Hôpital' (length=18) 'distance' => int 425 'stationID' => int 771 16 => array (size=4) 0 => array (size=3) 'name' => string 'Bastille' (length=8) 'distance' => int 531 'stationID' => int 397 1 => array (size=3) 'name' => string 'Xavier Jouvin' (length=13) 'distance' => int 589 'stationID' => int 438
其他同结构数组能正常json_encode,但该数组编码失败。排查发现:当mb_detect_encoding返回ASCII时编码正常,返回UTF-8则失效;json_last_error()返回JSON_ERROR_UTF8,说明存在格式错误的UTF-8字符。
原因分析
JSON规范要求所有字符串必须是有效UTF-8编码,出现JSON_ERROR_UTF8通常是两种情况:
- 字符串实际是其他编码(比如ISO-8859-1、GBK),却被当作UTF-8处理
- UTF-8字符串存在截断、字节损坏的情况(比如读取文件时未完整获取)
从数组里的La Tronche Hôpital包含特殊字符ô来看,很大概率是这类特殊字符的编码格式不规范导致的。
解决办法
1. 递归修复数组所有字符串的UTF-8编码
写一个递归函数遍历数组,把所有字符串转成标准UTF-8,同时过滤无效字节:
function fixUtf8($data) { if (is_array($data)) { foreach ($data as $k => $v) { $data[$k] = fixUtf8($v); } return $data; } elseif (is_string($data)) { // 先尝试从ISO-8859-1转UTF-8,失败则清理无效字符 $fixed = mb_convert_encoding($data, 'UTF-8', 'ISO-8859-1'); if (!$fixed) { $fixed = preg_replace('/[\x00-\x1F\x7F-\xFF]/u', '', $data); } return $fixed; } return $data; } // 修复后再转JSON $fixedArr = fixUtf8($originalArr); $json = json_encode($fixedArr);
2. 强制生成JSON(适合临时调试)
如果想保留尽可能多的数据,可以用JSON_PARTIAL_OUTPUT_ON_ERROR参数跳过错误字符,配合JSON_UNESCAPED_UNICODE保留原字符:
$json = json_encode($originalArr, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
注意:这个方法会丢失错误字符,不建议生产环境使用。
3. 从源头修正编码
如果数组来自数据库、文件或外部接口,先确认数据源编码:
- 从MySQL读取时,设置连接编码为utf8mb4:
mysqli_set_charset($dbConn, 'utf8mb4'); - 读取文件时,指定正确的源编码转成UTF-8:
$content = file_get_contents('data.txt'); // 假设源文件是ISO-8859-1,根据实际情况调整 $content = mb_convert_encoding($content, 'UTF-8', 'ISO-8859-1');
验证修复结果
修复后可以用以下代码确认:
// 检查特殊字符的编码 echo mb_detect_encoding($fixedArr['tram B'][1]['name'], 'UTF-8,ISO-8859-1', true); // 确认JSON编码是否成功 $json = json_encode($fixedArr); if ($json === false) { echo json_last_error_msg(); } else { echo $json; }
内容的提问来源于stack exchange,提问作者LegendaryDev320
相关产品推荐
相关产品推荐

