<?php
$arr = ['msg' => '中文內容'];
echo json_encode($arr);
// 輸出: {"msg":"\u4e2d\u6587\u5185\u5bb9"}
// 中文被轉為 Unicode 轉義序列,難以閱讀、調試困難
<?php
$arr = ['msg' => '中文內容'];
echo json_encode($arr, JSON_UNESCAPED_UNICODE);
// 輸出: {"msg":"中文內容"}
// 直接輸出 UTF-8 字符,可讀性最佳
<?php
$options = JSON_UNESCAPED_UNICODE // 中文不轉義
| JSON_UNESCAPED_SLASHES // 斜線不轉義 \/ -> /
| JSON_PRETTY_PRINT // 格式化縮排(開發/日誌用)
| JSON_NUMERIC_CHECK; // 數字字符串自動轉數字
$data = [
'url' => 'https://example.com/path',
'price' => '199.00',
'title' => '中文標題',
];
echo json_encode($data, $options);
利用 urlencode 繞過內建 Unicode 轉義:
<?php
function jsonEncodeChinese(array $data): string
{
// 1. 遞歸 urlencode 所有字符串值
array_walk_recursive($data, function (&$value) {
if (is_string($value)) {
$value = urlencode($value);
}
});
// 2. json_encode(此時中文已為 %E4%B8%AD%EF%BC%88... 形式,不會被再次轉義)
$json = json_encode($data);
// 3. urldecode 還原中文
return urldecode($json);
}
$arr = ['msg' => '中文內容'];
echo jsonEncodeChinese($arr); // {"msg":"中文內容"}
json_encode 遇到非 ASCII 字符預設輸出 \uXXXX。urlencode 將中文編碼為 %XX%XX 形式(ASCII 字符),json_encode 視為普通字符串不再轉義。urldecode 還原為 UTF-8 中文。<?php
// MySQL 5.7+ JSON 字段直接存入
$pdo->prepare('INSERT INTO logs (data) VALUES (?)')
->execute([json_encode($data, JSON_UNESCAPED_UNICODE)]);
// 查詢時
$row = $pdo->query('SELECT data FROM logs WHERE id=1')->fetch();
$data = json_decode($row['data'], true); // 直接得到中文
<?php
// PHP 端
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// JS 端
fetch('/api/data')
.then(r => r.json())
.then(data => console.log(data.title)); // 直接顯示中文,無需 decode
<?php
function streamJsonArray(iterable $items): Generator
{
yield '[';
$first = true;
foreach ($items as $item) {
if (!$first) yield ',';
// 單項編碼時加上旗標
yield json_encode($item, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$first = false;
}
yield ']';
}
header('Content-Type: application/json; charset=utf-8');
foreach (streamJsonArray($hugeDataset) as $chunk) {
echo $chunk;
@ob_flush(); @flush();
}
<?php
$data = ['emoji' => '😀🎉', 'rare' => '𠮷']; // U+20BB7
// PHP 7.0+ 完美支援 UTF-8 (包括 4 字節字符)
echo json_encode($data, JSON_UNESCAPED_UNICODE);
// {"emoji":"😀🎉","rare":"𠮷"}
// PHP 5.6 及以下可能需 mbstring 且注意編碼設置
| 誤區 | 正確做法 |
|---|---|
用 preg_replace('/\\\\u([0-9a-f]{4})/i', ...) 後處理 |
直接用 JSON_UNESCAPED_UNICODE,效能高、無 Bug |
以為 JSON_UNESCAPED_UNICODE 會導致安全問題 |
只影響輸出編碼,不改變數據內容;配合 Content-Type: charset=utf-8 完全安全 |
存入 MySQL 前先 addslashes |
使用預處理語句,無需手動轉義 |
| API 返回未設置 charset | 必須 header('Content-Type: application/json; charset=utf-8') |
| PHP 版本 | JSON_UNESCAPED_UNICODE | 備註 |
|---|---|---|
| 5.4.0+ | ✅ 完整支援 | 推薦最低版本 |
| 5.3.x | ❌ 不支援 | 用 urlencode 技巧 |
| 7.0+ | ✅ 完整支援 | 更好的 UTF-8/錯誤處理 |
| 8.0+ | ✅ 完整支援 | 更嚴格的類型、異常而非警告 |
結論:PHP 5.4+ 直接使用 JSON_UNESCAPED_UNICODE 旗標,簡潔、高效、標準;舊版本才需 urlencode 繞過技巧。始終設置正確的 HTTP Header 字符集,確保全鏈路 UTF-8 一致性。