Решение проблемы вложенных bbcode в phpbb 3.0.x

18 октября 2011 г.

Приведу простой пример:
[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.х разработчики переделают обработчик ббкодов.

Теги: рубрика PHP
  • Похожие статьи
  • Предыдущие из рубрики