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

PHP 解碼 Unicode 與 Escape 加密字串完整函式

     編輯:PHP 綜合知識

前言

前端傳遞資料常將中文編碼為 Unicode (\u4e2d\u6587) 或 Escape (%u4e2d%u6587) 格式。PHP 需解碼還原為 UTF-8 字串。本文提供完整解碼函式、編碼對照表與效能優化版。

一、通用解碼函式 uni_decode()

<?php
/**
 * 解碼 Unicode (\uXXXX) 與 HTML 實體 (〹) 為 UTF-8
 * @param string $str 含編碼字串
 * @return string 解碼後 UTF-8 字串
 */
function uni_decode($str) {
    // 1. 匹配 HTML 實體:&#數字;
    preg_match_all('/&#(\d{2,5});/', $str, $htmlMatches);
    
    // 2. 匹配 JS Unicode:\uXXXX 或 %uXXXX
    preg_match_all('/[\\\\%]u([0-9a-fA-F]{4})/', $str, $jsMatches);
    
    // 合併所有需替換的原始片段
    $sources = array_merge($htmlMatches[0], $jsMatches[0]);
    
    // 轉換為 Unicode 碼點
    $codepoints = [];
    foreach ($htmlMatches[1] as $cp) $codepoints[] = (int)$cp;
    foreach ($jsMatches[1] as $cp) $codepoints[] = hexdec($cp);
    
    // 逐一替換
    foreach ($codepoints as $i => $cp) {
        $utf8 = codepointToUtf8($cp);
        $str = str_replace($sources[$i], $utf8, $str);
    }
    return $str;
}

/**
 * Unicode 碼點轉 UTF-8 字串
 */
function codepointToUtf8($cp) {
    if ($cp < 0x80) {
        return chr($cp);
    } elseif ($cp < 0x800) {
        return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F));
    } elseif ($cp < 0x10000) {
        return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
    } elseif ($cp < 0x200000) {
        return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
    }
    return '';  // 超出範圍
}

// 測試
$str = '%u5927%u5BB6%u597D%uFF0C%E6%88%91%E6%98%AF%E5%AD%A4%E9%AD%82%EF%BC%1
\u8FD9\u662F\u6D4B\u8BD5\u6587\u672C\uFF01'; echo uni_decode($str); // 輸出:大家好,我是孤魂!這是測試文字! ?>

二、效能優化版:單次 preg_replace_callback

<?php
function uniDecodeFast($str) {
    return preg_replace_callback(
        '/(?:&#(\d{2,5});|[\\\\%]u([0-9a-fA-F]{4}))/',
        function($m) {
            $cp = $m[1] ? (int)$m[1] : hexdec($m[2]);
            return codepointToUtf8($cp);
        },
        $str
    );
}
?>

三、Escape 編碼函式(PHP 實作 JavaScript escape)

<?php
/**
 * PHP 實作 JavaScript escape()
 * @param string $str UTF-8 字串
 * @return string Escape 編碼字串
 */
function php_escape($str) {
    $result = '';
    $len = strlen($str);
    for ($i = 0; $i < $len; $i++) {
        $c = $str[$i];
        $ord = ord($c);
        
        // ASCII 字母數字及 * @ - _ + . / 保持不變
        if (($ord >= 48 && $ord <= 57) ||   // 0-9
            ($ord >= 65 && $ord <= 90) ||   // A-Z
            ($ord >= 97 && $ord <= 122) ||  // a-z
            strpos('*@-_+./', $c) !== false) {
            $result .= $c;
        } elseif ($ord < 128) {
            // 其他 ASCII:%XX
            $result .= '%' . strtoupper(dechex($ord));
        } else {
            // 多位元組字元:%uXXXX (需取得 Unicode 碼點)
            // 簡易版:假設 UTF-8,轉換為 Unicode
            $utf8Char = $c;
            $bytes = 1;
            if (($ord & 0xE0) === 0xC0) $bytes = 2;
            elseif (($ord & 0xF0) === 0xE0) $bytes = 3;
            elseif (($ord & 0xF8) === 0xF0) $bytes = 4;
            
            for ($j = 1; $j < $bytes; $j++) {
                $utf8Char .= $str[++$i];
            }
            
            // UTF-8 轉 Unicode 碼點
            $cp = 0;
            if ($bytes === 1) $cp = ord($utf8Char);
            elseif ($bytes === 2) $cp = ((ord($utf8Char[0]) & 0x1F) << 6) | (ord($utf8Char[1]) & 0x3F);
            elseif ($bytes === 3) $cp = ((ord($utf8Char[0]) & 0x0F) << 12) | ((ord($utf8Char[1]) & 0x3F) << 6) | (ord($utf8Char[2]) & 0x3F);
            elseif ($bytes === 4) $cp = ((ord($utf8Char[0]) & 0x07) << 18) | ((ord($utf8Char[1]) & 0x3F) << 12) | ((ord($utf8Char[2]) & 0x3F) << 6) | (ord($utf8Char[3]) & 0x3F);
            
            $result .= '%u' . strtoupper(str_pad(dechex($cp), 4, '0', STR_PAD_LEFT));
        }
    }
    return $result;
}

// 測試
echo php_escape('中文測試123');  
// 輸出:%u4E2D%u6587%u6E2C%u8A66123
?>

四、編碼格式對照表

格式範例來源PHP 解碼關鍵
HTML 十進制實體中文網頁顯示preg_match('/&#(\d+);/')
HTML 十六進制實體中文網頁顯示preg_match('/&#x([0-9A-F]+);/i')
JS Unicode\u4e2d\u6587JavaScript 字串preg_match('/\\\\u([0-9A-F]{4})/i')
Escape%u4E2D%u6587JS escape()、舊版 AJAXpreg_match('/%u([0-9A-F]{4})/i')
URL 編碼%E4%B8%AD%E6%96%87HTTP 參數傳遞urldecode() / rawurldecode()

五、實戰:處理前端傳來的混合編碼資料

<?php
function decodeMixedInput($input) {
    // 1. 先 URL 解碼(處理 %20, %E4%B8%AD...)
    $decoded = urldecode($input);
    
    // 2. 再解碼 Unicode/Escape/HTML 實體
    $decoded = uniDecodeFast($decoded);
    
    // 3. 移除可能殘留的控制字元
    $decoded = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $decoded);
    
    return $decoded;
}

// 範例:AJAX 接收
$raw = $_POST['content'] ?? '';
$clean = decodeMixedInput($raw);
// 存入資料庫、全文檢索等
?>

六、常見問題

  • 雙重編碼: 前端 escape(escape(str)) 導致 %25u4E2D,解決:多次解碼直到不變化。
  • 補字元: Emoji 😀 (U+1F600) 需 4 bytes UTF-8,Escape 為 %uD83D%uDE00 (UTF-16 代理對),codepointToUtf8 需支援 >0xFFFF。
  • 效能: 大量字串解碼用 preg_replace_callback 單次通過,避免多次 preg_match_all + 迴圈替換。

小結

PHP 解碼 Unicode/Escape 核心:正則提取碼點 → 碼點轉 UTF-8 位元組序列。通用函式 uni_decode() 處理 HTML 實體與 JS Unicode,php_escape() 反向編碼。生產環境建議統一使用 UTF-8 + JSON 傳輸,避免多重編碼帶來的解碼複雜度與安全風險。

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