web開發中經常涉及前端網頁——php——mysql之間的數據交互,當數據只有英文時通常不會有什么問題,但一旦涉及中文,三個地方的某一處字符編碼不一致(如,網頁使用的時gbk而mysql使用utf-8)就有可能導致亂碼的出現。
(注:關於字符編碼請參見百度百科:http://baike.baidu.com/view/1204863.htm?fr=aladdin)
前端網頁編碼:
通常我們都認為可以通過<head>標簽內的<meta>項(如<META http-equiv="content-type" content="text/html; charset=xxx">)來設置整個頁面的字符編碼。大部分頁面可以采用這種方式來告訴瀏覽器顯示這個頁面的時候采用什么編碼,但是有的時候我們會發現有了這句還是不行,不管xxx是哪一種,瀏覽器采用的始終都是一種編碼。
這種情況涉及到http協議通信中的頭部(header)部分,實際上,用戶瀏覽網頁時,服務器發送給用戶的內容不僅包括我們的網頁(包括html/css/js這些代碼內容),還包括被稱為頭部(header)的描述性內容,這些內容會告知客戶端將要接收的數據的類型(是html還是純文本還是多媒體文件等)、大小、來源等信息(如果想要看一下這些信息,可以使用telnet工具(而不是通過瀏覽器)按照http協議自己發起get等請求試試)。由於頭部是優先於html發送的,<meta>作為html的一部分其優先級也低於頭部,如果在頭部中已經包含了有關網頁字符編碼的描述,瀏覽器最終就會按頭部中說明的字符編碼集來解析網頁。
在php中,可以使用 header("content-type:text/html; charset=xxx"); 來發送關於字符集的頭部。
而對於apache服務器來說,它具有一個AddDefaultCharset的功能,也就是會為每個發送的網頁按照服務器默認的字符集設定好對應頭部。
查看/etc/apache2/httpd.conf(2.4之前)或/etc/apache2/conf-available/charset.conf(2.4及以后),里面有一句AddDefaultCharset xxx如果這一句未處於注釋狀態,那么為每個網頁添加默認字符集頭部的功能就處於開啟狀態,此時單獨設置<meta>標簽里的字符集便沒有效果。
注意:html頁面所標明的編碼方式應該與實際在編寫html頁面(其實就是純文本)時保存所用的編碼方式一致。
一般而言,為了兼容中文甚至更多的其它語言,使用utf-8編碼方式是最省事的一種方式,因為utf-8幾乎支持世界上的所有常用語言。
mysql數據庫編碼:
在終端下mysql -uusername -ppassword 后進入mysql的控制程序,再鍵入show variables like 'character%'; (注意往mysql終端中鍵入命令語句或sql語句時分號不可以省略)可以看到類似下圖:
上面列舉了mysql在各個層面上所使用的字符集,其中(*)
character-set-server/default-character-set:服務器字符集,默認情況下所采用的。
character-set-database:數據庫字符集。
character-set-table:數據庫表字符集。
優先級依次增加。所以一般情況下只需要設置character-set-server,而在創建數據庫和表時不特別指定字符集,這樣統一采用character-set-server字符集。
character-set-client:客戶端的字符集。客戶端默認字符集。當客戶端向服務器發送請求時,請求以該字符集進行編碼。
character-set-results:結果字符集。服務器向客戶端返回結果或者信息時,結果以該字符集進行編碼。
在客戶端,如果沒有定義character-set-results,則采用character-set-client字符集作為默認的字符集。所以只需要設置character-set-client字符集。
於是我們會發現,上圖所示的character-set-server使用的不是utf8(注:在mysql中,utf-8編碼方式的表示為utf8,沒有“-”)。這是因為mysql默認的存儲方式在沒有修改的情況下就是latin1。在這種情況下,我們在使用mysql終端進行創建數據庫和數據表的操作時,若在sql語句中沒有指定所使用字符集,那么存儲時使用的編碼方式就會是latin1,明顯,中文存放在這種本來用於存放拉丁文的編碼方式下顯示出來肯定是亂碼。
那么怎么修改它呢,可以使用set character-set-server = utf8;(由於character-set-server優先級高,只修改它即可達到修改數據庫存儲編碼方式的效果)。此后在終端里使用sql建表時表的存儲編碼方式即是utf-8。
但是,這個修改只對當前服務有效,使用quit;退出后再次進入mysql終端就會發現字符集又變回了latin1了。想要使修改永久生效的方法我目前找到的資料顯示只有通過重新編譯mysql時修改編譯參數達到,如果有高手知道怎么不通過編譯實現煩請留言告知。
php編碼:
那么,說到了mysql,php在和mysql進行交互時要怎么保證傳輸數據過程中不出現亂碼呢?
按照(*)處的描述,實際上,為了使得存入mysql和從mysql中取出數據時不出現亂碼,我們只要使得以下三個系統參數設置為與服務器字符集character-set-server相同的字符集。 他們是:
character_set_client:客戶端的字符集。
character_set_results:結果字符集。
character_set_connection:連接字符集。
設置這三個系統參數可以通過向MySQL發送語句:set names xxx (xxx可以是utf8)來實現
因此,當涉及從php往mysql發送中文等非英文字符時,在mysql_connect語句后使用mysql_query("set names utf8");語句(這里假設數據庫存儲用的是utf8)后就可以放心傳送和取回中文了。
此外,由於html頁面實際上也可能由php動態生成,怎么保證php動態生成的頁面所使用的編碼方式和頭部或<meta>里聲明的一樣呢?
在php目錄下找到php.ini文件修改default_charset = "utf-8“即可使得php在輸出頁面時使用utf-8來編碼。
參考:
http://zhidao.baidu.com/link?url=u6hNAXaLxOYEcBIViascG2fgPRorVYQyN9eULCiVyNCKihlqUGJmCBOZWtp6KS8DO7UbWuCr3GeodvukDJLdQ_
http://niutuku.com/tech/Mysql/237673.shtml