PHP Bom头导致乱码或者其他错误
转载至:https://www.cnblogs.com/wt645631686/p/6868826.html
前几天我们公司服务器出现了一个离奇的问题,服务器与本地文件代码完全一致,本地运行正常,到了测试环境服务器之后,各种问题一个又一个浮现,先是后台验证码不显示,以为是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>
文章来源: markwcm.blog.csdn.net,作者:黄啊码,版权归原作者所有,如需转载,请联系作者。
原文链接:markwcm.blog.csdn.net/article/details/105577218
- 点赞
- 收藏
- 关注作者
评论(0)