PHP DomDocument无法处理utf-8字符(☆)

networking服务器以utf-8编码提供响应,所有文件都以utf-8编码保存,我所知道的设置已经被设置为utf-8编码。

这里有一个快速的程序,来testing输出是否工作:

<?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()); 

该scheme的输出是:

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

其中呈现为:

★你好††世界††


我可能做错了什么? 我必须告诉DomDocument正确处理utf-8多less具体的内容?

DOMDocument::loadHTML()需要一个HTMLstring。

根据规格,HTML使用ISO-8859-1编码(ISO拉丁字母1)作为默认值。 这是因为更长,见6.1。 HTML文档字符集 。 实际上,这更多的是普通网页浏览器对Windows-1252的默认支持。

因为PHP的DOMDocument是基于libxml的,并且带来了专为HTML 4.0devise的HTMLparser ,

我会说,假设你可以加载ISO-8859-1编码的string是安全的。

你的string是UTF-8编码。 把所有高于127 / h7F的字符转换成HTML实体 ,你没事的。 如果你不想这样做,那么mb_convert_encodingHTML-ENTITIES目标编码是一样的:

  • 那些具有命名实体的angular色将获得命名实体。 € -> &euro;
  • 其他人得到他们的数字(十进制)实体,例如☆ -> &#9734;

以下是一个代码示例,通过使用callback函数使进度更加可见:

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

这个string的输出示例如下:

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

无论如何,这只是为了更深入地观察你的string。 你想要它可以转换成一个编码loadHTML可以处理。 这可以通过将US-ASCII所有外部转换为HTML实体来完成:

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

注意你的input实际上是UTF-8编码的。 如果您甚至有混合编码(可能会发生一些input),则mb_convert_encoding只能处理每个string的一个编码。 我已经在上面概述了如何在正则expression式的帮助下更具体地进行stringreplace,所以我现在留下进一步的细节。

另一种select是提示编码。 这可以通过修改文档并添加一个

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

这是一个指定字符集的Content-Type。 对于不能通过networking服务器访问的HTMLstring(例如,保存在磁盘上或像在你的例子中的string内),这也是最好的做法。 Web服务器通常设置为响应头。

如果你不关心错误的警告,你可以把它添加到string的前面:

 $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> 

有一个更快的解决scheme,在DOMDocument中加载您的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 
 <?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>