относительно простой Preg_match_all вызывает 502 Bad Gateway

У меня есть функции preg_match_all с шаблоном:

preg_match_all(
    '/\[(if) ([^\]]*)\]
    ((?:(?!\[if).|(?R))*?)
    \[endif\]/sx',
    $text,
    $matches
);

Я думаю, это довольно простой шаблон, он ищет синтаксис [if condition] sometext [endif], но также поддерживает встраивание ifs f.e. [if condition1] aa [if condition2] bb [endif] [endif]. Я использовал переключатель s для обработки новых строк как точек (так как я хочу, чтобы он работал многострочно) и x для облегчения чтения (но удаление x не решает проблему).

Он отлично работает для большинства входных данных, которые у меня есть, но для некоторых конкретных входных данных вызывает ошибку 502 Bad gateway на сервере nginx без каких-либо ошибок или исключений в журналах. Я использую nginx + php-fpm (5.6.15-1+deb.sury.org~trusty+1), но то же самое происходит и на php7.

Вот вызывает PHP-код 502 Bad gateway error, который вы можете легко проверить, очень просто, просто переменная и регулярное выражение.

http://pastebin.com/G54Xa0as

Пожалуйста, убедитесь, что вы скопировали контент 1:1, со всеми пробелами, табуляциями и т.д.

Самое странное, что вы можете удалить почти любую строку или даже удалить один отступ (любые несколько пробелов в любом месте), чтобы он заработал.

У меня больше нет идей, что здесь не так, я смог создать этот единственный файл, чтобы продемонстрировать свою проблему, но не знаю, как это исправить.


person atay    schedule 26.05.2016    source источник
comment
Я не могу воспроизвести это на eval.in: eval.in/577522   -  person jeroen    schedule 26.05.2016
comment
@jeroen правильно, удивительно, он отлично работает с php, только что проверил, используя php test.php, и он работает, как и ожидалось. Проблема возникает только при открытии файла через nginx с php-fpm (nginx/1.8.0)   -  person atay    schedule 26.05.2016
comment
Попробуйте \[(if)\s+([^\]]*+)\]((?>(?!\[(?:end)?if\b).|(?R))*)\[endif\] или даже \[(if)\s+([^\]]*+)\]((?>[^[]++(?:\[(?!(?:end)?if\b)[^[]*)*|(?R))*)\[endif\].   -  person Wiktor Stribiżew    schedule 26.05.2016
comment
@WiktorStribiżew ваше решение работает, спасибо!   -  person atay    schedule 26.05.2016


Ответы (1)


Ваше регулярное выражение содержит отрицательный просмотр вперед, который «закаляет» точечный шаблон. Однако вам не удалось добавить к нему конечный разделитель, и поэтому он стал довольно «тяжелым».

Я предлагаю добавить конечный разделитель ([endif]) в предварительную проверку:

\[(if)\s+([^\]]*+)\]((?>(?!\[(?:end)?if\b).|(?R))*)\[endif\]
                             ^^^^^^^^

См. демонстрацию.

Или вы даже можете развернуть закаленный жадный жетон как

\[(if)\s+([^\]]*+)\]((?>[^[]++(?:\[(?!(?:end)?if\b)[^[]*)*|(?R))*)\[endif\]

См. демонстрацию регулярного выражения (однако, если [ может следовать за [if...], это не сработает).

Кроме того, обратите внимание, что в вашем регулярном выражении есть пробел после (if), и, поскольку вы используете модификатор /x, он не считается буквальным пробелом, а игнорируется. Вот почему я изменил его на \s+.

person Wiktor Stribiżew    schedule 26.05.2016