PHP移除JavaScript

22

我正试图从HTML中去除JavaScript。

但是,我无法使用PHP使正则表达式起作用;它给了我一个空数组。为什么呢?

<?php
$var = '
<script type="text/javascript"> 
function selectCode(a) 
{ 
   var e = a.parentNode.parentNode.getElementsByTagName(PRE)[0]; 
   if (window.getSelection) 
   { 
      var s = window.getSelection(); 
       if (s.setBaseAndExtent) 
      { 
         s.setBaseAndExtent(e, 0, e, e.innerText.length - 1); 
      } 
      else 
      { 
         var r = document.createRange(); 
         r.selectNodeContents(e); 
         s.removeAllRanges(); 
         s.addRange(r); 
      } 
   } 
   else if (document.getSelection) 
   { 
      var s = document.getSelection(); 
      var r = document.createRange(); 
      r.selectNodeContents(e); 
      s.removeAllRanges(); 
      s.addRange(r); 
   } 
   else if (document.selection) 
   { 
      var r = document.body.createTextRange(); 
      r.moveToElementText(e); 
      r.select(); 
   } 
} 
</script>
';

   function remove_javascript($java){
   echo preg_replace('/<script\b[^>]*>(.*?)<\/script>/i', "", $java);

   }    
?>

3
我认为最好使用一些合适的库来清除那些<script>标签,因为正则表达式无法涵盖所有情况。例如:<scr/***/ipt> EVIL_CODES </scr/* */ipt>。请注意,我的翻译保持了原文的意思和语气,并尽可能地使其通俗易懂。 - YOU
无法工作,得到相同的东西。 - Saxtor
1
如果你想要防止XSS,我认为在尝试无用的方法之前,你应该先阅读这个页面http://ha.ckers.org/xss.html。有很多注入脚本的方法。 - Arkh
1
@Arkh 是完全正确的。我不知道这是否意味着提供了某种程度的XSS安全性,但它并没有。考虑微不足道的输入<scrip<script></script>t>alert(1337)</script>。它匹配内部空脚本标记,但删除它会留下一个新的脚本标记。更不用说URL、事件处理程序、CSS等中的脚本了。 - Mike Samuel
8个回答

66

这应该可以解决:

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

/s是为了使点号"."匹配换行符。

警告:不要使用这种类型的正则表达式来对网站用户输入进行清理。有太多绕过它的方法。要进行清理,请使用像http://htmlpurifier.org/这样的库。


我认为这并没有涵盖之前提到的情况,< scr /* */ ipt >,这正是试图规避此类检查的人所做的事情。 - Dimitrios Mistriotis
一个浏览器真的会运行<scr/* */ipt>标签内的内容吗?我很难相信... - gnud
8
我已经稍微修改/改善了它(尤其是匹配标签中的可选空格,浏览器也会忽略它): $html = preg_replace('~<\s*\bscript\b[^>]*>(.*?)<\s*\/\s*script\s*>~is', '', $html); (提示:这是一段 PHP 代码,用于从 HTML 中删除 <script> 标签及其内容。) - blueyed
嘿,gnude,当他们更新数据库以剥离所有注释时,是的,是的... 哈哈。 :) - Shanimal
不要忘记简单的解决方法 <img src="nonexistent" onerror="evil()">。仅删除脚本标签仍会使您容易受到注入的JavaScript攻击。 - Kyborek
如果您的文档有许多<script>标签,那么“?”是关键 - 懒惰量词“尽可能少地匹配字符”。 - vanduc1102

4

这可能做得比你想要的更多,但根据你的情况,你可能想看看strip_tags


2

这里有一个想法

while (true) {
  if ($beginning = strpos($var,"<script")) {
    $stringLength = (strpos($var,"</script>") + strlen("</script>")) - $beginning;
    substr_replace($var, "", $beginning, $stringLength);
  } else {
    break
  }
}

1
您可以使用以下PHP函数从HTML字符串中删除任何JavaScript代码。
您可以在此处阅读更多信息: https://mradeveloper.com/blog/remove-javascript-from-html-with-php
function sanitizeInput($inputP)
{
    $spaceDelimiter = "#BLANKSPACE#";
    $newLineDelimiter = "#NEWLNE#";
                                
    $inputArray = [];
    $minifiedSanitized = '';
    $unMinifiedSanitized = '';
    $sanitizedInput = [];
    $returnData = [];
    $returnType = "string";

    if($inputP === null) return null;
    if($inputP === false) return false;
    if(is_array($inputP) && sizeof($inputP) <= 0) return [];

    if(is_array($inputP))
    {
        $inputArray = $inputP;
        $returnType = "array";
    }
    else
    {
        $inputArray[] = $inputP;
        $returnType = "string";
    }

    foreach($inputArray as $input)
    {
        $minified = str_replace(" ",$spaceDelimiter,$input);
        $minified = str_replace("\n",$newLineDelimiter,$minified);

        //removing <script> tags
        $minifiedSanitized = preg_replace("/[<][^<]*script.*[>].*[<].*[\/].*script*[>]/i","",$minified);

        $unMinifiedSanitized = str_replace($spaceDelimiter," ",$minifiedSanitized);
        $unMinifiedSanitized = str_replace($newLineDelimiter,"\n",$unMinifiedSanitized);

        //removing inline js events
        $unMinifiedSanitized = preg_replace("/([ ]on[a-zA-Z0-9_-]{1,}=\".*\")|([ ]on[a-zA-Z0-9_-]{1,}='.*')|([ ]on[a-zA-Z0-9_-]{1,}=.*[.].*)/","",$unMinifiedSanitized);

        //removing inline js
        $unMinifiedSanitized = preg_replace("/([ ]href.*=\".*javascript:.*\")|([ ]href.*='.*javascript:.*')|([ ]href.*=.*javascript:.*)/i","",$unMinifiedSanitized);

                                    
        $sanitizedInput[] = $unMinifiedSanitized;
    }

    if($returnType == "string" && sizeof($sanitizedInput) > 0)
    {
        $returnData = $sanitizedInput[0];
    }
    else
    {
        $returnData = $sanitizedInput;
    }
                                
    return $returnData;
}
           

1
在您的情况下,您可以将该字符串视为一个以换行符分隔的字符串列表,并删除包含脚本标记(第一个和倒数第二个)的行,甚至不需要使用正则表达式。
但是,如果您试图防止XSS,仅删除脚本标记可能是不够的。

谢谢你们的建议,不过我的目的是在我的类代码中创建一个ripper,所以这是必需的。谢谢! - Saxtor

1
function clean_jscode($script_str) {
    $script_str = htmlspecialchars_decode($script_str);
    $search_arr = array('<script', '</script>');
    $script_str = str_ireplace($search_arr, $search_arr, $script_str);
    $split_arr = explode('<script', $script_str);
    $remove_jscode_arr = array();
    foreach($split_arr as $key => $val) {
        $newarr = explode('</script>', $split_arr[$key]);
        $remove_jscode_arr[] = ($key == 0) ? $newarr[0] : $newarr[1];
    }
    return implode('', $remove_jscode_arr);
}

0

这对我非常有用。试试这段代码。

while(($pos = stripos($content,"<script"))!==false){
    $end_pos = stripos($content,"</script>");
    $start = substr($content, 0, $pos);
    $end = substr($content, $end_pos+strlen("</script>"));
    $content = $start.$end;
}
$text = strip_tags($content);

-1

我使用这个:

function clear_text($s) {
    $do = true;
    while ($do) {
        $start = stripos($s,'<script');
        $stop = stripos($s,'</script>');
        if ((is_numeric($start))&&(is_numeric($stop))) {
            $s = substr($s,0,$start).substr($s,($stop+strlen('</script>')));
        } else {
            $do = false;
        }
    }
    return trim($s);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接