使用PHPExcel自身simple導出沒問題,複製到個人代碼中再導出就會出現「您嘗試打開的文件1.xls的格式與文件擴展名指定的格式不一致...」。php
經過排查問題發現幾點差別:web
1.我直接調用乾淨的導出代碼正常,在調用導出代碼前調用了$table=D("someAction");就會出問題(ThinkPHP),其餘代碼包括M()->query("select ....");以及其餘簡單代碼都不會致使導出錯誤。app
2.Excel生成到本地後FTP出來正常,直接經過web導出下載就會出問題。google
3.比較正常和不正常的xls文件,正常excel文件開頭爲D0 CF 11,而導出錯誤的文件在文件頭多了3個字節:EF BB BF。。。這是爲何呢?編碼
google發現一個相關信息,utf-8的BOM:spa
UTF- 8以字節爲編碼單元,沒有字節序的問題。UTF-16以兩個字節爲編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每一個編碼單元的字節序。例如收到 一個「奎」的Unicode編碼是594E,「乙」的Unicode編碼是4E59。若是咱們收到UTF-16字節流「594E」,那麼這是「奎」仍是 「乙」?.net
Unicode規範中推薦的標記字節順序的方法是BOM。BOM不是「Bill Of Material」的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:excel
在 UCS編碼中有一個叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,因此不該該出如今實際傳輸中。UCS規範建議咱們在傳輸字節流前,先傳輸 字符"ZERO WIDTH NO-BREAK SPACE"。code
這樣若是接收者收到FEFF,就代表這個字節流是Big-Endian的;若是收到FFFE,就代表這個字節流是Little-Endian的。所以字符"ZERO WIDTH NO-BREAK SPACE"又被稱做BOM。blog
UTF- 8不須要BOM來代表字節順序,但能夠用BOM來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者能夠用咱們前面介紹的編碼方法驗證一下)。因此若是接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。
Windows就是使用BOM來標記文本文件的編碼方式的。
google發現問題源頭(仍是GOOGLE給力!!)
http://phpexcel.codeplex.com/discussions/237813
上文解決方法有誤。按照上述方法,在緩衝區處理BOM頭。問題沒有解決。經過ob_get_contents導出到文件查看,並無發現BOM頭的存在,BOM頭是在發送之後某個階段添加的。
無奈,批量修改全部源碼的BOM頭。問題完全解決。
回過頭一想,爲何添加了D('someAction')行代碼就出問題。可能由於該代碼自動連接了某些代碼文件,而這些文件都是帶有BOM開頭的utf-8文件。
附批量修改全部文件BOM頭的腳本:http://blog.csdn.net/lgg201/archive/2010/09/02/5860125.aspx
OK, I finally found a work arround. I put the following 2 lines of code before redirecting output to the client browser and it looks that it fixed the problem. Probably that strange characters were sent to the browser. So, calling ob_end_clean() seams to clean the output buffer before sending the excel document. ob_start() is also important to reopen the output buffer.
...
ob_end_clean(); // Added by me
ob_start(); // Added by me
// Redirect output to a clients web browser (Excel5) header('Content-Type: application/vnd.ms-excel'); ...