删除 PHP 中的所有 REAL Javascript 注释

Posted

技术标签:

【中文标题】删除 PHP 中的所有 REAL Javascript 注释【英文标题】:Remove all REAL Javascript comments in PHP 【发布时间】:2015-08-14 21:33:18 【问题描述】:

我正在寻找一种解决方案,以使用 php 去除 html 代码中的所有 javascript cmets

我想剥离 仅 Javascript cmets(不是 HTML cmets 等)。我认为 regex 不是解决方案,因为它无法理解是 real comment 还是字符串的一部分。示例:

<script>

// This is a comment
/* This is another comment */

// The following is not a comment
var src="//google.com"; 

</script>

有办法吗?非常感谢提前

【问题讨论】:

使用a PHP DOM parser。 完全正确。 javascript 不是常规语言(HTML 也不是),因此您不能仅使用正则表达式对其进行解析。您将需要提出一个不同的解析器或使用一些可能已经存在的模块。 @Cu3PO42:再一次,这是一个错误的论点,因为通常称为正则表达式与理论上称为正则表达式不同。通常称为正则表达式的工具(以多种语言实现)大多数时候能够解析非正则语言。 【参考方案1】:

要做的第一件事:你需要提取脚本标签的内容。为此,请使用 DOMDocument:

$dom = new DOMDocument;
$dom->loadHTML($html);

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

第二步是删除每个脚本节点的所有 javascript cmets。

如果需要,您可以使用第三方 javascript 解析器,但也可以使用正则表达式。您需要做的就是防止将引号之间的部分考虑在内。

为此,您必须搜索引号之间的第一部分并丢弃它们。用 javascript 做到这一点的唯一困难是引号可以在正则表达式模式中,例如:/pattern " with a quote/

所以你也需要找到模式来防止任何错误。

模式示例:

$pattern = <<<'EOD'
~
(?(DEFINE)
    (?<squoted> ' [^'\n\\]*+ (?: \\. [^'\n\\]* )*+ ' )
    (?<dquoted> " [^"\n\\]*+ (?: \\. [^"\n\\]* )*+ " )
    (?<tquoted> ` [^`\\]*+ (?s: \\. [^`\\]*)*+ ` )
    (?<quoted>  \g<squoted> | \g<dquoted> | \g<tquoted> )
    
    (?<scomment> // \N* )
    (?<mcomment> /\* [^*]*+ (?: \*+ (?!/) [^*]* )*+ \*/ )
    (?<comment> \g<scomment> | \g<mcomment> )
    
    (?<pattern> / [^\n/*] [^\n/\\]*+ (?>\\.[^\n/\\]*)* / [gimuy]* ) 
)

(?=[[(:,=/"'`])
(?|
    \g<quoted> (*SKIP)(*FAIL)
  |
    ( [[(:,=] \s* ) (*SKIP) (?: \g<comment> \s* )*+ ( \g<pattern> )
  | 
    ( \g<pattern> \s* ) (?: \g<comment> \s* )*+ 
    ( \. \s* ) (?:\g<comment> \s* )*+ ([A-Za-z_]\w*)
  |
    \g<comment>
)
~x
EOD;

然后你替换每个脚本节点的内容:

foreach ($scriptNodes as $scriptNode) 
    $scriptNode->nodeValue = preg_replace($pattern, '$9$10$11', $scriptNode->nodeValue);


$html = $dom->saveHTML();

demo

图案细节:

((?DEFINE)...) 是一个您可以放置​​稍后需要的所有子模式定义的区域。 “真正的”模式开始于之后。

(?&lt;name&gt;...) 被命名为子模式。它与捕获组相同,只是您可以使用其名称(如\g&lt;name&gt;)而不是其编号来引用它。

*+ 是possessive quantifiers

\N 表示不是换行符的字符

(?=[[(:,=/"'])&lt;/code&gt; is a [lookahead][3] that checks if the next character is one of these &lt;code&gt;[ ( : , = / " ' 。此测试的目的是防止在字符不同时测试以下交替的每个分支。如果你删除它,模式将同样工作,只是快速跳过字符串中无用的位置。

(*SKIP) 是一个回溯控制动词。当模式在它之后失败时,将不会尝试在它之前匹配的所有位置。

(*FAIL) 也是一个回溯控制动词,强制模式失败。

(?|..(..)..(..)..|..(..)..(..)..) 是一个分支重置组。在其中,捕获组在每个分支中分别具有相同的数字(此模式为 9 和 10)

【讨论】:

【参考方案2】:

使用这个功能

function removeComments(str) 
    str = ('__' + str + '__').split('');
    var mode = 
        singleQuote: false,
        doubleQuote: false,
        regex: false,
        blockComment: false,
        lineComment: false,
        condComp: false 
    ;
    for (var i = 0, l = str.length; i < l; i++) 
 
        if (mode.regex) 
            if (str[i] === '/' && str[i-1] !== '\') 
                mode.regex = false;
            
            continue;
        
 
        if (mode.singleQuote) 
            if (str[i] === "'" && str[i-1] !== '\') 
                mode.singleQuote = false;
            
            continue;
        
 
        if (mode.doubleQuote) 
            if (str[i] === '"' && str[i-1] !== '\') 
                mode.doubleQuote = false;
            
            continue;
        
 
        if (mode.blockComment) 
            if (str[i] === '*' && str[i+1] === '/') 
                str[i+1] = '';
                mode.blockComment = false;
            
            str[i] = '';
            continue;
        
 
        if (mode.lineComment) 
            if (str[i+1] === 'n' || str[i+1] === 'r') 
                mode.lineComment = false;
            
            str[i] = '';
            continue;
        
 
        if (mode.condComp) 
            if (str[i-2] === '@' && str[i-1] === '*' && str[i] === '/') 
                mode.condComp = false;
            
            continue;
        
 
        mode.doubleQuote = str[i] === '"';
        mode.singleQuote = str[i] === "'";
 
        if (str[i] === '/') 
 
            if (str[i+1] === '*' && str[i+2] === '@') 
                mode.condComp = true;
                continue;
            
            if (str[i+1] === '*') 
                str[i] = '';
                mode.blockComment = true;
                continue;
            
            if (str[i+1] === '/') 
                str[i] = '';
                mode.lineComment = true;
                continue;
            
            mode.regex = true;
 
        
 
    
    return str.join('').slice(2, -2);

使用这两个链接 http://trinithis.awardspace.com/commentStripper/stripper.html

http://james.padolsey.com/javascript/removing-comments-in-javascript/

进一步参考检查它Javascript comment stripper

【讨论】:

【参考方案3】:

此正则表达式适用于您的示例:

^\/(?:\/|\*).*

PHP 代码:

$re = "/^\\/(?:\\/|\\*).*/m"; 
$str = "<script>\n\n// This is a comment\n/* This is another comment */\n\n// The following is not a comment\nvar src=\"//google.com\"; \n\n</script>"; 

preg_match_all($re, $str, $matches);

DEMO


或者这个,验证*/

^\/2.*|\/\*.*\*\/$

PHP 代码:

$re = "/^\\/2.*|\\/\\*.*\\*\\/$/m"; 
$str = "<script>\n\n// This is a comment\n/* This is another comment */\n\n// The following is not a comment\nvar src=\"//google.com\"; \n\n</script>"; 

preg_match_all($re, $str, $matches);

DEMO2

【讨论】:

以上是关于删除 PHP 中的所有 REAL Javascript 注释的主要内容,如果未能解决你的问题,请参考以下文章

htmlentities() 和 mysql_real_escape_string() 是不是足以清理 PHP 中的用户输入? [复制]

函数中的 PHP Mysqli_real_escape_string 期望参数为 1。空值

有人在我的数据库中删除了一个表。如何? [复制]

有人在我的数据库中删除了一个表。如何? [复制]

PHP文件Real Mime [重复]

php mysqli mysqli_query() mysqli_real_query()