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

时间:2012-02-27 08:38:42

标签: php javascript html regex events

请帮助解析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>

我需要在没有引号的情况下执行此操作,因为所有现代浏览器都允许在没有quoutes的情况下执行属性。

注意:我不仅仅是onclick解析..这是所有的特征,从&#39;开始。#/ p>

注意(2):不要尝试为HTML PARSER提供建议,因为它会为PARRE提供非常大的DOM树。

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

2 个答案:

答案 0 :(得分:5)

使用正则表达式进行标记时没有任何问题。但是使用正则表达式创建一个完整的HTML标记化器是很多工作,很难做到正确。我建议使用正确的解析器,因为你可能还需要删除脚本标签等。

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

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


关于容错的注意事项

浏览器通常会容忍错误。 由于难以对标签进行标记并获取属性,因为当存在“无效”数据时,浏览器会看到它们。 由于浏览器之间的容错和处理不同,因此无法在所有情况下制定适合所有情况的解决方案。

因此:某些浏览器(当前版本,过去版本或未来版本)可能会将我的代码认为不是标记的内容视为标记,并执行JS代码。< / p>

在我的代码中,我试图模仿最近谷歌Chrome版本的标签(和容错/处理)的标记化。 Firefox似乎以类似的方式做到了。

IE 7有所不同,在某些情况下它并不是宽容的(这比它更宽容更好)。 (IE 6 - 不要去那里。见XSS Filter Evasion Cheat Sheet


相关链接:


代码

$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);
}


使用示例

Online example

$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"   />

答案 1 :(得分:4)

使用DOMDocument可能会更好。

您可以使用它来迭代您尝试解析的HTML文件所代表的DOM树,查找要删除的各种on *属性。

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