php UTF-8、Unicode和BOM問(wèn)題
更新時(shí)間:2010年05月18日 23:50:45 作者:
經(jīng)常遇到的問(wèn)題是,使用了BOM編碼后,PHP腳本執(zhí)行錯(cuò)誤,或使用fileStream讀取并轉(zhuǎn)換為XML會(huì)報(bào)錯(cuò)"The markup in the document following the root element must be well-formed."。
一、介紹
UTF-8 是一種在web應(yīng)用中經(jīng)常使用的一種 Unicode 字符的編碼方式,使用 UTF-8 的好處在于它是一種變長(zhǎng)的編碼方式,對(duì)于 ANSII 碼編碼長(zhǎng)度為1個(gè)字節(jié),這樣的話在傳輸大量 ASCII 字符集的網(wǎng)頁(yè)時(shí),可以大量節(jié)約網(wǎng)絡(luò)帶寬。
UTF-8簽名(UTF-8 signature)也叫做BOM(Byte Order Mark),是UTF編碼方案里用于標(biāo)識(shí)編碼的標(biāo)準(zhǔn)標(biāo)記。BOM,是UTF編碼方案里用于標(biāo)識(shí)編碼的標(biāo)準(zhǔn)標(biāo)記,在UTF-16里本來(lái)是FF FE,變成UTF-8就成了EF BB BF。這個(gè)標(biāo)記是可選的,因?yàn)閁TF8字節(jié)沒(méi)有順序,所以它可以被用來(lái)檢測(cè)一個(gè)字節(jié)流是否是UTF-8編碼的。微軟做這種檢測(cè),但有些軟件不做這種檢測(cè),而把它當(dāng)作正常字符處理。微軟在自己的UTF-8格式的文本文件之前加上了EF BB BF三個(gè)字節(jié), windows上面的notepad等程序就是根據(jù)這三個(gè)字節(jié)來(lái)確定一個(gè)文本文件是ASCII的還是UTF-8的, 然而這個(gè)只是微軟暗自作的標(biāo)記, 其它平臺(tái)上并沒(méi)有對(duì)UTF-8文本文件做個(gè)這樣的標(biāo)記。也就是說(shuō)一個(gè)UTF-8文件可能有BOM,也可能沒(méi)有BOM。
只有一個(gè)BOM,是不會(huì)有問(wèn)題的。如果多個(gè)文件設(shè)置了簽名,在二進(jìn)制流中就會(huì)包含多個(gè)UTF-8簽名,也就是導(dǎo)致XML轉(zhuǎn)換失敗的"root element must be well-formed"原因。
二、查看和轉(zhuǎn)換
既然一個(gè)UTF-8文件可能有BOM,也可能沒(méi)有,那該如何區(qū)分呢?
只要用帶十六進(jìn)制編輯方式的軟件,例如,用UltraEdit-32打開文件,切換到十六進(jìn)制編輯模式,察看文件頭部是否有EF BB BF。有,則為帶BOM方式。
Windows自帶的notepad記事本,保存為UTF-8時(shí),默認(rèn)就帶BOM。
轉(zhuǎn)換的方法有很多,常見(jiàn)的UltraEdit-32或NotePad++都可以,以UltraEdit-32為例。打開文件后,選擇“另存為”,在“格式”一欄中有如下選擇:

另外,DreamWeaver CS3也有類似的選項(xiàng),在“首選項(xiàng)”中,如果選擇 Unicode (UTF-8) 作為默認(rèn)編碼,則可以選擇“包括 Unicode 簽名 (BOM)”選項(xiàng),以在文檔中包括字節(jié)順序標(biāo)記 (BOM)。否則,不帶BOM:

三、其他知識(shí)
從http://blog.csdn.net/thimin/archive/2007/08/03/1724393.aspx 一文了解到:
所謂的unicode保存的文件實(shí)際上是utf-16,只不過(guò)恰好跟unicode的碼相同而已,但在概念上unicode與utf是兩回事,unicode是內(nèi)存編碼表示方案,而utf是如何保存和傳輸unicode的方案。utf-16還分高位在前 (LE)和高位在后(BE)兩種。官方的utf編碼還有utf-32,也分LE和BE。非unicode官方的utf編碼還有utf-7,主要用于郵件傳輸。utf-8的單字節(jié)部分是和iso-8859-1兼容的,這主要是一些舊的系統(tǒng)和庫(kù)函數(shù)不能正確處理utf-16而被迫出來(lái)的,而且對(duì)英語(yǔ)字符來(lái)說(shuō),也節(jié)省保存的文件空間(以非英語(yǔ)字符浪費(fèi)空間為代價(jià))。在iso-8859-1的時(shí)候,utf8和iso-8859-1都是用一個(gè)字節(jié)表示的,當(dāng)表示其它字符的時(shí)候,utf-8會(huì)使用兩個(gè)或三個(gè)字節(jié)。
一段關(guān)于BOM的更詳細(xì)說(shuō)明,來(lái)自這里:
在UCS 編碼中有一個(gè)叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS規(guī)范建議我們?cè)趥鬏斪止?jié)流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個(gè)字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個(gè)字節(jié)流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來(lái)表明字節(jié)順序,但可以用BOM來(lái)表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節(jié)流,就知道這是UTF-8編碼了。
Windows就是使用BOM來(lái)標(biāo)記文本文件的編碼方式的。
PHP也不支持BOM。
PHP在設(shè)計(jì)時(shí)就沒(méi)有考慮BOM的問(wèn)題,也就是說(shuō)他不會(huì)忽略UTF-8編碼的文件開頭BOM的那三個(gè)字符。由于必須在<?或者<?php后面的代碼才會(huì)作為PHP代碼執(zhí)行,所以這三個(gè)字符將會(huì)直接輸出。如果插件的文件有這個(gè)問(wèn)題,將會(huì)導(dǎo)致在后臺(tái)頁(yè)面里激活或者不激活插件后顯示白屏,如果是模版文件有這個(gè)問(wèn)題,將會(huì)導(dǎo)致這三個(gè)字符直接輸出,造成頁(yè)面上方有一個(gè)小空行。國(guó)外的英文插件和模版一般都是用的ASCII碼的編碼方式,不會(huì)有BOM,只有國(guó)內(nèi)的插件和模版會(huì)由于作者的不知情造成問(wèn)題。還有,大家修改模版的時(shí)候,由于輸出頁(yè)面使用UTF-8編碼,那么修改模版的時(shí)候如果有加入中文字符的話,必須把文件轉(zhuǎn)成UTF-8編碼才能正常顯示,這個(gè)時(shí)候如果所使用的編輯器自動(dòng)加上了BOM的話,將會(huì)造成在頁(yè)面上輸出這三個(gè)字符,顯示效果就要看瀏覽器了,一般是一個(gè)空行或是一個(gè)亂碼。
※ 補(bǔ)充一句:特別是當(dāng)使用php導(dǎo)入模板的時(shí)候,更容易因?yàn)檫@三個(gè)字符,導(dǎo)致瀏覽異常。
UTF-8 是一種在web應(yīng)用中經(jīng)常使用的一種 Unicode 字符的編碼方式,使用 UTF-8 的好處在于它是一種變長(zhǎng)的編碼方式,對(duì)于 ANSII 碼編碼長(zhǎng)度為1個(gè)字節(jié),這樣的話在傳輸大量 ASCII 字符集的網(wǎng)頁(yè)時(shí),可以大量節(jié)約網(wǎng)絡(luò)帶寬。
UTF-8簽名(UTF-8 signature)也叫做BOM(Byte Order Mark),是UTF編碼方案里用于標(biāo)識(shí)編碼的標(biāo)準(zhǔn)標(biāo)記。BOM,是UTF編碼方案里用于標(biāo)識(shí)編碼的標(biāo)準(zhǔn)標(biāo)記,在UTF-16里本來(lái)是FF FE,變成UTF-8就成了EF BB BF。這個(gè)標(biāo)記是可選的,因?yàn)閁TF8字節(jié)沒(méi)有順序,所以它可以被用來(lái)檢測(cè)一個(gè)字節(jié)流是否是UTF-8編碼的。微軟做這種檢測(cè),但有些軟件不做這種檢測(cè),而把它當(dāng)作正常字符處理。微軟在自己的UTF-8格式的文本文件之前加上了EF BB BF三個(gè)字節(jié), windows上面的notepad等程序就是根據(jù)這三個(gè)字節(jié)來(lái)確定一個(gè)文本文件是ASCII的還是UTF-8的, 然而這個(gè)只是微軟暗自作的標(biāo)記, 其它平臺(tái)上并沒(méi)有對(duì)UTF-8文本文件做個(gè)這樣的標(biāo)記。也就是說(shuō)一個(gè)UTF-8文件可能有BOM,也可能沒(méi)有BOM。
只有一個(gè)BOM,是不會(huì)有問(wèn)題的。如果多個(gè)文件設(shè)置了簽名,在二進(jìn)制流中就會(huì)包含多個(gè)UTF-8簽名,也就是導(dǎo)致XML轉(zhuǎn)換失敗的"root element must be well-formed"原因。
二、查看和轉(zhuǎn)換
既然一個(gè)UTF-8文件可能有BOM,也可能沒(méi)有,那該如何區(qū)分呢?
只要用帶十六進(jìn)制編輯方式的軟件,例如,用UltraEdit-32打開文件,切換到十六進(jìn)制編輯模式,察看文件頭部是否有EF BB BF。有,則為帶BOM方式。
Windows自帶的notepad記事本,保存為UTF-8時(shí),默認(rèn)就帶BOM。
轉(zhuǎn)換的方法有很多,常見(jiàn)的UltraEdit-32或NotePad++都可以,以UltraEdit-32為例。打開文件后,選擇“另存為”,在“格式”一欄中有如下選擇:

另外,DreamWeaver CS3也有類似的選項(xiàng),在“首選項(xiàng)”中,如果選擇 Unicode (UTF-8) 作為默認(rèn)編碼,則可以選擇“包括 Unicode 簽名 (BOM)”選項(xiàng),以在文檔中包括字節(jié)順序標(biāo)記 (BOM)。否則,不帶BOM:

三、其他知識(shí)
從http://blog.csdn.net/thimin/archive/2007/08/03/1724393.aspx 一文了解到:
所謂的unicode保存的文件實(shí)際上是utf-16,只不過(guò)恰好跟unicode的碼相同而已,但在概念上unicode與utf是兩回事,unicode是內(nèi)存編碼表示方案,而utf是如何保存和傳輸unicode的方案。utf-16還分高位在前 (LE)和高位在后(BE)兩種。官方的utf編碼還有utf-32,也分LE和BE。非unicode官方的utf編碼還有utf-7,主要用于郵件傳輸。utf-8的單字節(jié)部分是和iso-8859-1兼容的,這主要是一些舊的系統(tǒng)和庫(kù)函數(shù)不能正確處理utf-16而被迫出來(lái)的,而且對(duì)英語(yǔ)字符來(lái)說(shuō),也節(jié)省保存的文件空間(以非英語(yǔ)字符浪費(fèi)空間為代價(jià))。在iso-8859-1的時(shí)候,utf8和iso-8859-1都是用一個(gè)字節(jié)表示的,當(dāng)表示其它字符的時(shí)候,utf-8會(huì)使用兩個(gè)或三個(gè)字節(jié)。
一段關(guān)于BOM的更詳細(xì)說(shuō)明,來(lái)自這里:
在UCS 編碼中有一個(gè)叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS規(guī)范建議我們?cè)趥鬏斪止?jié)流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個(gè)字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個(gè)字節(jié)流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來(lái)表明字節(jié)順序,但可以用BOM來(lái)表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節(jié)流,就知道這是UTF-8編碼了。
Windows就是使用BOM來(lái)標(biāo)記文本文件的編碼方式的。
PHP也不支持BOM。
PHP在設(shè)計(jì)時(shí)就沒(méi)有考慮BOM的問(wèn)題,也就是說(shuō)他不會(huì)忽略UTF-8編碼的文件開頭BOM的那三個(gè)字符。由于必須在<?或者<?php后面的代碼才會(huì)作為PHP代碼執(zhí)行,所以這三個(gè)字符將會(huì)直接輸出。如果插件的文件有這個(gè)問(wèn)題,將會(huì)導(dǎo)致在后臺(tái)頁(yè)面里激活或者不激活插件后顯示白屏,如果是模版文件有這個(gè)問(wèn)題,將會(huì)導(dǎo)致這三個(gè)字符直接輸出,造成頁(yè)面上方有一個(gè)小空行。國(guó)外的英文插件和模版一般都是用的ASCII碼的編碼方式,不會(huì)有BOM,只有國(guó)內(nèi)的插件和模版會(huì)由于作者的不知情造成問(wèn)題。還有,大家修改模版的時(shí)候,由于輸出頁(yè)面使用UTF-8編碼,那么修改模版的時(shí)候如果有加入中文字符的話,必須把文件轉(zhuǎn)成UTF-8編碼才能正常顯示,這個(gè)時(shí)候如果所使用的編輯器自動(dòng)加上了BOM的話,將會(huì)造成在頁(yè)面上輸出這三個(gè)字符,顯示效果就要看瀏覽器了,一般是一個(gè)空行或是一個(gè)亂碼。
※ 補(bǔ)充一句:特別是當(dāng)使用php導(dǎo)入模板的時(shí)候,更容易因?yàn)檫@三個(gè)字符,導(dǎo)致瀏覽異常。
您可能感興趣的文章:
- PHP解碼unicode編碼的中文字符代碼分享
- php utf-8轉(zhuǎn)unicode的函數(shù)
- 淺析PHP中的UNICODE 編碼與解碼
- PHP中正則表達(dá)式對(duì)UNICODE字符碼的匹配方法
- PHP如何實(shí)現(xiàn)Unicode和Utf-8編碼相互轉(zhuǎn)換
- 簡(jiǎn)單談?wù)刾hp中的unicode和utf8編碼
- php制作unicode解碼工具(unicode編碼轉(zhuǎn)換器)代碼分享
- 用php實(shí)現(xiàn)gb2312和unicode間的編碼轉(zhuǎn)換
- PHP解密Unicode及Escape加密字符串
- php實(shí)現(xiàn)utf-8轉(zhuǎn)unicode函數(shù)分享
- PHP實(shí)現(xiàn)Unicode編碼相互轉(zhuǎn)換的方法示例
相關(guān)文章
PHP curl模擬瀏覽器采集阿里巴巴的實(shí)現(xiàn)代碼
都說(shuō)阿里巴巴有不能采集和防采集的神話,今天就用張老師講的Curl采集寫了一個(gè)模擬瀏覽器的代碼。2011-04-04PHP連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)頁(yè)面增刪改查效果
這篇文章主要介紹了如何利用PHP實(shí)現(xiàn)連接SQL數(shù)據(jù)庫(kù),從而對(duì)頁(yè)面進(jìn)行增刪改查功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-03-03詳解WordPress中簡(jiǎn)碼格式標(biāo)簽編寫的基本方法
這篇文章主要介紹了詳解WordPress中簡(jiǎn)碼格式標(biāo)簽編寫的基本方法,文中講到了添加和移除簡(jiǎn)碼等的一些PHP函數(shù)的用法,需要的朋友可以參考下2015-12-12解析PHP中的file_get_contents獲取遠(yuǎn)程頁(yè)面亂碼的問(wèn)題
本篇文章是對(duì)PHP中的file_get_contents獲取遠(yuǎn)程頁(yè)面出現(xiàn)亂碼的問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP中使用循環(huán)實(shí)現(xiàn)的金字塔圖形
這篇文章主要介紹了PHP中使用循環(huán)實(shí)現(xiàn)的金字塔圖形,本文是一篇PHP的課堂筆記,完成老師的作業(yè)總結(jié)而來(lái),需要的朋友可以參考下2014-11-11