preg_match crush apache

时间:2016-06-12 18:16:49

标签: regex apache preg-match preg-match-all

我有一个模板引擎。解析tpl文件。但是当tpl文件有很多{if},{foreach}或{language}阻止preg_match crush apache。

这是我的preg_match函数;

preg_match_all('$\{(if|foreach)[\s]*(.*?)[\s]*\}((?:[^{]*(?:\{(?!\/?(if|foreach)[^}]*\})[^{]*)*|(?R))*)\{\/\1\}$iu',$content,$output);

这是apache日志

[Sun Jun 12 21:04:41.135620 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00428: Parent: child process 7620 exited with status 255 -- Restarting.
[Sun Jun 12 21:04:41.235425 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00455: Apache/2.4.9 (Win64) PHP/5.5.12 configured -- resuming normal operations
[Sun Jun 12 21:04:41.236426 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00456: Apache Lounge VC11 Server built: Mar 16 2014 12:42:59
[Sun Jun 12 21:04:41.236426 2016] [core:notice] [pid 1888:tid 552] AH00094: Command line: 'c:\\wamp\\bin\\apache\\apache2.4.9\\bin\\httpd.exe -d C:/wamp/bin/apache/apache2.4.9'
[Sun Jun 12 21:04:41.284459 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00418: Parent: Created child process 9668
[Sun Jun 12 21:04:41.642877 2016] [mpm_winnt:notice] [pid 9668:tid 452] AH00354: Child: Starting 64 worker threads.
[Sun Jun 12 21:04:42.047450 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00428: Parent: child process 9668 exited with status 255 -- Restarting.
[Sun Jun 12 21:04:42.147702 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00455: Apache/2.4.9 (Win64) PHP/5.5.12 configured -- resuming normal operations
[Sun Jun 12 21:04:42.147702 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00456: Apache Lounge VC11 Server built: Mar 16 2014 12:42:59
[Sun Jun 12 21:04:42.147702 2016] [core:notice] [pid 1888:tid 552] AH00094: Command line: 'c:\\wamp\\bin\\apache\\apache2.4.9\\bin\\httpd.exe -d C:/wamp/bin/apache/apache2.4.9'
[Sun Jun 12 21:04:42.194580 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00418: Parent: Created child process 10824
[Sun Jun 12 21:04:42.487866 2016] [mpm_winnt:notice] [pid 10824:tid 452] AH00354: Child: Starting 64 worker threads.

但是当我尝试regex101.com时,它的成功匹配没有任何错误。 https://regex101.com/r/uW8rZ8/3

2 个答案:

答案 0 :(得分:1)

Regex101可能没有任何错误,但效果不佳。如果你看一下,它会说:2 matches - 10792 steps,这意味着你的正则表达式可能是灾难性的回溯。如果不是,那么您可能没有使用正确的工具......您是否考虑过使用实际的解析器?一个旨在处理递归匹配的文件?

如果您仍然认为需要使用正则表达式,则需要修复一些缺陷。

我不熟悉您必须直接帮助您解决所遇到的错误(甚至是错误?),但我认为您需要解决一些更紧迫的问题才能解决其他问题。这个过程可能会解决您遇到的问题,因为它很可能是相关的。

现在最重要的是你的正则表达式缺乏可读性。我不知道你的正则表达式是做什么的。我不是你的普通程序员......我喜欢正则表达式,而且我通常能够轻松阅读它们。但不是这个。 (问题的一部分也可能是事实并非如此为什么你正在使用这个正则表达式。)

我的第一个建议是使用x修饰符,它允许您使用间距,就像在普通程序中一样。我修改了你的原始正则表达式以使用间距,我也删除了过多的反斜杠:

{(if|foreach)
[\s]*
(.*?)
[\s]*}
((?:
  [^{]*
  (?:{
    (?!/?
      (if|foreach)[^}]*}
    )
    [^{]*
  )*|(?R))*
)
{/\1}

我过去曾用regex编写了一个类似的递归解析器,所以我对这类东西有一些经验。从我记忆中来看,我的解析器更快,而且它的可读性更高(因为它的流程类似于BNF风格的解析器)。根据我的解析器,我想我现在的速度更快了:

$re = "`
{(if)     ((?&exp))}(*PRUNE)\s*((?&line)*)\s*(*PRUNE){/if}|
{(foreach)((?&exp))*}(*PRUNE)\s*((?&line)*)\s*(*PRUNE){/foreach}
|(?&other)+

|(*F)(?:
   (?'line'  (?&if)|(?&for)|(?&other)+)
   (?'if'    {if     (?&exp)}(*PRUNE)\s*(?&line)*\s*(*PRUNE){/if})
   (?'for'   {foreach(?&exp)}(*PRUNE)\s*(?&line)*\s*(*PRUNE){/foreach})
   (?'other' ([^{]+|{)(?! (/?if|/?foreach)))
   (?'exp'   [^}]*)
)`xis"; 

答案 1 :(得分:1)

即使你的模式适用于regex101,你也接近灾难性的bac​​tracking。您使用regex101而不是使用服务器进行模式化的原因很简单:配置不一样。

您的模式中缺少两件事:

  • 使用占有量词(或原子群)禁止在不适用的情况下进行回溯。
  • 展开(?:A|B)*A*+(?:BA*)*+之类的内容,以避免更改并减少步骤数。

遵循这些建议将使您的模式效率提高3倍:

~
{ (if\b|foreach\b) \s*+
( [^\s}]*+ (?:\s+[^\s}]+)*+ ) \s* }
(
    [^{]*+
    (?:  { (?!/?if\b|/?foreach\b) [^{]*
      |  (?R)                     [^{]* )*+

)
{/\1}
~ixu

demo