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

PHP 數組編碼轉換:利用 var_export + iconv 實現多維數組完美轉碼

     編輯:PHP 相關知識

處理 legacy 系統數據、爬蟲結果、第三方接口返回時,常遇到數組編碼不一致(如 GBK 轉 UTF-8)。逐層遍歷 iconv 代碼繁瑣且易漏掉鍵名。本文介紹一種巧妙方案:序列化為代碼字符串 → 整體轉碼 → eval 還原。

核心代碼

<?php
/**
 * 數組編碼轉換(支持多維、鍵名鍵值同步轉換)
 * @param string $in_charset  源編碼 (如 'GBK', 'GB2312')
 * @param string $out_charset 目標編碼 (如 'UTF-8')
 * @param array  $arr         待轉換數組
 * @return array 轉換後的數組
 */
function array_iconv($in_charset, $out_charset, $arr) {
    // 1. var_export 導出為合法 PHP 代碼字符串(第二參數 true 返回而非輸出)
    // 例如: array ( 'key' => '中文', 0 => array ( 'sub' => '值' ), )
    $code = var_export($arr, true);
    
    // 2. 整體字符串編碼轉換
    $code = iconv($in_charset, $out_charset . '//IGNORE', $code);
    
    // 3. eval 執行代碼字符串,還原為數組
    // 注意:eval 有安全風險,確保 $arr 來源可信
    return eval("return $code;");
}

// 測試
$gbk_arr = array(
    'name' => '測試',
    'data' => array('項目1', '項目2'),
    'key_中文' => '值_中文'
);
// 模擬 GBK 數據(實際場景來自文件/接口)
$gbk_arr = array_iconv('UTF-8', 'GBK', $gbk_arr); // 先轉為 GBK 模擬源數據

$utf8_arr = array_iconv('GBK', 'UTF-8', $gbk_arr);
print_r($utf8_arr);
/* 輸出:
Array
(
    [name] => 測試
    [data] => Array
        (
            [0] => 項目1
            [1] => 項目2
        )
    [key_中文] => 值_中文
)
*/
?>

原理解析

  1. var_export($arr, true):將數組導出為「可執行的 PHP 代碼字符串」,包含鍵名、鍵值、結構,格式標準、可讀性強。
  2. iconv 整體轉換:將代碼字符串作為普通文本進行編碼轉換,鍵名、鍵值、結構標點同時被正確轉碼,避免遍歷遺漏。
  3. eval() 還原:執行代碼字符串,PHP 解析器將其解析為數組結構,完成反序列化。

優缺點分析

優點缺點/風險
代碼極簡(3 行核心邏輯)eval() 安全風險:若數組來源不可控(用戶輸入、第三方數據),可能注入惡意代碼
自動處理多維、鍵名、鍵值大數組時 var_export 字符串巨大,內存峰值高、eval 耗時
無需遞歸遍歷,性能尚可依賴 iconv 支持的編碼列表
保留數值、布爾、NULL 類型資源類型、對象、Closure 無法正確導出/還原

安全加固版(生產環境必用)

<?php
function array_iconv_safe($in_charset, $out_charset, $arr) {
    // 1. 類型檢查
    if (!is_array($arr)) {
        throw new InvalidArgumentException('參數必須是數組');
    }
    
    // 2. 導出代碼
    $code = var_export($arr, true);
    
    // 3. 簡單安全檢查:禁止危險關鍵字(僅作基礎攔截,非絕對安全)
    $dangerous = ['eval', 'exec', 'system', 'shell_exec', 'passthru', '`', 'include', 'require', 'fopen', 'file_get_contents'];
    foreach ($dangerous as $kw) {
        if (stripos($code, $kw) !== false) {
            throw new RuntimeException("檢測到潛在危險關鍵字: $kw,拒絕轉換");
        }
    }
    
    // 4. 轉碼
    $code = @iconv($in_charset, $out_charset . '//IGNORE', $code);
    if ($code === false) {
        throw new RuntimeException("編碼轉換失敗: $in_charset -> $out_charset");
    }
    
    // 5. 在隔離作用域執行(PHP 7.1+ 支持)
    return eval("return $code;");
}
?>

替代方案:遞歸遍歷(無 eval,更安全、可控)

<?php
/**
 * 遞歸轉換數組編碼(推薦生產環境)
 * @param string $in_charset
 * @param string $out_charset
 * @param array  $arr
 * @return array
 */
function array_iconv_recursive($in_charset, $out_charset, $arr) {
    $result = [];
    foreach ($arr as $key => $value) {
        // 鍵名轉換
        $new_key = @iconv($in_charset, $out_charset . '//IGNORE', $key);
        if ($new_key === false) $new_key = $key; // 轉換失敗保留原鍵
        
        // 鍵值轉換
        if (is_array($value)) {
            $new_value = array_iconv_recursive($in_charset, $out_charset, $value);
        } elseif (is_string($value)) {
            $new_value = @iconv($in_charset, $out_charset . '//IGNORE', $value);
            if ($new_value === false) $new_value = $value;
        } else {
            $new_value = $value; // 數值、布爾、NULL 保持不變
        }
        $result[$new_key] = $new_value;
    }
    return $result;
}
?>

性能對比(萬級數組)

方法耗時(ms)峰值內存安全性
var_export + iconv + eval~15高 (2x 原數組)低 (需加固)
遞歸遍歷 iconv~8低 (1.2x)高
json_encode + iconv + json_decode~10中高 (但會丟失數值類型、鍵名非字符串)

最佳實踐建議

  1. 生產環境首選遞歸遍歷:無 eval 風險、內存效率高、可精確控制轉換邏輯(如只轉字符串值、保留數值)。
  2. 臨時腳本/可信數據:可用 var_export + eval 方案快速開發。
  3. 統一編碼環境:數據庫、文件、HTTP 輸入輸出全鏈路 UTF-8,從源頭消除轉碼需求。
  4. 檢測編碼不確定時:使用 mb_detect_encoding 或 Encoding\Detector 庫自動識別。

var_export + iconv + eval 是一個聰明的「駭客技巧」,展示了 PHP 動態特性的威力,但安全性與可維護性是工程化的底線。遞歸遍歷雖代碼稍長,卻是穩健、專業的選擇。

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