【PHP】一个bom头引发的血案

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

<?php

session_start();

$_SESSION['test'] = 'test';

$_SESSION['name'] = 'name';

$data = serialize($_SESSION);

...更多后续代码

?>


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

但是运行后却报错:

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

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

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

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

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

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

那么什么是bom头呢?

BOM: Byte Order Mark
就是一个字节顺序标签,类似一个标记,又叫签名, 

BOM签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别,但是BOM虽然在编辑器中不显示,但是会产生输出,就像多了一个空行。
一般的编码集中并不会出现bom头,unicode编码集中会出现。
常见的bom头是:【摘录自:http://www.cnblogs.com/chengmo/archive/2010/10/30/1864004.html】

  UTF-8    ║ EF BB BF 
  UTF-16LE ║ FF FE (小尾)
  UTF-16BE ║ FE FF (大尾)
  UTF-32LE ║ FF FE 00 00 
  UTF-32BE ║ 00 00 FE FF

为什么bom头会产生乱码?

【摘录自:http://www.cnblogs.com/chengmo/archive/2010/10/30/1864004.html】

有bom头的存储或者字节流,它一定是unicode字符集编码。到底属于那一种(utf-8还是utf-16或是utf-32),通过头可以判断出来。

由于已经说过utf-16,utf-32不指定bom头,解析程序默认就认为是ansi编码,出现乱码。而utf-8指定或者不指定程序都可判断知道对于的字符集编码。

问题就出在这里,可能有的应用程序(ie6浏览器),它就认为如果utf-8编码,就不需要指定bom头,它可以自己判断,相反指定了bom头,它还会出现问题

(因为它把头当utf-8解析出现乱码了)。这里不截图了,cnblogs里面谈这个比较多,目前ie6会出现问题。其它ie7+,firefox,chrome不会出现,会忽略掉bom头。

统一解决办法是:存为utf-8编码是,不需要加入bom头,其它utf-16,utf-32加入。


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

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


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

<?php
if (isset($_GET['dir'])){//config the basedir
    $basedir=$_GET['dir'];
}else{
    $basedir= '.';
}

$auto = 1;

checkdir($basedir);

function checkdir($basedir){
    if($dh = opendir($basedir)) {
        while(($file = readdir($dh)) !== false) {
            if($file != '.' && $file!= '..'){
                if(!is_dir($basedir."/".$file)) {
                    echo"filename: $basedir/$file".checkBOM("$basedir/$file")."<br>";
                }else{
                    $dirname= $basedir."/".$file;
                    checkdir($dirname);
                }
            }
        }
    closedir($dh);
    }
}

function checkBOM ($filename) {
    global$auto;
    $contents= file_get_contents($filename);
    $charset[1] =substr($contents, 0, 1);
    $charset[2] =substr($contents, 1, 1);
    $charset[3] =substr($contents, 2, 1);
    if(ord($charset[1]) == 239 && ord($charset[2]) == 187 &&ord($charset[3]) == 191) {
        if($auto == 1) {
            $rest= substr($contents, 3);
            rewrite ($filename,$rest);
            return("<font color=red>BOM found,automatically removed.</font>");
        }else {
            return("<font color=red>BOM found.</font>");
        }
    }
    elsereturn ("BOM Not Found.");
}

function rewrite ($filename,$data) {
    $filenum= fopen($filename,"w");
    flock($filenum, LOCK_EX);
    fwrite($filenum,$data);
    fclose($filenum);
}

?>



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

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

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

特此记录下来,希望对大家有帮助。

(2011-11-03  happyelements)
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值