我有一个谜题要问你,或者也许没有。 检查这一部分:
$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); 没有这条线,一切正常。
还有一些事情需要注意: 正则表达式的敏感部分是对“select”的最后一个贪婪搜索。如果找不到第二个选择,则会崩溃。查询的长度很重要。另外,请注意,在同一台机器上运行 phpunits 时,不存在此问题。
我的猜测是ltrim对字符串做了一些事情,但我不确定是什么。
有人能解释一下吗?
编辑。好吧,看来ltrim不是问题。如果我只是给出没有起始空白的字符串,我就会崩溃。它可能与 pcre.backtrack_limit 和 pcre.recursion_limit 设置有关,但我已经尝试过,但没有改变。
编辑2。崩溃是浏览器中的“连接中断”。没有整个服务器崩溃,但脚本执行停止。再次,日志中没有错误。
问题已解决。我必须在最后用/s 替换 (.|\n) 。非常感谢大家!
最佳答案
在 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 在评论中建议的那样。然后您可以简单地使用 .
来匹配包括换行符在内的任何内容。它只需检查 n 个可能性,而不是 2^n 个可能性。
注意:一些正则表达式引擎足够聪明,可以避免这个陷阱。理论上,如果第二个“选择”不存在,引擎应该足够聪明,知道它永远无法匹配,因此放弃。例如,当我在 Perl 中测试它时,没有问题。而上面的 PHP 正则表达式测试器没有问题。但也许您的 PHP 版本比较旧并且没有那么优化。
关于php ltrim 破坏正则表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13856025/