为什么preg_match_all会破坏这个正则表达式?

时间:2018-01-22 16:15:26

标签: php regex apache preg-match-all pcre

我一直在为今天大部分时间的神秘崩溃而苦苦挣扎,我终于解决了这个问题,但我并不理解我自己的修复。

代码的目的是替换模板中的占位符。

以下是重现问题所需的最终PHP代码。

$path = realpath("path_to_template.html");
$content = file_get_contents($path);
$loop_regex = '/{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}/s';
$data = array(
    "Trainees"=> array(
        array(
             "display_name" => "Joe",
             "status" => "Pending",
             "invited_date" => "01 Sep 2018",
             "percentage" => "80%"
       )
    )
);

preg_match_all($loop_regex, $content, $output_array);

模板:

<table>
    <tbody>
    <tr>
        <th>Trainee</th>
        <th>Status</th>
        <th>Invited</th>
        <th>Score</th>
        <th>Action</th>
    </tr>
    {{*Trainees}}
    <tr>
        <td>{{display_name}}</td>
        <td>{{status}}</td>
        <td>{{invited_date}}</td>
        <td>{{percentage}}</td>
        <td>Some action button</td>
    </tr>
    {{/Trainees}}
    </tbody>
</table>

一切都很好,直到我尝试在模板中添加更多内容。 ERR_CONNECTION_RESET突然碰到preg_match_all。

断点似乎只与{{Trainees}}组内容的大小相关,当它达到约395个字符时,就会中断。

我通过Drupal博客发现,将其添加到Apache httpd.config可以修复它。

<IfModule mpm_winnt_module>
   ThreadStackSize 8388608
</IfModule>

但我真的不明白为什么这段代码会超出堆栈大小,因此我可能很容易用更多的内容打破它。

欢迎任何理论。

环境: WAMPServer 3.0.8,PHP 5.6.25,Apache 2.4.23

2 个答案:

答案 0 :(得分:1)

表达式

{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}

非常无效,更好用

{{\*(\w+)}}(.+?){{/\w+}}

与其他分隔符,例如而是~

<小时/> 您的旧表达式需要 780步(请参阅this demo on regex101.com),而后者只需 404步(请参阅another demo here)。

答案 1 :(得分:0)

在内部,我还发现切换到PHP 7.0.10也可以避免这个问题,但这可能会掩盖我原来的正则表达式中的低效率,所以Jan的回答似乎是正确的。