這幾天想給網(wǎng)站加一個WAP版,根據(jù)wml協(xié)議的規(guī)定,必須符合XML標準,采用utf8編碼字符。這事說起來簡單但做起來難,昨天折騰了大半天的,首先倒騰一些庫的PHP和template文件,把ANSI轉成UTF-8,同時還要去掉UTF-8規(guī)定的開頭三字節(jié)長度標識符,否則PHP無法識別;然后研究和調整數(shù)據(jù)庫編碼,找了很多資料鉆研MySQL編碼的細節(jié),排列組合式的測試,最后發(fā)現(xiàn)被誤導了,根本不用研究那么多,用最簡單的方式就可以了。無論如何,最后總算是大功告成了。在網(wǎng)上查資料的時候,發(fā)現(xiàn)很多都語焉不詳,這里把心得總結一下。
網(wǎng)站采用PHP腳本語言,是基于Discuz搭建的,基本編碼是前臺和數(shù)據(jù)處理采用GBK(ANSI),數(shù)據(jù)庫采用MySQL默認的latin1。我發(fā)現(xiàn)Discuz存儲和處理數(shù)據(jù)庫編碼的方式相比文章《MySQL的字符集問題》所描述的情形來說比較簡單粗暴,僅僅SET NAMES 'latin1',然后不分青紅皂白把字符串往里扔,而不管什么character_set_client、character_set_connection、character_set_results還是collation_connection。雖說簡單粗暴,但是這其實是MySQL推薦實現(xiàn)的方式,即數(shù)據(jù)庫具體的數(shù)據(jù)字符集保持和SET NAMES的參數(shù)一致,這樣進行讀寫是兼容性最好的。盡量不要采用對這
三個參數(shù)分別設置不同值的方式,那樣會帶來潛在的bug和混亂。
由于SET NAMES ‘x’ 等效于:
SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;
而SET character_set_connection = x; 執(zhí)行的同時也自動指定了collation_connection為x的默認字符集collation(如x為utf8則collation_connection為utf8_general_ci),因此SET NAMES必須和數(shù)據(jù)列中指定的字符集一致,否則會報錯。
而SET CHARACTER SET則不同,但它將連接的collation_connection和collation_connection分別設置為默認數(shù)據(jù)列的字符集和collation。
SET CHARACTER SET x 等效于:
SET character_set_client = x;
SET character_set_results = x;
SET collation_connection = @@collation_database;
SET collation_connection同時也會自動設置character_set_connection為同樣的值,這樣SET CHARACTER SET就無論如何設置,在進行數(shù)據(jù)庫存取操作的時候都不會報錯。但是邏輯上就需要程序員自己來保證。
數(shù)據(jù)庫管理程序并不負責給你的字符串進行編碼,你的SET只是告訴數(shù)據(jù)庫:“哥們,你就按我說的編碼那么處理吧,出了事我負責。”
由于Discuz這種“簡單粗暴”而又由于其兼容性而值得推薦的對字符集的處理方式,所以對于之前的網(wǎng)站系統(tǒng),前臺數(shù)據(jù)編碼處理流程:
網(wǎng)站直接將GBK扔給數(shù)據(jù)庫 |SET character_set_client = 'lain1' |SET character_set_connection = 'lain1'
存儲及訪問:GBK--------------->數(shù)據(jù)庫認為其為latin1進行接收---------------->以latin1編碼存儲
SET character_set_connection = 'lain1' |SET character_set_results = 'lain1' |網(wǎng)站直接把latin1當GBK輸出
讀取:數(shù)據(jù)庫讀取編碼為latin1的數(shù)據(jù)---------------->以編碼為latin1輸出------------------>GBK
所以,在寫WAP頁面或者有要把網(wǎng)站轉成UTF-8編碼的需求的時候,其實很簡單,只要在腳本程序里,把字符串編碼轉換一下就可以了。比如這里我們用PHP,那么用iconv或者mbstring都可以:
$str = iconv("gbk//IGNORE", "UTF-8//IGNORE", $str);
$str = mb_convert_encoding($str, "UTF-8", "gbk");
現(xiàn)總結到這里,在下才疏學淺,如有紕漏,還望指正。