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

PHP 實現 JavaScript escape() 編碼函數:Unicode 轉義、UTF-8 相容、純 PHP 無依賴

     編輯:PHP 相關知識

PHP 實現 JavaScript escape() 編碼函數:Unicode 轉義、UTF-8 相容、純 PHP 無依賴

JS escape() (已棄用但存量代碼廣泛使用) 將字串編碼為 %XX (Latin-1) 或 %uXXXX (Unicode)。PHP 無原生對應函數,本文提供純 PHP 實現,支援 UTF-8 輸入、正確處理多字節字符、輸出與 JS escape() 完全一致的字串,並對比 encodeURIComponent 現代替代方案。

一、escape() 編碼規則回顧

字符範圍編碼輸出範例
ASCII 字母數字 * @ - _ + . /不編碼a → a
ASCII 其餘 (空格、標點、控制字符)%XX (十六進位)空格 → %20
非 ASCII (Unicode > U+00FF)%uXXXX (4位十六進位)中 → %u4E2D

二、純 PHP 實現 (UTF-8 安全)

<?php
/**
 * 模擬 JavaScript escape() 編碼
 * @param string $string UTF-8 編碼字串
 * @return string escape() 風格編碼字串
 */
function jsEscape(string $string): string
{
    $result = '';
    $length = strlen($string);
    $safeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*@-_+./';

    for ($i = 0; $i < $length; ) {
        $byte = ord($string[$i]);

        // 1. 單字節 ASCII
        if ($byte <= 0x7F) {
            $char = $string[$i];
            if (strpos($safeChars, $char) !== false) {
                $result .= $char;
            } else {
                $result .= '%' . strtoupper(dechex($byte));
            }
            $i++;
            continue;
        }

        // 2. 多字節 UTF-8 序列解碼
        $bytes = 0;
        if (($byte & 0xE0) === 0xC0) $bytes = 2;      // 110xxxxx
        elseif (($byte & 0xF0) === 0xE0) $bytes = 3; // 1110xxxx
        elseif (($byte & 0xF8) === 0xF0) $bytes = 4; // 11110xxx
        else { $i++; continue; } // 非法序列跳過

        // 邊界檢查
        if ($i + $bytes > $length) { $i++; continue; }

        $seq = substr($string, $i, $bytes);
        $i += $bytes;

        // 解碼為 Unicode 碼點
        $codepoint = 0;
        if ($bytes === 2) {
            $codepoint = (($seq[0] & 0x1F) << 6) | ($seq[1] & 0x3F);
        } elseif ($bytes === 3) {
            $codepoint = (($seq[0] & 0x0F) << 12) | (($seq[1] & 0x3F) << 6) | ($seq[2] & 0x3F);
        } elseif ($bytes === 4) {
            $codepoint = (($seq[0] & 0x07) << 18) | (($seq[1] & 0x3F) << 12) | (($seq[2] & 0x3F) << 6) | ($seq[3] & 0x3F);
        }

        // 3. 輸出編碼
        if ($codepoint <= 0xFF) {
            // Latin-1 範圍用 %XX
            $result .= '%' . strtoupper(dechex($codepoint));
        } else {
            // Unicode 用 %uXXXX (補齊 4 位)
            $result .= '%u' . strtoupper(str_pad(dechex($codepoint), 4, '0', STR_PAD_LEFT));
        }
    }
    return $result;
}

// 測試對比
$test = 'Hello 世界! @#¥%';
echo "JS escape(): " . jsEscape($test) . "\n";
// 輸出: Hello%20%u4E16%u754C%21%20%40%23%C2%A5%25
?>

三、解碼函數 (unescape 相容)

<?php
function jsUnescape(string $string): string
{
    // 先處理 %uXXXX
    $string = preg_replace_callback('/%u([0-9A-Fa-f]{4})/', function ($m) {
        return mb_chr(hexdec($m[1]), 'UTF-8');
    }, $string);

    // 再處理 %XX
    $string = preg_replace_callback('/%([0-9A-Fa-f]{2})/', function ($m) {
        return chr(hexdec($m[1]));
    }, $string);

    return $string;
}

// 往返測試
$orig = '測試 Test 123!@#';
$enc = jsEscape($orig);
$dec = jsUnescape($enc);
var_dump($orig === $dec); // true
?>

四、現代替代方案對比

函數標準輸出範例PHP 對應推薦度
escape()已棄用 (ECMA-262 3rd)%u4E2D自定義 jsEscape()❌ 僅維舊
encodeURI()保留 URI 結構字符%E4%B8%ADrawurlencode() + 保留字符⚠️ 完整 URL
encodeURIComponent()編碼所有非保留字符%E4%B8%ADrawurlencode()✅ 現代標準
rawurlencode()RFC 3986%E4%B8%AD原生✅ 推薦

五、遷移建議

  1. 新代碼: 統一用 rawurlencode() (PHP) / encodeURIComponent() (JS),UTF-8 百分號編碼,互通無障礙
  2. 存量 escape(): 後端用本文 jsEscape() 產生相容字串,前端改用 decodeURIComponent() 解碼 (需先將 %uXXXX 轉為 %XX%XX)
  3. 雙向轉換工具:
<?php
// escape() → 標準百分號編碼
function escapeToStandard(string $escaped): string
{
    // %uXXXX → UTF-8 字節 → %XX%XX...
    return preg_replace_callback('/%u([0-9A-Fa-f]{4})/', function ($m) {
        $cp = hexdec($m[1]);
        $utf8 = mb_chr($cp, 'UTF-8');
        return rawurlencode($utf8);
    }, $escaped);
}

// 標準 → escape()
function standardToEscape(string $standard): string
{
    return jsEscape(rawurldecode($standard));
}
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved