PHP DOMDocument:解析未转换字符串时出错

PHP DOMDocument:解析未转换字符串时出错,php,html,domdocument,Php,Html,Domdocument,我在用PHP的DOMDocument解析HTML时遇到问题 我正在分析的HMTL具有以下脚本标记: <script type="text/javascript"> var showShareBarUI_params_e81 = { buttonWithCountTemplate: '<div class="sBtnWrap"><a href="#" onclick="$onClick"><div class="sBtn"&

我在用PHP的DOMDocument解析HTML时遇到问题

我正在分析的HMTL具有以下脚本标记:

<script type="text/javascript">
    var showShareBarUI_params_e81 =
    {
        buttonWithCountTemplate: '<div class="sBtnWrap"><a href="#" onclick="$onClick"><div class="sBtn">$text<img src="$iconImg" /></div><div class="sCountBox">$count</div></a></div>',
    }
</script>
/>
使DOMDocument认为脚本已完成,但它缺少结束标记。如果您使用getElementByTagName提取脚本,您将在该img标记处关闭标记,其余标记将在HTML上显示为文本

我的目标是删除此页面中的所有脚本,因此如果我对该标记执行
removeChild()
,则该标记将被删除,但在呈现页面时,以下部分将显示为文本:

</div><div class="sCountBox">$count</div></a></div>',
        }
    </script>
$count',
}
修复HTML不是一个解决方案,因为我正在开发一个通用解析器,需要处理所有类型的HTML

我的问题是,我是否应该在将HTML提供给DOMDocument之前进行任何清理,或者是否有一个选项可以在DOMDocument上启用以避免触发此问题,或者即使我可以在加载HTML之前剥离所有标记

有什么想法吗?


编辑 经过一些研究,我发现了DOMDocument解析器的真正问题。考虑下面的HTML:

<div> <!-- Offending div without closing tag -->
<script type="text/javascript">
       var test = '</div>';
       // I should not appear on the result
</script>

var检验='';
//我不应该出现在结果上
使用以下php代码删除脚本标记():

loadHTML(file_get_contents('js.html')、LIBXML_html_NOIMPLIED、LIBXML_html_NODEFDTD);
//@$dom->loadHTMLFile('script.html')//修复不存在的标记
而($nodes=$dom->getElementsByTagName(“脚本”)){
如果($nodes->length==0)中断;
$script=$nodes->item(0);
$script->parentNode->removeChild($script);
}
//返回$dom->saveHTML();
$final=$dom->saveHTML();
echo$final;
结果如下:

<div> <!-- Offending div without closing tag -->
<p>';
       // I should not appear on the result
</p></div>

",;
//我不应该出现在结果上

问题是第一个div标记没有关闭,DOMDocument似乎将JS字符串中的div标记作为html而不是简单的JS字符串


我能做些什么来解决这个问题?请记住,修改HTML不是一个选项,因为我正在开发一个通用解析器。

您是否尝试过将libxml设置为使用内部错误

$use_errors = libxml_use_internal_errors(true);
// your parsing code here
libxml_clear_errors();
libxml_use_internal_errors($use_errors);

它可能允许dom文档继续解析(可能)。

我在html文件上测试了以下代码,如下所示:

<p>some text 1</p>
<img src="http://www.example.com/images/some_image_1.jpg">
<p>some text 2</p>
<p>some text 3</p>
<img src="http://www.example.com/images/some_image_2.jpg">

<script type="text/javascript">
    var showShareBarUI_params_e81 =
    {
        buttonWithCountTemplate: '<div class="sBtnWrap"><a href="#" onclick="$onClick"><div class="sBtn">$text<img src="$iconImg" /></div><div class="sCountBox">$count</div></a></div>',
    }
</script>

<p>some text 4</p>
<p>some text 5</p>
<img src="http://www.example.com/images/some_image_3.jpg">
一些文本1

一些文本2

一些文本3

var showShareBarUI_参数_e81= { 按钮WithCountTemplate:“”, } 一些文本4

一些文本5

php代码是:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

    $dom = new DOMDocument;
    $dom->preserveWhiteSpace = false;
    @$dom->loadHTML(file_get_contents('script.html'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    //@$dom->loadHTMLFile('script.html'); //fix tags if not exist 

    $nodes = $dom->getElementsByTagName("script");

    foreach($nodes as $i => $node){
        $script = $nodes->item($i);
        $script->parentNode->removeChild($script);
    }

    //return $dom->saveHTML();
    $dom->saveHtmlFile('script.html');
loadHTMLFile('script.html')//修复不存在的标记
$nodes=$dom->getElementsByTagName(“脚本”);
foreach($i=>$node的节点){
$script=$nodes->item($i);
$script->parentNode->removeChild($script);
}
//返回$dom->saveHTML();
$dom->saveHtmlFile('script.html');
它适用于给定的示例,我认为您应该使用我在加载html代码时使用的选项

根据上次问题更新编辑:

实际上,你不能用正则表达式解析[X]HTML(阅读本文了解更多信息) 但是,如果您的唯一目的只是删除脚本标记,那么您可以确保它之间没有作为字符串的
标记。您可以使用此正则表达式:

$html = mb_convert_encoding(file_get_contents('script2.html'), 'HTML-ENTITIES', 'UTF-8');
$new_html = preg_replace('/<script(.*?)>(.*?)<\/script>/si', '', $html);
file_put_contents('script-result.html', $new_html);
$html=mb\u convert\u编码(文件获取内容('script2.html'),'html-ENTITIES','UTF-8');
$new_html=preg_replace('/(.*?)/si',''$html);
文件内容('script-result.html',$new\u html);
坦率地说,问题是您可能没有标准的HTML代码。但我认为最好尝试其他链接的库


否则,我想您应该编写一个特殊的解析器来删除脚本标记,并处理其中的单引号和双引号。

解析html文档主要是关于它的内容,而不是脚本。 特别是在不知道脚本的行为和起源的情况下使用这些脚本可能是危险的

因此,当涉及html内容时,您可以使用这种方法(我已经在评论中指出了这一点)编写OMIT脚本:

具体到您的示例:

<?php
$html = <<<END
<!DOCTYPE html>
<html><body><h1>Hey now</h1>
<script type="text/javascript">
    var showShareBarUI_params_e81 =
    {
        buttonWithCountTemplate: '<div class="sBtnWrap"><a href="#" onclick="onClick"><div class="sBtn">text<img src="iconImg" /></div><div class="sCountBox">count</div></a></div>'
    }
</script>
</body></html>
END;

$dom = new DOMDocument();
$dom->preserveWhiteSpace = true; // needs to be before loading, to have any effect
$dom->loadXML($html);
    while (($r = $dom->getElementsByTagName("script")) && $r->length) {
        $r->item(0)->parentNode->removeChild($r->item(0));
    }
$dom->formatOutput = false;
print $dom->saveHTML();

//Outputs
//<!DOCTYPE html><html><head></head><body><h1>Hey now</h1></body></html>
getElementsByTagName(“脚本”)&&&$r->length){
$r->item(0)->parentNode->removeChild($r->item(0));
}
$dom->formatOutput=false;
打印$dom->saveHTML();
//输出
//嘿现在
在加载到DOMDocument或检查其他html解析库之前,您还可以尝试使用一些正则表达式删除脚本标记。 最后,您必须意识到,在某些情况下,即使是完美的表达式也会崩溃,DOMDocument解析器不如真正的浏览器引擎好。 一切都是为了解析和找到最佳解决方案

PHP简单HTML DOM解析器示例:

require_once'libs/simplehtmldom_1_5/simple_html_dom.php';
$html=var test='';//我不应该出现在结果上

我为您的问题提供了不同的解决方案:

我的目标是删除此页面中的所有脚本

然后可以使用preg_replace_回调函数删除它们,然后将html解析为DOM。以下是工作演示:

$htmlWithScript=“something>
var showShareBarUI_参数_e81=
{
按钮WithCountTemplate:“”,
}
";
$htmlWithoutScript=preg\u replace\u回调(“~.*ui”,函数($matches){
返回“”;
},$htmlWithScript);
编辑


但我怎么能在不召唤克图鲁的情况下做到这一点呢

评论不错,但我不知道你在问什么:) 如果它正在加载html,那么您可以加载带有文件\u get\u contents()的html

如果您不了解它将如何删除标记: preg_replace_回调允许您根据regexp搜索匹配项并进行转换。在这种情况下,请删除它们(返回“”;) Regexp正在查找的起始标记具有任何属性(.*)和结束标记之间的任何内容

修改者:

U->表示取消冻结(尽可能短的匹配)

i->不区分大小写(也将匹配)

$html = mb_convert_encoding(file_get_contents('script2.html'), 'HTML-ENTITIES', 'UTF-8');
$new_html = preg_replace('/<script(.*?)>(.*?)<\/script>/si', '', $html);
file_put_contents('script-result.html', $new_html);
<?php
$html = <<<END
<!DOCTYPE html>
<html><body><h1>Hey now</h1>
<script type="text/javascript">
    var showShareBarUI_params_e81 =
    {
        buttonWithCountTemplate: '<div class="sBtnWrap"><a href="#" onclick="onClick"><div class="sBtn">text<img src="iconImg" /></div><div class="sCountBox">count</div></a></div>'
    }
</script>
</body></html>
END;

$dom = new DOMDocument();
$dom->preserveWhiteSpace = true; // needs to be before loading, to have any effect
$dom->loadXML($html);
    while (($r = $dom->getElementsByTagName("script")) && $r->length) {
        $r->item(0)->parentNode->removeChild($r->item(0));
    }
$dom->formatOutput = false;
print $dom->saveHTML();

//Outputs
//<!DOCTYPE html><html><head></head><body><h1>Hey now</h1></body></html>
require_once 'libs/simplehtmldom_1_5/simple_html_dom.php';
$html = <<<END
<div> <!-- Offending div without closing tag -->
<script type="text/javascript">
       var test = '</div>';
       // I should not appear on the result
</script>
END;

$dom = str_get_html($html);
echo $dom;

//outputs with no error or warnings
//<div> <!-- Offending div without closing tag --><script type="text/javascript">var test = '</div>';// I should not appear on the result  </script>
$htmlWithScript = "<html><body><div>something></div><script type=\"text/javascript\">
var showShareBarUI_params_e81 =
{
    buttonWithCountTemplate: '<div class=\"sBtnWrap\"><a href=\"#\" onclick=\"\$onClick\"><div class=\"sBtn\">\$text<img src=\"\$iconImg\" /></div><div class=\"sCountBox\">\$count</div></a></div>',
}
</script></body></html>";



$htmlWithoutScript = preg_replace_callback('~<script.*>.*</script>~Uis', function($matches){
return '';
}, $htmlWithScript);