錯誤重現
<?php
$str = '測試•特殊符號'; // UTF-8
echo iconv('UTF-8', 'GBK', $str);
// Notice: iconv(): Detected an illegal character in input string
// 輸出被截斷:只顯示 "測試" 後內容丟失
?>
根因分析
- 目標編碼(GBK/GB2312)字符集不包含源字符串中的某些字符(如特殊符號 ●、Emoji、生僻字)。
- iconv 默認行為:遇到非法字符**立即停止轉換並報錯**,導致後續內容全部丟失。
兩大解決方案
方案一:擴大目標編碼範圍(推薦首選)
<?php
// GBK 是 GB2312 超集,包含更多字符
echo iconv('UTF-8', 'GBK', $str); // 多數情況下可正常輸出
?>
方案二:忽略非法字符(//IGNORE 後綴)
<?php
// 遇到無法轉換字符直接跳過,不報錯,不中斷
echo iconv('UTF-8', 'GBK//IGNORE', $str);
// 輸出: "測試特殊符號" (● 被靜默移除)
?>
深度對比://IGNORE vs //TRANSLIT
| 後綴 | 行為 | 適用場景 |
| //IGNORE | 靜默丟棄非法字符,繼續處理後續內容 | 數據清洗、日誌記錄、非關鍵展示 |
| //TRANSLIT | 嘗試找視覺相近字符替換(如 → "->"),失敗則丟棄並**報錯** | 需要保持可讀性的文本轉換 |
替代方案:mb_convert_encoding
<?php
// 需啟用 mbstring
echo mb_convert_encoding($str, 'GBK', 'UTF-8');
// 內部自動忽略非法字符,不報錯,性能較 iconv 低
?>
最佳實踐建議
- **源頭統一 UTF-8**,避免轉碼需求。
- 必須轉 GBK 時,**優先使用
iconv('UTF-8', 'GBK//IGNORE', $str)**。
- 關鍵業務(如支付訂單號、身份證號)**嚴禁使用 //IGNORE**,應預先驗證字符集合法性。
- 封裝統一轉碼工具函數,集中管理編碼策略。
封裝工具函數示例
<?php
function safeConvert($str, $toEncoding, $fromEncoding = 'UTF-8') {
if (function_exists('iconv')) {
return @iconv($fromEncoding, $toEncoding . '//IGNORE', $str);
}
return @mb_convert_encoding($str, $toEncoding, $fromEncoding);
}
// 使用
$gbkStr = safeConvert($utf8Str, 'GBK');
?>