JavaScript 的 escape()/unescape() 與 PHP 的 urlencode()/urldecode() 編碼規則不同(前者對 Unicode 字符輸出 %uXXXX 格式),直接互用會導致中文亂碼。本文提供 PHP 版完整實現,解決前後端交互編碼不一致問題。
<?php
/**
* JS escape PHP 實現
* @param string $string 待編碼字符串
* @param string $in_encoding 輸入編碼,默認 UTF-8
* @param string $out_encoding 輸出編碼,默認 UCS-2(JS escape 內部用 UTF-16BE)
* @return string 編碼後字符串
*/
function escape($string, $in_encoding = 'UTF-8', $out_encoding = 'UCS-2') {
$return = '';
if (function_exists('mb_get_info')) {
for ($x = 0; $x < mb_strlen($string, $in_encoding); $x++) {
$str = mb_substr($string, $x, 1, $in_encoding);
if (strlen($str) > 1) { // 多字節字符(中文等)
$return .= '%u' . strtoupper(bin2hex(mb_convert_encoding($str, $out_encoding, $in_encoding)));
} else { // ASCII 字符
$return .= '%' . strtoupper(bin2hex($str));
}
}
}
return $return;
}
?>
<?php
/**
* JS unescape PHP 實現
* @param string $str 待解碼字符串
* @return string 解碼後字符串(UTF-8)
*/
function unescape($str) {
$ret = '';
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
if ($str[$i] === '%' && isset($str[$i + 1]) && $str[$i + 1] === 'u') {
// %uXXXX 格式(Unicode)
$val = hexdec(substr($str, $i + 2, 4));
if ($val < 0x7f) {
$ret .= chr($val);
} elseif ($val < 0x800) {
$ret .= chr(0xc0 | ($val >> 6)) . chr(0x80 | ($val & 0x3f));
} else {
$ret .= chr(0xe0 | ($val >> 12)) .
chr(0x80 | (($val >> 6) & 0x3f)) .
chr(0x80 | ($val & 0x3f));
}
$i += 5;
} elseif ($str[$i] === '%') {
// %XX 格式(ASCII)
$ret .= urldecode(substr($str, $i, 3));
$i += 2;
} else {
$ret .= $str[$i];
}
}
return $ret;
}
?>
escape() 內部將字符串按 UTF-16BE (UCS-2) 編碼後輸出 %uXXXX。iconv('UTF-8', 'GBK', $result)。<?php
// 前端 JS: escape('腳本之家') → "%u811A%u672C%u4E4B%u5BB6"
// 後端 PHP 接收 $_GET['kw'] 後:
$kw = unescape($_GET['kw']); // 還原為 UTF-8 "腳本之家"
// 若項目為 GBK:
$kw_gbk = iconv('UTF-8', 'GBK//IGNORE', $kw);
// 反向:PHP 生成給 JS 用的編碼
$js_encoded = escape('腳本之家'); // 可直接拼接到 URL 供 JS unescape 使用
?>
現代項目推薦使用 json_encode()/json_decode()(PHP 5.2+ 內置),JSON 格式原生支持 Unicode,無需手動 escape,且被所有語言標準庫支持,更安全、可讀性更強。