PHP 5.2 引入 JSON 擴展,但 json_encode 對中文處理存在兩大痛點:GBK/GB2312 編碼字符串直接返回空字符;UTF-8 中文被轉為 Unicode 轉義序列(如 \u4e2d\u6587),導致傳輸體積增大、前端解析麻煩。本文提供多種兼容方案。
false 或空字符JSON_UNESCAPED_UNICODE 選項<?php
/**
* JSON 兼容處理類
* 解決:GBK 轉 UTF-8、Unicode 轉義還原為中文
*/
class Json {
/**
* 編碼:自動處理編碼轉換 + Unicode 還原
* @param mixed $data 待編碼數據(支援陣列、物件、字符串)
* @param string $inputCharset 輸入數據編碼,預設 UTF-8
* @return string JSON 字符串
*/
public static function encode($data, $inputCharset = 'UTF-8') {
// 1. 統一轉為 UTF-8
if (strtoupper($inputCharset) !== 'UTF-8') {
$data = self::convertToUtf8($data, $inputCharset);
}
// 2. json_encode
$json = json_encode($data);
// 3. 將 \uXXXX 還原為 UTF-8 字符(PHP 5.2/5.3 核心技巧)
// 使用 preg_replace_callback 避免已棄用的 /e 修飾符
$json = preg_replace_callback(
'/\\\\u([0-9a-fA-F]{4})/',
function ($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE');
},
$json
);
return $json;
}
/**
* 解碼:自動處理編碼
*/
public static function decode($json, $outputCharset = 'UTF-8') {
$data = json_decode($json, true);
if (strtoupper($outputCharset) !== 'UTF-8') {
$data = self::convertFromUtf8($data, $outputCharset);
}
return $data;
}
// 遞歸轉換陣列/物件編碼到 UTF-8
private static function convertToUtf8($data, $fromCharset) {
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = self::convertToUtf8($val, $fromCharset);
}
return $data;
} elseif (is_object($data)) {
foreach ($data as $key => $val) {
$data->$key = self::convertToUtf8($val, $fromCharset);
}
return $data;
} elseif (is_string($data)) {
return mb_convert_encoding($data, 'UTF-8', $fromCharset);
}
return $data;
}
// 遞歸轉換 UTF-8 到目標編碼
private static function convertFromUtf8($data, $toCharset) {
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = self::convertFromUtf8($val, $toCharset);
}
return $data;
} elseif (is_object($data)) {
foreach ($data as $key => $val) {
$data->$key = self::convertFromUtf8($val, $toCharset);
}
return $data;
} elseif (is_string($data)) {
return mb_convert_encoding($data, $toCharset, 'UTF-8');
}
return $data;
}
}
// 使用示例
$arr = ['name' => '中文測試', 'city' => '北京'];
// GBK 環境下
echo Json::encode($arr, 'GBK');
// 輸出: {"name":"中文測試","city":"北京"} 而非 {"name":"\u4e2d\u6587\u6d4b\u8bd5",...}
若無法升級 PHP 或修改後端,可在前端接收後處理:
<script>
// 將 \uXXXX 還原為中文
function unicodeToChinese(str) {
return str.replace(/\\u([0-9a-fA-F]{4})/g, function (match, grp) {
return String.fromCharCode(parseInt(grp, 16));
});
}
// 使用
var jsonStr = '{"name":"\\u4e2d\\u6587","city":"\\u5317\\u4eac"}';
var obj = JSON.parse(jsonStr);
obj.name = unicodeToChinese(obj.name); // "中文"
obj.city = unicodeToChinese(obj.city); // "北京"
</script>
<?php
// PHP 5.4+ 直接支援
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// 完整選項說明
$options = 0;
$options |= JSON_UNESCAPED_UNICODE; // 不轉義 Unicode,直接輸出中文
$options |= JSON_UNESCAPED_SLASHES; // 不轉義 /
$options |= JSON_NUMERIC_CHECK; // 數值字符串轉為數字
$options |= JSON_PRETTY_PRINT; // 格式化輸出(調試用)
$json = json_encode($data, $options);
<?php
// 編碼前強制轉 UTF-8
function jsonEncodeCompat($data, $inputCharset = 'UTF-8') {
if (strtoupper($inputCharset) !== 'UTF-8') {
$data = mb_convert_encoding($data, 'UTF-8', $inputCharset);
}
// PHP 5.3+ 可用 JSON_FORCE_OBJECT 等選項
return json_encode($data);
}
// 解碼後轉回目標編碼
function jsonDecodeCompat($json, $outputCharset = 'UTF-8') {
$data = json_decode($json, true);
if (strtoupper($outputCharset) !== 'UTF-8') {
$data = mb_convert_encoding($data, $outputCharset, 'UTF-8');
}
return $data;
}
| 場景 | 建議方案 | 關鍵點 |
|---|---|---|
| 新項目/可升級 PHP | 升級至 PHP 7.4+,使用 JSON_UNESCAPED_UNICODE | 原生支援、效能最佳、維護成本最低 |
| 維護老項目 PHP 5.2/5.3 | 封裝 Json 類(方案一) | 統一入口、自動處理編碼、前端無感知 |
| 無法修改後端 | 前端 JS 還原 Unicode | 零後端改動、適用第三方 API |
| 混合編碼環境 | 統一內部使用 UTF-8,邊界處轉換 | 資料庫、模板、API 統一 UTF-8,避免亂碼源頭 |
mb_convert_encoding($str, 'UTF-8', 'GBK')preg_replace /e 修飾符 → PHP 7.0+ 已移除,必須用 preg_replace_callback<meta charset="utf-8"> → 瀏覽器正確解碼JSON 中文處理的核心原則是:內部統一 UTF-8,邊界自動轉換。PHP 5.2/5.3 時代雖有缺陷,但通過封裝類或前端輔助可完美解決。現代項目請務必升級 PHP 版本,享受原生 JSON_UNESCAPED_UNICODE 帶來的簡潔與高效。