侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

win2003下PHP使用preg_match_all导致apache崩溃问题的解决方法

Windows  /  管理员 发布于 5年前   408

小编的平台是windows server 2003(32位系统) + Apache/2.2.9 (Win32) + PHP/5.2.17,在使用正则表达式 preg_match_all (如 preg_match_all("/ni(.*?)wo/", $html, $matches);)进行分析匹配比较长的字符串 $html 时(大于10万字节,一般用于分析采集回来的网页源码),Apache服务器会崩溃自动重启。
    在Apache错误日志里有这样的提示:
复制代码 代码如下:[Thu Apr 11 18:31:31 2013] [notice] Parent: child process exited with status 128 -- Restarting.
[Thu Apr 11 18:31:31 2013] [notice] Apache/2.2.9 (Win32) PHP/5.2.17 configured -- resuming normal operations
[Thu Apr 11 18:31:31 2013] [notice] Server built: Jun 13 2008 04:04:59
[Thu Apr 11 18:31:31 2013] [notice] Parent: Created child process 2964
[Thu Apr 11 18:31:31 2013] [notice] Disabled use of AcceptEx() WinSock2 API
[Thu Apr 11 18:31:31 2013] [notice] Child 2964: Child process is running
[Thu Apr 11 18:31:31 2013] [notice] Child 2964: Acquired the start mutex.
[Thu Apr 11 18:31:31 2013] [notice] Child 2964: Starting 350 worker threads.
[Thu Apr 11 18:31:31 2013] [notice] Child 2964: Listening on port 80.
    经过查阅Apache官方以及论坛资料后,发现win平台下用正则 preg_match_all 或preg_match 分析比较长的字符串时,导致apache崩溃重启的原因是windows平台下默认分配的线程堆栈空间 ThreadStackSize 太小导致的。 win32默认只有256KB,而在 linux下默认值是 8M,这就是为什么同样的程序在 linux平台下正常,而在 win平台下不正常的原因。
    根据PCRE library的官方说明:256 KB 的堆栈空间对应的pcre.recursion_limit大小应该不超过524。
Here is a table of safe values of pcre.recursion_limit for a variety of executable stack sizes:
下面就是一张Stacksize和pcre.recursion_limit对应的建议安全值,超过这个数值就极有可能发生堆栈溢出,apache crash:
复制代码 代码如下: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

如果你没有调整堆栈大小,就必须在使用正则的PHP页面最开头加入:
复制代码 代码如下:<?php
ini_set("pcre.recursion_limit", "524"); // PHP default is 100,000.
?>

查看具体的错误可以使用下面的代码:
复制代码 代码如下:$resultsArray = preg_match_all("/table.*?<a>/isU", $html, $contents);
if ($resultsArray === 0){
echo get_pcre_err();
}
function get_pcre_err(){
        $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);
}

对于正则的修饰符 isU 说明:
复制代码 代码如下:i: 表示in-casesensitive,即大小写不敏感
s: PCRE_DOTALL,表示点号可以匹配换行符。
U: 表示PCRE_UNGREEDY,表示非贪婪,相当于perl/python语言的.*?,在匹配过程中,对于.*正则,一有匹配立即执行,而不是等.*搜索了所有字符再一一返回

    在使用正则表达式时,我们应该尽量避免递归调用,递归容易导致堆栈溢出。比如:
/<table((?!<table).)*?<\/a>/isU 就会发生错误,而使用 /<table.*?<\/a>/i 就正常。

    那么如何增加win平台下 ThreadStackSize 的大小呢? 在apache的配置文件 httpd.conf 里启用 “Include conf/extra/httpd-mpm.conf”(删除前面的注释#),然后在 httpd-mpm.conf 文件里的 mpm_winnt_module 配置模块里设置 “ThreadStackSize 8400000”即可(大约8M)。
复制代码 代码如下:<IfModule mpm_winnt_module>
    ThreadStackSize 8400000
    ThreadsPerChild      200
    MaxRequestsPerChild    10000
    Win32DisableAcceptEx
</IfModule>
    这里需要注意的是,32位的Apache程序只能最多使用大约2GB内存空间! 因此,ThreadStackSize 和ThreadsPerChild 的值相乘后(8M * 200)不应该超过2G,否则无法启动apache,出现的错误日志如下:
复制代码 代码如下:[Thu Apr 11 20:02:45 2013] [crit] (OS 8)存储空间不足,无法处理此命令。  : Child 4832: _beginthreadex failed. Unable to create all worker threads. Created 212 of the 220 threads requested with the ThreadsPerChild configuration directive.

    通过上面的提示,小编可以告诉大家的是在我的这台服务器上,当线程堆栈大小设为8M时,我可以设置的线程数最多是212个。


  • 上一条:
    Win2008 R2安装.NET Framework 4的windows6.1-KB958488-V6001-x64出现灾难性故障解决方法
    下一条:
    Windows下通过DOS命令登录MYSQL的方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Windows 10的告别:2025年10月14日,一段时代的终结(0个评论)
    • windows 11激活_Win11 KMS激活流程步骤(1个评论)
    • 安装Windows 11系统的注意了,看看你的cpu是否在微软兼容列表排除中(1个评论)
    • 微软将于2022年9月20日推送Windows11 22H2新版本,推测2024发布windows 12(0个评论)
    • windows11系统中可以关闭禁止的服务及介绍(1个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-01
    • 2018-06
    • 2020-06
    • 2021-06
    • 2021-07
    • 2022-01
    • 2022-04
    • 2022-08
    • 2023-08
    • 2023-10
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客