zoukankan      html  css  js  c++  java
  • PHP与Unicode签名(BOM)

    新手玩php被bom玩死了,记录下来,转载自http://www.sitejs.com/sitejs-5190-1.html

    摘要:在编写或者修改用UTF-8编码保存的PHP文件时,有时会莫名其妙出现一些问题: 1. 页面显示一个锘字,其他一片空白; 2. 不能登入或者不能登出; 3. 页顶出现一条空白; 4. 页顶出现错误警告;...

    在编写或者修改用UTF-8编码保存的PHP文件时,有时会莫名其妙出现一些问题: 
    1. 页面显示一个“锘”字,其他一片空白; 
    2. 不能登入或者不能登出; 
    3. 页顶出现一条空白; 
    4. 页顶出现错误警告; 
    5. 其它不正常的情况; 
    6. 生成的图片浏览器无法识别。 
    分析原因: 
     文件以UTF-8编码保存时,有两种情情况:带Unicode签名(BOM)和不带Unicode签名。BOM信息是文件开头的一串隐藏的字符,用于让某些编辑器识别这是个UTF-8编码的文件。 

    类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM——Byte Order Mark)。它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。对于一般的文件,这样并不会产生什么麻烦。 

    但对于 PHP来说,PHP在设计时就没有考虑BOM的问题,不会忽略UTF-8编码的文件开头BOM的那三个字符,会把BOM作为该文件开头正文的一部分。由于必须在<?或者<?php后面的代码才会作为PHP代码执行,所以将会造成在页面上输出这三个字符,显示效果就要看浏览器了,一般是一个空行或是一个乱码。由于在html一开头有这3个字符的存在,即使页面的 top padding 设置为0,也无法让整个网页紧贴浏览器顶部。由于受COOKIE送出机制的限制,在这些文件开头已经有BOM的文件中,COOKIE无法送出(因为在 COOKIE送出前PHP已经送出了文件头),所以登入和登出功能失效。一切依赖COOKIE、SESSION实现的功能全部无效。 

    解决办法: 

    在编辑、更改任何文本文件时,请务必使用不会乱加BOM的编辑器。Linux下的编辑器应该都没有这个问题。WINDOWS下,请勿使用记事本等编辑器。推荐的编辑器是:Editplus 2.12版本以上;EmEditor;UltraEdit(需要取消‘添加BOM’的相关选项);Dreamweaver(需要取消‘添加BOM’的相关选项)等。 

    对于已经添加了BOM的文件,要取消的话,可以用以上编辑器另存一次。(Editplus需要先另存为gb,再另存为UTF-8。) 

    ultraedit, editplus, notepad四个工具对UTF-8 的支持不相同,下面是对四个工具对UTF-8 支持的总结: 
      UTF-8 BOM header: 是三个字符: EF BB BF。 
      1. notepad 
    notepad 在保存时,选择UTF-8 格式,会在文件头写上BOM header. 
      2. editplus 
    文件保存时,选择UTF-8 格式,不会在文件头写上 BOM header. 
      3. ultraedit 
    ultraedit 对UTF-8 的支持最为完备。在advanced->configuration中可以 选择文件保存时是否写上BOM header. 
      4. vi 
    指的是Linux 下的vim, 如果UTF-8 文件开头有BOM header, 其能够正常显示UTF-8编码,否则,显示为乱码。 
      还有一些编码转换工具,比如,可以用java 写一个简单的编码转换工具,这些工具是不会增加BOM header的。 

    附录: 

    UltreEdit的配置,将选项“保存时对所有UTF-8写入UTF-8文件头标记(BOM)”关闭。即:Write UTF-8 BOM header to ALL UTF-8 files when saved OFF。 
    不同版本有可能没有,而要把“自动检测utf8”关掉。这样看utf8文件就乱码了。 
    建议用editplus了。 


    检测目录下文件是否有BOM程序: 
    <? 
    //此文件用于快速测试UTF8编码的文件是不是加了BOM,并可自动移除 
    //By Bob Shen 

    $basedir=".";; //修改此行为需要检测的目录,点表示当前目录 
    $auto=0; //是否自动移除发现的BOM信息。1为是,0为否。 

    //以下不用改动 

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

    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>"); 


    else return ("BOM Not Found."); 


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

    ?> 

  • 相关阅读:
    for循环,pydev提示未使用的变量,解决办法
    sc 与net命令的区别
    Selenium测试Ajax程序(转)
    Python yield 使用浅析(转)
    python操作Excel读写--使用xlrd
    Python操作Mysql实例代码教程在线版(查询手册)
    MySQL之alter语句用法总结
    使用WebDriver遇到的那些坑(转)
    python 列表转为字典的两个小方法
    python
  • 原文地址:https://www.cnblogs.com/eboard/p/2648882.html
Copyright © 2011-2022 走看看