• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    深度分析正则(pcre)最大回溯/递归限制
    POST TIME:2021-10-18 05:41
    今天,Tank问了一个问题, 对于如下的正则:
    复制代码 代码如下:

    /script>.*?\/script>/i

    当要匹配的字符串长度大于100014的时候, 就不会得出正确结果:
    复制代码 代码如下:

    $reg = "/script>.*?\/script>/is";
    $str = "script>********/script>"; //长度大于100014
    $ret = preg_replace($reg, "", $str); //返回NULL

    难道正则对匹配的串有长度限制?
    不是, 当然不是, 原因是这样的, 在PHP的pcre扩展中, 提供了俩个设置项.
    复制代码 代码如下:

    pcre.backtrack_limit //最大回溯数
    pcre.recursion_limit //最大嵌套数

    默认的backtarck_limit是100000(10万).
    这个问题, 就和设置项backtrack_limit有关系. 现在要弄清这个问题的原因, 关键就是什么是”回溯”.
    这个正则, 使用非贪婪模式, 非贪婪模式匹配原理简单来说是, 在可配也可不配的情况下, 优先不匹配. 记录备选状态, 并将匹配控制交给正则表达式的下一个匹配字符, 当之后的匹配失败的时候, 再溯, 进行匹配.
    举个例子:
    复制代码 代码如下:

    源字符串: aaab
    正则: .*?

    匹配过程开始的时候, “.*?”首先取得匹配控制权, 因为是非贪婪模式, 所以优先不匹配, 将匹配控制交给下一个匹配字符”b”, “b”在源字符串位置1匹配失败(“a”), 于是回溯, 将匹配控制交回给”.*?”, 这个时候, “.*?”匹配一个字符”a”, 并再次将控制权交给”b”, 如此反复, 最终得到匹配结果, 这个过程中一共发生了3次回溯.
    现在我们来看看文章开头的例子, 默认的backtrack_limit是100000, 而源字符串的开头是9个字符, 一共是99997个字符.
    另外, 因为match函数自身的逻辑, 在文章开头的例子下, 会导致回溯计数增3(有兴趣的可以参看pcrelib/pcre_exec.c中match函数逻辑部分), 所以在匹配到"“之前, pcre中的回溯计数刚好是100000,于是就正常匹配, 退出.
    而, 只要在增加一个字符, 就会导致回溯计数大于100000, 从而导致匹配失败退出.
    在PHP 5.2以后, 提供了:
    复制代码 代码如下:

    int preg_last_error ( void )
    Returns the error code of the last PCRE regex execution.

    我们应该经常检查这个函数的返回值, 当不为零的时候说明上一个正则函数出错, 特别的对于文章的例子, 出错返回(PREG_BACKTRACK_LIMIT_ERROR)
    最后, 在顺便说一句, 非贪婪模式导致太多回溯, 必然会有一些性能问题, 适当的该写下正则, 是可以避免这个问题的. 比如将文章开头例子中的正则修改为:
    复制代码 代码如下:

    /script>[^]*\/script>/i

    就不会导致这么多的回溯了~
    而recursion_limit限制了最大的正则嵌套层数, 如果这个值, 设置的太大, 可能会造成耗尽栈空间爆栈. 默认的100000似乎有点太大了…
    就比如对于一个长度为10000的字符串, 如下这个看似”简”的单正则:
    复制代码 代码如下:

    //默认recursion_limit为100000
    $reg = /(.+?)+/is;
    $str = str_pad("laruence", 10000, "a"); //长度为1万
    $ret = preg_repalce($reg, "", $str);

    会导致core, 这是因为嵌套太多, 导致爆栈.
    当然, 你可以通过修改栈的大小来暂时的解决这个问题, 比如修改栈空间为20M以后, 上面的代码就能正常运行, 但这肯定不是最完美的解法. 根本之道, 还是优化正则.
    最后: 正则虽易, 用好却难.. 尤其在做大数据量的文本处理的时候, 如果正则设计不慎, 很容易导致深度嵌套, 另外考虑到性能, 还是建议能用字符串处理尽量使用字符串处理代替.
    您可能感兴趣的文章:
    • PHP 正则表达式效率 贪婪、非贪婪与回溯分析(推荐)
    • 正则中的回溯定义与用法分析【JS与java实现】
    • 编写高质量的js之正确理解正则表达式回溯
    • 小议正则表达式效率 贪婪、非贪婪与回溯
    • PHP正则表达式的效率 回溯与固化分组
    • 正则表达式之回溯
    • AS3 js正则表达式 反向引用(backreference)
    • 详解JavaScript正则表达式之分组匹配及反向引用
    • php正则表达式的模式修正符和逆向引用使用介绍
    • PHP正则表达式的逆向引用与子模式分析
    • JavaScript正则表达式之后向引用实例代码
    • VBS教程:正则表达式简介 -后向引用
    • 正则表达式学习教程之回溯引用backreference详解
    上一篇:小议正则表达式效率 贪婪、非贪婪与回溯
    下一篇:精确查找PHP WEBSHELL木马 修正版
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信