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

PHP 自動偵測字串編碼 (UTF-8 / GB2312) 並轉碼為 UTF-8 實用函數

     編輯:PHP 相關知識

處理跨系統資料交換 (如 API 串接、表單提交、檔案匯入) 時,常遇到編碼不一導致亂碼。本文提供一個輕量級函數 safeEncoding(),自動偵測字串為 UTF-8 或 GB2312/GBK,並統一轉換為 UTF-8 (或指定目標編碼)。

核心函數

<?php
/**
 * 自動偵測字串編碼並轉換為目標編碼 (預設 UTF-8)
 *
 * @param string $string  待處理字串
 * @param string $outEncoding 目標編碼,預設 'UTF-8'
 * @return string 轉換後字串
 */
function safeEncoding($string, $outEncoding = 'UTF-8') {
    $encoding = 'UTF-8'; // 預設假設為 UTF-8
    $len = strlen($string);

    for ($i = 0; $i < $len; $i++) {
        $char = $string[$i];
        $ord = ord($char);

        // ASCII 範圍 (0-127) 直接跳過,所有編碼相容
        if ($ord < 128) {
            continue;
        }

        // 檢測 UTF-8 三位元組模式: 1110xxxx 10xxxxxx 10xxxxxx
        if (($ord & 0xE0) === 0xE0) { // 224 = 11100000
            // 確保還有至少 2 個位元組
            if ($i + 2 < $len) {
                $char1 = $string[$i + 1];
                $char2 = $string[$i + 2];
                if (($char1 & 0x80) === 0x80 && ($char2 & 0x80) === 0x80) {
                    $encoding = 'UTF-8';
                    break; // 確認為 UTF-8,停止檢測
                }
            }
        }

        // 檢測 GB2312/GBK 雙位元組模式: 110xxxxx 10xxxxxx (首位元組 0x81-0xFE, 次位元組 0x40-0xFE 除 0x7F)
        if (($ord & 0xC0) === 0xC0) { // 192 = 11000000
            if ($i + 1 < $len) {
                $char1 = $string[$i + 1];
                if (($char1 & 0x80) === 0x80) {
                    $encoding = 'GB2312';
                    break; // 確認為 GB 系列,停止檢測
                }
            }
        }
    }

    // 已是目標編碼直接返回
    if (strtoupper($encoding) === strtoupper($outEncoding)) {
        return $string;
    }

    // 使用 iconv 轉碼,//IGNORE 忽略無法轉換字元,//TRANSLIT 嘗試音譯
    return iconv($encoding, $outEncoding . '//IGNORE', $string);
}
?>

使用範例

<?php
// 模擬 GB2312 編碼字串 (實際環境可能來自 $_POST、檔案讀取、API 回傳)
$gbString = iconv('UTF-8', 'GB2312', '測試中文內容');
echo '原始編碼偵測: ' . mb_detect_encoding($gbString) . PHP_EOL; // 可能偵測不準

$utf8String = safeEncoding($gbString);
echo '轉碼後: ' . $utf8String . PHP_EOL;
echo '轉碼後編碼: ' . mb_detect_encoding($utf8String) . PHP_EOL;

// 指定輸出為 GBK (較少見需求)
$gbkString = safeEncoding($utf8String, 'GBK');
?>

原理解析

  • UTF-8:中文字為 3 位元組,首位元組 1110xxxx (0xE0-0xEF),後續兩位元組皆為 10xxxxxx (0x80-0xBF)。
  • GB2312/GBK:中文字為 2 位元組,首位元組 110xxxxx (0x81-0xFE),次位元組 10xxxxxx (0x40-0xFE, ≠0x7F)。
  • ASCII (0-127):所有編碼相同,單位元組,直接跳過。
  • 函數掃描字串,遇到首個非 ASCII 位元組即嘗試匹配上述特徵,匹配成功即斷定編碼並停止,效能極佳。

適用場景與限制

場景適用性說明
表單提交 (舊系統 GB2312 → 新系統 UTF-8)★★★★★最常見用途,自動修正亂碼
API 串接 (不確定對方編碼)★★★★☆配合 Content-Type 標頭更準確
CSV/Excel 檔案匯入★★★★☆建議先用 mb_detect_encoding 輔助
純英文/數字/符號字串★★★★★ASCII 範圍直接返回,零開銷
Big5、Shift_JIS、EUC-KR 等其他編碼★☆☆☆☆本函數僅區分 UTF-8/GB 系列,其他編碼會誤判
極短字串 (如單字「中」)★★★☆☆特徵碼不足可能誤判,建議加長度判斷

進階建議

  1. 優先信任來源標頭:若有 Content-Type: charset=... 或 ``, 直接用該編碼,不需偵測。
  2. 檔案層級偵測:讀取檔案時可先檢查 UTF-8 BOM (EF BB BF),有 BOM 確定為 UTF-8。
  3. 生產環境建議:引入 mbstring 擴充並使用 mb_detect_encoding($str, ['UTF-8', 'GB2312', 'GBK', 'ASCII'], true),官方實作更完善。
  4. 資料庫連線編碼:務必執行 SET NAMES utf8mb4,從源頭避免編碼問題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved