【问题标题】:PHP - Remove all content inside <script> and CDATA of HTML stringPHP - 删除 <script> 中的所有内容和 HTML 字符串的 CDATA
【发布时间】:2016-02-20 07:39:04
【问题描述】:

我应该删除从通用网站 URL 的 file_get_contents 获取的 PHP 字符串中标签之间的所有内容(和标签)。 我正在使用正则表达式:

preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $string);

它工作正常,但我的问题是,如果脚本包含 CDATA 标记,它将无法工作。字符串的一个例子是:

<script type='text/javascript'>
/* <![CDATA[ */
var variable = {"ajax":"....."}
/* ]]> */
</script>

我猜问题出在那些“/”和“/”标签上。


我已经在 google 和 Stack Overflow 上进行了搜索,但是对于特定类型的 cdata 标签(带有 /* 和 */)毫无疑问,所以没有任何效果。

有什么建议吗?

编辑: 正如史蒂夫回答的那样,我现在正在使用这样的代码:

foreach($dom->getElementsByTagName('script') as $scripttag){
$scripttag->parentNode->removeChild($scripttag);
}

然后我有:

foreach($dom->getElementsByTagName('ins') as $string) {
    $string2 .= $string->nodeValue;
    $string2 .= ' ';
}

但这会返回一个带有脚本标签的 $string2。

编辑 2(已解决): 在 Steve 的帮助下,我发现使用 Xpath 可以解决问题:

$xpath = new DOMXpath($dom);
foreach ($xpath->query('//script') as $node) {
   $node->parentNode->removeChild($node);
}

这也会删除另一个标签内的脚本标签,例如:

<ins><script>First JS</script></ins>
<ins>Hello</ins>
<script>Second JS</script>

会输出

Hello

谢谢大家的帮助!

【问题讨论】:

  • 用于 html 解析的正则表达式不是一个好主意。并且不要忘记删除
  • 有什么问题?我看到它有效"nicely"(当然,仅使用提供的示例)。
  • @stribizhev 这是用正则表达式解析 html 的问题,从攻击者的角度来看,我不遵守规则......regex101.com/r/zV1yA2/1
  • 您好,感谢您的建议,但正如我对史蒂夫的回答,我也在使用 DOMDocument,但不知道是否可以在删除内容后重新使用它...
  • 那么请更新您的问题[...] I'm using the RegEx expression [...] - 我不建议使用库,但您应该查看htmlpurifier 库。

标签: php html regex dom domdocument


【解决方案1】:

不要为此使用正则表达式,使用适当的 html 解析器,如 domdocument:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
//removing elements from a nodelist resets the internal pointer, so traverse backwards:
$elements = $dom->getElementsByTagName('script');
$count = $elements->length;
while(--$count){
    $elements->item($count)->parentNode->removeChild($elements->item($count));
}

//you can do further dom manipulation here if needed
$insertContents='';
foreach($dom->getElementsByTagName('ins') as $insert){
    $insertContents .= $insert->nodeValue . ' ';
}
//if you need the complete html at all:
$html = $dom->saveHTML();
//your desired string:
echo $insertContents;

【讨论】:

  • 嗨,感谢您的回答,但我已经将 DOMDocument 用于 $dom->getElementsByTagName('ins');是否可以使用另一个函数而不是 $dom->saveHTML();保存新的 dom 对象并将其重新用于其他 getElements? (对不起,我对 dom 的无知)
  • 您可以继续使用同一个实例 - 您可以多次调用getElementsByTagName,并且只有在完成处理后才调用saveHTML
  • 嗨史蒂夫,很抱歉我的坚持,但如果我像你说的那样使用那个代码,它会保留脚本标签。特别是,我所做的是foreach($dom-&gt;getElementsByTagName('ins') as $string) { $string2 .= $string-&gt;nodeValue; $string2 .= ' '; } 但是这会返回一个 $string2再次使用脚本标签...再次为我的无知感到抱歉。
  • @TekLitto 哎呀,对不起。我的错。事实证明,在遍历元素时删除元素时需要小心 - 请参阅更新
  • 谢谢@Steve,现在效果很好,但是还有一个小问题,如果我有类似&lt;ins&gt;&lt;script&gt;First JS&lt;/script&gt;&lt;/ins&gt;&lt;script&gt;Second JS&lt;/script&gt; echo $insertContents;会输出“First JS”,能解决吗?
猜你喜欢
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-08
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
  • 2017-06-03
相关资源
最近更新 更多