zoukankan      html  css  js  c++  java
  • PHP文件头BOM头问题

    前几天我们公司服务器出现了一个离奇的问题,服务器与本地文件代码完全一致,本地运行正常,到了测试环境服务器之后,各种问题一个又一个浮现,先是后台验证码不显示,以为是session写入失败,又是怀疑gd库,又是觉得服务器gd路径错误,又排查目录权限,各种方法试之无效,百度必应各种搜索,整个公司一半以上PHP排查问题,我们之前的代码如下

    public function createImage()
        {
            $word = $this -> randomCode();
            // 记录字符串
            $_SESSION[$this -> _space]['code'] = base64_encode($this -> encryptsCode($word));
        
            $this -> image = ImageCreate($this -> _width, $this -> _height);
            ImageColorAllocate($this -> image, 220, 220, 220);
            // 在图片上添加扰乱元素
            $this -> disturbPixel();
            // 在图片上添加字符串
            $this -> drawCode($word);   
            ob_end_clean();     ------------------------------------服务器文件上解决问题仅仅加了这么一行函数
            ob_clean();  //关键代码,防止出现'图像因其本身有错无法显示'的问题。
            header("Content-type:text/html;charset=utf-8"); // 设置页面的编码风格
            header("Content-type: image/PNG");
            ImagePng($this -> image);
            ImageDestroy($this -> image);
            
        }

    言归正传,虽然这个问题解决了,但是购物车好好地失效了,原因是我们前端发现很多文件都带了BOM头上去,经过百度各种帖子,找到了检查BOM文件的方法

    本地文件上传到服务器上,某些文件头部总是出现一条空白,无论怎么修改文件都无法去除空白,用firebug查看header部分同样有一片空白,删除后空白消失,但是在文件里却无法找到那个空白的部分

    BOM头

    BOM: Byte Order Mark

    UTF-8 BOM又叫UTF-8 签名,其实UTF-8 的BOM对UFT-8没有作用,是为了支援UTF-16,UTF-32才加上的BOM,BOM签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别,但是BOM虽然在编辑器中不显示,但是会产生输出,就像多了一个空行

    这些大部分是编辑器的问题,PHP文件采用UTF-8编码,PHP开发大部分使用的文本编辑软件如:Zend studio、editplus、eclipse等等都可以显示并编辑UTF-8编码的文件,但是也有一些软件不能满足这个要求.

    类似如windows的记事本,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM).它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码.对于一般的文件,这样并不会产生什么麻烦.但对于 PHP来说,BOM是个大麻烦.

    对于BOM,PHP并不会忽略,在读取、包含或者引用这些文件时,PHP会把BOM作为文件开头正文的一部分,根据嵌入式语言的特点,这串字符将被直接执行(显示)出来.这就导致了一些页面的头部总是有一条白条,尽管样式padding、margin等各方面都设置好也无法让整个网页紧贴浏览器顶部,这头部白条就是这3个不可见的字符(0xEF 0xBB 0xBF,即BOM);

    另外还有的问题就是,受COOKIE送出机制的限制,在这些文件开头已经有BOM的文件中,COOKIE无法送出(因为在COOKIE送出前PHP已经送出了文件头),所以登入和登出功能失效.一切依赖COOKIE、SESSION实现的功能全部无效.

    所以,在编辑、修改任何文本文件的时候,请使用不会乱加BOM的编辑器.Linux下的编辑器应该都没有这个问题.WINDOWS下,请勿使用记事本等编辑器.推荐使用Editplus,Zend studio、eclipse等编辑器.

    其他的对于已经添加了BOM的文件,要取消的话,可以用不会乱加BOM的编辑器另存一次.当然也可以使用以下方法去除该目录下所有文件的头部BOM:

    检查哪些文件存在BOM

    <?php
    /*检测并清除BOM*/
    
    $basedir = ROOT_PATH;
    $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")." 
    ";
                    }else{
                        $dirname = $basedir."/".$file;
                        checkdir($dirname);
                    }
                }
            }//end while
            closedir($dh);
        }//end if($dh
    }//end function
    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 "";
            }else{
                return ("");
            }
        }
        else return ("BOM Not Found.");
    }//end function
    function rewrite($filename, $data){
        $filenum = fopen($filename, "w");
        flock($filenum, LOCK_EX);
        fwrite($filenum, $data);
        fclose($filenum);
    }//end function

    然后百度一些工具,有专门清除BOM头的,其次可以使用Notepad++来清除

    补充:以上PHP代码可能会有遗漏,在用以上方法测试完成可以用一下一下方法

    function printDir($d){
        $dir=dir($d);
        while(false != $row = $dir->read()){
            if($row=='.' || $row=='..') continue;
                if(is_dir($d.$row)){
                    printDir($d.$row.'/');
                }else{
                    $f=fopen($d.$row,"r");
                     if($f){
                        $str=fgets($f,102);
                        if (ord($str{0}) == 239 && ord($str{1}) == 187 && ord($str{2}) == 191) {
                        echo $d.$row.'
    ';
                    }
                }
                fclose($f);
            }
        }
    }

    想要花哨一点儿,也可以这样玩,不同的服务器要区分路径的格式问题

    <?php 
    /**
     * copyright (c) crossphp.cn
     * author aray
     * created 2009-07-25
     *
     **/
    error_reporting(E_ALL & ~E_NOTICE);
    $exts = array(
        '.x',
        '.html',
        '.dwt',
        '.lbi',
        '.tpl',
        '.php',
        '.js',
        '.css',
        '.xml',
        '.txt',
    );
    
    $start = false;
    if ($_POST && !empty($_POST['path']) )
    {
        $start = true;
        $PATH = $_POST['path'];
        $PATH = addslashes($PATH);
        $EXTS = $_POST['exts'];
    }
    
    function ReadDirs($path, $ext)
    {
        global $BOM;
        echo $path;
        $dir = opendir($path );
        echo '<ul>';
        while ( ($file = readdir($dir )))
        {
            if ($file == '.' || $file == '..') continue;
            
            $f = $path . '/' . $file;
            
            if (is_dir($f))
            {
                echo '<li class="folder"><span class="symbol">1</span>' . $file;
                echo '<ul>' . ReadDirs($f, $ext) . '</ul></li>';
            }
            else
            {
                $flag = false;
                if ( is_array($ext) )
                {
                    if (! in_array(getExt($file), $ext) )
                    {
                        continue;    
                    }
                    else
                    {
                        $flag = true;
                    }
                }
                else
                {
                    $flag = true;
                }
                if ($flag)
                {
                    $cssClass = 'file';
                    if (checkBOM($f))
                    {
                        $cssClass = 'bom';
                        $BOM[] = str_replace('//','/',str_replace('\','/',$f));
                    }
                    echo '<li class="'.$cssClass.'"><span class="symbol">2</span>' . $file . $isBom . "</li>";
                }
            }
        }
        echo '</ul>';
    }
    
    function getExt($filename )
    {
        $ext = strrchr($filename,'.');
        // 根本没有扩展名
        if ( empty($ext) )
        {
            return null;
        }
        return $ext;
    }
    
    function checkBOM($filename )
    {
        $contents = file_get_contents($filename);
        $char[1] = substr($contents, 0, 1); // 1
        $char[2] = substr($contents, 1, 1); // 2
        $char[3] = substr($contents, 2, 1); // 3
        // EF BB BF
        if ( ord($char[1]) == 239 && ord($char[2]) == 187 && ord($char[3]) == 191 ) 
        {
            return true;
        }
        return false;
    }
    ?>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>BOM检测工具</title>
    <style type="text/css">
    body, td, th {
        font-size: 14px;
    }
    body {
        margin-left: 15%;
        margin-top: 2px;
        margin-right: 15%;
        margin-bottom: 2px;
    }
    form {
        margin: 0px;
        padding: 0px;
    }
    ul {
        margin: 0px 0px 0px auto;
        padding: 0px;
    }
    .symbol {
        font-family: Wingdings;
        font-size: 20px;
        padding-right: 10px;
    }
    .path {
        color: #0033CC;
    }
    li {
        color: #333333;
        list-style: none;
    }
    .bom {
        color: #ff00ff;
    }
    .folder {
        color: #0000ff;
    }
    .file {
        color: #333333;
    }
    </style>
    </head>
    <body>
    <br/>
    <br/>
    <table width="100%" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#8DAFDA">
      <tr>
        <td height="70" align="center" valign="middle" bgcolor="#CBDBEE"><form id="form1" name="form1" method="post" action="">
            <table border="0" cellspacing="0" cellpadding="0">
              <tr>
                <td height="30" align="left" valign="middle"> 文件夹:</td>
                <td align="left" valign="middle"><select name="path" >
                    <?php $dir = opendir(dirname(dirname(__FILE__))); while ( ($f = readdir($dir)) )
                    { if ($f == '..' || is_file('./' . $f) ) continue;  ?>
                    <option value="../<?=$f?>" <?php if($_POST['path'] == '.\'.$f) echo 'selected';?> >
                    <?=$f?>
                    </option>
                    <?php }?>
                  </select></td>
                <td align="left" valign="middle"><input type="submit" name="button" id="button" value="提交" /></td>
              </tr>
            </table>
            <?php foreach($exts as $ext){ ?>
            <label>
              <input type="checkbox" name="exts[]" value="<?=$ext?>" 
              <?php if(is_array($_POST['exts']) && in_array($ext, $_POST['exts'])) echo 'checked'; ?> />
              <?=$ext?>
            </label>
            <?php }?>
          </form></td>
      </tr>
    </table>
    <div id="result"><br/>
      <br/>
      <?php if($start){?>
      <?php     echo '搜索路径: 
      <span class="path">' . str_replace('\\','\',$PATH) . '</span> ,
       实际路径:  <span class="path">' . realpath($PATH) . '</span><br/>';    echo '文件列表: ';
           ReadDirs( $PATH, $EXTS);?>
      <br/>
      <br/>
      <?php if ($BOM) { ?>
      发现BOM文件列表:<br/>
      <ul>
        <?php foreach( $BOM as $f){?>
        <li class="bom">
          <?=$f?>
        </li>
        <?php }?>
      </ul>
      <?php }?>
      <?php }?>
    </div>
    </body>
    </html>

     

  • 相关阅读:
    jvm内存溢出问题
    表单提交后台正则表达式验证
    java项目改为web项目
    图片按像素压缩
    系统和压缩内存占用空间大
    teamview修改id
    新浪天气api
    SpringBoot+MySql+Mybatis+ thymeleaf 搭建个人博客
    FFmpeg的简单使用
    禁止f12及浏览器右键查看
  • 原文地址:https://www.cnblogs.com/wt645631686/p/6868826.html
Copyright © 2011-2022 走看看