PHPExcel导出格式错误问题--格式与文件扩展名格式不一致--解决方案

使用PHPExcel自身simple导出没问题,复制到我的代码中再导出就会出现“您尝试打开的文件1.xls的格式与文件扩展名指定的格式不一致...”。

通过排查问题发现几点差异:

1.我直接调用干净的导出代码正常,在调用导出代码前调用了$table=D("someAction");就会出问题(ThinkPHP),其他代码包括M()->query("select ....");以及其他简单代码都不会导致导出错误。

2.Excel生成到本地后FTP出来正常,直接通过web导出下载就会出问题。

3.比较正常和不正常的xls文件,正常excel文件开头为D0 CF 11,而导出错误的文件在文件头多了3个字节:EF BB BF。。。这是为什么呢?

google发现一个相关信息,utf-8的BOM:

UTF- 8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到 一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是 “乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在 UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

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');
...

你可能感兴趣的:(PHPExcel导出格式错误问题--格式与文件扩展名格式不一致--解决方案)