久久男人AV资源网站无码_乱人伦人妻精品一区二区_亚洲国产精久久久久久久_狠狠躁夜夜躁人人爽天天BL

PHP中文編碼問題的終極解決方法

2014-07-04 宇易網絡 3080

PHP程序設計中中文編碼問題曾經困擾很多人,泰州網站建設經(jing)過長時間總結,跟大家分(fen)享如下。導致(zhi)這個問題的(de)(de)原因其實很簡單,每(mei)個國家(或區域)都規定了(le)(le)計算(suan)機(ji)信息(xi)(xi)交(jiao)換用(yong)(yong)的(de)(de)字(zi)符(fu)(fu)編(bian)碼(ma)集(ji),如美國的(de)(de)擴展ASCII碼(ma),中(zhong)(zhong)國的(de)(de)GB2312-80,日本(ben)(ben)的(de)(de)Shift-JIS等。作(zuo)為該國家/區域內(nei)信息(xi)(xi)處理(li)的(de)(de)基礎(chu),字(zi)符(fu)(fu)編(bian)碼(ma)集(ji)起著統一編(bian)碼(ma)的(de)(de)重要(yao)作(zuo)用(yong)(yong)。字(zi)符(fu)(fu)編(bian)碼(ma)集(ji)按(an)長度分(fen)為SBCS(單字(zi)節(jie)字(zi)符(fu)(fu)集(ji)),DBCS(雙字(zi)節(jie)字(zi)符(fu)(fu)集(ji))兩大類(lei)。早期的(de)(de)軟件(尤其是(shi)(shi)操作(zuo)系統),為了(le)(le)解(jie)決(jue)本(ben)(ben)地(di)字(zi)符(fu)(fu)信息(xi)(xi)的(de)(de)計算(suan)機(ji)處理(li),出現了(le)(le)各(ge)種本(ben)(ben)地(di)化(hua)(hua)版本(ben)(ben)(L10N),為了(le)(le)區分(fen),引進(jin)了(le)(le)LANG, Codepage等概念。但是(shi)(shi)由于各(ge)個本(ben)(ben)地(di)字(zi)符(fu)(fu)集(ji)代碼(ma)范(fan)圍重疊,相互間信息(xi)(xi)交(jiao)換困難;軟件各(ge)個本(ben)(ben)地(di)化(hua)(hua)版本(ben)(ben)獨立維護(hu)成本(ben)(ben)較高。因此有必要(yao)將本(ben)(ben)地(di)化(hua)(hua)工(gong)作(zuo)中(zhong)(zhong)的(de)(de)共性抽取出來,作(zuo)一致(zhi)處理(li),將特(te)別的(de)(de)本(ben)(ben)地(di)化(hua)(hua)處理(li)內(nei)容降低(di)到最少。這也就是(shi)(shi)所謂的(de)(de)國際化(hua)(hua)(118N)。各(ge)種語言信息(xi)(xi)被進(jin)一步規范(fan)為Locale信息(xi)(xi)。處理(li)的(de)(de)底層字(zi)符(fu)(fu)集(ji)變(bian)成了(le)(le)幾乎(hu)包(bao)含了(le)(le)所有字(zi)形的(de)(de)Unicode。

現在(zai)大(da)部分具有國際化特(te)征的(de)軟(ruan)件核心字(zi)(zi)(zi)符(fu)處理(li)都是以Unicode為基礎的(de),在(zai)軟(ruan)件運行(xing)時(shi)根據(ju)當時(shi)的(de)ocale/Lang/Codepage設(she)置確定相應的(de)本(ben)地(di)(di)字(zi)(zi)(zi)符(fu)編碼設(she)置,并(bing)依此處理(li)本(ben)地(di)(di)字(zi)(zi)(zi)符(fu)。在(zai)處理(li)過程(cheng)中(zhong)需要實現Unicode和本(ben)地(di)(di)字(zi)(zi)(zi)符(fu)集的(de)相互轉(zhuan)換(huan),甚或以Unicode為中(zhong)間的(de)兩個不同本(ben)地(di)(di)字(zi)(zi)(zi)符(fu)集的(de)相互轉(zhuan)換(huan)。這種(zhong)方式在(zai)網絡環境下被進一步延伸,任何網絡兩端的(de)字(zi)(zi)(zi)符(fu)信息也需要根據(ju)字(zi)(zi)(zi)符(fu)集的(de)設(she)置轉(zhuan)換(huan)成可(ke)接受(shou)的(de)內容。

數據庫中的字符集編碼問題

流行的(de)(de)關系數(shu)(shu)據(ju)(ju)庫(ku)系統都(dou)支持數(shu)(shu)據(ju)(ju)庫(ku)字(zi)(zi)符(fu)(fu)集編碼(ma),也就是說在創建數(shu)(shu)據(ju)(ju)庫(ku)時可以(yi)指定(ding)它(ta)自己(ji)的(de)(de)字(zi)(zi)符(fu)(fu)集設置(zhi),數(shu)(shu)據(ju)(ju)庫(ku)的(de)(de)數(shu)(shu)據(ju)(ju)以(yi)指定(ding)的(de)(de)編碼(ma)形式(shi)存儲。當應(ying)用(yong)程序訪問數(shu)(shu)據(ju)(ju)時,在入口和出口處都(dou)會(hui)有字(zi)(zi)符(fu)(fu)集編碼(ma)的(de)(de)轉換。對于(yu)中文數(shu)(shu)據(ju)(ju),數(shu)(shu)據(ju)(ju)庫(ku)字(zi)(zi)符(fu)(fu)編碼(ma)的(de)(de)設置(zhi)應(ying)當保證數(shu)(shu)據(ju)(ju)的(de)(de)完整性。GB2312、GBK、UTF-8等都(dou)是可選(xuan)的(de)(de)數(shu)(shu)據(ju)(ju)庫(ku)字(zi)(zi)符(fu)(fu)集編碼(ma);當然我們也可以(yi)選(xuan)擇ISO8859-1 (8-bit),只是我們得在應(ying)

用(yong)程序寫數據(ju)之(zhi)前先(xian)將(jiang)16Bit的(de)一(yi)個漢字(zi)或Unicode拆分成兩個8-bit的(de)字(zi)符(fu),讀(du)數據(ju)之(zhi)后也(ye)需要將(jiang)兩個字(zi)節合并起來,同(tong)時還要判別其中(zhong)的(de)SBCS字(zi)符(fu),因(yin)此我們并不(bu)推薦采用(yong)ISO8859-1作(zuo)為數據(ju)庫字(zi)符(fu)集編碼。這樣不(bu)但沒有充分利用(yong)數據(ju)庫自身的(de)字(zi)符(fu)集編碼支持,而且同(tong)時也(ye)增加了編程的(de)復雜(za)度。編程時,可(ke)以先(xian)用(yong)數據(ju)庫管理(li)系統提供的(de)管理(li)功能檢查其中(zhong)的(de)中(zhong)文數據(ju)是否正確。

PHP程序在查(cha)詢(xun)數據庫之前,首(shou)先執行mysql_query("SET NAMES xxxx");其(qi)中xxxx是你(ni)網頁的編碼(ma)(charset=xxxx),如果(guo)網頁中charset=utf8,則(ze)xxxx=utf8,如果(guo)網頁中charset=gb2312,則(ze)xxxx=gb2312,幾乎所有WEB程序,都(dou)有一(yi)段連接(jie)數據庫的公共(gong)代(dai)碼(ma),放在一(yi)個文(wen)件里,在這(zhe)文(wen)件里,加入mysql_query("SET NAMES xxxx")就可以(yi)了。

SET NAMES顯示客戶(hu)端(duan)發送(song)的SQL語(yu)句中使(shi)(shi)用什(shen)(shen)么字符集(ji)(ji)。因此(ci),SET NAMES 'utf-8'語(yu)句告(gao)訴服(fu)務(wu)器(qi)"將來從(cong)這個客戶(hu)端(duan)傳來的信息(xi)采(cai)用字符集(ji)(ji)utf-8"。它還(huan)為服(fu)務(wu)器(qi)發送(song)回(hui)客戶(hu)端(duan)的結果指定了(le)(le)字符集(ji)(ji)(例(li)如(ru),如(ru)果你使(shi)(shi)用一個SELECT語(yu)句,它表示列值使(shi)(shi)用了(le)(le)什(shen)(shen)么字符集(ji)(ji))。

定位問題時常用的技巧

定位(wei)中文(wen)(wen)(wen)編碼問題(ti)通(tong)常采用最笨(ben)的(de)也是(shi)最有(you)效的(de)辦法―在你(ni)認(ren)為有(you)嫌疑的(de)程序處理后打印字(zi)符(fu)串(chuan)(chuan)的(de)內(nei)碼。通(tong)過(guo)打印字(zi)符(fu)串(chuan)(chuan)的(de)內(nei)碼,你(ni)可以發現(xian)什么(me)時候(hou)中文(wen)(wen)(wen)字(zi)符(fu)被轉(zhuan)換成(cheng)Unicode,什么(me)時候(hou)Unicode被轉(zhuan)回中文(wen)(wen)(wen)內(nei)碼,什么(me)時候(hou)一個中文(wen)(wen)(wen)字(zi)成(cheng)了兩個Unicode字(zi)符(fu),什么(me)時候(hou)中文(wen)(wen)(wen)字(zi)符(fu)串(chuan)(chuan)被轉(zhuan)成(cheng)了一串(chuan)(chuan)問號,什么(me)時候(hou)中文(wen)(wen)(wen)字(zi)符(fu)串(chuan)(chuan)的(de)高位(wei)被截掉了……

取用合(he)適的樣本字(zi)符串也有(you)(you)助于區分問題的類(lei)型。如:"aa啊aa?@aa"等中(zhong)英相間,GB、GBK特征字(zi)符均有(you)(you)的字(zi)符串。一般來說,英文(wen)(wen)字(zi)符無論怎么(me)轉(zhuan)換或處理,都(dou)不(bu)會失(shi)真(zhen)(如果遇到(dao)了,可以嘗(chang)試著增加連續的英文(wen)(wen)字(zi)母長度)。

解決各種應(ying)用(yong)的亂碼問題(ti)

1)使用標簽設置頁面編碼

這(zhe)個標(biao)簽的(de)(de)作(zuo)用(yong)是聲明客戶(hu)端(duan)的(de)(de)瀏(liu)覽器用(yong)什么(me)字符集編(bian)碼(ma)(ma)(ma)(ma)顯示(shi)該頁(ye)(ye)面(mian),xxx可(ke)(ke)以為GB2312、GBK、UTF-8(和(he)MySQL不同,MySQL是UTF8)等等。因此,大部分頁(ye)(ye)面(mian)可(ke)(ke)以采用(yong)這(zhe)種(zhong)(zhong)方式來告訴瀏(liu)覽器顯示(shi)這(zhe)個頁(ye)(ye)面(mian)的(de)(de)時候采用(yong)什么(me)編(bian)碼(ma)(ma)(ma)(ma),這(zhe)樣才不會造成編(bian)碼(ma)(ma)(ma)(ma)錯誤而產生亂(luan)碼(ma)(ma)(ma)(ma)。但(dan)是有的(de)(de)時候我們(men)會發現有了這(zhe)句(ju)還是不行,不管xxx是哪一種(zhong)(zhong),瀏(liu)覽器采用(yong)的(de)(de)始終都(dou)是一種(zhong)(zhong)編(bian)碼(ma)(ma)(ma)(ma),這(zhe)個情況我后面(mian)會談到。

請(qing)注(zhu)意, 是屬于HTML信息(xi)的(de),僅(jin)僅(jin)是一個聲明,僅(jin)表(biao)明服務(wu)器(qi)(qi)已(yi)經把HTML信息(xi)傳到了瀏覽器(qi)(qi)。

2) header("content-type:text/html; charset=xxx");

這(zhe)(zhe)個(ge)函(han)(han)數(shu)header()的(de)(de)(de)作用(yong)(yong)是(shi)(shi)把括號里(li)面的(de)(de)(de)信(xin)(xin)息發(fa)到http標頭。如(ru)果括號里(li)面的(de)(de)(de)內容為文中所說那樣(yang),那作用(yong)(yong)和 標簽基本(ben)相同,大家對(dui)(dui)照第(di)一個(ge)看(kan)發(fa)現字符都差(cha)不多(duo)的(de)(de)(de)。但是(shi)(shi)不同的(de)(de)(de)是(shi)(shi)如(ru)果有(you)這(zhe)(zhe)段(duan)函(han)(han)數(shu),瀏(liu)覽器就(jiu)會永遠采用(yong)(yong)你(ni)所要求的(de)(de)(de)xxx編(bian)碼,絕對(dui)(dui)不會不聽(ting)話,因(yin)此這(zhe)(zhe)個(ge)函(han)(han)數(shu)是(shi)(shi)很有(you)用(yong)(yong)的(de)(de)(de)。為什么會這(zhe)(zhe)樣(yang)呢(ni)?那就(jiu)得說說http標頭和HTML信(xin)(xin)息的(de)(de)(de)差(cha)別了:

http標(biao)頭(tou)是服務器(qi)以(yi)http協議傳送HTML信息(xi)到(dao)瀏覽(lan)器(qi)前所送出的字串。而(er) 標(biao)簽是屬于(yu)HTML信息(xi)的,所以(yi)header()發(fa)送的內(nei)容(rong)先到(dao)達瀏覽(lan)器(qi),通俗點就是header()的優先級高于(yu)(不(bu)知道可(ke)(ke)不(bu)可(ke)(ke)以(yi)這樣講)。假如(ru)一個(ge)PHP頁面既有(you)header("content-type:text/html; charset=xxx"),又有(you),瀏覽(lan)器(qi)就只認(ren)前者http標(biao)頭(tou)而(er)不(bu)認(ren)meta了。當然這個(ge)函數(shu)只能(neng)在PHP頁面內(nei)使用。

同樣也(ye)留有一個問題,為什么(me)前者(zhe)就絕對(dui)起作用,而(er)后者(zhe)有時候(hou)就不行(xing)呢(ni)?這就是(shi)接下來要談的Apache的原因(yin)了。

3) AddDefaultCharset

Apache根目(mu)錄的conf文件夾里(li),有整(zheng)個Apache的配置文檔(dang)httpd.conf。

用文(wen)本編(bian)輯(ji)器打開httpd.conf,第(di)708行(不(bu)同版本可(ke)能不(bu)同)有(you)AddDefaultCharset xxx,xxx為(wei)編(bian)碼(ma)名稱。這(zhe)行代碼(ma)的意思:設(she)置整個服務器內的網頁文(wen)件(jian)http標頭里(li)的字符集為(wei)你默認的xxx字符集。有(you)這(zhe)行,就(jiu)相當于(yu)給(gei)每(mei)個文(wen)件(jian)都加了一(yi)行header("content-type:text/html; charset=xxx")。這(zhe)下就(jiu)明(ming)白為(wei)什(shen)么明(ming)明(ming) 設(she)置了是utf-8,可(ke)瀏(liu)覽器始終采用gb2312的原因。

如果(guo)網頁里有(you)header("content-type:text/html; charset=xxx"),就把默認(ren)的(de)字(zi)符集改為你設置的(de)字(zi)符集,所以這(zhe)個(ge)函數(shu)永遠有(you)用(yong)。如果(guo)把AddDefaultCharset xxx前面加個(ge)"#",注釋掉這(zhe)句(ju),而且(qie)頁面里不含header("content-type…"),那這(zhe)個(ge)時候就輪到meta標簽起作用(yong)了。

下面列(lie)出以上的優先(xian)順序:

.. header("content-type:text/html; charset=xxx")

.. AddDefaultCharset xxx

..

如果(guo)你是web程序員,建議給你的(de)每(mei)個頁(ye)面都(dou)加個header("content-type:text/html; charset=xxx"),這樣就(jiu)可(ke)(ke)以保證它(ta)在(zai)任何服務(wu)器都(dou)能(neng)正確顯示,可(ke)(ke)移植性也比較強。

4)PHP.ini中的default_charset配置:

php.ini中的(de)(de)(de)default_charset = "gb2312"定(ding)義了PHP的(de)(de)(de)默認語(yu)言(yan)字符集。一般(ban)推薦注釋掉(diao)此行,讓瀏覽器根(gen)據網頁頭中的(de)(de)(de)charset來自(zi)動選擇語(yu)言(yan)而(er)非做一個強制性的(de)(de)(de)規定(ding),這樣就可以在同臺(tai)服務器上提供(gong)多種(zhong)語(yu)言(yan)的(de)(de)(de)網頁服務。

結束語

其實(shi)PHP開發中(zhong)(zhong)(zhong)的(de)(de)中(zhong)(zhong)(zhong)文(wen)編碼并沒有想像(xiang)的(de)(de)那么復(fu)雜,雖(sui)然(ran)定位和解決問(wen)題(ti)沒有定規,各(ge)種運(yun)行環境也各(ge)不(bu)盡然(ran),但(dan)后面的(de)(de)原理是一樣的(de)(de)。了解字(zi)符集的(de)(de)知識是解決字(zi)符問(wen)題(ti)的(de)(de)基礎。不(bu)過,隨(sui)著(zhu)中(zhong)(zhong)(zhong)文(wen)字(zi)符集的(de)(de)變化,不(bu)僅僅是PHP編程,中(zhong)(zhong)(zhong)文(wen)信息處理中(zhong)(zhong)(zhong)的(de)(de)問(wen)題(ti)還是會(hui)存(cun)在一段時(shi)間的(de)(de)。


相關文章

展開
聯系電話: 客服QQ: