php+mysql+apache編碼深度解析

我們在做PHP項目的時候,經常會遇到中文亂碼的問題,有時候編碼問題還導致MYSQL的報錯。中文亂碼總共有三個原因

1:APACHE服務器設置導致亂碼

2:PHP,或者HTML頁面編碼導致中文亂碼

3:MYSQL數據庫的表以及字段編碼導致中文亂碼

我們分別從這三個部分來探究PHP程序設計中的編碼問題

在這之前我們要了解一些基本理論:

1、文件編碼

每個文件在保存的時候都可以選擇以什麼編碼保存,例如用WINDOWS的記事本創建一個文件可以選擇ANSI 以及UTF8等等編碼。我們選擇了什麼編碼該文件就以這種編碼方式保存在硬盤上。 讀取該文件數據的時候也會指定一種編碼來打開,如果指定的編碼與文件保存的時候的編碼不一樣的話就會出現亂碼

2、HTML的編碼

在網頁頭部一般有這樣一個<HEAD>區域

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
這個的意思是讓客戶端知道,接下來輸出的是html代碼(text/html),並且以下輸出的內容都將是utf-8編碼的。如果我們用記事本創建一個HTML文件 該文件包含

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />

但是在保存的時候卻以ANSI編碼格式保存,那麼我們用瀏覽器打開這個文件時,瀏覽器看見META 行的UTF8編碼設置後 就將文件以UTF8格式輸出,而文件本來是ANSI編碼,這樣便出現了中文亂碼。

一:APACHE服務器編碼

在APACHE配置文件中有一行是編碼的設置 默認的是AddDefaultCharset ISO-8859-1,大部分人認爲應該將這句改爲 AddDefaultCharset UTF-8 。而蝸牛認爲這是誤人子弟。 這項配置是告訴APACHE服務器選用什麼樣的編碼來輸出WEB頁面(這樣做會忽略,HTML頁面中的頁面編碼的設置 EG:<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″ />),如果我們建立一個GB2312的頁面就會出現中文亂碼 。所以最好的方法是將AddDefaultCharset ISO-8859-1這一項註釋掉 #AddDefaultCharset

二:PHP編碼問題

php最終生成的是文本文件,而他要從數據庫中取出文本數據,還要把文本數據寫到數據庫中。由於MYSQL並不知道PHP發送給他的是什麼編碼的數據,所以需要客戶端PHP告訴他存取的是什麼編碼的數據。然後MYSQL會自動將PHP傳送來的數據轉換成目標編碼格式的數據。

比如: PHP要將 文本數據DATE 寫入到數據庫字段field中,PHP發送的是UTF-8編碼的數據,而DATE是以GB2312方式存儲的。這時候PHP通過設置告訴MYSQL 我發的是UTF-8格式,MYSQL接到數據後 說:”我知道了,來誰專門負責將UTF-8轉換成GB2312“ 於是MYSQL中的一個專門負責此事的小兵跑來 把數據拿走經過加工放到指定位置,如果PHP誤將UTF-8編碼的數據 當作GB2312編碼 送給MYSQL的時候,MYSQL會叫上次那個負責UTF-8—-GB2312的小兵來負責,而小兵不管三七二十一按同樣方法轉換存起來,這就出現了錯誤,亂碼就產生了。取數據的時候也一樣,PHP要告訴MYSQL要取出什麼樣編碼的數據。

PHP通過character_set_client告訴MYSQL,php存入數據庫的是什麼編碼方式

PHP通過character_set_results告訴MYSQL,php需要取什麼樣編碼的數據

PHP通過character_set_connection告訴MYSQL,PHP查詢中的文本,使用什麼編碼

就算上面的大家都注意了,還有個問題也可能導致亂碼。那就是PHP文件(生成的HTML頁面)本身的編碼問題

如果MYSQL傳來的數據 編碼與PHP本身編碼不一致也會導致亂碼

三:MYSQL編碼問題

Mysql目前支持多字符集,並且,支持在不同的字符集之間轉換(便於移植和支持多語言)。
Mysql可以設置服務器級字符集、數據庫級字符集、數據表級字符集、表列的字符集,實際上,最終使用字符集的地方是存儲字符的列,比如,你設置 table1中col1列是字符類型,col1纔用到了字符集,如果table1表的col2列是int類型,col2不使用字符集的概念。
服務器級字符集、數據庫級字符集、數據表級字符集都是爲列的字符集做默認選項的。
Mysql一定有一個字符集,可以通過啓動時加參數指定 ,也可以編譯時指定,也可以在配置文件裏指定。Mysql服務器字符集,只是做爲數據庫級的默認值。創建數據庫時,你可以指定字符集,如果沒指定,就使用服務器的字符集。同理,創建表時,你可以指定表級的字符集,如果沒指定,使用數據庫的字符集做爲表的字符集。創建列時,你可以指定某列的字符集,如果沒指定,就使用表的字符集。
通常情況下,您只需設置服務器級的字符集,其它的數據庫級,表級,以及列級的字符集,都繼承自服務器級字符集。
由於UTF8是最廣的字符集,所以,一般情況下,我們設置Mysql服務器級的字符集爲UTF8!

總結:

要保證不亂碼,需將三個編碼統一:

一:是網頁自身的編碼

二:是HTML裏指定的編碼

三:是PHP告訴Mysql的編碼(包括character_set_client和character_set_results)。

第一和第二個編碼,如果使用DW之類的編輯器寫的網頁,通常是一致的,但用記事本寫的網頁,有可能不一致。
第三個編碼,需要手工通知Mysql。這步可以通過在PHP裏使用mysql_query(“set names characterX”)來實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章