Ограничение PHP preg_match_all

Я использую preg_match_all для очень длинного шаблона.

при запуске кода я получил эту ошибку:

Предупреждение: preg_match_all (): Ошибка компиляции: регулярное выражение слишком велико при смещении 707830

После поиска я получил решение, поэтому я должен увеличить значение pcre.backtrack_limit и pcre.recursion_limit в php.ini

Но после того, как я увеличил значение и перезапустил свой apache, у него все еще была та же проблема. Мой PHP verison – 5.3.8

Solutions Collecting From Web of "Ограничение PHP preg_match_all"

увеличение обратного хода PCRE и ограничение рекурсии могут решить проблему, но все равно не удастся, когда размер ваших данных достигнет нового предела. (не масштабируется с большим количеством данных)

пример:

 <?php // essential for huge PCREs ini_set("pcre.backtrack_limit", "23001337"); ini_set("pcre.recursion_limit", "23001337"); // imagine your PCRE here... ?> 

чтобы действительно решить основную проблему, вы должны оптимизировать свое выражение и (если возможно) разделить свое сложное выражение на «части» и переместить некоторую логику в PHP. Надеюсь, вы поняли эту идею, прочитав пример. Вместо того, чтобы пытаться найти подструктуру напрямую с помощью одного PCRE, я демонстрирую более «итеративный» подход, который все глубже и глубже проникает в структуру с использованием PHP. пример:

 <?php $html = file_get_contents("huge_input.html"); // first find all tables, and work on those later $res = preg_match_all("!<table.*>(?P<content>.*)</table>!isU", $html, $table_matches); if ($res) foreach($table_matches['content'] as $table_match) { // now find all cells in each table that was found earlier .. $res = preg_match_all("!<td.*>(?P<content>.*)</td>!isU", $table_match, $cell_matches); if ($res) foreach($cell_matches['content'] as $cell_match) { // imagine going deeper and deeper into the structure here... echo "found a table cell! content: ", $cell_match; } } 

Эта ошибка связана не с производительностью регулярного выражения, а с самим регулярным выражением. Изменение pcre.backtrack_limit и pcre.recursion_limit не будет иметь никакого эффекта, потому что регулярное выражение никогда не будет работать. Проблема в том, что регулярное выражение слишком велико, и решение состоит в том, чтобы сделать регулярное выражение меньше – намного, намного меньше.

Я пишу этот ответ, потому что я пошатнулся по той же проблеме. Как отметил Алан Мур , корректировка пределов обратной связи и рекурсии не поможет решить проблему.

Описанная ошибка возникает, когда игла превышает максимально возможный размер иглы, который ограничен базовой библиотекой pcre. Описанная ошибка НЕ вызвана php, но базовой библиотекой pcre. Это сообщение об ошибке # 20, которое определено здесь:

https://github.com/php/…/pcre_compile.c#L477

php просто распечатывает errortext, полученный из библиотеки pcre при сбое.

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

Его можно легко протестировать, используя этот простой скрипт из php's cli

 <?php // This script demonstrates the above error and dumps an info // when the needle is too long or with 64k iterations. $expand=$needle="_^b_"; while( ! preg_match( $needle, "Stack Exchange Demo Text" ) ) { // Die after 64 kbytes of accumulated chunk needle // Adjust to 32k for a better illustration if ( strlen($expand) > 1024*64 ) die(); if ( $expand == "_^b_" ) $expand = ""; $expand .= "a"; $needle = '_^'.$needle.'_ism'; echo strlen($needle)."\n"; } ?> 

Чтобы исправить ошибку, либо уменьшенную иглу нужно уменьшить, либо – если все необходимо для захвата – необходимо использовать несколько preg_match с дополнительным параметром смещения .

 <?php if ( preg_match( '/'.preg_quote( substr( $big_chunk, 0, 20*1024 ) // 1st 20k chars ) .'.*?'. preg_quote( substr( $big_chunk, -5 ) // last 5 ) .'/', $subject ) ) { // do stuff } // The match all needles in text attempt if ( preg_match( $needle_of_1st_32kbytes_chunk, $subj, $matches, $flags = 0, $offset = 32*1024*0 // Offset -> 0 ) && preg_match( $needle_of_2nd_32kbytes_chunk, $subj, $matches, $flags = 0, $offset = 32*1024*1 // Offset -> 32k ) // && ... as many preg matches as needed ) { // do stuff } // it would be nicer to put the texts in a foreach-loop iterating // over the existings chunks ?> при <?php if ( preg_match( '/'.preg_quote( substr( $big_chunk, 0, 20*1024 ) // 1st 20k chars ) .'.*?'. preg_quote( substr( $big_chunk, -5 ) // last 5 ) .'/', $subject ) ) { // do stuff } // The match all needles in text attempt if ( preg_match( $needle_of_1st_32kbytes_chunk, $subj, $matches, $flags = 0, $offset = 32*1024*0 // Offset -> 0 ) && preg_match( $needle_of_2nd_32kbytes_chunk, $subj, $matches, $flags = 0, $offset = 32*1024*1 // Offset -> 32k ) // && ... as many preg matches as needed ) { // do stuff } // it would be nicer to put the texts in a foreach-loop iterating // over the existings chunks ?> 

Вы поняли эту идею.

Несмотря на то, что этот ответ любезно приветствуется, я надеюсь, что он по-прежнему помогает людям, сталкивающимся с этой проблемой, без хорошего объяснения причин возникновения ошибки.