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

PHP GB2312/GBK 轉 UTF-8 編碼轉換類實現原理解析

     編輯:PHP 綜合知識

在 Unicode 普及前,中文系統廣泛使用 GB2312/GBK 編碼。遷移至 UTF-8 時,常需處理歷史數據編碼轉換。本文解析一個基於代碼表映射的 GB2UTF8 類實現原理,並對比現代 PHP 內建轉換函數的優勢。

類結構與核心邏輯

<?php
class GB2UTF8 {
    public $gb = '';        // 輸入 GB2312 字符串
    public $utf8 = '';      // 輸出 UTF-8 字符串
    private $codeTable = []; // GB2312 → Unicode 映射表
    private $errorMsg = '';

    public function __construct($inStr = '') {
        $this->gb = $inStr;
        $this->loadCodeTable();
        if ($this->gb !== '') $this->convert();
    }

    private function loadCodeTable($file = 'gb2312.txt') {
        $lines = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        if (!$lines) {
            $this->errorMsg = "Code table file not found: $file";
            return false;
        }
        foreach ($lines as $line) {
            // 格式: GB碼(4位十六進制) Unicode碼(4位十六進制)
            // 例: A1A1 4E2D  (「中」字)
            $gbCode = hexdec(substr($line, 0, 4));
            $uniCode = hexdec(substr($line, 5, 4));
            $this->codeTable[$gbCode] = $uniCode;
        }
        return true;
    }

    private function convert() {
        $this->utf8 = '';
        $str = $this->gb;
        
        while (strlen($str) > 0) {
            $byte = ord($str[0]);
            if ($byte > 127) { // 多位元組字符 (GBK 雙字節)
                if (strlen($str) < 2) break;
                $charBytes = substr($str, 0, 2);
                $str = substr($str, 2);
                
                $gbCode = hexdec(bin2hex($charBytes)) - 0x8080; // 還原區位碼
                if (isset($this->codeTable[$gbCode])) {
                    $uniCode = $this->codeTable[$gbCode];
                    $this->utf8 .= $this->unicodeToUtf8($uniCode);
                } else {
                    $this->utf8 .= '?'; // 無映射替換
                }
            } else { // ASCII 單字節
                $this->utf8 .= $str[0];
                $str = substr($str, 1);
            }
        }
        return $this->utf8;
    }

    private function unicodeToUtf8($codepoint) {
        // Unicode 碼點 → UTF-8 字節序列
        if ($codepoint < 0x80) {
            return chr($codepoint);
        } elseif ($codepoint < 0x800) {
            return chr(0xC0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3F));
        } elseif ($codepoint < 0x10000) {
            return chr(0xE0 | ($codepoint >> 12)) .
                   chr(0x80 | (($codepoint >> 6) & 0x3F)) .
                   chr(0x80 | ($codepoint & 0x3F));
        } elseif ($codepoint < 0x200000) {
            return chr(0xF0 | ($codepoint >> 18)) .
                   chr(0x80 | (($codepoint >> 12) & 0x3F)) .
                   chr(0x80 | (($codepoint >> 6) & 0x3F)) .
                   chr(0x80 | ($codepoint & 0x3F));
        }
        return '?';
    }
}

代碼表文件格式 (gb2312.txt)

A1A1 4E2D  # 中
A1A2 56FD  # 國
A1A3 4EBA  # 人
A1A4 6C11  # 民
...
# 共 6763 個漢字 + 682 個符號

使用示例

<?php
require_once 'GB2UTF8.class.php';

// 方式 1: 構造函數自動轉換
$converter = new GB2UTF8("中文測試");
echo $converter->utf8; // UTF-8 輸出

// 方式 2: 手動調用
$converter = new GB2UTF8();
$converter->gb = file_get_contents('legacy_gbk.txt');
$converter->convert();
file_put_contents('converted_utf8.txt', $converter->utf8);

// GD 圖片繪製中文
header('Content-Type: image/png');
$im = imagecreatetruecolor(400, 100);
$black = imagecolorallocate($im, 0, 0, 0);
$red = imagecolorallocate($im, 255, 0, 0);
$converter = new GB2UTF8("你好世界");
imagettftext($im, 24, 0, 10, 40, $red, 'SimHei.ttf', $converter->utf8);
imagepng($im);
imagedestroy($im);

現代 PHP 內建方案對比 (強烈推薦)

函數/擴展支援編碼性能依賴推薦度
mb_convert_encoding()100+ (含 GBK, GB2312, UTF-8, Big5...)高 (C 實現)mbstring⭐⭐⭐⭐⭐
iconv()GNU libiconv 支援的所有編碼高iconv⭐⭐⭐⭐
UConverter (intl)ICU 全集極高intl (PHP 5.5+)⭐⭐⭐⭐⭐
手工映射類僅代碼表覆蓋範圍低 (PHP 循環)無⭐ (教學/特殊環境)

內建函數使用示例

<?php
// mbstring (最常用)
$utf8 = mb_convert_encoding($gbkStr, 'UTF-8', 'GBK');
// 或自動檢測
$utf8 = mb_convert_encoding($str, 'UTF-8', 'auto');

// iconv (需處理 //IGNORE //TRANSLIT)
$utf8 = iconv('GBK', 'UTF-8//IGNORE', $gbkStr);

// intl UConverter (最高性能、最準確)
$conv = new UConverter('UTF-8', 'GB18030'); // GB18030 兼容 GBK
$utf8 = $conv->transcode($gbkStr);

// 批量轉換文件
$files = glob('legacy/*.txt');
foreach ($files as $f) {
    $content = file_get_contents($f);
    $utf8 = mb_convert_encoding($content, 'UTF-8', 'GBK');
    file_put_contents('utf8/' . basename($f), $utf8);
}

編碼檢測與避坑指南

<?php
// 檢測編碼 (mbstring)
$encoding = mb_detect_encoding($str, ['UTF-8', 'GBK', 'GB2312', 'BIG5'], true);
if ($encoding !== 'UTF-8') {
    $str = mb_convert_encoding($str, 'UTF-8', $encoding);
}

// 常見坑
// 1. GB2312 ≠ GBK:GBK 是 GB2312 超集,含更多字符。轉碼用 'GBK' 更安全
// 2. 瀏覽器編碼聲明必須一致:Header + Meta 双重保險
header('Content-Type: text/html; charset=UTF-8');
// 

// 3. 資料庫連線編碼
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=gbk', 'user', 'pass');
// 或查詢前執行
$pdo->exec('SET NAMES gbk');

總結

手工映射類適合理解編碼轉換原理、極簡環境無擴展支援場景。生產環境請直接使用 mb_convert_encoding() 或 UConverter,享受 C 級性能、完整字符集覆蓋、標準化錯誤處理。遷移項目建議:統一內部編碼為 UTF-8,邊界處(輸入/輸出/資料庫/外部 API)做轉碼適配。

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