| 函數 | 擴展依賴 | 特點 | 推薦度 |
|---|---|---|---|
mb_convert_encoding() | mbstring (PHP 內置常開啟) | 支持超多編碼、無 BUG、語法簡潔、性能好 | ⭐⭐⭐⭐⭐ (首選) |
iconv() | iconv (系統庫,通常內置) | 標準 POSIX、GBK 轉換有已知 BUG、需 //IGNORE 容錯 | ⭐⭐⭐ (無 mbstring 環境備選) |
mb_convert_variables() | mbstring | 批量轉換數組/對象變量 | ⭐⭐⭐⭐ |
<?php
// 基本語法:mb_convert_encoding($str, $to_encoding, $from_encoding)
// $from_encoding 可省略,自動檢測(不推薦,不準確)
// 1. GBK → UTF-8 (最常見)
$utf8 = mb_convert_encoding($gbkStr, 'UTF-8', 'GBK');
// 2. UTF-8 → GBK (輸出兼容舊系統)
$gbk = mb_convert_encoding($utf8Str, 'GBK', 'UTF-8');
// 3. 批量轉換數組
$post = mb_convert_variables('UTF-8', 'GBK', $_POST); // 直接修改 $_POST 引用
// 4. 指定多種可能源編碼(自動檢測,較慢)
$utf8 = mb_convert_encoding($str, 'UTF-8', 'UTF-8, GBK, ISO-8859-1');
?>
已知 BUG:
iconv處理 GBK/GB2312 時,遇到某些字符(如—U+2014 全角破折號、•圓點號)會中斷轉換並返回 false/空字符串,且後續字符全部丟失。
<?php
// ❌ 錯誤:遇到問題字符直接失敗
$gbk = iconv('UTF-8', 'GBK', $utf8Str);
// ✅ 正確:添加 //IGNORE 忽略無法轉換字符
$gbk = iconv('UTF-8', 'GBK//IGNORE', $utf8Str);
// 或 //TRANSLIT 嘗試近似字符替換
$gbk = iconv('UTF-8', 'GBK//TRANSLIT', $utf8Str);
// 反向同理
$utf8 = iconv('GBK', 'UTF-8//IGNORE', $gbkStr);
?>
<?php
/**
* 智能轉碼:自動檢測編碼並轉為 UTF-8
* @param mixed $data 字符串、數組、對象
* @return mixed 轉換後的數據
*/
function toUtf8($data) {
if (is_string($data)) {
// 嚴格模式檢測
$encoding = mb_detect_encoding($data, ['UTF-8', 'GBK', 'GB2312', 'ISO-8859-1', 'ASCII'], true);
if ($encoding && $encoding !== 'UTF-8') {
return mb_convert_encoding($data, 'UTF-8', $encoding);
}
return $data; // 已是 UTF-8 或無法檢測
} elseif (is_array($data)) {
foreach ($data as $key => $value) {
$data[$key] = toUtf8($value);
}
return $data;
} elseif (is_object($data)) {
foreach ($data as $key => $value) {
$data->$key = toUtf8($value);
}
return $data;
}
return $data;
}
// 入口統一處理
$_GET = toUtf8($_GET);
$_POST = toUtf8($_POST);
$_REQUEST = toUtf8($_REQUEST);
?>
<?php
// PDO (推薦)
$pdo = new PDO(
"mysql:host=localhost;dbname=test;charset=utf8mb4",
'user', 'pass',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
]
);
// mysqli
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$mysqli->set_charset('utf8mb4'); // 必須調用!構造函數 charset 參數不可靠
// 等效原始 SQL(理解原理)
/*
SET NAMES utf8mb4; -- 設置客戶端/連接/結果集編碼
SET CHARACTER SET utf8mb4; -- 同 SET NAMES
SET COLLATION_CONNECTION = 'utf8mb4_unicode_ci'; -- 設置排序規則
*/
?>
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'
skip-character-set-client-handshake = 1 # 強制忽略客戶端編碼請求,統一服務端設置
mb_convert_encoding($str, 'UTF-8', 'GBK') → 亂碼。必須先檢測。mb_detect_encoding 非嚴格模式:mb_detect_encoding($str, 'UTF-8, GBK') 會按順序猜測,純 ASCII 字符串會被誤判為第一個編碼。必須第三參數 true 啟用嚴格模式。//IGNORE 導致數據截斷:iconv 轉 GBK 遇特殊字符直接截斷,數據悄悄丟失。mb_convert_encoding,避免 iconv 系統調用開銷。mb_convert_variables('UTF-8', 'GBK', $_POST) 一次性處理超全局變量。$_GET/POST/REQUEST,業務代碼假設輸入已是 UTF-8,不再重複轉碼。mb_convert_encoding:功能全、無 BUG、性能好。iconv(...//IGNORE):無 mbstring 環境下的備選,必加 //IGNORE。SET NAMES utf8mb4 等。toUtf8($_POST) 等,業務層零編碼邏輯。