早期 PHP 專案常需處理 UTF-8、GBK、Big5 等多種編碼共存情況。本文介紹一個輕量級編碼轉換類別 qswhU,支援數值實體(〹)、十六進位實體(あ)、URL 編碼(%u4E2D)及 UTF-8 位元組序列轉 GBK,並內建常用中文字對照表。
<?php
class qswhU {
private $qswhData; // 內建 Unicode→GBK 對照表(從 qswhU.php 載入)
public function __construct($filename = 'qswhU.php') {
$this->qswhData = file($filename, FILE_IGNORE_NEW_LINES);
}
// 統一解碼入口
public function decode($str, $pattern = 0) {
$patterns = [
'/(\w+);/iU', // 0: 數值實體 〹
'/((%\w\w)+)/i', // 1: URL 編碼 %E4%B8%AD
'/%u(\w{4,5})/iU' // 2: JavaScript escape %u4E2D
];
if (is_int($pattern)) {
if ($pattern >= count($patterns)) die('Invalid pattern index');
$pattern = $patterns[$pattern];
}
return preg_replace_callback($pattern, [$this, 'u2gb'], $str);
}
// 核心轉換邏輯
private function u2gb($matches) {
$str = $matches[1];
$ret = '';
// 處理 URL 編碼 %E4%B8%AD%u4E2D 格式
if (preg_match_all('/%\w{2}/', $str, $m)) {
foreach ($m[0] as $i => $byte) {
$chr1 = hexdec(substr($byte, 1));
// 判斷 UTF-8 位元組序列長度
$thresholds = [0xF0, 0xE0, 0xC0, 0];
for ($j = 0; $j < 4; $j++) if ($chr1 > $thresholds[$j]) break;
$chr = $chr1 - $thresholds[$j];
while (++$j < 4) {
$chr = $chr * 0x40 + (hexdec(substr($m[0][++$i], 1)) - 0x80);
}
$str = dechex($chr);
}
} else {
// 處理 あ 或 あ 格式
if (strtolower($str[0]) === 'x') $str = substr($str, 1);
elseif (strlen($str) != 4) $str = dechex($str);
}
// Unicode 碼位 → GBK 雙位元組
if (strlen($str) == 4) {
$p = hexdec(substr($str, 0, 2)) - 0x4D;
$q = hexdec(substr($str, 2)) * 4;
if (isset($this->qswhData[$p])) {
$ret .= chr(hexdec(substr($this->qswhData[$p], $q, 2)));
$ret .= chr(hexdec(substr($this->qswhData[$p], $q + 2, 2)));
}
} else {
$ret .= chr(hexdec($str)); // ASCII 直接轉換
}
return $ret;
}
}
<?php
require_once 'qswhU.php';
$converter = new qswhU('qswhU.php'); // 需下載對照表檔案
// 1. 數值實體轉換
$html = '中文測試: 中文测试';
echo $converter->decode($html, 0); // 輸出 GBK 編碼字串
// 2. URL 編碼轉換
$url = '%E4%B8%AD%E6%96%87';
echo $converter->decode($url, 1);
// 3. JavaScript escape 轉換
$js = '%u4E2D%u6587';
echo $converter->decode($js, 2);
// 4. 自訂正則模式
$custom = 'U+4E2D U+6587';
echo $converter->decode($custom, '/U\+(\w{4})/i');
該檔案為純文字,每行對應一個 Unicode 區塊(如 0x4D00-0x4DFF),每行 1024 字元(256 字元 × 4 十六進位數字),記錄 GBK 雙位元組編碼。檔案較大(約 100KB),需從 官方來源 下載。
| 方案 | 優點 | 適用場景 |
|---|---|---|
iconv('UTF-8', 'GBK//IGNORE', $str) | 內建、效能高、支援完整字集 | 一般編碼轉換首選 |
mb_convert_encoding($str, 'GBK', 'UTF-8') | 多位元組字串函數、可偵測編碼 | 需自動偵測來源編碼時 |
UConverter (intl 擴展) | ICU 庫支援、最完整轉換規則 | 企業級國際化應用 |
Composer 套件 patchwork/utf8 | 純 PHP 實作、無擴展依賴 | 無法安裝擴展的共享主機 |
iconv 或 mbstring,僅在極舊環境(PHP 4/早期 5.x)考慮此類別。理解編碼轉換底層原理有助於排查疑難雜症,但生產環境請優先使用成熟的內建函數或庫。