代码之家  ›  专栏  ›  技术社区  ›  ʞɔıu

需要防止php regex segfault

  •  1
  • ʞɔıu  · 技术社区  · 15 年前

    为什么会出现下面的segfault,如何防止它?

    <?php
    
    $str = ' <fieldset> <label for="go-to">Go to: </label>  ' 
           . str_repeat(' ', 10000) 
           . '<input type="submit" value="Go" /> </fieldset> </form>';
    
    preg_match_all("@
    </?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
    (?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags
    [\?\!\.]+
    @ix", $str, $matches);
    
    ?>
    

    我相信这会导致……等等……堆栈溢出。

    编辑:

    上面是一个简化的版本——演示问题的模式。更完整的版本:

    @
    </?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
    (?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* # continue, allow text content and some inline tags
    
    # normal sentence ending
    [\?\!\.]+ # valid ending characters -- note elipses allowed
    (?<!\b[ap]m\.)(?<!\b[ap]\.m\.)(?<!digg this\!)(?<!Stumble This\!) # disallow some  false positives that we don't care about
    \s*
    (?:&apos;|&\#0*34;|'|&lsquo;)?\s* # closing single quotes, in the unusual case like "he said: 'go away'".
    (?:"|&quot;|&\#0*34;|&\#x0*22;|&rdquo;|&\#0*8221;|&\#x0*201D;|''|``|\xe2\x80\x9d|&\#0*148;|&\#x0*94;|\x94|\))?\s* # followed by any kind of close-quote char
    (?=\<) # should be followed by a tag.
    @ix
    

    目的是找到似乎以有效的英语句子结尾的HTML块。我发现这种方法非常擅长区分“内容”文本(如文章正文)和“布局”文本(如导航元素)之间的区别。然而,有时如果标签之间有大量空白,它就会爆炸。

    4 回复  |  直到 15 年前
        1
  •  2
  •   Alan Moore Chris Ballance    15 年前

    我要尝试的第一件事是使所有量词都具有所有格性,使所有组都具有原子性:

    "@</?+(?![bisa]\b)(?!em\b)[^>]*+>
    (?>[^<]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+
    [?!.]+
    @ix"
    

    我认为杰里米是对的:这不是回溯 本身 这让你很痛苦,这是所有的状态信息,regex引擎必须保存,使回溯成为可能。正则表达式的构造方式似乎是这样的:如果必须回溯,它无论如何都会失败。所以使用所有格量词和原子群,不要费心保存所有无用的信息。

    编辑:为了允许使用句尾标点符号,您可以在第二行添加另一个选项:

    (?>[^<?!.]++|(?![^?!.\s<]++<)[?!.]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+
    

    加法匹配一个或多个所说的字符,除非它们是元素中最后一个非空白字符。

        2
  •  1
  •   tplaner    15 年前

    我相当肯定,即使是较新版本的PHP也与已知段故障问题的PCRE7.0捆绑在一起。我不认为有任何纠正问题的意图,因为它在技术上是PCRE问题,而不是PHP问题。

    如果你告诉我们你试图完成什么,你最好的办法就是写一个替代表达式。

    问题在于: http://bugs.php.net/bug.php?id=40909

        3
  •  0
  •   Jeremy Stein    15 年前

    这仍然是你想要的吗?

    </?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
    (?:(?>[^<\?\!\.]*)|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags
    [\?\!\.]+
    
        4
  •  0
  •   Rik Heywood    15 年前

    你的正则表达式会导致大量的回溯。中间有10000个字符,会变得非常混乱和缓慢。不过,我还是不指望它会崩溃…!