删除脚本和样式标记中的所有内容


Remove everything within script and style tags

我有一个名为$articleText的变量,它包含html代码。在<script><style> html元素中存在scriptstyle代码。我想扫描$articleText并删除这些代码。如果我也可以删除实际的html元素<script></script><style></style>,我也会这样做。

我想我需要使用正则表达式,但我不熟练。

有人能帮忙吗?

我希望我能提供一些代码,但正如我所说,我不擅长正则表达式,所以我没有任何东西可以展示。

我不能使用DOM。我需要特别针对这些特定的标签使用regex

不要在HTML上使用RegEx。PHP提供了一种用于解析DOM结构的工具,称为DomDocument。

<?php
// some HTML for example
$myHtml = '<html><head><script>alert("hi mom!");</script></head><body><style>body { color: red;} </style><h1>This is some content</h1><p>content is awesome</p></body><script src="someFile.js"></script></html>';
// create a new DomDocument object
$doc = new DOMDocument();
// load the HTML into the DomDocument object (this would be your source HTML)
$doc->loadHTML($myHtml);
removeElementsByTagName('script', $doc);
removeElementsByTagName('style', $doc);
removeElementsByTagName('link', $doc);
// output cleaned html
echo $doc->saveHtml();
function removeElementsByTagName($tagName, $document) {
  $nodeList = $document->getElementsByTagName($tagName);
  for ($nodeIdx = $nodeList->length; --$nodeIdx >= 0; ) {
    $node = $nodeList->item($nodeIdx);
    $node->parentNode->removeChild($node);
  }
}

你可以在这里试试:https://eval.in/private/4f225fa0dcb4eb

文档

  • DomDocument-http://php.net/manual/en/class.domdocument.php
  • DomNodeList-http://php.net/manual/en/class.domnodelist.php
  • DomDocument::getElementsByTagName-http://us3.php.net/manual/en/domdocument.getelementsbytagname.php

即使regex对于这类任务也不是一个好工具,对于简单的小任务来说,它也可以工作。


如果您只想删除标签的内部文本,请使用:

preg_replace('/(<(script|style)'b[^>]*>).*?(<'/'2>)/is', "$1$3", $txt);

请参阅此处的演示。

如果您还想删除标记,那么上面代码中的替换字符串将为空,所以只有""

我认为这应该满足您的需要(假设没有嵌套的脚本和样式标记):

preg_replace('/(<script[^>]*>.+?<'/script>|<style[^>]*>.+?<'/style>)/is', '', $articleText);

以下是示例数据:

$in = '
<html>
    <head>
        <script type="text/javascript">window.location="somehwere";</script>
        <style>
            .someCSS {border:1px solid black;}
        </style>
    </head>
    <body>
        <p>....</p>
        <div>
            <script type="text/javascript">document.write("bad stuff");</script>
        </div>
        <ul>
            <li><style type="text/css">#moreCSS {font-weight:900;}</style></li>
        </ul>
    </body>
</html>';

现在是拼写出来的版本:

$dom = new DOMDocument('1.0','UTF-8');
$dom->loadHTML($in);
removeByTag($dom,'style');
removeByTag($dom,'script');
var_dump($dom->saveHTML());
function removeByTag($dom,$tag) {
    $nodeList = $dom->getElementsByTagName($tag);
    removeAll($nodeList);
}
function removeAll($nodeList) {
    for ( $i = $nodeList->length; --$i >=0; ) {
        removeSelf($nodeList->item($i));
    }
}
function removeSelf($node) {
    $node->parentNode->removeChild($node);
}

还有一个替代方案(做同样的事情,只是没有函数声明):

$dom = new DOMDocument('1.0','UTF-8');
$dom->loadHTML($in);
for ( $list = $dom->getElementsByTagName('script'), $i = $list->length; --$i >=0; ) {
    $node = $list->item($i);
    $node->parentNode->removeChild($node);
}
for ( $list = $dom->getElementsByTagName('style'), $i = $list->length; --$i >=0; ) {
    $node = $list->item($i);
    $node->parentNode->removeChild($node);
}
var_dump($dom->saveHTML());

诀窍是在删除节点时向后迭代。getElementsByTagName将为您遍历整个DOM,因此您不必(这些都没有ChildNodes、nextSibling、nextChildd之类的东西)。

也许最好的解决方案是介于这两个极端例子之间。


我忍不住了,这可能是我建议的最好版本。它不包括一个增量器($i)来把事情搞砸,并从自下而上删除:

$dom = new DOMDocument('1.0','UTF-8');
$dom->loadHTML($in);
removeElementsByTagName($dom,'script');
removeElementsByTagName($dom,'style');
function removeElementsByTagName($dom,$tagName) {
    $list = $dom->getElementsByTagName($tagName);
    while ( $node = $list->item(0) ) {
        $node->parentNode->removeChild($node);
    }
}
var_dump($dom->saveHTML());

删除节点时,它们会在父节点的子列表中向上移动,因此1变为0,2变为1,依此类推。继续执行此操作(while),直到不再存在为止(->item返回null)。还将其封装在一个可重用函数中。

假设这既是为了不让你的设计被随机风格搞砸,也是为了保护你的网站不受用户脚本的影响,删除这些标签并不能单独保证你的安全。

考虑事件属性(例如:onmouseover,onclick)的情况:

<h1 onclick="console.log('user made this happen');">User Scripting Test</h1>

甚至更糟的

<h1 onclick='function addCSSRule(a,b,c,d){"insertRule"in a?a.insertRule(b+"{"+c+"}",d):"addRule"in a&&a.addRule(b,c,d)}var style=document.createElement("style");style.appendChild(document.createTextNode("")),document.head.appendChild(style),sheet=style.sheet,addCSSRule(sheet,"*","color: #ff0!important");'>Messing with your styles!</h1>

这样一来,开始在文档中插入各种各样的东西就相当简单了。

样式表mods的最后一个例子取自David Walsh-https://davidwalsh.name/add-rules-stylesheets

唯一的解决方案

是使用一个经过验证的专门从事这方面的第三方库。我建议使用HTML净化器。它将消除用户输入中的样式、脚本和讨厌的事件属性。

要做到这一点,正则表达式将非常迟钝,因为标签中可能存在标签,以及标签属性等混淆结构。

我建议在DOM(PHP或JavaScript)中这样做,它可以通过实际解析来识别和删除不需要的标签。