問題長什麼樣子
修復前
INSERT INTO wp_posts (post_title) VALUES ('䏿–‡ 高雄 客戶');修復後
INSERT INTO wp_posts (post_title) VALUES ('中文 高雄 客戶');原因在哪裡
WordPress 以 UTF-8 儲存文字。但很多老網站的資料表是用 latin1 建立的,或是用 latin1 連線資料庫。只要寫入和讀取犯的是同一個錯,平常沒有人察覺。換到新主機、用 phpMyAdmin 匯出,或更改連線字元集之後,所有中文就會同時變成亂碼。
wp-config.php裡的DB_CHARSET是latin1,或與資料表不一致。- 備份用
latin1匯出,卻用utf8mb4匯入,或是反過來。 - 某個外掛或匯入腳本把已經亂掉的文字又轉了一次,這就是二次亂碼。
修復匯出檔
- 更動任何東西之前,先備份資料庫。
- 把有問題的資料表匯出成
.sql檔,可以用 phpMyAdmin,也可以用mysqldump --default-character-set=utf8mb4。 - 把檔案拖進上面的輸入框。Mojibuster 只修復壞掉的部分,並列出每一處變更。
- 下載修復後的檔案,用
utf8mb4匯入一個全新的測試資料庫。 - 確認網站顯示無誤後,再匯入正式資料庫。
備份檔不會被上傳,這一點很重要,因為裡面通常有使用者帳號、電子郵件地址和留言。
小心序列化資料
WordPress 會把部分設定以 PHP 序列化的形式存進 wp_options 和 wp_postmeta,例如 s:6:"中文";。其中的數字是位元組數,不是字數。把亂碼還原成中文後長度就對不上了,WordPress 會直接丟棄這個值。所以請先修復 wp_posts、wp_comments、wp_terms 這類內容資料表;選項類資料更適合用 WP-CLI 的 wp search-replace,它會同步更新長度。
在 MySQL 中解決根本原因
- 把資料表和連線都改為
utf8mb4,並在wp-config.php中設定define('DB_CHARSET', 'utf8mb4');。 - 如果
latin1欄位裡存的其實是 UTF-8 位元組,不要直接轉換,否則會被再編碼一次。常見做法是經過二進位型別中轉:先MODIFY … LONGBLOB,再MODIFY … LONGTEXT CHARACTER SET utf8mb4。 - 所有變更都先在資料庫副本上試驗。
常見問題
能一次修復整個 WordPress 資料庫嗎?
可以,較大的 SQL 備份檔也能處理。但要留意 wp_options 和 wp_postmeta 中的序列化資料,這類資料用 WP-CLI 更合適。
備份檔裡本來正確的字元會被更動嗎?
不會。Mojibuster 只修復明顯損壞的字元序列,正確的文字維持原樣。
utf8 和 utf8mb4 有什麼不同?
MySQL 的 utf8 最多只存 3 位元組的字元,表情符號會遺失。utf8mb4 才是完整的 UTF-8,WordPress 應該用它。
除了 WordPress,其他系統也適用嗎?
適用。Joomla、Drupal、Magento,或建構在 MySQL、MariaDB 上的自建系統都有同樣的問題,解法也一樣。