前几天我们公司服务器出现了一个离奇的问题,服务器与本地文件代码完全一致,本地运行正常,到了测试环境服务器之后,各种问题一个又一个浮现,先是后台验证码不显示,以为是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); //
$char[2] = substr($contents, 1, 1); //
$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>

PHP文件头BOM头问题的更多相关文章

  1. VA中用文件头注释和函数头注释Suggestions

    写C++代码,不能不用VA,这里贴两个我最常用的注释Suggestions. [1.File Header 文件头注释] /*** @file     $FILE_BASE$.$FILE_EXT$* ...

  2. PE文件格式详解,第二讲,NT头文件格式,以及文件头格式

    PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...

  3. Visual Studio+VAssistX自动添加注释,函数头注释,文件头注释

    转载:http://blog.csdn.net/xzytl60937234/article/details/70455777 在VAssistX中为C++提供了比较规范注释模板,用这个注释模板为编写的 ...

  4. UTF-8 编码的文件在处理时要注意 BOM 文件头问题

    最近在给项目团队开发一个基于 Java 的通用的 XML 分析器时,设计了一个方法,能够读取现成的 XML 文件进行分析处理,当然 XML 都是采用 UTF-8 进行编码的.但是在用 UltraEdi ...

  5. 第二讲,NT头文件格式,以及文件头格式

    今天详解NT 头格式,以及文件头格式,以及作用, 关于DOS头文件格式,以及DOSStub昨天的博客已经写过了.主要是分散讲解.便于理解. 一丶最小PE的生成,以及标准PE的生成 ps: (如果直接学 ...

  6. java utf-8文件处理bom头

    UTF? UTF,是UnicodeTransformationFormat的缩写,意为Unicode转换格式. 即怎样将Unicode定义的数字转换成程序数据.utf是对Unicode的一种编码格式化 ...

  7. PHP 下载文件时自动添加bom头的方法

    首先弄清楚,什么是bom头?在Windows下用记事本之类的程序将文本文件保存为UTF-8格式时,记事本会在文件头前面加上几个不可见的字符(EF BB BF),就是所谓的BOM(Byte order ...

  8. php中隐形字符65279(utf-8的BOM头)问题和fwrite写入文件bom头导致的乱码问题解决

     php中隐形字符65279(utf-8的BOM头)问题 今天在CSDN看到一个php输出空白隐形字符65279的问题,在网上找了下,发下这个65279字符是php用来标记文件是utf-8编码的,输出 ...

  9. 什么是BOM头(字节顺序标记(ByteOrderMark))

    在utf-8编码文件中BOM在文件头部,占用三个字节,用来标示该文件属于utf-8编码,现在已经有很多软件识别bom头,但是还有些不能识别bom头,比如PHP就不能识别bom头,这也是用记事本编辑ut ...

随机推荐

  1. linux_磁盘分区

    分区并没有数据内容只是改变分区表,保存在0磁头,0磁道1扇区除MBR引导后64bytes中,只能有4个组分区,4个以上要一个扩展分区 引导MBR,保存在446字节中 磁盘想要存放数据,首先要分区,可以 ...

  2. Halcon一日一练:Halcon异常判断方法

    1.TryCatch tryCatch处理的方式如下: try *可能会出现错误的语句 .... catch(Exception) *获取错误代码 ErrorCode:=Exception[] **对 ...

  3. ATS 分级缓存

    理解缓存分级cache hierarchies 缓存分级是由彼此能够相互通信的各级缓存组成的,ATS支持几种类型的缓存分级.所有的缓存分级都有父子缓存概念. 父缓存位于缓存分级的较高级别,ATS能将请 ...

  4. Python之Django rest_Framework

    Django Rest Framework 一.rest api    a.api就是接口         如: - http://www.oldboyedu.com/get_user/       ...

  5. 【Spring】HttpMessageConverter的作用及替换

    相信使用过Spring的开发人员都用过@RequestBody.@ResponseBody注解,可以直接将输入解析成Json.将输出解析成Json,但HTTP 请求和响应是基于文本的,意味着浏览器和服 ...

  6. TensorflowTutorial_一维数据构造简单CNN

    使用一维数据构造简单卷积神经网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 神经网络对于一维数据非常重要,时序数据集.信号处理数据集和一些文本嵌入数据集都是一维数据,会频繁的使用到神经网 ...

  7. Tensorflow ActiveFunction激活函数解析

    Active Function 激活函数 原创文章,请勿转载哦~!! 觉得有用的话,欢迎一起讨论相互学习~Follow Me Tensorflow提供了多种激活函数,在CNN中,人们主要是用tf.nn ...

  8. C#基础(三)--运算符及条件控制语句

    上一章我们了解了C#的一些数据基本类型.如何定义使用变量及类型之间的相互转换.可能大家会发现程序只能按照我们的要求从上向下这样顺序一条一条的执行. 那么程序能按照我们的要求,当某个条件成立的时候才执行 ...

  9. easyUI---datagrid合并单元格代码实现

    1.html部分: <div id="table1"></div> 2.js部分: $('#table1').datagrid({ data : data, ...

  10. WPF中,多key值绑定问题,一个key绑定一个界面上的对象

    问题说明: 当用到dictionary<key,value>来储存数据的时候,有时候需要在界面上绑定一个key来显示value,这时候有两种思路: 一种是写一个自定义的扩展类,类似Bind ...