首先,我的数据库使用Windows-1250作为本机字符集。我输出的数据为UTF-8。我在我的网站上使用iconv()函数将Windows-1250字符串转换为UTF-8字符串,它完美无缺。
问题是当我使用PHP DOM解析存储在数据库中的一些HTML时(HTML是WYSIWYG编辑器的输出而且无效,它没有html,head,body标签等)。
HTML看起来像这样,例如:
<p>Hello</p>
这是我用来解析数据库中某个HTML的方法:
private function ParseSlideContent($slideContent)
{
var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters
$doc = new DOMDocument('1.0', 'UTF-8');
// hack to preserve UTF-8 characters
$html = iconv('Windows-1250', 'UTF-8', $slideContent);
$doc->loadHTML('<?xml encoding="UTF-8">' . $html);
$doc->preserveWhiteSpace = false;
foreach($doc->getElementsByTagName('img') as $t) {
$path = trim($t->getAttribute('src'));
$t->setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path));
}
foreach ($doc->getElementsByTagName('object') as $o) {
foreach ($o->getElementsByTagName('param') as $p) {
$path = trim($p->getAttribute('value'));
$p->setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path));
}
}
foreach ($doc->getElementsByTagName('embed') as $e) {
if (true === $e->hasAttribute('pluginspage')) {
$path = trim($e->getAttribute('src'));
$e->setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path));
} else {
$path = end(explode('data/media/video/', trim($e->getAttribute('src'))));
$path = 'data/media/video/' . $path;
$path = '/clientarea/utils/locate-video?path=' . urlencode($path);
$width = $e->getAttribute('width') . 'px';
$height = $e->getAttribute('height') . 'px';
$a = $doc->createElement('a', '');
$a->setAttribute('href', $path);
$a->setAttribute('style', "display:block;width:$width;height:$height;");
$a->setAttribute('class', 'player');
$e->parentNode->replaceChild($a, $e);
$this->slideContainsVideo = true;
}
}
$html = trim($doc->saveHTML());
$html = explode('<body>', $html);
$html = explode('</body>', $html[1]);
return $html[0];
}
上面方法的输出是一个垃圾,所有特殊字符都被替换为像š的奇怪的东西。
还有一件事。 在我的开发服务器上运行。
但它在生产服务器上不起作用。
有什么建议吗?
生产服务器的PHP版本:PHP Version 5.2.0RC4-dev
开发服务器的PHP版本:PHP Version 5.2.13
更新:
我自己正在研究解决方案。我从这个PHP错误报告中获得灵感(虽然不是一个真正的错误):http://bugs.php.net/bug.php?id=32547
这是我提出的解决方案。我明天会试一试,让你知道它是否有效:
private function ParseSlideContent($slideContent)
{
var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters
$doc = new DOMDocument('1.0', 'UTF-8');
// hack to preserve UTF-8 characters
$html = iconv('Windows-1250', 'UTF-8', $slideContent);
$doc->loadHTML('<?xml encoding="UTF-8">' . $html);
$doc->preserveWhiteSpace = false;
// this might work
// it basically just adds head and meta tags to the document
$html = $doc->getElementsByTagName('html')->item(0);
$head = $doc->createElement('head', '');
$meta = $doc->createElement('meta', '');
$meta->setAttribute('http-equiv', 'Content-Type');
$meta->setAttribute('content', 'text/html; charset=utf-8');
$head->appendChild($meta);
$body = $doc->getElementsByTagName('body')->item(0);
$html->removeChild($body);
$html->appendChild($head);
$html->appendChild($body);
foreach($doc->getElementsByTagName('img') as $t) {
$path = trim($t->getAttribute('src'));
$t->setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path));
}
foreach ($doc->getElementsByTagName('object') as $o) {
foreach ($o->getElementsByTagName('param') as $p) {
$path = trim($p->getAttribute('value'));
$p->setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path));
}
}
foreach ($doc->getElementsByTagName('embed') as $e) {
if (true === $e->hasAttribute('pluginspage')) {
$path = trim($e->getAttribute('src'));
$e->setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path));
} else {
$path = end(explode('data/media/video/', trim($e->getAttribute('src'))));
$path = 'data/media/video/' . $path;
$path = '/clientarea/utils/locate-video?path=' . urlencode($path);
$width = $e->getAttribute('width') . 'px';
$height = $e->getAttribute('height') . 'px';
$a = $doc->createElement('a', '');
$a->setAttribute('href', $path);
$a->setAttribute('style', "display:block;width:$width;height:$height;");
$a->setAttribute('class', 'player');
$e->parentNode->replaceChild($a, $e);
$this->slideContainsVideo = true;
}
}
$html = trim($doc->saveHTML());
$html = explode('<body>', $html);
$html = explode('</body>', $html[1]);
return $html[0];
}
答案 0 :(得分:5)
你的“黑客”没有意义。
您正在将Windows-1250 HTML文件转换为UTF-8,然后预先<?xml encoding="UTF-8">
。这不行。用于HTML文件的DOM扩展:
我建议您将Windows-1250转换为ISO-8859-1并且不添加任何内容。
编辑建议不是很好,因为Windows-1250的字符不在ISO-8859-1中。由于您处理的内容类型没有meta
元素的片段,您可以添加自己的片段以强制解释为UTF-8:
<?php
//script and output are in UTF-8
/* Simulate HTML fragment in Windows-1250 */
$html = <<<XML
<p>ĄĽź ‰ ‡ … á (some exist on win-1250, but not LATIN1 or even win-1252)</p>
XML;
$htmlInterm = iconv("UTF-8", "Windows-1250", $html); //convert
/* Append meta header to force UTF-8 interpretation and convert into UTF-8 */
$htmlInterm =
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" .
iconv("Windows-1250", "UTF-8", $htmlInterm);
/* Omit libxml warnings */
libxml_use_internal_errors(true);
/* Build DOM */
$d = new domdocument;
$d->loadHTML($htmlInterm);
var_dump($d->getElementsByTagName("body")->item(0)->textContent); //correct UTF-8
给出:
string(79) "ĄĽź ‰ ‡ … á (some exist on win-1250, but not LATIN1 or even win-1252)"
答案 1 :(得分:1)
两种解决方案。
您可以将编码设置为标题:
<?php header("Content-Type", "text/html; charset=utf-8"); ?>
或者您可以将其设置为META标记:
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
编辑:如果两者都设置正确,请执行以下操作:
如果您确信正在发送正确的标头,那么找到错误的最佳机会是开始查看原始字节。发送到相同浏览器的相同字节将产生相同的结果,因此您需要开始查找它们不相同的原因。 Fiddler / Wireshark将为此提供帮助。
答案 2 :(得分:0)
我遇到了同样的问题。我的修复是使用notepad ++并将php文档的编码设置为“UTF-8 without BOM”。希望这有助于其他任何人。