核心問題:連線字元集與儲存字元集不一致
MySQL 依連線字元集解讀傳入 SQL,再轉換為資料表字元集儲存。若三者(頁面、連線、儲存)不一致,會產生「錯錯碰巧對」或「存取亂碼」現象。
三種典型情境實測
情境一:頁面 GBK、連線 latin1(預設)、儲存 utf8
- 存入:GBK → 被誤判為 latin1 → 轉 utf8 存入(產生錯誤 utf8)。
讀出:錯誤 utf8 → 轉 latin1 → 正好還原為 GBK → 頁面正常顯示。
- 現象:phpMyAdmin(utf8 連線)看亂碼,網頁正常。資料實際損壞,遷移極難。
情境二:頁面 GBK、連線 GBK、儲存 utf8 (正確做法)
- 存入:GBK → 正確識別 → 轉 utf8 存入(正確 utf8)。
- 讀出:utf8 → 轉 GBK → 頁面正常。phpMyAdmin 也正常。
情境三:頁面 GBK、連線 latin1、儲存 GBK
- 存入:GBK → 誤判 latin1 → 轉 GBK 存入(產生亂碼 GBK)。
- 讀出:亂碼 GBK → 轉 latin1 → 正好還原 GBK → 頁面正常,工具看亂碼。
編碼轉換驗證
// GBK 字串誤作 latin1 轉 utf8
$str = "中文測試";
$str_tran = iconv('latin1', 'utf-8', $str); // 顯示亂碼
$str_re = iconv('utf-8', 'latin1', $str_tran); // 還原 "中文測試"
// 但 GBK 誤作 utf8 轉 gbk 會報錯
// iconv('utf-8', 'gbk', $str); // 錯誤!
證明:latin1 可作為「透明中介」承載任意位元組序列,utf8 則有嚴格格式要求,不可亂轉。
修正原則與工具
- 原則:同一應用全鏈路(頁面、連線、資料庫、資料表、欄位)統一字元集,推薦全 utf8mb4。
- 連線設定:程式碼啟動後立即執行
SET NAMES utf8mb4(或對應字元集)。
- 修復既有錯誤資料:需分步驟「導出 → 修正編碼 → 導入」,可用支援多級轉換工具(如 latin1→gbk→utf8),不可跨級直接轉。
- 備份工具推薦:帝國備份王,分卷備份支援任意大小資料庫。
PHP 環境啟用 iconv
Windows 下編輯 php.ini,取消註解 extension=php_mbstring.dll(含 iconv 功能),重啟 Web 伺服器。