PHP文件中的UTF-8 BOM签名
我在写一些有注释的PHP类时,偶然发现了一个问题。我的名字(对于@author标签)以PHP文件中的UTF-8 BOM签名,php,utf-8,character-encoding,byte-order-mark,Php,Utf 8,Character Encoding,Byte Order Mark,我在写一些有注释的PHP类时,偶然发现了一个问题。我的名字(对于@author标签)以ș结尾(这是一个UTF-8字符,…我知道是个奇怪的名字) 尽管我将文件保存为UTF-8,但一些朋友报告说,他们看到的字符完全乱七八糟(È™)。通过添加BOM签名,可以解决此问题。但这件事让我有点困扰,因为除了我在维基百科和其他类似问题上看到的以外,我对它了解不多 我知道它在文件的开头添加了一些东西,据我所知,这并没有那么糟糕,但我很担心,因为我读到的唯一有问题的场景涉及到PHP文件。由于我编写PHP类是为了共享
ș
结尾(这是一个UTF-8字符,…我知道是个奇怪的名字)
尽管我将文件保存为UTF-8,但一些朋友报告说,他们看到的字符完全乱七八糟(È™代码>)。通过添加BOM签名,可以解决此问题。但这件事让我有点困扰,因为除了我在维基百科和其他类似问题上看到的以外,我对它了解不多
我知道它在文件的开头添加了一些东西,据我所知,这并没有那么糟糕,但我很担心,因为我读到的唯一有问题的场景涉及到PHP文件。由于我编写PHP类是为了共享它们,所以100%兼容比在评论中留下我的名字更重要
但我正在努力理解其中的含义,我应该不用担心就使用它吗?或者有可能造成损害的情况吗?当?BOM将导致已发送的标题出现错误时,您不能在PHP文件中使用BOM。事实上,BOM是发送到浏览器的实际数据。浏览器会很高兴地忽略它,但仍然无法发送标题
我相信问题真的是你和你朋友的编辑器设置。如果没有BOM表,朋友的编辑器可能无法自动将文件识别为UTF-8。他可以尝试设置编辑器,使编辑器期望文件为UTF-8格式(如果使用真正的IDE,如NetBeans,则甚至可以将其设置为项目设置,以便与代码一起传输)
另一种方法是尝试一些技巧:一些编辑器尝试根据输入的文本使用一些启发式方法来确定编码。您可以尝试用
<?php //Úτƒ-8 encoded
或者您可以在php.ini中激活输出缓冲,这将解决“已发送的标题”问题。如果您的站点有大量负载,那么使用输出缓冲来提高性能也是非常重要的。这是一篇老文章,已经得到了回答,但是我可以给您留下一些我在面对此BOM问题时发现的其他资源
使用此页面,您可以检查特定文件是否包含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中有一个选项,zend.multibyte
,它允许php读取带有BOM的文件,而无需给出已发送的标题
错误
从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
在PHP中,除了“headers ready sent”错误外,BOM表的存在还可能以更微妙的方式破坏浏览器中的HTML
请参见此以了解问题的概要
出现这种情况时,不仅呈现页面顶部通常有明显的空白,而且如果您在Firefox或Chrome中检查HTML,您可能会注意到头部部分是空的,其元素似乎在主体中。当然,查看源代码会显示所有应该显示的内容,但不知何故浏览器对其的解释是错误的。BOM实际上是识别UTF-8文件的最有效方式,现代浏览器和标准都支持并鼓励在HTTP响应体中使用它
对于PHP文件,它不是文件,而是作为响应发送的生成的输出,因此显然,在开始时将所有PHP文件与BOM一起保存不是一个好主意,但这并不意味着您不应该在响应中使用BOM
实际上,您可以在doctype声明之前安全地插入以下代码(如果您正在生成HTML作为响应):
进一步阅读:添加到@omabena answer使用此代码查找并从文件中删除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(".");
函数fopen_utf8($filename){
$file=@fopen($filename,“r”);
$bom=fread($file,3);
如果($bom!=b“\xEF\xBB\xBF”)
{
返回false;
}
其他的
{
返回true;
}
}
函数文件_数组($path,$exclude=“.|..| design”,$recursive=true){
$path=rtrim($path,“/”)“/”;
$folder\u handle=opendir($path);
$exclude_数组=分解(“|”,$exclude);
$result=array();
而(false!=($filename=readdir($folder\u handle)){
如果(!in_数组(strtolower($filename),$exclude_数组)){
如果(是_dir($path.$filename.“/”){
//需要包含完整的“路径”,否则它是一个无限循环
如果($recursive)$result[]=file_数组($path.$filename.“/”,$exclude,true);
}否则{
if(fopen_utf8($path.$filename))
{
//$result[]=$filename;
echo($path.$filename.“
”);
$pathname=$path.$filename;//将路径名更改为要删除BOM表的目标文件。
$file_handler=fopen($pathname,“r”);
$contents=fread($file_handler,filesize($pathname));
fclose($file\u handler);
对于($i=0;$i<3;$i++){
$bytes[$i]=ord(substr($contents,$i,1));
}
如果($bytes[0]==0xef&&$bytes[1]==0xbb&&$bytes[2]==0xbf){
$file_handler=fopen($pathname,“w”);
fwrite($file_handler,substr($contents,3));
fclose($file\u handler);
printf(“%s BOM已删除。
n”,$pathname);
}
}
}
}
}
返回$result;
}
$files=文件数组(“.”);
谢谢您的建议。我明白我的立场,我想我会做一个体面的选择,拼写我的nam,而不是编码检测启发式,这是一种奇怪的妥协