web程式亂碼深入分析【基礎原理篇】--php為例
做web應用程式開發也有很多年了,前後涉及有,asp,asp.net,jsp,php 。儘管語言都不相同,在日常開發中,無論那門語言都出現過,瀏覽器端的亂碼問題。 出現了,都會手忙腳亂一陣,上網查資料,一頁一頁看。 還有些緊張,因為boss可能還等著解決問題呢。 想必這些情況,做web開發的同人也是經常遇到的。 下面要講的是比較原理性的,我想如果對於亂碼產生原因找到了,以後出現類似問題。按照原理推論,一定也會很快解決。 (以下說明檔案,都是以文字檔案說明)
一、文字檔案編碼是什麼?
a、文字檔案編碼存在**了呢?我們知道,計算機儲存檔案,最終都是以二進位制儲存的,通過流方式讀取任何檔案,得到是8位的位元組流。乙個檔案生成了,同時也確定了它的編碼了。 以下通過軟體:winhex比較說明:二、php引擎怎麼樣獲得我的檔案編碼通過使用記事本:輸入「中」,另存為時候,分別選擇:utf-8,unicode,ansi編碼。我們通過winhex開啟比較下。
utf-8:ef bb bf e4 b8 ad 6位元組
unicode:ff fe 2d 4e 4位元組
ansi(gb2312):d6 d0 2位元組
同乙個漢字中,儲存為檔案後,實質儲存的位元組碼各不相同。
這裡我們一定想到乙個問題,讀取該檔案的軟體開啟這個檔案,怎麼都可以顯示出:「中」呢?
答案是:檢視屬性沒有任何不同
那檔案編碼存在:檔案的位元組碼裡面了?
哈哈,我也是這麼想的,通過查閱資料知道,unicode碼可以指定乙個bom(順序頭),unicode常見表現形式有:utf-8,utf- 16 順序頭不一樣,因此很多軟體可以通過這個標記來區分檔案是什麼編碼了。 上面例子,utf-8頭是:efbbbf,unicode le是:fffe.
是不是所有檔案編碼都會寫入到檔案位元組碼裡面呢?
如果真的這樣的話,那麼問題就簡單了。所有應用程式讀文字檔案時候,讀一下標記,那麼就知道它是什麼編碼。 其實,除了unicode有bom這個特殊頭外,其它編碼可沒有呢。 看到剛才那個:ansi(gb2312)編碼了嗎,值是:d6d0 剛才是「中」 在gb2312編碼表中的代號。
b、怎麼樣獲得檔案編碼呢?
上個例子中,我們知道,文字檔案編碼不可能都儲存在檔案位元組碼中。 那麼,應用程式讀取檔案怎麼樣判斷編碼呢?
我們用:zend 工具,以euc-jp生成乙個檔案,內容是:」中」 ,通過:winhex檢視該檔案,它的位元組碼是:c3 e6 。可以看到同樣都是:"中」 gb2312儲存檔案,得到位元組碼是:d6 d0 .
我用windows 記事本開啟:2個檔案看一下:
怎麼我檔案內容是:」中「,用euc_jp編碼儲存後,用記事本開啟,看到是:」面「 了呢? 是不是windows 記事本有問題呢?
記事本沒有任何問題,windows 記事本在開啟文字檔案時候,會先判斷bom類標記,如果發現文字檔案存在該標記。那麼,就能夠知道它對應的編碼了。然後,將位元組流轉換為對應編碼字串。 這樣顯示正常儲存時候內容。
如果,沒有bom頭標記的文字,記事本程式,就預設當:ansi編碼處理了(在簡體中文系統下,ansi編碼代表gb2312編碼,在日文作業系統 下,ansi編碼代表jis編碼),在簡體中文下,ansi對應是:gb2312。因此,記事本把」c3e6」當作gb2312處理。 c3e6在gb2312編碼表中對應是漢字:「面」 了。
文字檔案,儲存時候儲存編碼,與讀出時候設定編碼,如果不統一,就會造成亂碼!
其實,這裡說php引擎處理編碼,與記事本識別編碼基本是相同的。發現能夠識別編碼就識別,不能識別編碼就按照:三、瀏覽器怎麼樣獲得服務端的編碼php.in 中
default_charset = "iso-8859-1"
default_charset 指定編碼處理了,預設是:iso-8859-1。
這裡囉嗦一下,現在很多應用程式都會用:"iso-8859-1" 作為預設編碼,jsp也是這樣的。它的優點大家應該可以理解:iso-8859-1(eascii 擴充套件ascii編碼)以ascii為基礎,在空置的0xa0-0xff的範圍內,加入96個字母及符號,藉以供使用附加符號的拉丁字母語言使用。用乙個8 位字元可以表示任意字符集。在程式開發中,我們常用的變數,都會是英文本元空格之類,這些都會在解析時候保持原來不變。而對於的中文字元,都會是多位元組 的。iso-8859-1解析後,會變成一些西歐字元。 但是實際上,並不會影響程式任何邏輯。 因為那些亂七八糟的西歐字元,只是一些注釋,或者值而已。 程式語法完全沒有破壞!!
處理完的結果它還是位元組流,準備傳送給瀏覽器。
這裡我們知道,瀏覽器得到web服務端返回的檔案流,預設是:iso-8859-1 位元組碼。其實可以看作是與原始存檔案流的位元組碼是相同的。瀏覽器也是乙個軟體,它獲得了位元組流,它從那裡知道位元組流是什麼編碼呢?
這裡有幾種形式:
a、http resposne頭告知編碼
以下是:訪問:baidu.com httpwatch 抓包圖:
我們只抓取了:stream這個選項卡,可以通過這裡看到,右下返回內容是亂碼,其實這些就是伺服器返回位元組流。 再往上看:
b、通過html原始碼,meta頭告知
並不是所有伺服器端程式都會,都是很麼按章出牌,告知自己流編碼。很多時候,php開發人員沒有加入:
header("content-type:text/xml;charset=字元編碼"); 那麼瀏覽器還有其它方法處理嗎?
如果meta頭指定了,瀏覽器也一樣知道編碼是什麼了。
c、有一些問題:
如果header,meta兩個個都指定了以那個為準呢?
測試表明,以http 協議中,response 頭裡面的charset為主。 會忽視掉,meta指定。
如果header,meta兩個都沒有指定,會出現什麼情況呢?
這個時候,就像上面例子裡面的記事本了。 會怎麼出現依據瀏覽器自己本身設定預設編碼。如果你檔案剛好是:gb2312編寫,檢視瀏覽器預設編碼剛好也是:gb2312,那麼你的中文字元顯示正 常。如果換上乙個預設字元不一樣,就會出現亂碼情況。 這種情況,估計做web開發同人經常會遇到吧!
深入分析Synchronized原理
先看下面的話再看這篇部落格 可以在下面參考的網頁中了解monitorenter和monitorexit的作用,我就不盜用他們的話了,大致意思是,每個物件都有乙個monitor監視器,呼叫monitorenter就是嘗試獲取這個物件,成功獲取到了就將值 1,離開就將值減1。如果是執行緒重入,在將值 1...
FFmpeg深入分析之零 基礎
ffmpeg是相當強大的多 編譯碼框架,在深入分析其源 之前必須要有基本的多 基礎知識,否則其源 會非常晦澀難懂。本文將從介紹一些基本的多 只是,主要是為研讀ffmpeg源 做準備,比如一些編譯碼部分,只有真正了解了多 處理的基本流程,研讀ffmpeg源 才能事半功倍。了解了上面的乙個 檔案從開啟到...
FFmpeg深入分析之零 基礎
ffmpeg是相當強大的多 編譯碼框架,在深入分析其源 之前必須要有基本的多 基礎知識,否則其源 會非常晦澀難懂。本文將從介紹一些基本的多 只是,主要是為研讀ffmpeg源 做準備,比如一些編譯碼部分,只有真正了解了多 處理的基本流程,研讀ffmpeg源 才能事半功倍。了解了上面的乙個 檔案從開啟到...