从HTML内容中删除脚本标签

2020/10/31 17:02 · php ·  · 0评论

我正在使用HTML Purifier(http://htmlpurifier.org/)

我只想删除<script>标签。我不想删除内联格式或任何其他内容。

我该如何实现?

还有一件事,它还有其他方法可以从HTML删除脚本标签

因为这个问题被标记为 在这种情况下,我将用穷人的解决方案来回答:

$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);

但是,正则表达式不是用于解析HTML / XML的,即使您编写了一个完美的表达式,它最终也会被破坏,这是不值得的,尽管在某些情况下,快速修复某些标记很有用,而对于快速修复,忘记安全仅在您信任的内容/标记上使用正则表达式。

请记住,用户输入的任何内容均应视为不安全的

更好的解决方案是使用DOMDocument为此目的而设计的解决方案下面的代码片段演示了如何轻松,干净(与regex相比),(几乎)可靠和(几乎)安全来实现相同目的:

<?php

$html = <<<HTML
...
HTML;

$dom = new DOMDocument();

$dom->loadHTML($html);

$script = $dom->getElementsByTagName('script');

$remove = [];
foreach($script as $item)
{
  $remove[] = $item;
}

foreach ($remove as $item)
{
  $item->parentNode->removeChild($item); 
}

$html = $dom->saveHTML();

我故意删除了HTML,因为即使这样也可能会出错

使用PHPDOMDocument解析器。

$doc = new DOMDocument();

// load the HTML string we want to strip
$doc->loadHTML($html);

// get all the script tags
$script_tags = $doc->getElementsByTagName('script');

$length = $script_tags->length;

// for each tag, remove it from the DOM
for ($i = 0; $i < $length; $i++) {
  $script_tags->item($i)->parentNode->removeChild($script_tags->item($i));
}

// get the HTML string back
$no_script_html_string = $doc->saveHTML();

这使我使用以下HTML文档工作:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>
            hey
        </title>
        <script>
            alert("hello");
        </script>
    </head>
    <body>
        hey
    </body>
</html>

请记住,DOMDocument解析器需要PHP 5或更高版本。

$html = <<<HTML
...
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$tags_to_remove = array('script','style','iframe','link');
foreach($tags_to_remove as $tag){
    $element = $dom->getElementsByTagName($tag);
    foreach($element  as $item){
        $item->parentNode->removeChild($item);
    }
}
$html = $dom->saveHTML();

通过操纵字符串的一种简单方法。

$str = stripStr($str, '<script', '</script>');

function stripStr($str, $ini, $fin)
{
    while(($pos = mb_stripos($str, $ini)) !== false)
    {
        $aux = mb_substr($str, $pos + mb_strlen($ini));
        $str = mb_substr($str, 0, $pos).mb_substr($aux, mb_stripos($aux, $fin) + mb_strlen($fin));
    }

    return $str;
}

我一直在努力解决这个问题。我发现您只需要一个功能。explode('>',$ html); 任何标签的唯一公分母是<和>。然后,通常是引号(“)。一旦找到公分母,就可以很容易地提取信息。这就是我想出的:

$html = file_get_contents('http://some_page.html');

$h = explode('>', $html);

foreach($h as $k => $v){

    $v = trim($v);//clean it up a bit

    if(preg_match('/^(<script[.*]*)/ius', $v)){//my regex here might be questionable

        $counter = $k;//match opening tag and start counter for backtrace

        }elseif(preg_match('/([.*]*<\/script$)/ius', $v)){//but it gets the job done

            $script_length = $k - $counter;

            $counter = 0;

            for($i = $script_length; $i >= 0; $i--){
                $h[$k-$i] = '';//backtrace and clear everything in between
                }
            }           
        }
for($i = 0; $i <= count($h); $i++){
    if($h[$i] != ''){
    $ht[$i] = $h[$i];//clean out the blanks so when we implode it works right.
        }
    }
$html = implode('>', $ht);//all scripts stripped.


echo $html;

我看到这实际上仅适用于脚本标签,因为您永远不会有嵌套的脚本标签。当然,您可以轻松添加更多执行相同检查并收集嵌套标记的代码。

我称它为手风琴编码。implode(); explode(); 如果有一个共同的分母,这是使逻辑流畅的最简单方法。

更短:

$html = preg_replace("/<script.*?\/script>/s", "", $html);

在执行正则表达式时,可能会出错,因此这样做更安全:

$html = preg_replace("/<script.*?\/script>/s", "", $html) ? : $html;

这样,当“事故”发生时,我们得到原始的$ html而不是空字符串。

修改ctf0答案的示例。这应该只执行一次preg_replace,而且还应该检查是否有错误,并为正斜杠阻止字符代码。

$str = '<script> var a - 1; <&#47;script>'; 

$pattern = '/(script.*?(?:\/|&#47;|&#x0002F;)script)/ius';
$replace = preg_replace($pattern, '', $str); 
return ($replace !== null)? $replace : $str;  

如果您使用的是php 7,则可以使用null合并运算符进一步简化它。

$pattern = '/(script.*?(?:\/|&#47;|&#x0002F;)script)/ius'; 
return (preg_replace($pattern, '', $str) ?? $str); 

试试这个完整灵活的解决方案。它完美,并且由设在部分一些以前的答案,但包含额外的验证检查,并摆脱额外的隐含从HTMLloadHTML(...)功能。它分为两个独立的函数(一个具有先前的依赖性,因此请勿重新排序/重新排列),因此您可以将其与要同时删除的多个HTML标记一起使用(即不仅仅是'script'标记)。例如,removeAllInstancesOfTag(...)function接受一个array标记名,或者仅接受一个作为标记名string因此,事不宜迟,这里是代码:


/* Remove all instances of a particular HTML tag (e.g. <script>...</script>) from a variable containing raw HTML data. [BEGIN] */

/* Usage Example: $scriptless_html = removeAllInstancesOfTag($html, 'script'); */

if (!function_exists('removeAllInstancesOfTag'))
    {
        function removeAllInstancesOfTag($html, $tag_nm)
            {
                if (!empty($html))
                    {
                        $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); /* For UTF-8 Compatibility. */
                        $doc = new DOMDocument();
                        $doc->loadHTML($html,LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NOWARNING);

                        if (!empty($tag_nm))
                            {
                                if (is_array($tag_nm))
                                    {
                                        $tag_nms = $tag_nm;
                                        unset($tag_nm);

                                        foreach ($tag_nms as $tag_nm)
                                            {
                                                $rmvbl_itms = $doc->getElementsByTagName(strval($tag_nm));
                                                $rmvbl_itms_arr = [];

                                                foreach ($rmvbl_itms as $itm)
                                                    {
                                                        $rmvbl_itms_arr[] = $itm;
                                                    };

                                                foreach ($rmvbl_itms_arr as $itm)
                                                    {
                                                        $itm->parentNode->removeChild($itm);
                                                    };
                                            };
                                    }
                                else if (is_string($tag_nm))
                                    {
                                        $rmvbl_itms = $doc->getElementsByTagName($tag_nm);
                                        $rmvbl_itms_arr = [];

                                        foreach ($rmvbl_itms as $itm)
                                            {
                                                $rmvbl_itms_arr[] = $itm;
                                            };

                                        foreach ($rmvbl_itms_arr as $itm)
                                            {
                                                $itm->parentNode->removeChild($itm); 
                                            };
                                    };
                            };

                        return $doc->saveHTML();
                    }
                else
                    {
                        return '';
                    };
            };
    };

/* Remove all instances of a particular HTML tag (e.g. <script>...</script>) from a variable containing raw HTML data. [END] */

/* Remove all instances of dangerous and pesky <script> tags from a variable containing raw user-input HTML data. [BEGIN] */

/* Prerequisites: 'removeAllInstancesOfTag(...)' */

if (!function_exists('removeAllScriptTags'))
    {
        function removeAllScriptTags($html)
            {
                return removeAllInstancesOfTag($html, 'script');
            };
    };

/* Remove all instances of dangerous and pesky <script> tags from a variable containing raw user-input HTML data. [END] */


这是一个测试用法示例:


$html = 'This is a JavaScript retention test.<br><br><span id="chk_frst_scrpt">Congratulations! The first \'script\' tag was successfully removed!</span><br><br><span id="chk_secd_scrpt">Congratulations! The second \'script\' tag was successfully removed!</span><script>document.getElementById("chk_frst_scrpt").innerHTML = "Oops! The first \'script\' tag was NOT removed!";</script><script>document.getElementById("chk_secd_scrpt").innerHTML = "Oops! The second \'script\' tag was NOT removed!";</script>';
echo removeAllScriptTags($html);

希望我的回答对您有所帮助。请享用!

如果可用,我将使用BeautifulSoup。使这种事情非常容易。

不要尝试使用正则表达式。那就是疯狂。

  • 这是ClandestineCoderBinh WPO的合并

脚本标记箭头的问题在于它们可以具有多个变体

例如 (<= &lt;= &amp;lt;)&(> = &gt;= &amp;gt;

因此,与其创建具有类似bazillion变体的模式数组,不如做一个更好的解决方案是

return preg_replace('/script.*?\/script/ius', '', $text)
       ? preg_replace('/script.*?\/script/ius', '', $text)
       : $text;

这将删除任何script.../script与箭头代码/变量无关的内容,您可以在此处进行测试https://regex101.com/r/lK6vS8/1

这是Dejan Marjanovic的答案的简化版本:

function removeTags($html, $tag) {
    $dom = new DOMDocument();
    $dom->loadHTML($html);
    foreach (iterator_to_array($dom->getElementsByTagName($tag)) as $item) {
        $item->parentNode->removeChild($item);
    }
    return $dom->saveHTML();
}

可用于删除任何种类的标签,包括<script>

$scriptlessHtml = removeTags($html, 'script');
function remove_script_tags($html){
    $dom = new DOMDocument();
    $dom->loadHTML($html);
    $script = $dom->getElementsByTagName('script');

    $remove = [];
    foreach($script as $item){
        $remove[] = $item;
    }

    foreach ($remove as $item){
        $item->parentNode->removeChild($item);
    }

    $html = $dom->saveHTML();
    $html = preg_replace('/<!DOCTYPE.*?<html>.*?<body><p>/ims', '', $html);
    $html = str_replace('</p></body></html>', '', $html);
    return $html;
}

Dejan的回答很好,但是saveHTML()添加了不必要的doctype和body标签,这应该摆脱它。参见https://3v4l.org/82FNP

使用str_replace函数将其替换为空白空间或其他内容

$query = '<script>console.log("I should be banned")</script>';

$badChar = array('<script>','</script>');
$query = str_replace($badChar, '', $query);

echo $query; 
//this echoes console.log("I should be banned")

?>

本文地址:http://php.askforanswer.com/conghtmlneirongzhongshanchujiaobenbiaoqian.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!