php ltrim打破正则表达式?

时间:2012-12-13 08:44:35

标签: php regex trim

我有点谜题,或许不是。 检查这件作品:

$query = ' SELECT account.account_no,
       account.accountname,
       accountbillads.bill_city,
       account.website,
       account.phone,
       CASE
         WHEN ( users.user_name NOT LIKE "" ) THEN users.user_name
         ELSE groups.groupname
       END AS user_name,
       entity.crmid,
       account.accountid,
       account.parentid,
       partner.partnerid      
FROM   account
       INNER JOIN entity
               ON entity.crmid = account.accountid
       INNER JOIN currency_info AS CurrencyInfoTable
               ON CurrencyInfoTable.id =
                  entity.record_currency_id
WHERE  entity.deleted = 0   ';

$query = ltrim($query);

preg_match("/^select ((.|\n)*?)\bfrom\b((.|\n)*?)\bselect\b/i", $query, $matches);

print('finito');
print_r($matches);

在我的服务器上崩溃,没有任何错误。

令人惊讶的是,棘手的一行是 $ query = ltrim($ query); 没有这条线,一切正常。

还有一些事情要做: 正则表达式的敏感部分是对“选择”的最后一次不正确的搜索。如果找不到第二个选择,则崩溃。查询的长度很重要。另请注意,在phpunits运行中,在同一台机器上,此问题不存在。

我的聚会是 ltrim 对字符串做了些什么,但我不确定是什么。

有人可以解释一下吗?

编辑。好吧,似乎ltrim不是问题所在。如果我只是给出没有起始空白的字符串我就崩溃了。它可能与pcre.backtrack_limit和pcre.recursion_limit设置有关,但我已经尝试过了,并没有改变。

EDIT2。崩溃是浏览器中的“连接中断”。没有完整的服务器崩溃,但脚本执行暂停。再次,日志中没有错误。

问题解决了。我不得不在最后用/ s替换(。| \ n)。非常感谢你们!

2 个答案:

答案 0 :(得分:2)

虽然在PHP regex tester中对此进行测试不会导致任何问题,但我认为由于您构建表达式的方式可能会导致崩溃。考虑这个结构:

(.|\n)*?

潜在问题是|运算符与*结合使用。当它不匹配时,这可能会产生巨大的可能性树:

                    first character matches .
                               |
                          yes------no
                           |        |
         2nd character matches .    first character matches \n
                 |                                 |
            yes-----no                       yes--------no
             |       |                        |          |
      3rd char .    2nd char \n     2nd char matches .  2nd char matches .

正则表达式引擎必须检查2 ^ n种可能性,其中n是字符串中剩余的字符数。

解决方案是使用/s开关,如注释中建议的primo。然后,您只需使用.即可匹配任何内容,包括换行符。而不是2 ^ n种可能性,它只需要检查n种可能性。

注意:一些正则表达式引擎足够聪明,可以避免这个陷阱。理论上如果第二个“选择”不存在,引擎应该足够聪明,知道它永远不会匹配,因此放弃。例如,当我在Perl中测试它时,没有问题。上面的PHP正则表达式测试程序没有问题。但也许您的PHP版本较旧,而且不太优化。

答案 1 :(得分:0)

如果真的崩溃,你会看到至少一些消息。我猜,你根本看不到输出。这是因为你的正则表达式不起作用。

您可以通过删除正则表达式中的最终\bselect\b或将select附加到$query来修复此问题。然后输出一些匹配。