Иногда нам хочется добавить изюминку к нашим скриптам, сохранять в базе сообщения от пользователей не только в простом текстовом формате, но и давать им возможность форматировать свои сообщения как текст html. Здесь и нужны так называемые BB коды. То есть, это придуманные нами парные теги, которые при использовании нами будут преобразовываться в html теги.
BB код Преобразование Описание
[b] что-то здесь [/b] <b>что-то здесь</b> жирный текст
[i] что-то здесь [/i] <i>что-то здесь</i> наклонный текст
[u] что-то здесь [/u] <u>что-то здесь</u> подчеркнутый текст
[q]что-то здесь [/q] <table><tr><td>
что-то здесь
</td></tr></table> выделенная цитата
[ list ] что-то здесь[/list] <ul><li>что-то здесь</li></ul> не нумерованный список
[listn]что-то здесь [/listn] <ol><li>что-то здесь</li></ol> нумерованный список
(url)что-то здесь (/url) <a href="">что-то здесь</a> Url ссылка
Ранее в разделе Php база, мы научились с Вами сохранять данные в таком формате, чтобы он не причинил вреда при выводе его из базы в html текст, теперь будем добавлять BB коды, а потом их преобразовывать в html. Пользователю, которого мы лишили html форматирования, теперь становится интереснее. Но, как обычно, в любом начинании есть проблемы.
Одна из проблем в том, что пользователь может забыть закрыть тег, или, ещё хуже, какой-нибудь нехороший пользователь специально захочет Вам навредить. Так вот, как найти парные теги в сообщении полученном из формы, которое пользователь послал в Гостевую книгу или в Форум? Дело в том, что если у Вас простая Гостевая, это не требуется, но если есть BB коды, это становится актуально, ведь потом эти парные теги мы будем заменять на их html эквиваленты:
К примеру:
[b] что-то здесь [/b], посланное пользователем, преобразуется в
<b>что-то здесь</b>, в этих BB кодах
Теперь представьте, что пользователь по ошибке или специально открыл только один тег
[b] что-то здесь, а закрыть тег не захотел, то получится:
<b>что-то здесь, а закрыть тег не захотел, то получится
То есть, надо проверять парность тегов:
- убирать в начале текста закрывающийся тег [/b];
- убирать в конце текста открывающийся тег [b];
- убирать пустые парные теги [b] [/b];
- убирать повторяющиеся теги [b][b] или [/b][/b];
Создадим такую функцию и посмотрим как она работает:
<?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 = " [/b] [/b] [/b][b] Проб[b]у[b][b]ем [/b]Обм[b]ан[b]уть [b]Програ [/b] [/b] [/b]мму [b] [b] [b] ";
echo $string."\n<br><br>";
# применим функцию по сбору мусора
# в ней четыре аргумента: первые три показывают
# какой тег проверяем, а последний где проверяем
$string = Teg ("[","b","]",$string);
echo $string;
?>
В итоге работы программы получим:
[/b] [/b] [/b][b] Проб[b]у[b][b]ем [/b]Обм[b]ан[b]уть [b]Програ [/b] [/b] [/b]мму [b] [b] [b]
[b] Пробуем [/b]Обм[b]ануть Програ [/b]мму
То есть, в базу, при таком подходе мы запишем только парные теги. Вы скажете зачем всё это надо, но одно дело когда, например не закрылся тег [b], ещё пол беды (весь тест далее будет выделен жирным шрифтом), и совсем другое когда не закрылся [q], который мы будем преобразовывать в начало таблицы <table><tr><td> (представляете, что будет на странице при выводе такого не закрытого тега).
То есть, теперь подведем итог:
Пользователь послал сообщение $message, которое мы будем записывать в базу, как убрать html дескрипторы из сообщения мы знаем (раздел Php база), теперь оставим парные и уберем пустые теги BB кодов:
<?php
// оставим парные и уберем пустые теги
$message = Teg ("[","b","]",$message);
$message = Teg ("[","i","]",$message);
$message = Teg ("[","u","]",$message);
$message = Teg ("[","q","]",$message);
$message = Teg ("[","list","]",$message);
$message = Teg ("[","listn","]",$message);
$message = Teg ("(","url",")",$message);
// записываем сообщение в базу
$fp = fopen ("Base.dat","a");
fputs ($fp,"$message\n");
fclose ($fp);
?>
При таком подходе, мы оставляем мало шансов злоумышленнику навредить нам, и даем дополнительные возможности добросовестному пользователю по использованию html разметки в своих сообщениях.