从HTML标记中删除on*JS事件属性


Remove on* JS event attributes from HTML tags

请帮助在PHP中解析简单的html字符串(PHP regexp)。我需要从html代码中删除html-js事件。我对php正则表达式非常了解。

代码示例:

<button onclick="..javascript instruction..">

结果:<button>

<button onclick="..javascript instruction.." value="..">

结果:<button value="..">

<button onclick=..javascript instruction..>

结果:<button>

<button onclick=..javascript instruction.. value>

结果:<button value>

我需要在没有引号和的情况下这样做,因为所有现代浏览器都允许在没有quutes的情况下做属性。

注意:我不仅需要解析onclick。。这都是从"on"开始的atrributes。

注意(2):不要尝试建议HTML PARSER,因为它对PARSE来说将是一个非常大的DOM树。。

更新:谢谢您的回复!现在,我使用HTMLPurifier组件编写了一个小框架。

使用正则表达式标记没有错。但是,用regex制作一个完整的HTML标记器是一项艰巨的工作,而且很难做好。我建议使用合适的解析器,因为您可能需要删除脚本标记等

假设不需要完整的标记化器,则可以使用以下正则表达式和代码从HTML标记中删除on*属性。因为没有使用适当的标记化器,所以即使在脚本、注释、CDATA等中,它也会匹配看起来像标签的字符串。

不能保证所有输入/浏览器组合的所有事件属性都会被删除请参阅下面的注释。


容错注意事项

浏览器通常可以容忍错误。因此,当存在"无效"数据时,很难标记标签并获取属性,因为浏览器会看到它们。由于不同浏览器的容错能力和处理方式不同,因此不可能制定出在所有情况下都适用于它们的解决方案。

因此:一些浏览器(当前、过去或未来版本)可以将我的代码认为不是标记的东西视为标记,并执行JS代码。

在我的代码中,我试图模仿最近Google Chrome版本的标记标记化(以及容错/处理)。Firefox似乎也有类似的做法。

IE 7不同,在某些情况下它没有那么宽容(这比它更宽容要好)。(IE 6-让我们不要去那里。见XSS过滤器规避作弊表)


相关链接:

  • HTML5标记化
  • XSS过滤器规避备忘单


代码

$redefs = '(?(DEFINE)
    (?<tagname> [a-z][^'s>/]*+    )
    (?<attname> [^'s>/][^'s=>/]*+    )  # first char can be pretty much anything, including =
    (?<attval>  (?>
                    "[^"]*+" |
                    ''[^'']*+'' |
                    [^'s>]*+            # unquoted values can contain quotes, = and /
                )
    ) 
    (?<attrib>  (?&attname)
                (?: 's*+
                    = 's*+
                    (?&attval)
                )?+
    )
    (?<crap>    [^'s>]    )             # most crap inside tag is ignored, will eat the last / in self closing tags
    (?<tag>     <(?&tagname)
                (?: 's*+                # spaces between attributes not required: <b/foo=">"style=color:red>bold red text</b>
                    (?>
                        (?&attrib) |    # order matters
                        (?&crap)        # if not an attribute, eat the crap
                    )
                )*+
                's*+ /?+
                's*+ >
    )
)';

// removes onanything attributes from all matched HTML tags
function remove_event_attributes($html){
    global $redefs;
    $re = '(?&tag)' . $redefs;
    return preg_replace("~$re~xie", 'remove_event_attributes_from_tag("$0")', $html);
}
// removes onanything attributes from a single opening tag
function remove_event_attributes_from_tag($tag){
    global $redefs;
    $re = '( ^ <(?&tagname) ) | 'G 's*+ (?> ((?&attrib)) | ((?&crap)) )' . $redefs;
    return preg_replace("~$re~xie", '"$1$3"? "$0": (preg_match("/^on/i", "$2")? " ": "$0")', $tag);
}


示例用法

在线示例:

$str = '
<button onclick="..javascript instruction..">
<button onclick="..javascript instruction.." value="..">
<button onclick=..javascript_instruction..>
<button onclick=..javascript_instruction.. value>
<hello word "" ontest = "hai"x="y"onfoo=bar/baz  />
';
echo $str . "'n----------------------'n";
echo remove_event_attributes($str);

输出:

<button onclick="..javascript instruction..">
<button onclick="..javascript instruction.." value="..">
<button onclick=..javascript_instruction..>
<button onclick=..javascript_instruction.. value>
<hello word "" ontest = "hai"x="y"onfoo=bar/baz  />
----------------------
<button >
<button  value="..">
<button >
<button  value>
<hello word "" x="y"   />

您最好使用DOMDocument。

您可以使用它来遍历由要解析的HTML文件表示的DOM树,查找要删除的各种on*属性。

这种方法更有可能成功,因为DOMDocument实际上理解HTML文件的语义,而regex只是一个愚蠢的字符串解析器,不足以可靠地解析HTML。