下面的函数中断了我在$ patternvariables中提供的正则expression式。 如果我更改正则expression式,我很好,所以我认为这是问题。 虽然我没有看到这个问题,但即使它们已经打开,我也没有收到标准的PHP错误。
function parseAPIResults($results){ //Takes results from getAPIResults,returns array. $pattern = '/[(.|n)+]/'; $resultsArray = preg_match($pattern,$results,$matches); }
Firefox 6:连接重置
Chrome 14:错误101(net :: ERR_CONNECTION_RESET):连接重置。
IE 8:Internet Explorer无法显示网页
sed查找并用空格replace一个string
在Linux上的R中的string中删除(不分割)空格字符
variables是variablesbash的子string
如何使用Windows PowerShell的正则expression式删除一个文件名末尾的一个或多个空格?
更新:
Apache / PHP可能会崩溃。 以下是我运行脚本时的Apache错误日志:
[Sat Oct 01 11:41:40 2011] [notice]父:subprocess退出状态255 – 重启。
[Sat Oct 01 11:41:40 2011] [notice] Apache / 2.2.11(Win32)PHP / 5.3.0configuration – 恢复正常运行
在Windows 7上运行WAMP 2.0。
在Windows中修剪文本文件末尾的多余pipe道
Nginx使用什么正则expression式引擎?
使用sedreplace多个栏(特殊字符)与选项卡
用斜杠replacePHP扩展/使用.htaccess
我怎样才能让rubyShellWords.shellescape工作与多字节字符?
简单的问题。 复杂的答案!
是的,这类正则表达式将可重复(并且静静地)崩溃由于堆栈溢出未经处理的分段错误的Apache / PHP!
背景:
PHP preg_*系列正则表达式函数使用Philip Hazel强大的PCRE库 。 有了这个库,有一类正则表达式需要对其内部的match()函数进行大量的递归调用,这会占用大量的堆栈空间(并且所使用的堆栈空间与主题字符串的大小成正比被匹配)。 因此,如果主题字符串太长,则会发生堆栈溢出和相应的分段错误。 这个行为在PCRE文档中的最后一节中描述: pcrestack 。
PHP错误1:PHP设置: pcre.recursion_limit太大。
PCRE文档描述了如何通过将递归深度限制为大致等于链接应用程序的堆栈大小除以500的安全值来避免堆栈溢出分段错误。当递归深度如所推荐的那样被适当地限制时,库不会生成堆栈溢出,而是优雅地退出与错误代码。 在PHP下,这个最大的递归深度是用pcre.recursion_limit配置变量指定的,(不幸的是)默认值被设置为100,000。 这个值太大了! 这是一个pcre.recursion_limit的安全值表,用于各种可执行的堆栈大小:
Stacksize pcre.recursion_limit 64 MB 134217 32 MB 67108 16 MB 33554 8 MB 16777 4 MB 8388 2 MB 4194 1 MB 2097 512 KB 1048 256 KB 524
因此,对于具有256KB(较小)堆栈大小的Apache web服务器( httpd.exe )的Win32版本, pcre.recursion_limit的正确值应该被设置为524.这可以通过以下行PHP代码:
ini_set("pcre.recursion_limit","524"); // PHP default is 100,000.
将此代码添加到PHP脚本时,不会发生堆栈溢出,而会生成有意义的错误代码。 也就是说,它应该生成一个错误代码! (但不幸的是,由于另一个PHP错误, preg_match()不)。
PHP错误2: preg_match()错误时不返回FALSE。
preg_match()的PHP文档说错误时返回FALSE。 不幸的是,5.3.3及以下版本的PHP有一个错误( #52732 ),其中preg_match()在错误时不会返回FALSE (它会返回int(0) ,这是在不匹配的情况下返回的值) 。 这个bug在PHP 5.3.4版本中得到修复。
解:
假设您将继续使用WAMP 2.0(使用PHP 5.3.0),解决方案需要考虑上述两个错误。 这是我会建议的:
需要将pcre.recursion_limit减少到安全值:524。
每当preg_match()返回int(1)以外的任何东西时,都需要显式检查PCRE错误。
如果preg_match()返回int(1) ,那么匹配成功。
如果preg_match()返回int(0) ,则匹配不成功,或者出现错误。
以下是您的脚本的修改版本(设计为从命令行运行),它确定导致递归限制错误的主题字符串长度:
<?PHP // This test script is designed to be run from the command line. // It measures the subject string length that results in a // PREG_RECURSION_LIMIT_ERROR error in the preg_match() function. echo("Entering TEST.PHP...n"); // Set and display pcre.recursion_limit. (set to stacksize / 500). // Under Win32 httpd.exe has a stack = 256KB and 8MB for PHP.exe. //ini_set("pcre.recursion_limit","524"); // Stacksize = 256KB. ini_set("pcre.recursion_limit","16777"); // Stacksize = 8MB. echo(sprintf("PCRE pcre.recursion_limit is set to %sn",ini_get("pcre.recursion_limit"))); function parseAPIResults($results){ $pattern = "/[(.|n)+]/"; $resultsArray = preg_match($pattern,$matches); if ($resultsArray === 1) { $msg = 'Successful match.'; } else { // Either an unsuccessful match,or a PCRE error occurred. $pcre_err = preg_last_error(); // PHP 5.2 and above. if ($pcre_err === PREG_NO_ERROR) { $msg = 'Successful non-match.'; } else { // preg_match error! switch ($pcre_err) { case PREG_INTERNAL_ERROR: $msg = 'PREG_INTERNAL_ERROR'; break; case PREG_BACKTRACK_LIMIT_ERROR: $msg = 'PREG_BACKTRACK_LIMIT_ERROR'; break; case PREG_RECURSION_LIMIT_ERROR: $msg = 'PREG_RECURSION_LIMIT_ERROR'; break; case PREG_BAD_UTF8_ERROR: $msg = 'PREG_BAD_UTF8_ERROR'; break; case PREG_BAD_UTF8_OFFSET_ERROR: $msg = 'PREG_BAD_UTF8_OFFSET_ERROR'; break; default: $msg = 'Unrecognized PREG error'; break; } } } return($msg); } // Build a matching test string of increasing size. function buildTestString() { static $content = ""; $content .= "A"; return '['. $content .']'; } // Find subject string length that results in error. for (;;) { // Infinite loop. Break out. $str = buildTestString(); $msg = parseAPIResults($str); printf("Length =%10dr",strlen($str)); if ($msg !== 'Successful match.') break; } echo(sprintf("nPCRE_ERROR = "%s" at subject string length = %dn",$msg,strlen($str))); echo("Exiting TEST.PHP..."); ?>
当你运行这个脚本时,它会连续读出主题字符串的当前长度。 如果pcre.recursion_limit默认值太高,则可以测量导致可执行文件崩溃的字符串的长度。
注释:
在调查这个问题的答案之前,我不知道PHP错误,当PCRE库中发生错误时, preg_match()无法返回FALSE 。 这个bug肯定会让很多使用preg_match的代码受到质疑! (我当然要做我自己的PHP代码清单。)
在Windows下,Apache Web服务器可执行文件( httpd.exe )使用256KB的堆栈大小构建。 PHP命令行可执行文件( PHP.exe )使用8MB的堆栈大小构建。 pcre.recursion_limit的安全值应根据脚本正在运行的可执行文件(分别为524和16777)进行设置。
在* nix系统下,Apache网络服务器和命令行可执行文件通常都是以8MB的堆栈大小构建的,所以这个问题不会经常遇到。
PHP开发人员应该将pcre.recursion_limit的默认值设置为安全值。
PHP开发者应该将preg_match()修正应用于PHP 5.2版本。
Windows可执行文件的堆栈大小可以使用CFF Explorer免费软件程序进行手动修改。 您可以使用此程序来增加Apache httpd.exe可执行文件的堆栈大小。 (这在XP下运行,但Vista和Win7可能会抱怨。)
我遇到了同样的问题。 感谢ridgerunner发布的答案。
尽管知道为什么PHP崩溃是有帮助的,但对于我来说这并不能真正解决问题。 为了解决这个问题,我需要调整我的正则表达式来节省内存,所以PHP不会崩溃。
所以问题是如何改变正则表达式。 上面发布的PCRE手册链接已经描述了一个与您的例子非常相似的正则表达式的解决方案。
那么如何解决你的正则表达式? 首先,你说你想匹配“一个或一个换行符”。 注意 ”。” 是一个正则表达式中的一个特殊字符,它不仅可以匹配一个点,而且可以匹配任何字符,所以您需要将其转义。 (我希望我没有把你弄错,这是有意的。)
$pattern = '/[(.|n)+]/';
接下来,我们可以复制括号内的量词:
$pattern = '/[(.+|n+)+]/';
这不会改变表达式的含义。 现在我们使用占有量词而不是普通的量词:
$pattern = '/[(.++|n++)++]/';
所以这应该和原来的正则表达式有相同的含义,但是在PHP中工作不会崩溃。 为什么? 拥有量词“吃”了字符,不允许回溯。 因此,PCRE不必使用递归,堆栈不会溢出。 在括号内使用它们似乎是一个好主意,因为我们不需要经常量化替代方案。
总而言之,最佳实践似乎是:
尽可能使用占有量词。 这意味着:++,* +,?+ {} +而不是+,*,?,{}。
在可能的情况下移动替代括号内的量词
按照这些规则,我能够解决自己的问题,我希望这会帮助别人。
我遇到了同样的问题,你需要将模式变成类似的东西
$pattern = '|/your pattern/|s';
结尾的's'基本上意味着将字符串视为一行。
preg_match返回为该模式找到的匹配数量。 当你有一个匹配,它导致了一个致命的错误在PHP( print_r(1) ,例如,导致错误)。 print_r(0)(当你改变模式,没有匹配)不打印出0。
你想print_r($matches)
顺便说一句,你的模式不能正确逃脱。 使用双引号表示您需要跳过括号前的反斜杠。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。