Mysql自4.1以後,增加了對字元集的支援。筆者之前對Mysql比較瞭解,剛接觸4.1時,感覺Mysql有點多此一舉,但後來細想發現,對字元集的支援,雖然對開發人員來說,會麻煩一些,但不可否認,是一種進步。對字元集的支援,不僅更加支援多語言,而且,也方便移植。
剛開始使用Mysql4.1,你可能感覺有點不適,下面,簡單闡述一下筆者對Mysql4.1字元集的理解,再講述如何PHP如何適應Mysql的這種變化,希望大家看過這文章後,能夠有所收穫。
如果你對電腦基礎知識不瞭解,請直接閱讀“結論篇”
一.原理篇
Mysql的字元集裡有兩個概念,一個是“Character set(字元集)”,另一個是“Collations”。
1. Collations
Collations翻成中文是“校正”,在網頁開發的過程中,這個詞彙,只在Mysql裡使用,主要作用是指導Mysql對字元的比較,比如, ASCII字元集裡,Collations規定了a小於b,a等於a,以及a是否等於A之類的。通常,大家基本可以忽略Collations的存在,因為每個字元集都有一個預設的Collations,通常,使用預設的Collations就可以了。
2.字元集
與這對比的是,字元集是個更廣的概念,即使是Windows下普通的文字檔,也滲及到字元集的問題。不同的字元集,規定了不同的字元的編碼方式。一個 character set (字元集)是一組符號和編碼,比如,ASCII字元集,包括的字元有:數字,大小寫字母,分號、換行之類的符號,編碼方式是用一個7bit表示一個字元(A的編碼是65,b的編碼是98)。ASCII只規定了英文字母的編碼,非英文語言不能用ASCII編碼錶示,為此,不同的國家,都為自己的語言做了編碼,比如,我們國家,就有GB2312編碼。但每個國家之間的編碼不同,也存在著一些跨平台的問題,為此,一些國際化標準組織,就制定了一些國際通用的編碼,最常用的就是UTF8了。ASCII只對英文符號和英文字母做了編碼,GB2312對英文符號,英文字母,漢字做了編碼,UTF8對世界上所有的語言文字做了編碼,所以,GB1212的字元包含了ASCII字元,UTF8包含了GB2312字元。由此可見,UTF8是所含最廣字元的字元集,所以,在一些多語言的WEB系統中,一般用UTF8字元集(PHPMyAdmin使用UTF8編碼)。
任何文本的儲存,都滲及到字元集的概念。包括資料庫,也包括普通的文字檔。
主要術語:
字元:漢字,英文字母,標點符號,拉丁文等等。
編碼:將字元轉換成電腦儲存的格式,比如,A用65表示。
字元集:一組字元以及對應的編碼方式。
a. Mysql的字元集
Mysql目前支援多字元集,並且,支援在不同的字元集之間轉換(便於移植和支援多語言)。
Mysql可以設定伺服器級字元集、資料庫級字元集、資料表級字元集、表列的字元集,實際上,最終使用字元集的地方是儲存字元的列,比如,你設定 table1中col1列是字元類型,col1才用到了字元集,如果table1表的col2列是int類型,col2不使用字元集的概念。
伺服器級字元集、資料庫級字元集、資料表級字元集都是為列的字元集做預設選項的。
Mysql一定有一個字元集,可以通過啟動時加參數指定,也可以編譯時間指定,也可以在設定檔裡指定。Mysql伺服器字元集,只是做為資料庫級的預設值。建立資料庫時,你可以指定字元集,如果沒指定,就使用伺服器的字元集。同理,建立表時,你可以指定表級的字元集,如果沒指定,使用資料庫的字元集做為表的字元集。建立列時,你可以指定某列的字元集,如果沒指定,就使用表的字元集。
通常情況下,您只需設定伺服器級的字元集,其它的資料庫級,表級,以及列級的字元集,都繼承自伺服器級字元集。
由於UTF8是最廣的字元集,所以,一般情況下,我們設定Mysql伺服器級的字元集為UTF8!
b. 普通文本的字元集問題
任何文本的儲存,都存在著字元集的問題,普通文字檔也不例外。
Windows2000+的系統中,開啟記事本,“儲存為…”對話方塊,就有一個選項,可以讓你選擇儲存文本的編碼方式。
通常情況下,大家都使用Windows2000+的系統,都使用預設的編碼,所以,不會碰到字元集的問題。
Windows下,儲存文字檔時,可以選擇編碼方式,但開啟文字檔時,都是自動判斷編碼方式的。網上有一個用Windows2000+的記事本玩移動,聯通的笑話,大家可以搜搜,就是因為Windows在開啟文字檔時,編碼判斷錯誤引起的問題。
因為自動判斷編碼有時會錯誤,所以,有的文字檔,規定了如何識別自身所使用的編碼。HTML檔案就是一個這樣的例子。
HTML是文字檔。儲存HTML檔案的時候,需要使用一個編碼,並且,在HTML檔案裡,也使用HTML文法,指定了該檔案所使用的編碼(比如< meta http-equiv="content-type" content="text/html; charset=UTF-8">)。如果HTML檔案沒有指定編碼,則瀏覽器自動識別檔案的編碼。如果HTML指定了編碼,則瀏覽器使用HTML指定的編碼。
通常情況下,HTML檔案指定的charset和HTML檔案自身的編碼是一致的,但也有不一致的情況,如果不一致,就會導致網頁亂碼(此處亂碼,只和文字檔有關,和資料庫無關。)使用專門的網頁編輯工具(比如Dreamwave),會自動根據網頁中的charset值來編碼檔案。
c. php+mysql的字元集問題
PHP最終產生的是文字檔,但他要取資料庫裡的文本,或將文本存進資料庫。
由於Mysql支援多字元集,預設情況下,Mysql不知道PHP發給他的是什麼編碼的字元,所以,Mysql要求用戶端(PHP)告訴他存取的字元集是什麼。
PHP通過設定character_set_client,告訴Mysql,PHP存進資料庫的是什麼編碼方式。
PHP通過設定character_set_results,告訴Mysql,PHP需要取什麼樣編碼的資料。
PHP通過設定character_set_connection,告訴Mysql,PHP查詢中的文本,使用什麼編碼。
MYSQL使用設定的編碼方式儲存文本。
假設Mysql使用setserver來儲存文本,PHP的character_set_client是setclient,PHP的 character_set_results是setresult。那麼,Mysql將PHP發來的文本,從setclient編碼方式,轉換成 setserver編碼方式,再存入資料庫,如果PHP取文本,Mysql將文本從setserver轉換成setresult,再發送給PHP。
PHP檔案(最終產生的HTML檔案)本身有個編碼,如果Mysql傳過來的編碼,與PHP檔案自身的編碼不同,那麼,整個網頁,必然亂碼。所以,PHP一般將自己的編碼方式,告訴Mysql。
要保證不亂碼,就必須將三個編碼統一:一是網頁自身的編碼,二是HTML裡指定的編碼,三是PHP告訴Mysql的編碼(包括character_set_client和character_set_results)。
第一和第二個編碼,如果使用DW之類的編輯器寫的網頁,通常是一致的,但用記事本寫的網頁,有可能不一致。
第三個編碼,需要手工通知Mysql。這步可以通過在PHP裡使用mysql_query(“set names characterX”)來實現。
d.字元集的轉換問題
如果小字集轉換成大字元集,不會遺失資料,但大字集,轉換成小字集,可能會遺失資料。
比如,UTF8裡有的字元,GB2312不一定有,所以,從UTF8轉換到GB2312可能會丟失一些字元。
但有種情況例外,先從GB2312轉成UTF8,再從UTF8轉成GB2312,這種情況是不會丟資料的,因為,剛開始轉換的文本,都是GB2312裡的字元,所以,整個過程都是GB2312的字元在轉換,不會丟失。
正因為UTF8能容納世界上的所有字元,所以,資料庫一般使用UTF8編碼。這使得,任何字元都可以存進UTF8編碼的資料庫。
e. PHPMyAdmin亂碼的問題
PHPMyAdmin支援多國語言,這就必定要求HTML頁面使用UTF8編碼。
HTML頁面使用UTF8編碼,這就必定要求PHPMyAdmin串連Mysql時,character_set_client和character_set_results使用UTF8編碼。
當前情況下,PHP串連Mysql只能是使用set names(或其它幾個語句)來通知Mysql的編碼方式,如果沒有顯式的聲明編碼方式,都將使用latin1編碼。一般的程式,都沒有顯式聲明 character_set_client變數,所以,都是將gb2312文本,按latin1編碼方式存在資料庫,PHPMyAdmin再用utf8格式讀取,肯定是亂碼的。
如果PHP程式按正確的編碼存入資料庫,肯定是沒有問題的。所以,需要修改的不是PHPMyAdmin.(雖然有時修改PHPMyAdmin可以解決亂碼問題,但這不是問題的根本)
二.總結篇
上面的講得有點亂,總結一下:
1.資料庫盡量使用utf8儲存(修改/etc/my.cnf,在[mysqld]段加上default-character-set=utf8)
(已有的資料庫,先轉成UTF8格式)
2.PHP程式在查詢資料庫之前,執行mysql_query(“set names xxxx”);其中xxxx是你網頁的編碼(charset=xxxx),如果網頁中charset=utf8,則xxxx=utf8,如果網頁中 charset=gb2312,則xxxx=gb2312,如果網頁中的charset=ipaddr,則xxxx=ipaddr (開個玩笑,沒這編碼)
幾乎所有WEB程式,都有一段串連資料庫的公用代碼,放在一個檔案裡,在這檔案裡,加入mysql_query(“set names”)就可以了。
3.PHPMyAdmin不需要做改動。
4.需要注意的是,為保證網頁實際編碼(Windows儲存對話方塊裡的編碼)和他聲明的編碼(charset=?)是一致的,請用DW之類的工具做網頁。
寫得有點倉促,希望大家指正和補充。