mb_detect_encoding() 是 PHP 多字節字符串擴展提供的編碼檢測函數,但廣為人知存在短字符串誤判問題 (如 GB2312 被誤判為 UTF-8)。本文剖析原理、優化參數順序、提供更可靠的替代方案。
string mb_detect_encoding(
string $str,
mixed $encoding_list = mb_detect_order(),
bool $strict = false
): string|false
$encoding_list:檢測順序數組或逗號分隔字符串,**第一個匹配即返回**,後續不再檢測。$strict:true 嚴格模式 (僅允許合法編碼序列),false 寬鬆模式 (盡力匹配)。$str = "%D0%BE%C6%AC"; // URL 編碼後的 GB2312 "中文" $enc = mb_detect_encoding($str, ['ASCII','UTF-8','GB2312','GBK','BIG5']); var_dump($enc); // 輸出: string(5) "UTF-8" ❌ 誤判!
原因: 短字節序列在 UTF-8 中恰好合法,且 UTF-8 在檢測列表中靠前,優先命中。
// 將目標編碼 (GBK/GB2312) 放在 UTF-8 之前 $enc = mb_detect_encoding($str, ['ASCII','GB2312','GBK','UTF-8','BIG5']); // 現在優先嘗試 GB2312/GBK,短字符串大概率正確命中
原則: 業務最常用/最可能的編碼放最前。中文環境通常:GB2312/GBK > UTF-8 > BIG5 > ASCII。
原理:若字符串屬於某編碼,則 iconv($enc, $enc.'//IGNORE', $str) === $str (轉換後無損失)。
function detectEncodingIconv($str, $candidates = ['GBK','UTF-8','GB2312','BIG5']) {
foreach ($candidates as $enc) {
// //IGNORE 忽略無法轉換字符,若結果與原串相同,極大概率是該編碼
if ($str === @iconv($enc, $enc . '//IGNORE', $str)) {
return $enc;
}
}
return false;
}
// 測試
$tests = [
'中文' => '中文', // UTF-8
'gbk' => iconv('UTF-8','GBK','中文'),
'gb2312' => iconv('UTF-8','GB2312','中文'),
];
foreach ($tests as $name => $s) {
echo "$name: " . detectEncodingIconv($s) . "\n";
}
// 輸出:
// 中文: UTF-8
// gbk: GBK
// gb2312: GB2312
優點:準確率極高,無需依賴檢測順序。缺點:需遍歷候選編碼,性能略低 (微秒級,通常可忽略)。
function detectEncodingStrict($str, $candidates = ['UTF-8','GBK','GB2312']) {
foreach ($candidates as $enc) {
if (mb_check_encoding($str, $enc)) {
return $enc;
}
}
return false;
}
mb_check_encoding 僅驗證字節序列是否合法,不轉換。配合業務邏輯順序使用。
// 統一轉為 UTF-8 內部處理
function toUtf8($str, $fromEncoding = null) {
if ($fromEncoding === null) {
$fromEncoding = detectEncodingIconv($str); // 或 mb_detect_encoding 優化版
}
if ($fromEncoding && strtoupper($fromEncoding) !== 'UTF-8') {
return iconv($fromEncoding, 'UTF-8//IGNORE', $str);
}
return $str;
}
// JSON 編碼前必須確保 UTF-8
$json = json_encode(['msg' => toUtf8($input)]);
| 編碼 | 中文範圍 | 備註 |
|---|---|---|
| GBK/GB2312 | \xA1-\xFE (雙字節) | 兼容 ASCII (\x00-\x7F) |
| UTF-8 | \xE4-\xE9\x80-\xBF\x80-\xBF (三字節主體) | Unicode \u4E00-\u9FA5 |
| BIG5 | \xA4-\xF9\x40-\x7E\xA1-\xFE | 繁體中文 |
extension_dir 正確 (如 C:\php\ext)extension=php_mbstring.dll (去掉分號)# CentOS/RHEL yum install php-mbstring # Ubuntu/Debian apt-get install php-mbstring # 編輯 php.ini 確保 extension=mbstring.so (通常自動添加) systemctl restart php-fpm
mb_detect_encoding **不可盲目信任**,短字符串極易誤判。iconv($enc,$enc.'//IGNORE',$str)===$str) 是工程上最可靠的通用方案。mbstring 擴展正確安裝啟用。