先後端交互過程當中的編碼

原由

最近在寫PHP,自己對PHP不太熟練。而後遇到編碼這個問題,困擾了大半天,索性,系統探索解決一番。php

先後端交互過程當中涉及的編碼

  1. Browser cilent: 首先,瀏覽器的設置裏有設置編碼格式,通常設置爲UTF-8。html

  2. AJAX request: AJAX異步請求的過程當中能夠設置編碼,contentType:"application/x-www-form-urlencoded; charset=utf-8"前端

  3. PHP cilent: PHP經過$_POST這個全局變量接收前端POST過來的數據,編碼格式爲AJAX在請求頭中設置的charset=utf-8,PHP操做的過程當中能夠經過iconv函數庫自行轉碼,例如iconv("UTF-8","GB2312//IGNORE",$data) mysql

  4. connection: 在PHP與數據庫鏈接的過程當中能夠設置connection過程當中使用的編碼格式,例如CodeIgniter框架能夠在數據庫配置文件database.php中,設置'char_set' => 'latin1'算法

  5. databases: 數據會先把數據從php客戶端的編碼轉爲轉爲connection中設置的編碼,再以字節流的形式傳輸並插入數據庫。sql

字符編碼

經常使用的編碼分爲數據庫

  • UTF-8 萬國碼,就是它是一種變長的編碼方式vim

  • latin1 又稱「西歐語言」,是mysql數據庫默認設置。爲單字節編碼segmentfault

  • gb2312 一共收錄了7445個字符,包括6763個漢字和682個其它符號。後端

  • GBK 漢字內碼擴展規範,支持繁體與簡體和許多符號

UTF-8

走上國際化就靠它了。如今推薦使用UTF-8,這樣外國人打開咱們的網站的時候不須要轉碼,直接就能使用。
很少說了,你們都認識。

看一下他的編碼特質
UTF-8的設計有如下的多字符組序列的特質

  • 單字節字符的最高有效比特永遠爲0。

  • 多字節序列中的首個字符組的幾個最高有效比特決定了序列的長度。最高有效位爲110的是2字節序列,而1110的是三字節序列,如此類推。

  • 多字節序列中其他的字節中的首兩個最高有效比特爲10。

UTF-8的這些特質,保證了一個字符的字節序列不會包含在另外一個字符的字節序列中。這確保了以字節爲基礎的部分字符串比對(sub-string match)
方法能夠適用於在文字中搜索字或詞。有些比較舊的可變長度8位編碼(如Shift JIS)沒有這個特質,故字符串比對的算法變得至關複雜。雖然這增長了UTF-8
編碼的字符串的信息冗餘,可是利多於弊。另外,數據壓縮並不是Unicode的目的,因此不可混爲一談。即便在發送過程當中有部分字節因錯誤或干擾而徹底丟失,
仍是有可能在下一個字符的起點從新同步,令受損範圍受到限制。

另外一方面,因爲其字節序列設計,若是一個疑似爲字符串的序列被驗證爲UTF-8編碼,那麼咱們能夠有把握地說它是UTF-8字符串。一段兩字節隨機序列碰巧爲合法的UTF-8而非ASCII的機率爲32分1。對於三字節序列的機率爲256分1,對更長的序列的機率就更低了。

latin1

latin1編碼是單字節編碼,向下兼容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間徹底和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號。

由於latin1編碼範圍使用了單字節內的全部空間,在支持latin1的系統中傳輸和存儲其餘任何編碼的字節流都不會被拋棄。換言之,把其餘任何編碼的字節流看成latin1編碼看待都沒有問題。
這是個很重要的特性,MySQL數據庫默認編碼是Latin1就是利用了這個特性,latin1編碼是一個8位的容器。

把一個gbk編碼的串寫入latin1的表,不會有任何問題,保存的是原封不動的字節流,從表中讀取已寫入的串也不會有任何問題,且讀出的字節流就和當初寫入的徹底一致。

讀取出來之後,若是在終端下,就會理解成locale類型(若是locale系gbk,當時寫入的gbk中文串可正常回顯)讀取出來之後,若是要寫入文件,則文件編碼方式即當時寫入的字節流編碼,如gbk寫入的,讀出存入文件後,文件編碼也是gbk!
可是若是混着寫(utf-8 + gbk),那編輯器就犯蒙了,就可能會顯示會有亂碼。

固然,基於可維護的角度,仍是統一爲UTF-8編碼格式,以避免出現亂碼。

GBK與gb2312

由於歷史緣由,不少網頁和數據庫依然使用這個編碼格式
應該逐步升級爲UTF-8。

文件編碼

每一個文件都設置了其編碼的格式,大部分推薦使用UTF-8。

VIM文件編碼示例

一個文本文件,vim打開的時候按某種編碼A打開,轉換成某種編碼B,而後保存的時候轉換成另外一種編碼C,其餘文本編輯器相似,可能沒有vim這麼能夠設置和自動完成。
編碼B:對於整個文件沒有影響,只是事關顯示的,就是vim與操做系統交互時候使用的編碼。

編碼A:使用 set fileencodings=ucs-bom,utf-8,gbk,cp936,latin-1設置。vim 按照設置的順序檢查檢測文件的編碼。由於某些編碼裏不存在某些二進制序列的組合,因此若是檢測到就認爲不是這種編碼,檢查下一種編碼,不然就認爲是這一種。由於latin-1能夠出現任何二進制序列的組合,因此若是放到第一個,那麼將永遠以latin-1顯示。

在通常的二進制文件裏是不存在字符編碼的標記的。可是Unicode裏面有個特殊叫作零寬度空格(FEFF)而FFFE是不存在的編碼,因此在Unicode的標準裏能夠人爲的在開始加入這個字符(這個字符在任何字體下都是沒有寬度的,在中文字符裏面沒有任何的效果跟沒有同樣,是爲了照顧東南亞某些語言的顯示而設置的)。這樣就便於文本編輯器檢查字符和字節順序,可是在代碼裏include這種文件常常會出問題(這但是個大坑,編譯器會認爲這是一個非法字符,但是你又看不到)。

編碼B:set fileencoding=utf-8,保存時候使用的編碼,保存的時候自動轉換爲另外一種編碼。可是若是一開始打開的時候就識別錯了編碼,再轉換的時候一個不存在的字符也是不會完轉換的。

參考資料

  1. mysql的latin1 支持中文

  2. UTF-8維基百科

  3. VIM 文件編碼識別與亂碼處理

WilsonLiu's blog首發地址:http://blog.wilsonliu.cn

相關文章
相關標籤/搜索