Решение проблемы вложенных bbcode в phpbb 3.0.x
Приведу простой пример:
[color=#FF0000]red [color=#000000]black [color=#0000FF]blue[/color][/color][/color]
В результате получаем:
red [color=#000000]black [color=#0000FF]blue[/color][/color]
Так как исправление этой ошибки запланировано только на 3.1.х версию форума (http://tracker.phpbb.com/browse/PHPBB3-9377), пришлось заняться этим самому, благо исходный код форума открытый и довольно хорошо структурирован.
Как видно из результата работы, обрабатывается только первый ббкод, все остальные остаются просто текстом. Проблема кроется в неправильном использовании функции preg_replace(), я бы даже сказал, в непонимании того как она работает. Для исправления нужно изменить всего два файла:
- /includes/message_parser.php
- /includes/bbcode.php
/includes/message_parser.php:
Ищем “function parse_bbcode()
“, в ней заменяем “foreach ($bbcode_data['regexp'] as $regexp => $replacement){…}
” на
foreach ($bbcode_data['regexp'] as $regexp => $replacement) { // The pattern gets compiled and cached by the PCRE extension, // it should not demand recompilation $deadlock = 0; while (@preg_match($regexp, $this->message) && $deadlock < 10) { $this->message = preg_replace($regexp, $replacement, $this->message); $deadlock++; } if($deadlock){ $bitfield->set($bbcode_data['bbcode_id']); } }
/includes/bbcode.php:
В функции function “bbcode_cache_init()
” нужно сделать небольшое исправление для регулярных выражений списков. Ищем “case 9:
” и меняем “'preg' => array(…)
” на приведённый ниже
'preg' => array( '#(\[\/?(list|\*):[mou]?:?$uid\])[\n]+(\[list=?([^\[]+):$uid\])#' => "\$1\n\$2", '#(\[\/?(\*):[mou]?:?$uid\])[\n]{1}#' => "\$1", '#(\[list=([^\[]+):$uid\])[\n]{1}#' => "\$1", '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_list('\$1')", ),
В этом же файле ищем “function bbcode_second_pass
” и заменяем код для “if (sizeof($str['search'])){…}
” и “if (sizeof($preg['search'])) {…}
” на приведённый ниже.
if (sizeof($str['search'])) { foreach ($str['search'] as $pattern) { $deadlock = 0; while (@preg_match($pattern, $message) && $deadlock < 10) { $message = str_replace($str['search'], $str['replace'], $message); $deadlock++; } } $str = array('search' => array(), 'replace' => array()); } if (sizeof($preg['search'])) { // we need to turn the entities back into their original form to allow the // search patterns to work properly if (!$undid_bbcode_specialchars) { $message = str_replace(array(':', '.'), array(':', '.'), $message); $undid_bbcode_specialchars = true; } foreach ($preg['search'] as $pattern) { $deadlock = 0; while (@preg_match($pattern, $message) && $deadlock < 10) { $message = preg_replace($preg['search'], $preg['replace'], $message); $deadlock++; } } $preg = array('search' => array(), 'replace' => array()); }
Вот собственно и все изменения. Хочу только отметить, что я поставил ограничение вложенности ббкодов равное 10, но если вам нужна большая вложенность, то просто измените число в проверке условий цикла $deadlock < 10.
Эти изменения не исправляют существующих недостатков ббкод-движка, но позволяют использовать вложенные ббкоды. Надеюсь что в версии 3.1.х разработчики переделают обработчик ббкодов.