PHP文件中的UTF-8 BOM签名

时间:2010-04-01 04:44:59

标签: php utf-8 character-encoding byte-order-mark

我正在编写一些评论过的PHP类,我偶然发现了一个问题。我的名字(对于@author标签)以ș(这是一个UTF-8字符,......和一个奇怪的名字,我知道)结束。

即使我将文件保存为UTF-8,一些朋友报告说他们看到这个角色完全搞砸了(È™)。添加BOM签名会消除此问题。但是这件事让我感到很麻烦,因为我不太了解它,除了我在维基百科上看到的以及其他一些类似的问题。

我知道它在文件的开头添加了一些东西,从我的理解它并没有那么糟糕,但我很担心,因为我读到的唯一有问题的场景涉及PHP文件。因为我正在编写PHP类来共享它们,所以100%兼容比在评论中使用我的名字更重要。

但是我试图理解其含义,我应该使用它而不用担心吗?或者是否有可能造成损害的情况?当α

8 个答案:

答案 0 :(得分:24)

实际上,BOM是发送到浏览器的实际数据。浏览器会很乐意忽略它,但是你仍然无法发送标题。

我认为问题确实是你和你朋友的编辑器设置。如果没有BOM,您朋友的编辑器可能无法自动将文件识别为UTF-8。他可以尝试设置他的编辑器,使编辑器期望一个文件是UTF-8(如果你使用真正的IDE,如NetBeans,那么这甚至可以成为你的项目设置可以随代码一起转移。)

另一种方法是尝试一些技巧:一些编辑器尝试使用基于输入文本的一些启发式来确定编码。您可以尝试使用

启动每个文件
<?php //Úτƒ-8 encoded

也许启发式会得到它。可能有更好的东西放在那里,你可以google什么样的编码检测启发式常见,或只是尝试一些: - )

总而言之,我建议只修改编辑器设置。

哦等等,我误读了最后一部分:为了将代码传播到任何地方,我猜你最安全的只是让所有文件只包含较低的7位字符,即纯ASCII,或只是接受一些人古代编辑看到你的名字写得好笑。没有故障安全方式。由于已经发送了标题,因此BOM肯定是糟糕的。另一方面,只要你只在注释中放入UTF-8字符等,一些编辑误解编码的唯一影响就是奇怪的字符。我会正确拼写你的名字并添加针对启发式的评论,这样大多数编辑都会得到它,但总会有人会看到伪造的字符。

答案 1 :(得分:13)

BOM会导致Headers already sent错误,因此,您无法在PHP文件中使用BOM

答案 2 :(得分:9)

这是一篇旧帖子,已经得到了解答,但我可以留下一些我在面对此BOM问题时找到的其他资源。

使用此页面

http://people.w3.org/rishida/utils/bomtester/index.php,您可以检查特定文件是否包含BOM。

还有一个方便的脚本,可以在当前目录中输出所有带有BOM的文件。

<?php 
function fopen_utf8 ($filename) { 
    $file = @fopen($filename, "r"); 
    $bom = fread($file, 3); 
    if ($bom != b"\xEF\xBB\xBF") 
    { 
        return false; 
    } 
    else 
    { 
        return true; 
    } 
} 

function file_array($path, $exclude = ".|..|design", $recursive = true) { 
    $path = rtrim($path, "/") . "/"; 
    $folder_handle = opendir($path); 
    $exclude_array = explode("|", $exclude); 
    $result = array(); 
    while(false !== ($filename = readdir($folder_handle))) { 
        if(!in_array(strtolower($filename), $exclude_array)) { 
            if(is_dir($path . $filename . "/")) { 
                                // Need to include full "path" or it's an infinite loop 
                if($recursive) $result[] = file_array($path . $filename . "/", $exclude, true); 
            } else { 
                if ( fopen_utf8($path . $filename) ) 
                { 
                    //$result[] = $filename; 
                    echo ($path . $filename . "<br>"); 
                } 
            } 
        } 
    } 
    return $result; 
} 

$files = file_array("."); 
?>

我在php.net上找到了代码

Dreamweaver也对此有所帮助,它为您提供了保存文件的选项,而不包括BOM内容

这是一个迟到的答案,但我仍然希望它有所帮助。 再见

答案 3 :(得分:7)

您也知道,php zend.multibyte中有一个选项,允许php使用BOM读取文件而不会出现Headers already sent错误。

来自php.ini文件:

; If enabled, scripts may be written in encodings that are incompatible with
; the scanner.  CP936, Big5, CP949 and Shift_JIS are the examples of such
; encodings.  To use this feature, mbstring extension must be enabled.
; Default: Off
;zend.multibyte = Off

答案 4 :(得分:2)

或者您可以在php.ini中激活输出缓冲,这将解决“已发送标头”问题。如果您的站点负载很重,则使用输出缓冲来提高性能也非常重要。

答案 5 :(得分:2)

在PHP中,除了“已发送标头”错误之外,BOM的存在还会以更微妙的方式搞砸浏览器中的HTML。

有关问题的概述,请参阅此link

发生这种情况时,不仅渲染页面的顶部通常会有明显的空间,而且如果您在Firefox或Chrome中检查HTML,您可能会注意到head部分为空,其元素似乎在身体。当然,查看源将显示它应该在哪里,但不知何故浏览器正在解释它错误。

答案 6 :(得分:1)

BOM实际上是识别UTF-8文件的最有效方式,现代浏览器和标准都支持并鼓励在HTTP响应体中使用它。

如果是PHP文件,它不是文件,而是生成的输出作为响应发送,所以显然在开头用BOM保存所有PHP文件不是一个好主意,但这并不意味着你不应该在回复中使用BOM。

事实上,您可以在doctype声明之前安全地注入以下代码(如果您生成HTML作为响应):

<?="\xEF\xBB\xBF"?>

进一步阅读:https://www.w3.org/International/questions/qa-byte-order-mark#transcoding

答案 7 :(得分:0)

添加到@omabena 答案使用此代码从您的文件中定位和删除 bom。请务必先备份您的文件以防万一。

function fopen_utf8 ($filename) { 
    $file = @fopen($filename, "r"); 
    $bom = fread($file, 3); 
    if ($bom != b"\xEF\xBB\xBF") 
    { 
        return false; 
    } 
    else 
    { 
        return true; 
    } 
} 

function file_array($path, $exclude = ".|..|design", $recursive = true) { 
    $path = rtrim($path, "/") . "/"; 
    $folder_handle = opendir($path); 
    $exclude_array = explode("|", $exclude); 
    $result = array(); 
    while(false !== ($filename = readdir($folder_handle))) { 
        if(!in_array(strtolower($filename), $exclude_array)) { 
            if(is_dir($path . $filename . "/")) { 
                                // Need to include full "path" or it's an infinite loop 
                if($recursive) $result[] = file_array($path . $filename . "/", $exclude, true); 
            } else { 
                if ( fopen_utf8($path . $filename) ) 
                { 
                    //$result[] = $filename; 
                    echo ($path . $filename . "<br>"); 
                    $pathname = $path . $filename; // change the pathname to your target file(s) which you want to remove the BOM.
                    $file_handler = fopen($pathname, "r");
                    $contents = fread($file_handler, filesize($pathname));
                    fclose($file_handler);
                    for ($i = 0; $i < 3; $i++){
                        $bytes[$i] = ord(substr($contents, $i, 1));
                    }
                    if ($bytes[0] == 0xef && $bytes[1] == 0xbb && $bytes[2] == 0xbf){
                        $file_handler = fopen($pathname, "w");
                        fwrite($file_handler, substr($contents, 3));
                        fclose($file_handler);
                        printf("%s BOM removed.<br/>n", $pathname);
                    }
                } 
            } 
        } 
    } 
    return $result; 
} 

$files = file_array(".");