一个BOM头引发的血案!!!

来源:互联网 发布:nginx body filter 编辑:程序博客网 时间:2024/04/30 15:08

今天在公司做项目的时候,服务器一直报500错误,检查代码以后代码没有任何问题,纠结了很长时间,最后出在了代码里面有了BOM头导致了项目不能运行,特此记录一下,以免大家跟我犯同样的错误。

事情的起源是一段很普通的代码:

[php] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <?php  
  2.   
  3. session_start();  
  4.   
  5. $_SESSION['test'] = 'test';  
  6.   
  7. $_SESSION['name'] = 'name';  
  8.   
  9. $data = serialize($_SESSION);  
  10.   
  11. ...更多后续代码  
  12.   
  13. ?>  


没有问题,很简单的一段设置session的代码。

但是运行后却报错:

Cannot send session cache limiter - headers already sent (output started at...) on line ...

报错信息很明显,就是在session_start()之前有了输出,导致后面的header发送失败。

因为很多情况下<?PHP  标签之前空格也会被当做header发送出去的,所以先检查这个。

仔细检查一下,没有空格,没有echo ,没有print等导致输出的问题,那么到底是什么问题呢?

应该有很多人都想到了,bom头。

对,这里就是bom头搞的鬼。

那么什么是bom头呢?

[plain] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. BOM: Byte Order Mark  
  2. 就是一个字节顺序标签,类似一个标记,又叫签名,   
  3.   
  4. BOM签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别,但是BOM虽然在编辑器中不显示,但是会产生输出,就像多了一个空行。  
  5. 一般的编码集中并不会出现bom头,unicode编码集中会出现。  
  6. 常见的bom头是:【摘录自:http://www.cnblogs.com/chengmo/archive/2010/10/30/1864004.html】  
  7.   
  8.   UTF-8    ║ EF BB BF   
  9.   UTF-16LE ║ FF FE (小尾)  
  10.   UTF-16BE ║ FE FF (大尾)  
  11.   UTF-32LE ║ FF FE 00 00   
  12.   UTF-32BE ║ 00 00 FE FF  
  13.   
  14. 为什么bom头会产生乱码?  
  15.   
  16. 【摘录自:http://www.cnblogs.com/chengmo/archive/2010/10/30/1864004.html】  
  17.   
  18. 有bom头的存储或者字节流,它一定是unicode字符集编码。到底属于那一种(utf-8还是utf-16或是utf-32),通过头可以判断出来。  
  19.   
  20. 由于已经说过utf-16,utf-32不指定bom头,解析程序默认就认为是ansi编码,出现乱码。而utf-8指定或者不指定程序都可判断知道对于的字符集编码。  
  21.   
  22. 问题就出在这里,可能有的应用程序(ie6浏览器),它就认为如果utf-8编码,就不需要指定bom头,它可以自己判断,相反指定了bom头,它还会出现问题  
  23.   
  24. (因为它把头当utf-8解析出现乱码了)。这里不截图了,cnblogs里面谈这个比较多,目前ie6会出现问题。其它ie7+,firefox,chrome不会出现,会忽略掉bom头。  
  25.   
  26. 统一解决办法是:存为utf-8编码是,不需要加入bom头,其它utf-16,utf-32加入。  

知道了这个,解决方案就很明显了:把utf-8的bom头去掉即可。

方式就是文件编码格式选择utf-8无bom。


另摘录一个网上找来的去除bom头的代码:

[php] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <?php  
  2. if (isset($_GET['dir'])){//config the basedir  
  3.     $basedir=$_GET['dir'];  
  4. }else{  
  5.     $basedir'.';  
  6. }  
  7.   
  8. $auto = 1;  
  9.   
  10. checkdir($basedir);  
  11.   
  12. function checkdir($basedir){  
  13.     if($dh = opendir($basedir)) {  
  14.         while(($file = readdir($dh)) !== false) {  
  15.             if($file != '.' && $file!= '..'){  
  16.                 if(!is_dir($basedir."/".$file)) {  
  17.                     echo"filename: $basedir/$file".checkBOM("$basedir/$file")."<br>";  
  18.                 }else{  
  19.                     $dirname$basedir."/".$file;  
  20.                     checkdir($dirname);  
  21.                 }  
  22.             }  
  23.         }  
  24.     closedir($dh);  
  25.     }  
  26. }  
  27.   
  28. function checkBOM ($filename) {  
  29.     global$auto;  
  30.     $contentsfile_get_contents($filename);  
  31.     $charset[1] =substr($contents, 0, 1);  
  32.     $charset[2] =substr($contents, 1, 1);  
  33.     $charset[3] =substr($contents, 2, 1);  
  34.     if(ord($charset[1]) == 239 && ord($charset[2]) == 187 &&ord($charset[3]) == 191) {  
  35.         if($auto == 1) {  
  36.             $restsubstr($contents, 3);  
  37.             rewrite ($filename,$rest);  
  38.             return("<font color=red>BOM found,automatically removed.</font>");  
  39.         }else {  
  40.             return("<font color=red>BOM found.</font>");  
  41.         }  
  42.     }  
  43.     elsereturn ("BOM Not Found.");  
  44. }  
  45.   
  46. function rewrite ($filename,$data) {  
  47.     $filenumfopen($filename,"w");  
  48.     flock($filenum, LOCK_EX);  
  49.     fwrite($filenum,$data);  
  50.     fclose($filenum);  
  51. }  
  52.   
  53. ?>  



另外一个常见的bom头的地方时xml文件。解析失败的话,有很大一部分原因是这个。

Error on line 1 of document  : Content is not allowed in prolog. Nested exception: Content is not allowed in prolog.

此时只要去掉bom头就行了。

解决的办法

用notepad++


里面的那个编码 转为无bom即可。。

希望可以帮到大家


0 0
原创粉丝点击