PHP и BBCode

У меня периодически появляется потребность в использовании «интерпретатора» BBCode в своих проектах (написанного на PHP), и постоянно нет времени искать какое-то более-менее удобоваримое решение, что в итоге выливается в использование или создание «костылей» для каждого конкретного случая.
Но вот, похоже, получилось найти то, что хотелось.

Моя претензия к подобным готовым решениям обычно в первую очередь заключается в неспособности этих библиотек правильно обрабатывать абзацы. Фактически они обычно вообще не используют абзацы (тэг P), вместо этого в результате своей работы они просто вставляют тег <br /> , заменяя обычные символы переноса строки. Я считаю такой метод эмулирования абзацев в 98 процентах, мягко говоря, не уместным. Но так как перенос строк по средствам <br /> намного легче реализовать вместо «человеческих» <p>, так большинство и делает 🙁 Некоторые даже придумывают оправдания, что мол с br даже правильнее, отчасти, из-за подобной лени разработчиков различных готовых библиотек, другая часть людей думает, что тэг P является устаревшим (ведь даже во многих готовых продуктах и сайтах абзацы формируются путем использования <br />) 🙂

Приступим

Но, кажется, есть свет в конце туннеля. Это готовый класс для работы с BBCode, который, судя по всему, отлично справляется со своей задачей (ничего лучше пока не видел). Единственный минус в том, что документация, представленная на сайте, не на русском языке. Этот минус я и хочу побороть в этой статье, приведя пример использования класса с русскими комментариями.

Для начала нужно скачать библиотеку (на момент написания статьи версия библиотеки была 0.3.3). В скачанном архиве в папке src вы обнаружите два нужных нам файла: stringparser.class.php и stringparser_bbcode.class.php.

Для примера предположим, что у нас есть пустой файл «index.php» и рядом с ним мы создадим папку «/bbcode/», содержащую в себе два упомянутых выше файла.
Для примера минимальное содержимое файла «index.php» должно быть таким (запустив этот пример можно будет сразу увидеть, работает ли библиотека):

< ?php
//Вставляем файл библиотеки
require_once 'bbcode/stringparser_bbcode.class.php';

//Создаем объект класса StringParser_BBCode
$bbcode = new StringParser_BBCode ();

//Добавляем объекту класса понятие о тэге [b]
//(в итоге только этот тэг и будет
//обрабатываться этим классом)
$bbcode->addCode ('b', 'simple_replace', null, array ('start_tag' => '<b>', 'end_tag' => '</b>'),
                  'inline', array ('block', 'inline'), array ());

//Обрабатываем тестовую строку и выводим ее в браузер
echo $bbcode->parse ('Тестовый текст, это слово должно быть [b]жирным[/b]');
?>

Функция addCode

Наибольший интерес в этом коде может вызвать, пожалуй, функция addCode у объекта класса StringParser_BBCode, вот ее прототип и список описание параметров:

void addCode (string $code, string $type, string $callback, string $params, string $content_type,
              array $allowed_in, array $not_allowed_in);

Эта функция добавляет понятие о тех или иных кодах (bb-кодах) для объекта класса, чтоб он мог потом обнаружить эти коды в тексте и соответствующим образом обработать их. Т.е. можно сказать, что изначально объект класса StringParser_BBCode вообще ничего не знает о стандартных bb-кодах и не способен обработать как-либо их. Поэтому этот объект нужно будет после каждой инициализации «обучать» всем разновидностям bb-кодов.

$code (в примере имеет значение ‘b’)
Код, который нужно искать в тексте для обработки. Т.е. если указать код test , то потом в обрабатываемом тексте будет искаться тэг [test] и обрабатываться в соответствии с указаниями в других параметрах рассматриваемой функции.
$type (в примере имеет значение ‘simple_replace’)
Указание того, как тэг должен обрабатываться (какого он типа). Есть различные предопределенные типы тэгов, которые будут описаны ниже. В нашем же примере указан тип ‘simple_replace’ который указывает на то, что тэг будет парным (открывающийся тэг [b] и закрывающийся [/b]) и что эти тэги будут заменены на указанные ниже html тэги.
$callback (в примере имеет значение null)
Позволяет указать имя функции, которая должна будет вызваться при обработке найденного тэга в тексте. В случае с типом тэга ‘simple_replace’ такая функция не вызывается, и, соответственно, в этом параметре можно указать null.
$params (в примере имеет значение array(‘start_tag’ => ‘‘, ‘end_tag’ => ‘‘))
В этом параметре в основном указывается, какой нужно вставлять html тэг взамен bb тэга. Наименование параметров напрямую зависит от того, какой тип тэга мы указали в параметре $type.
$content_type (в примере имеет значение ‘inline’)
Тип внутреннего содержимого тега. Может принимать значения: ‘inline’, ‘block’, ‘link’, ‘image’. Если я не ошибаюсь, можно прописывать и свои типы чтобы потом можно было указывать для этого содержимого свои индивидуальные фильтры (пример использования фильтров смотрите ниже).
$allowed_in (в примере имеет значение array (‘block’, ‘inline’))
В этом параметре можно указать, внутри каких типов объектов может находиться создаваемый bb-код (его обработка будет просто игнорироваться в ином случае). В нашем примере мы указали, что элемент может находиться как внутри блочных элементов, так и внутри линейных.
$not_allowed_in (в примере имеет значение array ())
Имеет назначение, противоположное по смыслу предыдущему параметру.

Виды обработки тэгов

Описание вариантов значения параметра $type в функции addCode.

‘simple_replace’
Описывает простой парный тэг. При использовании этого типа обработки тэга в параметре функции ‘params’ должны обязательно присутствовать две ячейки: $params[‘start_tag’] и $params[‘end_tag’]. ‘start_tag’ должен в себе содержать аналог открывающегося тэга в хтмл, а ‘end_tag’ – закрывающегося тэга соответственно.
‘simple_replace_single’
То же самое, что ‘simple_replace’, но используется только лишь для одинарных тэгов, которые, собственно говоря, не имеют содержимого (типа br, hr и т.п.). Требует наличия только параметра $params[‘start_tag’].
‘callback_replace’
При этом типе вы перекладываете на себя обработку по найденным совпадениям (с помощью своей callback функции) для парного тэга.
‘callback_replace_single’
То же самое, что и ‘callback_replace’, но только для одинарных тэгов.
‘usecontent’
То же самое что и ‘callback_replace’, только в содержимом такого тэга другие тэги не будут обрабатываться, например, это удобно для тэга code.
‘usecontent?’
Этот тип может себя вести как ‘usecontent’ или же как ‘callback_replace’ в зависимости от ситуации. Актуальность того или иного варианта определяется за счет присутствия заранее предполагаемого атрибута в bb тэге. Если атрибут найден, то будет использоваться обработка ‘callback_replace’, в другом случае тэг будет обрабатываться как ‘usecontent’. Имя атрибута для поиска указывается через параметр $params[‘usecontent_param’]. Если указано имя default, то подразумевается значение атрибута, присвоенное непосредственно тэгу, например, [url=http://link], значением атрибута default будет текст «http://link». Этот прием часто используется, например, для тэга [URL]. Этот тэг может использоваться в двух формах: [url]http://www.example.com/[/url] и [url=http://www.example.com/]Текст ссылки, а так же [b]жирный[/b] текст[/url]. В первом случае будет использоваться тип ‘usecontent’, т.к. текст ссылки должен выводиться без какого-либо форматирования (и, собственно, сама ссылка будет некорректна, если в ней будут посторонние символы). В другом случае должен быть использован тип ‘callback_replace’, т.к. сама ссылка передается отдельным параметром, а текст, обрамленный в ссылку, вполне может содержать в себе какое-то форматирование.
Примечание: Можно указать несколько параметров для их поиска, для чего в $params[‘usecontent_param’] нужно передать не строку, а массив, содержащий строки. Например: $bbcode->addCode (…, array(‘usecontent_param’ => array (‘parameter1’, ‘parameter2’)), …);.
‘callback_replace?’
Является противоположным вариантом типа ‘usecontent?’. Если один из атрибутов, указанных в usecontent_param, встречается в тэге, он будет обработан как ‘usecontent’, в противном случае как ‘callback_replace’.

Пример кода из «боевых» условий

Вот пример файла index.php с более расширенной конфигурацией класса для обрабатывания большего числа тэгов, в нем же и можно понять, как работают callback функции и т.п.:

< ?php
//Вставляем файл библиотеки
require_once 'bbcode/stringparser_bbcode.class.php';

//Приводит разнообразные переводы строк
//разных операционных систем в единый формат (\n)
function convertlinebreaks ($text) {
	return preg_replace ("/\015\012|\015|\012/", "\n", $text);
}

//Удалить все символы, кроме переводов строк
function bbcode_stripcontents ($text) {
	return preg_replace ("/[^\n]/", '', $text);
}

//Функция для обработки ссылок
function do_bbcode_url ($action, $attributes, $content, $params, $node_object) {
	if (!isset ($attributes['default'])) {
		$url = $content;
		$text = htmlspecialchars ($content);
	} else {
		$url = $attributes['default'];
		$text = $content;
	}
	//Часть функции, которая занимается
	//только валидацией данных тэга
	if ($action == 'validate') {
		if (substr ($url, 0, 5) == 'data:' || substr ($url, 0, 5) == 'file:'
		  || substr ($url, 0, 11) == 'javascript:' || substr ($url, 0, 4) == 'jar:') {
			return false;
		}
		return true;
	}
	//Непосредственное преобразование тэга в
	//html вариант с возвращением результата
	return '<a href="'.htmlspecialchars ($url).'">'.$text.'';
}

// Функция для вставки изображений
function do_bbcode_img ($action, $attributes, $content, $params, $node_object) {
	//Часть функции, которая занимается
	//только валидацией данных тэга
	if ($action == 'validate') {
		if (substr ($content, 0, 5) == 'data:' || substr ($content, 0, 5) == 'file:'
		  || substr ($content, 0, 11) == 'javascript:' || substr ($content, 0, 4) == 'jar:') {
			return false;
		}
		return true;
	}
	//Непосредственное преобразование тэга в
	//html вариант с возвращением результата
	return '<img src="'.htmlspecialchars($content).'" alt=""/>';
}

//Создаем объект класса StringParser_BBCode
$bbcode = new StringParser_BBCode();

//Добавляем фильтр (подробнее см. офф. документацию),
//задействуя нашу функцию convertlinebreaks, которая будет
//преобразовывать переводы строки в тексте к единому
$bbcode->addFilter (STRINGPARSER_FILTER_PRE, 'convertlinebreaks');

//Добавляем свои парсеры для разных типов объектов
//(подробнее см. офф. документацию)
//Мы указываем, через какую функцию должно пройти
//содержимое этих тэгов, например, через функцию
//htmlspecialchars для предотвращения XSS и т.д.
$bbcode->addParser (array ('block', 'inline', 'link', 'listitem'), 'htmlspecialchars');
$bbcode->addParser (array ('block', 'inline', 'link', 'listitem'), 'nl2br');
$bbcode->addParser ('list', 'bbcode_stripcontents');


//Добавляем bb-код [h1], используемый в виде:
//[h1]Текст заголовка первого уровня[/h1]
$bbcode->addCode ('h1', 'simple_replace', null, array ('start_tag' => '<h1>', 'end_tag' => '</h1>'),
				  'block', array ('listitem', 'block', 'link'), array ());
//Добавляем bb-код [h2], используемый в виде:
//[h2]Текст заголовка второго уровня[/h2]
$bbcode->addCode ('h2', 'simple_replace', null, array ('start_tag' => '<h2>', 'end_tag' => '</h2>'),
				  'block', array ('listitem', 'block', 'link'), array ());
//Добавляем bb-код [h3], используемый в виде:
//[h3]Текст заголовка третьего уровня[/h3]
$bbcode->addCode ('h3', 'simple_replace', null, array ('start_tag' => '<h3>', 'end_tag' => '</h3>'),
				  'block', array ('listitem', 'block', 'link'), array ());
//Добавляем bb-код [h4], используемый в виде:
//[h4]Текст заголовка четвертого уровня[/h4]
$bbcode->addCode ('h4', 'simple_replace', null, array ('start_tag' => '<h4>', 'end_tag' => '</h4>'),
				  'block', array ('listitem', 'block', 'link'), array ());
//Добавляем bb-код [h5], используемый в виде:
//[h5]Текст заголовка пятого уровня[/h5]
$bbcode->addCode ('h5', 'simple_replace', null, array ('start_tag' => '<h5>', 'end_tag' => '</h5>'),
				  'block', array ('listitem', 'block', 'link'), array ());
//Добавляем bb-код [h6], используемый в виде:
//[h6]Текст заголовка шестого уровня[/h6]
$bbcode->addCode ('h6', 'simple_replace', null, array ('start_tag' => '<h6>', 'end_tag' => '</h6>'),
				  'block', array ('listitem', 'block', 'link'), array ());

//Устанавливаем флаги для bb-кодов с h1 до h6,
//указывая, что они являются блочными элементами,
//что будет в дальнейшем благотворно влиять на умную
//генерацию html кода. Такой элемент, к примеру, не сможет
//находиться внутри других блочных элементов
$bbcode->setCodeFlag('h1', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
$bbcode->setCodeFlag('h2', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
$bbcode->setCodeFlag('h3', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
$bbcode->setCodeFlag('h4', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
$bbcode->setCodeFlag('h5', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
$bbcode->setCodeFlag('h6', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);

//Добавляем bb-код [b], используемый в виде:
//[b]выделенный текст[/b]
$bbcode->addCode ('b', 'simple_replace', null, array ('start_tag' => '<b>', 'end_tag' => '</b>'),
				  'inline', array ('listitem', 'block', 'inline', 'link'), array ());
//Добавляем bb-код [i], используемый в виде:
//[i]наклонный текст[/i]
$bbcode->addCode ('i', 'simple_replace', null, array ('start_tag' => '<i>', 'end_tag' => '</i>'),
				  'inline', array ('listitem', 'block', 'inline', 'link'), array ());
//Добавляем bb-код [url], используемый в виде:
//[url]http://www.needsite.domain[/url] и 
//[url=http://www.needsite.domain]Текст ссылки[/url]
$bbcode->addCode ('url', 'usecontent?', 'do_bbcode_url', array ('usecontent_param' => 'default'),
				  'link', array ('listitem', 'block', 'inline'), array ('link'));
//Добавляем bb-код [link], используемый в виде:
//[link]http://www.needsite.domain[/link]
$bbcode->addCode ('link', 'callback_replace_single', 'do_bbcode_url', array (),
				  'link', array ('listitem', 'block', 'inline'), array ('link'));
//Добавляем bb-код [img], используемый в виде:
//[img]http://www.needsite.domain/img.jpg[/img]
$bbcode->addCode ('img', 'usecontent', 'do_bbcode_img', array (),
				  'image', array ('listitem', 'block', 'inline', 'link'), array ());
//Добавляем bb-код [bild] (по смыслу то же самое,
//что и [img]), используемый в виде:
//[bild]http://www.needsite.domain/img.jpg[/bild]
$bbcode->addCode ('bild', 'usecontent', 'do_bbcode_img', array (),
				  'image', array ('listitem', 'block', 'inline', 'link'), array ());

//Создаем группу image из bb-кодов img и bild
//для последующей возможности задания
//неких правил для этих групп
$bbcode->setOccurrenceType ('img', 'image');
$bbcode->setOccurrenceType ('bild', 'image');
//Указываем, что тэги из группы image
//могут встречаться (обрабатываться) в тексте не более
//двух раз. В нашем случае это нужно для того,
//чтобы пользователь не мог вставить более двух
//картинок в текст сообщения
$bbcode->setMaxOccurrences ('image', 2);

//Добавляем bb-код [list]
$bbcode->addCode ('list', 'simple_replace', null, array ('start_tag' => '<ul>', 'end_tag' => '</ul>'),
				  'list', array ('block', 'listitem'), array ());
//Добавляем bb-код [*], указывая, что этот тэг
//может использоваться только внутри тэга
//с типом list (этот тип мы присвоили выше тэгу [list])
$bbcode->addCode ('*', 'simple_replace', null, array ('start_tag' => '<li>', 'end_tag' => '</li>'),
				  'listitem', array ('list'), array ());

//Устанавливаем флаги для тэгов [list] и [*]
//Указываем, что для кода [*] закрывающийся тэг
//не обязателен, таким образом, возможна будет
//следующая конструкция:
//[list]
//[*] Item
//[*] Item
//[/list]
//Закрывающий тэг будет добавляться автоматически
//в процессе формирования html кода
$bbcode->setCodeFlag ('*', 'closetag', BBCODE_CLOSETAG_OPTIONAL);
//Как я понял, этот флаг обозначает, что тэг [*]
//всегда может быть использован только
//в начале новой строки
$bbcode->setCodeFlag ('*', 'paragraphs', true);
//[list] является блочным элементом
$bbcode->setCodeFlag ('list', 'paragraph_type', BBCODE_PARAGRAPH_BLOCK_ELEMENT);
//Перед открывающимся тэгом [list]
//символ строки будет устранен
$bbcode->setCodeFlag ('list', 'opentag.before.newline', BBCODE_NEWLINE_DROP);
//Перед закрывающимся тэгом [list]
//символ строки будет устранен
$bbcode->setCodeFlag ('list', 'closetag.before.newline', BBCODE_NEWLINE_DROP);
//В итоге мы можем использовать списки в bb-коде,
//используя вместе теги list и *:
//[list]
//[*] Элемент списка
//[*] Элемент списка
//[*] и т.д.
//[/list]


//Активируем обработку параграфов
$bbcode->setRootParagraphHandling (true);
//Как я понял, таким образом указывается,
//какими символами нужно заменять встреченный
//перенос строки внутри абзаца
//(по сути, как обрабатывать пустые абзацы).
$bbcode->setParagraphHandlingParameters ("\n", '<p>', '</p>');

$res_text = "Тестовый текст [b]для проверки[/b] работы класса";

//На всякий случай удаляем все оставшиеся
//символы переноса строки в виде "\r",
//если такие остались в тексте
$res_text = str_replace("\r", '', $res_text);

//Вуаля!
echo $bbcode->parse($res_text);

Послесловие

Я, конечно же, не сделал полный перевод документации, а только самый необходимый минимум, за более подробной документацией вы можете обратиться на официальный сайт (вообще, там описано куда больше различных возможностей).

Эту библиотеку также не составляет труда внедрить в какой-либо php фреймворк, я, к примеру, с успехом проделывал это для cackePHP.

Если вы тоже встречали подобные библиотеки (корректно работающие с абзацам! 🙂 ) , интересно было бы узнать о них.

Автор

  • Muza

    Классная статья, кстати автору хочу предложить установить от яндекс.денег фишку на сайт “Дай рубль”. Я бы дал, так сказать на поддержание.

  • Liliana

    Спасибо, интересно=)

  • серый

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

  • Очень хорошая статья.
    От себя хочу заметить, что для PHP есть хорошая вещь, которая так и называется «Bulletin Board Code»
    (http://pecl.php.net/package/bbcode).
    Требует отдельной установки, потому не досягаема для клиентов большинства хостингов. Работает, конечно, быстрее любых классов.

    По поводу класса (который в статье):
    на 5 php в режиме E_STRICT, начнутся сыпаться нотисы,
    а конкретно: «Assigning the return value of new by reference is deprecated».
    Замена & на clone решит проблему.

    И в 356 строке заменяем:
    $res = StringParser_Node::destroyNode ($this->_root);

    на:
    $ex_node = new StringParser_Node();
    $res = $ex_node->destroyNode($this->_root);

  • Andrej

    Firefox не может найти сервер http://www.christian-seiler.de

  • Skelt

    Спасибо за статью;)

  • Алексей Павлов
  • Алексей Павлов

    Ой, код преобразовался в ссылку. Должно быть так:
    return ‘<a href=»‘.htmlspecialchars ($url).'»&gr;’.$text.'</a&gr;’;

    А вообще, статья очень хорошая, мне помогла. Спасибо автору.

  • Бутов Павел

    Где реклама я бы тебе кликнул =) статья полезная… только нужно разобратся чучуть…
    да и коменты полезные…

    а тут [b]bb[/b] коды работают ?

  • Бутов Павел

    поседел по разбирался это имено ТО что искал! ) действительно очень удобно ты все расписал спасибо.

  • Бутов Павел

    Кхм.. вот я думаю тут

    Можно хранить данные в том ввиде каком ввёл %UserName%
    тоесть с bb-кодом. и потом когда нужно будет выводить их в новости или форум(коменте) даные каждый раз будут обрабатываться но не проще ли хранить данные уже обработанными потомучто 1 раз обработал и больше не тратишь время сервачное только выводишь их беря из базы комент(новость)

    но тут возникает проблема редактирования… елси вдруг %username% решит редактировать комент (новость) совою… то ему обезательно данные нужно вернуть в первоночальном виде с bb кодом.. тут возинкает вопрос есть ли в данной библиотеке (очень уматной кстате) обратное преобразование когда теги заменяются bb-кодом?
    Даже елси такой нет ну чтоже придётся хранить коменты в том в виде в котором вводилиь и каждый раз их обрабатывать.. что как бы меня как начинающего кодера напригает.

  • Бутов Павел

    хронения уже обработаных данных мне кажется целесообразным по той причине что редактируют ность комент куда как режи чем смотрят…. на этом и экономия ресурсов сервака будет… кхм.. или я за зря замарачиваюсь ??

  • Бутов Павел

    кхм так же осталось не раскрыта в примере тема добавления не парного тега к примеру [hr]или еще какого… ..

    вобще я хотел его замутить для вставки смайлов типа [s1]
    получалась бы ссылка на смайл….
    кхм.. ну ладно еще по ковыряю…

  • Бутов Павел,
    Насчет экономии ресурсов это точно заморочка лишняя. Представь, во что выльется хранение обработанных данных, если, к примеру, ты захочешь изменить способ интерпретации bb кода (другие html тэги захочешь генерить). Или, к примеру, захочешь сделать отображение одних и тех же данных по разному (к примеру, в полной версии новости bb код будет обрабатываться по одному, а в кратком блоке последних новостей bb код будет парситься в более умеренных html) и т.д… В общем если не хранить оригинал сообщения с условной разметкой, то будет полнейшая потеря гибкости и куча не нужных проблем (типа как преобразовывать html в bb).
    Для экономии ресурсов в этом ключе, как раз и существует кэширование уже отрендеренных страниц или ее блоков. Т.е. сгенерил страницу -> положил ее на винт (или оперативку) и в следующие разы уже и база не дергается и bb парсер не напрягает процессор.

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

    ЗЫ. Здесь какая-то часть html работает, bb не парсится, вообще потом хочу готовую систему комментирования прикрутить (disqus)

  • Павел Бутов

    ух… ели нашёл )))) … делал я всё делал радовался жизни винт hdd накрылся и все труды на смарку ))) вот искал твою страницу 2 дня )) НАШЁЁЁЁЁЁЁЁЁЁЁЁЁЛ )) УРА! )))

    тоесть предлагаешь в базе хранить 2 данных
    html и bbcode вариант ? переодически или при изменеии bbcode обнавлять html вариант ?

    формму водда пойду искать… что бы bbсode %юзурнаме% вставляли не ручками а кнопками (лентяи) ))))

  • Павел Буто, Соболезную, не приятная это штука когда винт летит.
    Можно и так. Но я бы для начала html вариант все же в базе не хранил, а каждый раз его генерировал на основе bb-кода который лежит в базе.

  • shaks

    2Павел Бутов
    > тоесть предлагаешь в базе хранить 2 данных
    html и bbcode вариант ? переодически или при изменеии bbcode обнавлять html вариант ?

    ? В базе храниш bbcode, а при выводе конвертишь в хтмл

  • Приветствую. Что-то я в этом классе не вижу функции unparse(). Что делать если надо из HTML вернуть BBcode?

    • Это достаточно отдельная специфическая задача, мне такой библиотеки не попадалось на глаза (да и не нужно было как-то). Нагуглить получается только какие-то онлайн конвертаторы http://www.google.com.ua/search?aq=2&oq=html+to+bb&gcx=w&sourceid=chrome&ie=UTF-8&q=html+to+bbcode+online . Вообще обычно такое не нужно из-за того, что оригинальный текст в формате BBCode всегда должен сохраняться, а преобразовывается в html он уже на этапе вывода для посетителей сайта (в комментариях выше я достаточно подробно описывал принцип).

      • Не такая уже и специфическая задача, если есть функция «редактировать» и проект не допускает постоянно парсить контент. Но спасибо за ответ.

  • Andrey

    Админ как внедрить смайлы чтобы смайл выводился вот так .smile. ?

    • Можно определить свои дополнительные теги как описано здесь http://christian-seiler.de/projekte/php/bbcode/doc/en/chapter2.php
      Или же потом пробегаться по тексту и самому с помощью str_replace заменять ключевые символы на html который будет выводить нужные смайлы.

  • Rimon

    Подскажи как быть с одиночными тегами? типа или же в этом направлении использовать смайлы типа 🙂

    • Rimon

      Прошу прощения…скушал тег

  • А как быть с тегами типа
    [color=#ff0000]текст[/color]? не могли бы Вы привести пример?

  • Женек

    Помогите разобраться, проблема в том что данный bbcode выводит только первые две картинки, а остальные не хочет! Что делать, как исправить данную проблему?

    • Женек

      прошу прощения, РАЗОБРАЛСЯ!

  • Роман

    Подскажите пожалуйста, можно ли в качестве колбека использовать метод класса, а не функцию (например ExampleClass::example_function($params…) а не example_function($params…)) ? Если да, то как? Заранее спасибо.

  • Tutanhamon

    Неплохая статья. Вообще, bbcode имеет свои плюсы по сравнению с чистым html. С ним технически намного проще обращаться. Однако, bbcode накладывает и свои ограничения, включая процесс редактирования. Если необходимо разместить статью или объявление на html, то, обычно, возникает одна муторная проблема — необходимость в кропотливой замене скобочек на «». Конечно, данную проблему можно обойти, с помощью онлайн конвертера — http://ida-freewares.ru/html-bbcode.html
    Но, это не всегда удобно. Любой добавленный специфический тег в набор — автоматически добавляет сложностей и необходимость ручной замены символов.

  • Евгений

    Доброго времени суток,
    ezoterik!

    Понравилась статья, многое дало понять о себе, вот только как в исходном коде заставить тег выводиться с новой строки? В принципе она должна выводиться так как прописан n, однако перенос не осуществляется. Что делать?

    • Здравствуйте! Давно уже не работаю с BBCode (стараюсь везде использовать Markdown), поэтому, возможно, подзабыл какие-то нюансы. Я не очень понял зачем может понадобиться чтобы в итоговом HTML коде выводились переводы строк. Можно какой-то пример задачи где этот нюанс может быть принципиален?

      • Евгений

        Вы меня не поняли. В исходном коде не переходит тег на новую строчку. Все слитно тексттексттексттексттексттексттекст

        А хотелось бы чтобы было так

        текст

        текст

        текст

        текст