前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PHP Bom头导致乱码或者其他错误

PHP Bom头导致乱码或者其他错误

作者头像
黄啊码
发布于 2020-05-29 03:18:50
发布于 2020-05-29 03:18:50
1.1K00
代码可运行
举报
运行总次数:0
代码可运行

转载至:https://www.cnblogs.com/wt645631686/p/6868826.html

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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代码可能会有遗漏,在用以上方法测试完成可以用一下一下方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
        }
    }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/04/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Vue 框架学习系列五:Vue 3 与状态管理库 Pinia 的深度集成
在构建复杂的 Vue.js 应用时,状态管理是一个重要的考虑因素。Vuex 是 Vue.js 官方推荐的状态管理库,但随着 Vue 3 和 Composition API 的发布,一个新的状态管理库 Pinia 开始崭露头角。Pinia 提供了与 Vue 3 和 Composition API 更紧密的集成,同时保持了 Vuex 的核心概念,如 state、mutations、actions 和 getters。本篇文章将探讨如何在 Vue 3 应用中深度集成 Pinia。
china马斯克
2024/10/04
3190
pinia核心笔记
记录pinia核心源码阅读笔记,这里跳过hmr(热更新), mapHelpers(class 工具)等工具源码。 剔除的部分vue2.0兼容代码。 当前pinia版本2.0.13
copy_left
2022/05/13
1.1K0
pinia核心笔记
​轻松掌握vuex,让你对状态管理有一个更深的理解
Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式 。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
前端老鸟
2019/07/29
3.4K0
制作一个轻量级的状态管理插件:Vue-data-state
Vuex 是针对 Vue2 来设计的,因为 option API 本身有很多缺点,所以 Vuex 只好做各种补丁弥补这些缺点,于是变得比较“复杂”。
用户1174620
2021/04/28
8800
制作一个轻量级的状态管理插件:Vue-data-state
【玩转全栈】---- Pinia 组件状态管理器
Pinia 是一个用于 Vue 3 的状态管理库,旨在提供更加简洁、直观且灵活的状态管理模式。它由 Vue 官方团队成员开发,以其轻量级和高性能著称。Pinia 支持 Vue 3 的组合式 API,并允许开发者以一种更自然的方式组织和共享应用状态。与 Vuex 不同,Pinia 去除了复杂的概念如模块嵌套,转而采用扁平化的 store 结构,使得代码更加清晰易懂。此外,Pinia 还支持 TypeScript,提供了优秀的类型推断能力,增强了开发体验。通过 Pinia,你可以轻松地创建多个独立的 store 模块,每个模块都可以拥有自己的 state(状态)、getters(计算属性)、actions(方法)等,极大地简化了复杂应用中的状态管理。其灵活性还体现在对插件系统的良好支持,可以方便地扩展功能。总的来说,Pinia 是现代 Vue 应用中进行状态管理的理想选择。
用户11404404
2025/03/12
1060
Vue3之状态管理:Vuex和Pinia,孰强孰弱?
在前端开发中,状态管理器是一种用于管理应用程序全局状态的工具。它通常用于大型应用程序,可以帮助开发者更好地组织和管理状态,并提供一些强大的工具来简化状态的变更和使用。
用户6297767
2023/11/21
2.6K0
Vue3之状态管理:Vuex和Pinia,孰强孰弱?
Vue项目进阶:再谈Pinia函数式(composition API)用法
Hello大家好,前段时间写了一篇关于Pinia的composition API用法的文章《Pinia进阶:优雅的setup(函数式)写法+封装到你的企业项目》,收到了不少朋友的反馈和建议。笔者也结合最近项目情况和网友们的建议做一次优化,也算是一个比较完整的版本了,这包括:
南山种子外卖跑手
2022/04/21
3.5K0
Vue项目进阶:再谈Pinia函数式(composition API)用法
Pinia 入门:零基础开启 Vue 状态管理之旅
在现代 Vue 应用开发中,高效的状态管理是构建强大、可维护应用的关键。Pinia 作为一种新兴的状态管理方案,为 Vue 开发者带来了全新的体验。本文将带你从零开始,深入了解 Pinia 的基础知识,开启 Vue 状态管理的精彩之旅。
程序媛夏天
2024/11/19
3900
Pinia.js - Vue新一代状态管理器
安装成功会把依赖加在 package.json 的 dependencies 中。
青年码农
2022/09/27
1.3K1
Pinia.js - Vue新一代状态管理器
感受 Vue 新的状态管理工具之美之 Pinia---学习篇
相信在Vue中提到状态管理,大家一定会想到 Vuex。的确 Vuex确实是比较强大的,但Vuex 多少有点重,而且对 Typescript的支持也不是那么的友好,同时门槛也比较高,学习成本比较大。
用户9078190
2022/10/28
2530
感受 Vue 新的状态管理工具之美之 Pinia---学习篇
学习 Vue 3 全家桶 - vuex
现代 Web 应用都是由三大件构成,分别是:组件、数据和路由。在一些数据组件之间需要共享的时候,应该如何实现?
Cellinlab
2023/05/17
3480
学习 Vue 3 全家桶 - vuex
vue3了,试试轻量化的Vuex -- Pinia?
Pinia 是 Vue.js 的轻量级状态管理库,最近很受欢迎。它使用 Vue 3 中的新反应系统来构建一个直观且完全类型化的状态管理库。
玖柒的小窝
2021/11/04
1.5K0
vue3了,试试轻量化的Vuex -- Pinia?
Pinia入门-实现简单的用户状态管理
在整个应用程序中访问的数据(且不需要被持久化),例如导航栏中显示的用户信息,以及需要通过页面保留的数据,例如一个非常复杂的多步骤表格。
luciozhang
2023/04/22
7640
测试一下Pinia,Vuex 要出局了?
自从我开始使用Vue 3和组合API以来,我也尝试使用 Pinea 作为状态管理库。如果是从是 vue2 和 vuex 过来的,就会觉得用起来差别还是很大的。
前端小智@大迁世界
2022/09/01
6530
测试一下Pinia,Vuex 要出局了?
告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态 定义main.jscontroller组件设置监听和钩子局部状态
Vuex 是基于 Vue2 的 option API 设计的,因为 optionAPI 的一些先天问题,所以导致 Vuex 不得不用各种方式来补救,于是就出现了 getter、mutations、action、module、mapXXX 这些绕圈圈的使用方式。想要使用 Vuex 就必须先把这些额外的函数给弄明白。
用户1174620
2021/10/20
1.1K0
一杯茶的时间入门Vue新的状态管理库Pinia
Pinia 是 Vue.js 官方推荐的新一代状态管理库,它提供了非常简洁和直观的 API,可以极大地提高我们管理应用状态的效率。本文将深入介绍 Pinia 的各种高级用法,内容涵盖:
linwu
2023/08/08
4440
一杯茶的时间入门Vue新的状态管理库Pinia
Vue.js 状态管理:Pinia 与 Vuex
Vuex 和 Pinia 是用于管理 Vue.js 应用程序状态的标准 Vue.js 库。让我们比较一下他们的代码、语言、功能和社区支持。
海拥
2023/02/27
2.7K0
Vue3中使用Pinia详解
Pinia是一个专门为Vue.js设计的状态管理库,它提供了一种简单和直观的方式来管理应用程序的状态。在使用Pinia时,可以轻松地创建定义状态的存储,然后将其与Vue组件绑定,使它们能够使用该状态。和上一个博客提到的Vuex相比,Pinia 更加简单易用,体积更小,同时具有更好的 TypeScript 支持和插件系统。
九仞山
2023/10/14
9960
使用 Vue 3 与 TypeScript 构建 Web 应用: Todo
引言 界面: Vue.js 3 JavaScript 超集: TypeScript 包管理器: pnpm 前端工程化/打包: Vite 路由: Vue Router 状态管理: Pinia CSS 预处理器: Less 代码格式化: Prettier 代码质量: ESLint 预览
yiyun
2023/07/17
1.2K0
使用 Vue 3 与 TypeScript 构建 Web 应用: Todo
Pinia状态管理器学习笔记,持续记录
官方文档:https://pinia.vuejs.org/ 中文文档:https://pinia.web3doc.top/
房东的狗丶
2023/02/17
1.7K0
推荐阅读
相关推荐
Vue 框架学习系列五:Vue 3 与状态管理库 Pinia 的深度集成
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验