preg_match 粉碎阿帕奇
preg_match crush apache
我有一个模板引擎。解析 tpl 文件。但是当 tpl 文件有很多 {if},{foreach} 或 {language} 块时 preg_match crush apache.
这是我的 preg_match 函数;
preg_match_all('$\{(if|foreach)[\s]*(.*?)[\s]*\}((?:[^{]*(?:\{(?!\/?(if|foreach)[^}]*\})[^{]*)*|(?R))*)\{\/\}$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
Regex101 可能没有任何错误地运行,但它运行不正常。如果您看一下,它会显示:2 matches - 10792 steps
,这意味着您的正则表达式可能发生了灾难性的回溯。如果不是,那么您可能没有使用正确的工具...您是否考虑过使用 actual 解析器?一种设计用于处理递归匹配的?
如果您仍然觉得这个需要用正则表达式来完成,您需要修复一些缺陷。
我不熟悉你必须直接帮助你解决你遇到的错误的设置(他们甚至是错误吗?),但我认为你需要解决一些更紧迫的问题才能解决其他事宜。此过程可能会解决您遇到的问题,因为它很可能是相关的。
现在对我来说最重要的是你的正则表达式缺乏可读性。我不知道你的正则表达式是做什么的。而且我不是你的普通程序员......我喜欢正则表达式,而且我通常能够轻松阅读它们。但不是这个。 (部分问题可能还在于,您并不是很清楚为什么 使用此正则表达式。)
我的第一个建议是使用 x
修饰符,它允许您像在普通程序中一样使用间距。我修改了您原来的正则表达式以使用间距,并且还删除了过多的反斜杠:
{(if|foreach)
[\s]*
(.*?)
[\s]*}
((?:
[^{]*
(?:{
(?!/?
(if|foreach)[^}]*}
)
[^{]*
)*|(?R))*
)
{/}
我以前用正则表达式写过一个类似的递归解析器,所以我对这类东西有一些经验。据我所知,我的解析器速度更快,而且可读性更强(假设它的流程类似于 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";
即使您的模式适用于 regex101,您也接近灾难性的回溯。您的模式适用于 regex101 而不适用于您的服务器的原因很简单:配置不一样。
您的模式中缺少两件事:
- 使用所有格量词(或原子组)来禁止回溯无用的地方。
- 将
(?:A|B)*
之类的东西展开到 A*+(?:BA*)*+
以避免交替并减少步骤数。
遵循这些建议将使您的模式效率提高约 3 倍:
~
{ (if\b|foreach\b) \s*+
( [^\s}]*+ (?:\s+[^\s}]+)*+ ) \s* }
(
[^{]*+
(?: { (?!/?if\b|/?foreach\b) [^{]*
| (?R) [^{]* )*+
)
{/}
~ixu
我有一个模板引擎。解析 tpl 文件。但是当 tpl 文件有很多 {if},{foreach} 或 {language} 块时 preg_match crush apache.
这是我的 preg_match 函数;
preg_match_all('$\{(if|foreach)[\s]*(.*?)[\s]*\}((?:[^{]*(?:\{(?!\/?(if|foreach)[^}]*\})[^{]*)*|(?R))*)\{\/\}$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
Regex101 可能没有任何错误地运行,但它运行不正常。如果您看一下,它会显示:2 matches - 10792 steps
,这意味着您的正则表达式可能发生了灾难性的回溯。如果不是,那么您可能没有使用正确的工具...您是否考虑过使用 actual 解析器?一种设计用于处理递归匹配的?
如果您仍然觉得这个需要用正则表达式来完成,您需要修复一些缺陷。
我不熟悉你必须直接帮助你解决你遇到的错误的设置(他们甚至是错误吗?),但我认为你需要解决一些更紧迫的问题才能解决其他事宜。此过程可能会解决您遇到的问题,因为它很可能是相关的。
现在对我来说最重要的是你的正则表达式缺乏可读性。我不知道你的正则表达式是做什么的。而且我不是你的普通程序员......我喜欢正则表达式,而且我通常能够轻松阅读它们。但不是这个。 (部分问题可能还在于,您并不是很清楚为什么 使用此正则表达式。)
我的第一个建议是使用 x
修饰符,它允许您像在普通程序中一样使用间距。我修改了您原来的正则表达式以使用间距,并且还删除了过多的反斜杠:
{(if|foreach)
[\s]*
(.*?)
[\s]*}
((?:
[^{]*
(?:{
(?!/?
(if|foreach)[^}]*}
)
[^{]*
)*|(?R))*
)
{/}
我以前用正则表达式写过一个类似的递归解析器,所以我对这类东西有一些经验。据我所知,我的解析器速度更快,而且可读性更强(假设它的流程类似于 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";
即使您的模式适用于 regex101,您也接近灾难性的回溯。您的模式适用于 regex101 而不适用于您的服务器的原因很简单:配置不一样。
您的模式中缺少两件事:
- 使用所有格量词(或原子组)来禁止回溯无用的地方。
- 将
(?:A|B)*
之类的东西展开到A*+(?:BA*)*+
以避免交替并减少步骤数。
遵循这些建议将使您的模式效率提高约 3 倍:
~
{ (if\b|foreach\b) \s*+
( [^\s}]*+ (?:\s+[^\s}]+)*+ ) \s* }
(
[^{]*+
(?: { (?!/?if\b|/?foreach\b) [^{]*
| (?R) [^{]* )*+
)
{/}
~ixu