Php BB коды

Иногда нам хочется добавить изюминку к нашим скриптам, сохранять в базе сообщения от пользователей не только в простом текстовом формате, но и давать им возможность форматировать свои сообщения как текст html. Здесь и нужны так называемые BB коды. То есть, это придуманные нами парные теги, которые при использовании нами будут преобразовываться в html теги.

BB код Преобразование Описание
&#91;b&#93; что-то здесь &#91;/b&#93; <b>что-то здесь</b> жирный текст
&#91;i&#93; что-то здесь &#91;/i&#93; <i>что-то здесь</i> наклонный текст
&#91;u&#93; что-то здесь &#91;/u&#93; <u>что-то здесь</u> подчеркнутый текст
&#91;q&#93;что-то здесь &#91;/q&#93; <table><tr><td>
что-то здесь
</td></tr></table> выделенная цитата
&#91; list &#93; что-то здесь&#91;/list&#93; <ul><li>что-то здесь</li></ul> не нумерованный список
&#91;listn&#93;что-то здесь &#91;/listn&#93; <ol><li>что-то здесь</li></ol> нумерованный список
(url)что-то здесь (/url) <a href="">что-то здесь</a> Url ссылка
Ранее в разделе Php база, мы научились с Вами сохранять данные в таком формате, чтобы он не причинил вреда при выводе его из базы в html текст, теперь будем добавлять BB коды, а потом их преобразовывать в html. Пользователю, которого мы лишили html форматирования, теперь становится интереснее. Но, как обычно, в любом начинании есть проблемы.
Одна из проблем в том, что пользователь может забыть закрыть тег, или, ещё хуже, какой-нибудь нехороший пользователь специально захочет Вам навредить. Так вот, как найти парные теги в сообщении полученном из формы, которое пользователь послал в Гостевую книгу или в Форум? Дело в том, что если у Вас простая Гостевая, это не требуется, но если есть BB коды, это становится актуально, ведь потом эти парные теги мы будем заменять на их html эквиваленты:

К примеру:
&#91;b&#93; что-то здесь &#91;/b&#93;, посланное пользователем, преобразуется в
<b>что-то здесь</b>, в этих BB кодах

Теперь представьте, что пользователь по ошибке или специально открыл только один тег
&#91;b&#93; что-то здесь, а закрыть тег не захотел, то получится:
<b>что-то здесь, а закрыть тег не захотел, то получится

То есть, надо проверять парность тегов:
- убирать в начале текста закрывающийся тег &#91;/b&#93;;
- убирать в конце текста открывающийся тег &#91;b&#93;;
- убирать пустые парные теги &#91;b&#93; &#91;/b&#93;;
- убирать повторяющиеся теги &#91;b&#93;&#91;b&#93; или &#91;/b&#93;&#91;/b&#93;;

Создадим такую функцию и посмотрим как она работает:

<?php
    # функция, которая убирает мусор в парных тегах
function Teg ($one,$teg,$too,$path){
$on = preg_quote ($one,"~");
$to = preg_quote ($too,"~");
$saerch1 = preg_quote ($one,"~") . $teg . preg_quote ($too,"~");
$saerch2 = preg_quote ($one,"~") . "/" . $teg . preg_quote ($too,"~");
$path = preg_replace ("~[ ]+~"," ",$path); 
$path = trim ($path);
$path = preg_replace ("~(".$saerch1."[ ]?".$saerch1.")+~", $one.$teg.$too, $path); 
$path = preg_replace ("~(".$saerch2."[ ]?".$saerch2.")+~", $one."/".$teg.$too, $path); 
$path = preg_replace ("~ˆ([ ]*".$saerch2.")*~","",$path); 
$path = preg_replace ("~(".$saerch1."[ ]*)*$~","",$path); 
$_search = "~".$saerch1."(.+)".$saerch2."~U";
$search = array ();
if ( preg_match_all ($_search, $path, $array, PREG_PATTERN_ORDER)){
while ( list (, $val) = each ($array[0])){
$content = "~" . preg_quote ($val,"~") . "~U";
if ( !empty ($search[0])){ if ($content==$search[0]){continue;} }
if ( @array_search ($content,$search)){ continue; }
$search[] = $content;
$pp = preg_replace ("~".$on."[/]?".$teg.$to."~","",$val);
if ( !preg_match ("~[a-zA-Z0-9а-яА-Я_]~",$pp)){ $pp = " "; }
else { $pp = $one.$teg.$too.$pp.$one."/".$teg.$too; }
$replace[] = $pp;
}
$search[] = "~0~e";
$replace[] = "0";
$path = preg_replace ($search, $replace, $path); 
$path = preg_replace ("~[ ]+~"," ",$path); 
$path = preg_replace ("~".$on."([/]?)".$teg.$to."[ ]?".$on."\\1".$teg.$to."~s", $one."\\1".$teg.$too, $path);
}
if ( !preg_match ($_search, $path)){ $path = preg_replace ("~".$on."[/]?".$teg.$to."~", '', $path); }
return $path;
} 

    # строка с плохими парными тегами
$string = " &#91;/b&#93; &#91;/b&#93; &#91;/b&#93;&#91;b&#93; Проб&#91;b&#93;у&#91;b&#93;&#91;b&#93;ем &#91;/b&#93;Обм&#91;b&#93;ан&#91;b&#93;уть &#91;b&#93;Програ &#91;/b&#93; &#91;/b&#93; &#91;/b&#93;мму &#91;b&#93; &#91;b&#93; &#91;b&#93; ";
echo $string."\n<br><br>";

    # применим функцию по сбору мусора
    # в ней четыре аргумента: первые три показывают
    # какой тег проверяем, а последний где проверяем
$string = Teg ("&#91;","b","&#93;",$string);
echo $string;

?>


В итоге работы программы получим:

&#91;/b&#93; &#91;/b&#93; &#91;/b&#93;&#91;b&#93; Проб&#91;b&#93;у&#91;b&#93;&#91;b&#93;ем &#91;/b&#93;Обм&#91;b&#93;ан&#91;b&#93;уть &#91;b&#93;Програ &#91;/b&#93; &#91;/b&#93; &#91;/b&#93;мму &#91;b&#93; &#91;b&#93; &#91;b&#93;

&#91;b&#93; Пробуем &#91;/b&#93;Обм&#91;b&#93;ануть Програ &#91;/b&#93;мму

То есть, в базу, при таком подходе мы запишем только парные теги. Вы скажете зачем всё это надо, но одно дело когда, например не закрылся тег &#91;b&#93;, ещё пол беды (весь тест далее будет выделен жирным шрифтом), и совсем другое когда не закрылся &#91;q&#93;, который мы будем преобразовывать в начало таблицы <table><tr><td> (представляете, что будет на странице при выводе такого не закрытого тега).

То есть, теперь подведем итог:
Пользователь послал сообщение $message, которое мы будем записывать в базу, как убрать html дескрипторы из сообщения мы знаем (раздел Php база), теперь оставим парные и уберем пустые теги BB кодов:

<?php 
    // оставим парные и уберем пустые теги 
$message = Teg ("&#91;","b","&#93;",$message); 
$message = Teg ("&#91;","i","&#93;",$message); 
$message = Teg ("&#91;","u","&#93;",$message); 
$message = Teg ("&#91;","q","&#93;",$message); 
$message = Teg ("&#91;","list","&#93;",$message); 
$message = Teg ("&#91;","listn","&#93;",$message); 
$message = Teg ("(","url",")",$message); 
    // записываем сообщение в базу 
$fp = fopen ("Base.dat","a"); 
fputs ($fp,"$message\n"); 
fclose ($fp); 
?>

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

Добавлено: 02 Апреля 2018 19:11:40 Добавил: Андрей Ковальчук

Комментарии

PHP поддерживает комметарии в стиле 'C', 'C++' и оболочки Unix (стиль Perl). Например:

<?php
    echo "Это тест"; // Это однострочный комментарий в стиле c++
    /* Это многострочный комментарий
       еще одна строка комментария */
    echo "Это еще один тест";
    echo "Последний тест"; # Это комментарий в стиле оболочки Unix
?>

Однострочные комментарии идут только до конца строки или текущего блока PHP-кода, в зависимости от того, что идет перед ними. Это означает, что HTML-код после // ... ?> или # ... ?> БУДЕТ напечатан: ?> завершает режим PHP и возвращает режим HTML, а // или # не могут повлиять на это. Если включена директива asp_tags, то аналогичное поведение будет и с // %> и # %>. Однако, тег </script> не завершает режим PHP в однострочном комментарии.
<h1>Это <?php # echo "простой";?> пример</h1>
<p>Заголовок вверху выведет 'Это пример'.</p>

'C'-комментарии заканчиваются при первой же обнаруженной последовательности */. Убедитесь, что вы не вкладываете друг в друга 'C'-комментарии. Очень легко допустить эту ошибку при комментировании большого блока кода. .
<?php
 /*
    echo "Это тест"; /* Этот комментарий вызовет проблему */
 */
?>

Добавлено: 09 Февраля 2015 21:07:06 Добавил: Андрей Ковальчук

Разделение инструкций

Как в C или Perl, PHP требует окончания инструкций точкой запятой в конце каждой инструкции. Закрывающий тег блока PHP-кода автоматически применяет точку с запятой; т.е. нет необходимости ставить точку с запятой в конце последней строки блока с PHP-кодом. Закрывающий тег блока "поглотит" немедленно следующий за ним переход на новую строку, если таковой будет обнаружен.

<?php
    echo 'Это тест';
?>

<?php echo 'Это тест' ?>

<?php echo 'Мы опустили последний закрывающий тег';

Замечание:
[QUOTE]Закрывающий тег PHP-блока в конце файла не является обязательным, и в некоторых случаях его опускание довольно полезно, например, при использовании include() или require(), так, что нежелательные пробелы не останутся в конце файла и вы все еще сможете добавить http-заголовки после подключения к ответу сервера. Это также удобно при использовании буферизации вывода, где также нежелательно иметь пробелы в конце частей ответа, сгенерированного подключаемыми файлами.[\/QUOTE]

Добавлено: 09 Февраля 2015 21:04:18 Добавил: Андрей Ковальчук

Вставка в HTML

Когда PHP обрабатывает файл, он ищет открывающие и закрывающие теги, которые указывают PHP, когда начинать и заканчивать обработку кода между ними. Подобный способ обработки позволяет PHP внедряться во все виды различных документов, так как всё, что находится вне пары открывающих и закрывающих тегов, будет проигнорировано парсером PHP. В большинстве случаев PHP внедряется в HTML-документы, как это показано в следующем примере.
<p>Это будет проигнорировано.</p>
<?php echo 'А это будет обработано.'; ?>
<p>Это тоже будет проигнорировано.</p>
Можно использовать и более продвинутые структуры:
Пример #1 Продвинутое внедрение

<?php
if ($expression) {
    ?>
    <strong>Это истина.</strong>
    <?php
} else {
    ?>
    <strong>Это ложь.</strong>
    <?php
}
?>

Это работает так, как и ожидается, потому что когда PHP встречает закрывающие теги ?>, он просто начинает выводить все, что встретит (за исключением перевода строки, стоящим сразу после закрывающего тега - смотрите разделение инструкций), пока не встретит следующий открывающий тег. Вышеуказанный пример, разумеется, надуман, но при больших объемах текста выход из режима PHP обычно более эффективен, чем посылка всего текста через echo() или print().
Существует четыре набора тегов, которые могут быть использованы для обозначения PHP-кода. Из них только два <?php ?> и <script language="php"> </script>) всегда доступны. Другими двумя являются короткие теги и теги в стиле ASP, которые могут быть включены или выключены в конфигурационном файле php.ini. Хотя короткие теги и теги в стиле ASP могут быть удобны, они не так переносимы, как длинные версии, и поэтому не рекомендуются.
Замечание:
Кроме того, если вы намереваетесь вставлять PHP-код в XML или XHTML, чтобы соответствовать XML стандартам, ам следует использовать форму <?php ?>.
Пример #2 Открывающие и закрывающие теги PHP
1.
<?php echo 'если вы хотите работать с документами XHTML или XML, делайте так'; ?>


2.
<script language="php">
        echo 'некоторые редакторы (например, FrontPage) не
              любят инструкции обработки';
    </script>


3.
<? echo 'это простейшая инструкция обработки SGML'; ?>
    <?= выражение ?> Это синоним для "<? echo выражение ?>"


4.
<% echo 'Вы можете по выбору использовать теги в стиле ASP'; %>
    <%= $variable; # Это синоним для "<% echo . . ." %>

Несмотря на то, что теги указанные в первых двух примерах всегда доступны, наиболее широко используется (и рекомендуется) первый пример из этих двух.
Короткие теги (третий пример) доступны только когда они включены с помощью директивы short_open_tag в конфигурационном файле php.ini, либо если PHP был скомпилирован с опцией --enable-short-tags .
Теги в стиле ASP (четвертый пример) доступны только когда они были с помощью директивы asp_tags в конфигурационном файле php.ini.
Замечание:
Следует избегать использования коротких тегов при разработке приложений или библиотек, предназначенных для распространения или размещения на PHP-серверах, не находящихся под вашим контролем, так как короткие теги могут не поддерживаться на целевом сервере. Для создания переносимого, совместимого кода, не используйте короткие теги.
Замечание:
В PHP 5.2 и более ранних версиях парсер не позволял файлам содержать только один открытый тег <?php. Это было разрешено, начиная с версии PHP 5.3.
Замечание:
Начиная с версии PHP 5.4, короткий тег вывода <?= распознается всегда, вне зависимости от значения директивы short_open_tag.

Добавлено: 09 Февраля 2015 20:58:12 Добавил: Андрей Ковальчук