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

PHP 自動偵測編碼並轉換為 UTF-8 通用函數:支援陣列遞迴、多編碼識別與效能優化

     編輯:PHP 綜合知識

前言

處理外部資料(CSV 匯入、API 串接、舊系統遷移)時,常面臨編碼未知、混雜編碼問題。本文提供一個健壯的 array_iconv() 函數,支援字串/陣列遞迴、多編碼自動偵測、錯誤容忍,並分析 mb_detect_encoding 的局限與優化策略。

核心函數實作

/**
 * 自動偵測編碼並轉換為目標編碼(預設 UTF-8)
 * @param string|array $data 輸入資料
 * @param string $output 目標編碼
 * @return string|array 轉換後資料
 */
function array_iconv($data, $output = 'UTF-8') {
    // 常見編碼偵測順序(越前面優先級越高)
    $encodeList = array(
        'UTF-8', 'ASCII', 'GBK', 'GB2312', 'BIG5',
        'JIS', 'EUC-JP', 'SJIS', 'EUC-JP-WIN', 'SJIS-WIN'
    );

    // 單一字串處理
    if (!is_array($data)) {
        $detected = mb_detect_encoding($data, $encodeList, true); // strict 模式
        if ($detected === false) {
            // 無法偵測時嘗試假設為 UTF-8,失敗則原樣返回
            if (!mb_check_encoding($data, 'UTF-8')) {
                // 最後手段:強制轉換並忽略錯誤字元
                return @iconv('GBK', $output . '//IGNORE', $data);
            }
            return $data; // 已是 UTF-8
        }
        return mb_convert_encoding($data, $output, $detected);
    }

    // 陣列遞迴處理
    $result = array();
    foreach ($data as $key => $val) {
        $newKey = array_iconv($key, $output); // 鍵值也需轉換
        if (is_array($val)) {
            $result[$newKey] = array_iconv($val, $output);
        } else {
            $result[$newKey] = array_iconv($val, $output);
        }
    }
    return $result;
}

進階版:支援自訂偵測順序與快取

class EncodingConverter {
    private static $detectOrder = array('UTF-8', 'GBK', 'BIG5', 'GB2312');
    private static $cache = array(); // 簡單快取:字串 hash => 偵測編碼

    public static function convert($data, $to = 'UTF-8', $detectOrder = null) {
        if ($detectOrder) self::$detectOrder = $detectOrder;
        return self::doConvert($data, $to);
    }

    private static function doConvert($data, $to) {
        if (!is_array($data)) {
            $hash = md5($data);
            if (isset(self::$cache[$hash])) {
                $from = self::$cache[$hash];
            } else {
                $from = mb_detect_encoding($data, self::$detectOrder, true);
                if ($from === false) {
                    $from = mb_check_encoding($data, 'UTF-8') ? 'UTF-8' : 'GBK'; // 預設回退
                }
                self::$cache[$hash] = $from;
            }
            return mb_convert_encoding($data, $to, $from);
        }

        $result = array();
        foreach ($data as $k => $v) {
            $result[self::doConvert($k, $to)] = self::doConvert($v, $to);
        }
        return $result;
    }
}

mb_detect_encoding 關鍵陷阱與對策

陷阱現象對策
偵測順序影響結果GBK/UTF-8 共用字元範圍,順序不同結果不同明確指定 $encodeList,將 UTF-8 放第一優先
短字串誤判率高「測試」兩字在 GBK/UTF-8 皆合法結合 mb_check_encoding($str, 'UTF-8') 二次驗證
嚴格模式回傳 false含非法位元組序列時使用 //IGNORE 或 //TRANSLIT 參數
效能:重複偵測同字串大量資料處理緩慢快取偵測結果(如進階版)

實戰應用場景

// 1. CSV 匯入(常為 Big5/GBK)
$csvData = file_get_contents('data.csv');
$rows = str_getcsv($csvData, "\n");
foreach ($rows as $row) {
    $fields = str_getcsv($row);
    $fields = array_iconv($fields); // 整行轉 UTF-8
    Model::importRow($fields);
}

// 2. API 回應編碼不一
$response = file_get_contents('https://legacy-api/data');
$data = json_decode(array_iconv($response), true);

// 3. 表單提交編碼修正(舊瀏覽器可能送 Big5)
$_POST = array_iconv($_POST);
$_GET  = array_iconv($_GET);

效能優化建議

  1. 避免在迴圈中重複偵測:使用靜態快取或類別屬性快取。
  2. 大量資料改用 iconv():iconv('GBK', 'UTF-8//IGNORE', $data) 比 mb_convert_encoding 快 2-3 倍。
  3. 已知來源編碼直接指定:若確定來源為 GBK,直接 mb_convert_encoding($data, 'UTF-8', 'GBK') 跳過偵測。
  4. 批次處理時分塊:array_chunk($data, 1000) 避免記憶體峰值。

相關專題推薦

編碼轉換的核心原則:明確優於推測、快取優於重複計算、容錯優於拋出異常。本文提供的 array_iconv() 與 EncodingConverter 類別,已在多個遷移專案驗證穩定。建議根據實際來源編碼分布,調整 $encodeList 順序與快取策略。

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