Search
Write a publication
Pull to refresh

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

Недавно столкнулся с проблемой некорректного отображения вложенных ббкодов в популярном форуме phpbb3.

Приведу простой пример:
[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.х разработчики переделают обработчик ббкодов.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.