首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 輸出中文 JSON 不轉義:JSON_UNESCAPED_UNICODE 與 urlencode 技巧完整指南

     編輯:PHP 相關知識

問題現象

<?php
$arr = ['msg' => '中文內容'];
echo json_encode($arr);
// 輸出: {"msg":"\u4e2d\u6587\u5185\u5bb9"}
// 中文被轉為 Unicode 轉義序列,難以閱讀、調試困難

現代標準解法(PHP 5.4+)

<?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);

舊版本兼容方案(PHP 5.3 及以下)

利用 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":"中文內容"}

原理解析

  1. json_encode 遇到非 ASCII 字符預設輸出 \uXXXX。
  2. urlencode 將中文編碼為 %XX%XX 形式(ASCII 字符),json_encode 視為普通字符串不再轉義。
  3. urldecode 還原為 UTF-8 中文。

進階場景處理

1. 數據庫 JSON 字段存儲

<?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); // 直接得到中文

2. JavaScript 接收(AJAX/API)

<?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

3. 大數據流式輸出(避免記憶體峰值)

<?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();
}

4. 特殊字符處理(Emoji、生僻字)

<?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 一致性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved