DOMDocument::loadHTML()
函数需要一个HTML字符串作为参数。
HTML默认使用ISO-8859-1
编码(即第一拉丁字母表),参照标准规定。这一点早在很久以前就有了,详见6.1 HTML文档字符集。但实际上,常用的网络浏览器更倾向于支持Windows-1252
编码。
我提到这一点是因为PHP的DOMDocument基于libxml,它使用的是设计用于HTML 4.0的HTML解析器。
因此可以认为,使用ISO-8859-1
编码的字符串是安全的。
然而,你的字符串使用的是UTF-8
编码。只需将所有ASCII码大于127 / h7F的字符转换成HTML实体,就可以顺利加载。如果不想自己手动转换,可以使用mb_convert_encoding
函数并设置目标编码为HTML-ENTITIES
:
- 那些已经有命名实体的字符,将得到所对应的命名实体。例如:
€ -> €
- 其他字符将被转换成相应的十进制数字实体,例如:
☆ -> ☆
下面是一个代码示例,通过回调函数使该过程更加清晰可见:
$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);
以下是针对您字符串的示例输出:
☆ -> ☆
☆ -> ☆
☆ -> ☆
无论如何,那只是为了更深入地查看您的字符串。您要将它转换为
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">
这是指定字符集的Content-Type。对于不通过Web服务器(例如保存在磁盘上或内部字符串中,如您的示例中)提供的HTML字符串,这也是最佳实践。Web服务器通常将其设置为响应标头。
如果您不关心错误放置的警告,可以将其添加到字符串前面:
$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>
˜
等不是用于utf8,而是ANSI。例如,“dagger”可以在http://hexutf8.com/?q=e280a0中找到。 - jar