PHP的DomDocument无法处理UTF-8字符(☆)PHP的DomDocument无法处理UT

2019-06-14 13:25发布

该Web服务器是服务响应使用UTF-8编码,所有的文件都保存使用UTF-8编码,我知道设定的一切都已经被设置为UTF-8编码。

这里有一个快速程序,以测试输出的工作原理:

<?php
$html = <<<HTML
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test!</title>
</head>
<body>
    <h1>☆ Hello ☆ World ☆</h1>
</body>
</html>
HTML;

$dom = new DomDocument("1.0", "utf-8");
$dom->loadHTML($html);

header("Content-Type: text/html; charset=utf-8");
echo($dom->saveHTML());

该程序的输出是:

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Test!</title></head><body>
    <h1>&acirc;&#152;&#134; Hello &acirc;&#152;&#134; World &acirc;&#152;&#134;</h1>
</body></html>

其呈现为:

â~†你好â~†世界â~†


还有什么比我做错了? 如何更具体的我必须告诉DOM文档处理UTF-8是否正确?

Answer 1:

DOMDocument::loadHTML()需要一个HTML字符串。

HTML采用ISO-8859-1编码(ISO拉丁字母1号)作为默认每它的规格。 这是因为时间越长,见6.1。 HTML文档字符集 。 在现实中则多为默认支持Windows-1252中共同化网页浏览器。

我回去那么远,因为PHP的DOM文档是基于libxml的,并且带来了HTMLParser的这是专为HTML 4.0。

我会说这是安全的假设,然后,你可以加载ISO-8859-1编码字符串。

你的字符串是UTF-8编码。 打开超过127个/ H7F更高的所有字符转换成HTML实体和你的罚款。 如果你不想这样做你自己,那是什么mb_convert_encodingHTML-ENTITIES编码对象不:

  • 已命名实体的人物,会得到一个名为entitiy。 € -> &euro;
  • 其他人得到他们的数字(十进制)的实体,如☆ -> &#9734;

下面是一个代码示例,使进度更加明显一点用回调函数:

$html = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function($match) {
    list($utf8) = $match;
    $entity = mb_convert_encoding($utf8, 'HTML-ENTITIES', 'UTF-8');
    printf("%s -> %s\n", $utf8, $entity);
    return $entity;
}, $html);

为您的字符串此示例输出:

☆ -> &#9734;
☆ -> &#9734;
☆ -> &#9734;

无论如何,这只是为了寻求更深入的字符串。 你想拥有它要么转换成编码loadHTML可以对付。 这可以通过所有外转换完成US-ASCII到HTML实体:

$us_ascii = mb_convert_encoding($utf_8, 'HTML-ENTITIES', 'UTF-8');

小心你的输入实际上是UTF-8编码。 如果你有甚至混合编码(也可以用一些投入发生) mb_convert_encoding只能处理每串一个编码。 我已经概述上面如何更具体做字符串替换使用正则表达式的帮助,所以我离开进一步的细节现在。

另一种方法是暗示的编码。 这可以在你的情况下,通过修改文件并添加完成

<meta http-equiv="content-type" content="text/html; charset=utf-8">

这是一种内容类型指定一个字符集。 这也是HTML字符串,通过一个网络服务器(例如,在你的榜样保存在磁盘上或内部的字符串等)是不可用的最佳实践。 通常设置webserver的,作为响应头。

如果你不小心放错位置的警告,你可以将其添加在前面的字符串:

$dom = new DomDocument();
$dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$html);

每HTML 2.0规范,即只能出现在的元素<head>文档的部分,将被自动放置在那里。 这是在这里发生了什么,太。 输出(漂亮的印刷电路板):

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta charset="utf-8">
    <title>Test!</title>
  </head>
  <body>
    <h1>☆ Hello ☆ World ☆</h1>    
  </body>
</html>


Answer 2:

还有为更快速地解决,在加载DOM文档HTML文档后,您只需设置(或更好说复位)原始编码。 下面是一个示例代码:

$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="UTF-8">' . $html);

foreach ($dom->childNodes as $item)
    if ($item->nodeType == XML_PI_NODE)
        $dom->removeChild($item);
$dom->encoding = 'UTF-8'; // reset original encoding


Answer 3:

<?php
  header("Content-type: text/html; charset=utf-8");
  $html = <<<HTML
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test!</title>
</head>
<body>
    <h1>☆ Hello ☆ World ☆</h1>
</body>
</html>
HTML;

  $html = mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8");
  $dom = new DomDocument("1.0", "utf-8");
  $dom->loadHTML($html);

  header("Content-Type: text/html; charset=utf-8");
  echo($dom->saveHTML());

输出:

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Test!</title></head><body>
    <h1>&#9734; Hello &#9734; World &#9734;</h1>
</body></html>


文章来源: PHP DomDocument failing to handle utf-8 characters (☆)