2007年6月15日 星期五

MySQL亂碼

最近幫一台Web伺服器裡的drupal網站作搬遷,從MySQL 4.0.X遷移到5.0.X的環境中,果然馬上遇到了傳說中的亂碼大戰。

drupal眾所皆知是以utf8編碼的,因此他的資料庫也是以utf8編碼,照理來說移植到新的環境應該不會出錯,沒想到將MySQL dump檔案匯入新環境後,出來的中文全成了亂碼,連在新環境直接輸入中文也會變成亂碼,我的臉也當場綠了。趕緊上網找解法,沒想到關鍵字一進去,居然讓我找出了十數種解法,每種解法背後的原理都不一樣,有的是從php著手,有的是改動MySQL的起始參數,玲瑯滿目令我頭昏眼花。

每一種解法都去試實在折磨人,因此我用了對照法來偵查到底是哪個環節出現錯誤,以對症下藥。首先,我在新環境中安裝了另一個版本一模一樣的drupal,發現它可以正確輸入輸出中文,這代表我的安裝環境的確可以讓循規蹈矩的drupal正常處理utf8,但是用偷雞摸狗法遷移過去的drupal則不行。

既然知道了,接下來的解決手段就簡單多了,我們只要把這兩個drupal的每個面向都弄得一模一樣或許就能解決問題!因此我將舊主機的drupal資料庫以mysqldump不加參數的情況輸出old.sql,新主機的對照組drupal一樣處理,得到new.sql,接著比較他們的同異點。我發現這兩份.sql檔都是純純正正的utf8編碼,以firefox瀏覽這兩個檔案,在utf8檢視環境下都可以看到中文,換句話說新舊版本的mysql輸出的過程是正常的。因此,問題應該就出在輸入的過程有錯吧!趕緊將old.sql與new.sql的相異處修正,將這分修改過參數的old.sql扔進新環境,結果在drupql出現的又是亂碼!嗯,問題就出在這裡了。

我將mysqladmin的參數列印出來,找找新舊mysql server的編碼是不是出現問題,新server的參數長這樣:

| character_set_client | latin1
| character_set_connection | latin1
| character_set_database | latin1
| character_set_filesystem | binary
| character_set_results | latin1
| character_set_server | latin1
| character_set_system | latin1
| collation_connection | latin1_general_ci
| collation_database | latin1_general_ci
| collation_server | latin1_general_ci

這代表甚麼意思呢?意思就是說當我們把.sql輸入這個server時,無論他是甚麼樣的編碼,一律當成latin1處理!難怪我們的utf8會變成亂碼!因為他在存進資料庫時就已經幫我們亂轉一通了,因此我以這篇文章提到的方式將參數改成utf8編碼,問題的核心就在他的文章中的一段話:

下面的 client 則是設定當 client 連線時要使用什麼語系,但可惜的是這個設定不是每個client都會鳥它,基本上只有 mysql 自已家的程式,例如 mysql.exe, mysqld.exe, mysqladmin.exe 或是 MySQL Control Center這種程式會去讀取這個設定檔然後改用 utf8 連線。
當我改完設定重啟mysql後,將old.sql重新餵進mysql server之後,好久不見的utf8中文終於重回我的drupal網站了,可喜可賀!

從這件事,我學到了一個經驗:若是一件事情有錯,先找另一個成功的case,然後盡量修改自己失敗case的條件,讓它與成功者越相像越好,在檢查每個環節是否相像的流程時,往往能找到問題的癥結,進而解決它!有時整個流程不必做完,問題就已迎刃而解囉。

5 則留言:

Unknown 提到...

請問一下,我也是跟你遇到一樣問題
不過我照您說的全改為utf8,匯入後還是亂碼
該怎麼辦XD..

Peachwa & Neversay 提到...

這個問題,要先確定mysql版本是從哪版換到哪版,我要換的版本是3.4.X換到5.X,才會出現的問題,你要先確定版本,再到google上找找有沒有相對應版本的翻譯問題,因為mysql亂碼的問題我看過不下五六種解法,這些解法之中說不定有你要的。
另外,最好先將mysql資料庫備份出來,再用諸如firefox的瀏覽器開啟這個檔案,看看他在哪種文字編碼能出現你要的樣子,有時候問題是出在資料庫輸出時就變成不可解的亂碼囉。

Unknown 提到...

感謝你這麼快回覆,我完整說明一下
原本我是用xoops big5版,
我先將資料庫轉為utf8,再導入drupal,
轉為utf8時在xoops介面下時顯示中文是正常
但是導入drupal之後就變成亂碼,
從phpmyadmin看drupal跟xoops是一樣的亂碼
不過xoops可正常顯示,drupal卻不行,資料校對設定都是utf8

Peachwa & Neversay 提到...

以我的經驗,用mysql的dump指令將資料庫導出,用可變換編碼的瀏覽器或文字編輯器,查看導出的東西是否能看,確定了他的編碼形式再導入新的資料庫,兩階段轉換才能保證他的編碼形式正確。
若是跳過dump的階段,就很難察覺他的問題,我之前也是直接轉換資料庫而出問題找了半天也看不出轉換問題出在哪,在乖乖導出變成文字檔後我才慢慢測試出問題在哪,所以不要以myphpadmin顯示有沒有問題當作評斷標準喔。
另外,我轉換的環境同樣是drupal之間,只是mysql版本不同,所以我也不知道xoops轉換會做什麼事。這點可能要找找其他人問問囉。 @@

Peachwa & Neversay 提到...

我又遇到了類似的問題,而且找到一個比較基本的解決方法,請參考看看囉:
請看本連結