Нужно, иначе будет возможность сделать пустой тэг (например "<b></b>") а это нарушение HTML стандарта
И конечно же я тоже вставлю своё слово Я использую парсёр специальных маркеров (ББ кодов) основанный на конечном автомате. Это позволяет контролировать содержимое каждого атрибута каждого маркера, причём атрибутов может быть сколько угодно и их порядок следования не важен. Отслеживается уровень взаимной вложенности маркеров и вообще огромный простор для деятельности. Также это позволяет легко создавать новые правила парсировки новых специальных маркеров. Фактически у меня сейчас половина HTML тэгов преобразуется в специальные маркеры, всё остальное обрабатывается htmlspecialchars() а затем всё обратно преобразуется в HTML и сохраняет в базе данных для пказа пользователям. Я не вижу смысла экономить на длине сообщений, тем более, что экономия мизерная. Сделано это для того, чтобы пользователи без права использования HTML кода в сообщениях могли пользоваться визуальным редактором. Всё выше перечисленное относиться к пользователями не имеющим право использовать HTML код. Если у пользователя есть это право, то сообщение проходит обработку фильтром HTML кода. Который также реализован на основе конечного автомата, проверяет значения атрибутов HTML тэгов (процедура проверки конфигурируется индивидуально для каждого тэга и атрибута), контролирует взаимную вложенность тэгов их допустимость (в том числе структуру тэгов таблицы). Есть отдельный парсёр тэга style. В данный момент я тестирую безопасность данного фильтра, в моих планах сделать режим разрешённого HTML кода доступным по умолчанию всем пользователям форума и чата.
BBCode list, списки Код (Text): $text = ' Список: [list] [*] Привет МИР! [*] Да здавствует МИР! [*] Пока МИР! [/list] '; PHP: <?php $text = preg_replace_callback('#\[list\](.*)\[/list\]#Usi', create_function('$matches', ' $html = "<ul>\n"; $list = explode("[*]", $matches[1]); array_shift($list); foreach ($list as $li) { $html .= "<li>" . trim($li) . "</li>\n"; } return $html . "</ul>"; ') , $text); print $text; ?> Вариант с поддержкой нумерованных списков Код (Text): [list=order] PHP: <?php $text = preg_replace_callback('#\[list(.*)\](.*)\[/list\]#Usi', create_function('$matches', ' $html = ($matches[1] == "=order" ? "<ol>\n" : "<ul>\n"); $list = explode("[*]", $matches[2]); array_shift($list); foreach ($list as $li) { $html .= "<li>" . trim($li) . "</li>\n"; } return $html . ($matches[1] == "=order" ? "</ol>\n" : "</ul>\n"); ') , $text); ?> Код (Text): Список: <ul> <li>Привет МИР!</li> <li>Да здавствует МИР!</li> <li>Пока МИР!</li> </ul> PS надо бы на форуме исправить функцию подстветки BBCode php, а то в внутри этих BB тэгов успешно обрабатываются и другие
И очень полезный, но нигде не используемый BBCode PHP: <? $text = preg_replace( '#\[man\]([a-z0-9_]+)\[/man\]#Usi', '<a href="http://php.net/$1">$1</a>', $text); ?>
Между прочим о парсинге с помощью регулярок. Непосредственно сталкивался с одной проблемой, которая вызывает "500 - Internal Server Error" - в трекере там регулярки типа preg_replace('/[tag](.*)?[/tag]/', .. , ...); так вот. переодически бывают моменты, когда входишь в описание торрента и выскакивает 500-я ошибка. Оказываеться, иногда товарищи умудряються весь текст (а это порой пара килобайт) загнать в [/size ] или какой-нить другой тег. В итоге обработать такое кол-во текста PHP просто не может и страница отваливаеться с 500-й ошибкой. И это не смотря на то, что сервачёк то у меня не какой-нить захудалый, а вполне мощьная машина, да и оперативки там не 200-300 мегов, а 2 гига. Да и вообще, как показывает практика (между прочим и здесь есть проблемы с регулярками, я VB отписал один конкретный глюк), когда дело доходит до сложных комбинаций BBCode, обычные парсеры регулярками уже не подходят, потому что всё подряд заменять не нужно. Приходиться сперва что-то вырезать, парсить и потом вырезанное вставлять обратно. Вообщем то подход конечно неплохой, но приходиться при добавлении нового функционала дописывать всякие исключения, приходиться не забывать про порядок выполнения операций и.т.д. Вот щас в данный момент в бумтайм проэкте мы используем парсер, который использует регулярки только для [ a][/a ], [a=url][/a], [ img][/img ], всё остальное заменяеться обычным str_replace (что кстати весьма и весьма шустро), однако к примеру при парсинге BBCode приходиться вырезать теги цитат, что-бы они в визивике были в виде BBcode, а не HTML - уже пришлось писать исключение руками. И таких вот задачь много. ДА хотя-бы взять тут на форуме - впишите в [php ] [/php ] любой практичесчки из тегов в исходниках - получите невъебенные глюки. А всё потому, что при обработке [php ] [/php ] всё что между ними надо пропускать ТОЛЬКО через обработчик [php ][/php ] и не давать другим обработчикам вообще притрагиваться к тому, что между [php ] и [/php ] А ещё веселее если у вас в коде будет так: $str = 'bla bla [/php ]'; Будет глюк. Вообщем лично я пришел к выводу, что нужен класс, который работает по теории конечных автоматов и который при своей работе рокуводствуеться конфигурационным масивом, где можно настроить к примеру что в теге TAG вообще ничего не парсить, пока он не закроеться. Или что в тегк TAG2 не применять обработчик тега TAG3
http://www.pc.uz/documents/text/732.html Нашёл у себя в закладках. Там именно класс и работает именно на теории конечных атвоматов ЗЫ Тока сейчас чё-то не открывается, но потом глянь
Вот человек понимает суть проблемы и явно сталкивался с геммороем на этой основе Вообщем в обозримом будущем у меня на работе задача доработки нашего парсера сообщений до нормального состояния будет, я и здесь выложу то что получиться, вместе может ещё и доработаем
очень полезный функция PHP: <? function bbcontrol($text,$thisbb) { for($i=0,$c=count($thisbb);$i<$c;$i++) { preg_match_all("#\[(".$thisbb[$i].")\]#isU",$text,$openbb); preg_match_all("#\[\/(".$thisbb[$i].")\]#isU",$text,$closebb); if (count($openbb[1])>count($closebb[1])) { if (preg_match("#\[\/".$thisbb[$i]."\]#is",$text)) { $exp=explode("[/".$thisbb[$i]."]",$text); for($z=0,$k=count($openbb[1])-count($closebb[1]);$z<$k;$z++) { $exp[0].="[/".$thisbb[$i]."]"; } $text=join("[/".$thisbb[$i]."]",$exp); } else { $text=str_replace("[".$thisbb[$i]."]","[".$thisbb[$i]."]",$text); } }else if (count($openbb[1])<count($closebb[1])) { if (preg_match("#\[".$thisbb[$i]."\]#is",$text)) { $exp=explode("[".$thisbb[$i]."]",$text); for($z=0,$k=count($closebb[1])-count($openbb[1]);$z<$k;$z++) { $exp[0].="[".$thisbb[$i]."]"; } $text=join("[".$thisbb[$i]."]",$exp); }else { $text=str_replace("[/".$thisbb[$i]."]","[/".$thisbb[$i]."]",$text); } } } return $text; } ?>
Привет всем. Лично я столкнулся с BB-кодами совсем недавно, поэтому тема еще свежа. Когда потребовался такой фильтр, я изучал многие решения CMS, и метод конечных автоматов отдельно. Ежу понятно, что strtr и str_replace - самое оно, пока не приходишь к мысли ввести таблицы, списки и теги с параметрами. Метод конечных - дает все, но Боже мой, это фильтр для сайта, или сайт для демонстрации этого фильтра? Там же прорва килобайт, и все это - ручками на PHP, как будто он не интерпретатор. В результате - жалобы на быстродействие и необходимость в обязаловку кешировать готовые страницы. Поэтому для готовки такого фильтра имхо стоит следовать правилу: использовать внутренние функции и ассоциативные массивы по-максимуму. И никаких эвалов отдельных файлов для каждого парного тега, о чем думали разработчики? )) Вот типа того и получилось. Недостатки - пока не брался за теги, блокирующие или модифицирующие парзинг типа [ PHP ] или [ NOBB ] Если угодно, можно юзать с учетом, что доработки будут выложены здесь же - мне самому интересно PHP: <?php if (eregi("bbsm",$_SERVER['PHP_SELF'])) { Header("Location: http://{$_SERVER['SERVER_NAME']}/index.php"); die(); } $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT']; require_once "$DOCUMENT_ROOT/config.php"; // Берем с конфга путь к тематическим смайликам $dir_smiles = "/$dir_theme/img/smiles"; // СМАЙЛИКИ $smiles = array( 's' => array( ':)', ':-)', ';)', ';-)', ':(', ':-(', ':D', ':-D', ':o', ':-o', ':p', ':-p', ':confused:', ':rolleyes:', ':cool:', ':eek:', ':mad:' ), 'r' => array( '<img class="smiles" alt=":)" title=":)" src="'.$dir_smiles.'/smile.gif" />', '<img class="smiles" alt=":)" title=":)" src="'.$dir_smiles.'/smile.gif" />', '<img class="smiles" alt=";)" title=";)" src="'.$dir_smiles.'/wink.gif" />', '<img class="smiles" alt=";)" title=";)" src="'.$dir_smiles.'/wink.gif" />', '<img class="smiles" alt=":(" title=":(" src="'.$dir_smiles.'/frown.gif" />', '<img class="smiles" alt=":(" title=":(" src="'.$dir_smiles.'/frown.gif" />', '<img class="smiles" alt=":D" title=":D" src="'.$dir_smiles.'/biggrin.gif" />', '<img class="smiles" alt=":D" title=":D" src="'.$dir_smiles.'/biggrin.gif" />', '<img class="smiles" alt=":o" title=":o" src="'.$dir_smiles.'/redface.gif" />', '<img class="smiles" alt=":o" title=":o" src="'.$dir_smiles.'/redface.gif" />', '<img class="smiles" alt=":p" title=":p" src="'.$dir_smiles.'/tongue.gif" />', '<img class="smiles" alt=":p" title=":p" src="'.$dir_smiles.'/tongue.gif" />', '<img class="smiles" alt=":confused:" title=":confused:" src="'.$dir_smiles.'/confused.gif" />', '<img class="smiles" alt=":rolleyes:" title=":rolleyes:" src="'.$dir_smiles.'/rolleyes.gif" />', '<img class="smiles" alt=":cool:" title=":cool:" src="'.$dir_smiles.'/cool.gif" />', '<img class="smiles" alt=":eek:" title=":eek:" src="'.$dir_smiles.'/eek.gif" />', '<img class="smiles" alt=":mad:" title=":mad:" src="'.$dir_smiles.'/mad.gif" />', ), ); // ОДИНОЧНЫЕ ТЕГИ $bb_list1 = array( 'sl' => '[', 'sr' => ']', '_' => ' ', 'br' => '<br />', 'hr' => '<hr />', 'hrns' => '<hr noshade/>', ); // ДВОЙНЫЕ ТЕГИ $bb_list2 = array( // array( начинающие теги, // функция отработки параметра (корректирует цифру после тега, проверяет параметр), // конец заголовка, // завершающие теги, // после каких тегов может идти, // какие теги закрывает - если элемент по определению является вложенным, то - в начале, // а если нет - в конце // ) // Знак $ обозначает вставку номера тега (например H1, H2 имеют номера 1, 2) // Номер тега при разборе отделяется от имени тега и может быть скорректирован // функцией-валидатором 'b' => array( '<b', '', '>', '</b>'), 'u' => array( '<u', '', '>', '</u>'), 'i' => array( '<i', '', '>', '</i> '), // пробел в конце из-за глюка IE7 с float и курсивом 'em' => array( '<em', '', '>', '</em> '), 'tt' => array( '<tt', '', '>', '</tt>'), 's' => array( '<s', '', '>', '</s>'), 'sup' => array( '<sup', '', '>', '</sup>'), 'sub' => array( '<sub', '', '>', '</sub>'), 'pre' => array( '<pre', '', '>', '</pre>'), 'big' => array( '<big', '', '>', '</big>'), 'p' => array( '<p', '', '>', '</p>'), 'p=' => array( '<p align=', 'bbp_align', '>', '</p>'), 'h' => array( '<h$', 'bbp_h', '>', '</h$>'), 'h=' => array( '<h$ align="', 'bbp_h', '">', '</h$>'), 'center' => array( '<div style="text-align:center', '', '">', '</div>'), 'left' => array( '<div style="text-align:left', '', '">', '</div>'), 'right' => array( '<div style="text-align:right', '', '">', '</div>'), 'justify' => array( '<div style="text-align:justify', '', '">', '</div>'), 'align' => array( '<div style="text-align:', 'bbp_align', '">', '</div>'), 'table' => array( '<table', '', '>', '</table>', '', '|tr|th|td|'), 'table=' => array( '<table', 'bbp_table', '>', '</table>', '', '|tr|th|td|'), 'tr' => array( '<tr', '', '>','</tr>', '|table|tr|th|td|', '|tr|th|td|'), 'tr=' => array( '<tr', 'bbp_tr', '>','</tr>', '|table|tr|th|td|', '|tr|th|td|'), 'th' => array( '<th', '', '>','</th>', '|tr|th|td|', '|th|td|'), 'th=' => array( '<th', 'bbp_thtd', '>','</th>', '|tr|th|td|', '|th|td|'), 'td' => array( '<td', '', '>','</td>', '|tr|th|td|', '|th|td|'), 'td=' => array( '<td', 'bbp_thtd', '>','</td>', '|tr|th|td|', '|th|td|'), 'list' => array( '<ul', '', '>','</ul>', '', '|*|'), 'list=' => array( '<ol style="list-style-type:', 'bbp_list', '">','</ol>', '', '|*|'), '*' => array( '<li', '', '>','</li>', '|list|*|', '|*|'), 'color=' => array( '<span style="color:', 'bbp_color', '">', '</span>'), 'url=' => array( '<a href="', 'bbp_url', '">', '</a>'), ); // ФУНКЦИИ-ПАРЗЕРЫ // 1. разобрать параметр // 2. проверить на валидность части параметра, вернуть FALSE, если проверка не пройдена // Как вариант, вернуть значение по умолчанию. // 3. преобразовать параметр в код HTML, c учетом возможных подстановок констант function bbp_h(&$n, &$prm) { $n = max(min($n, 6), 1); return preg_match('/^"?(center|left|right|)"?/is', $prm, $pat) ? $pat[1] : FALSE; } function bbp_align(&$n, &$prm) { return preg_match('/^"?(center|left|right|justify)"?/is', $prm, $pat) ? $pat[1] : FALSE; } function bbp_url(&$n, &$prm) { return preg_match('/"?([a-z]?[:\/\/]?[a-z0-9\-_]?\.?[a-z0-9\.\/%&#=\?\-_]+)"?/is', $prm, $pat) ? $pat[1] : FALSE; } function bbp_list(&$n, &$prm) { static $subset = array( 'none', 'disc', 'circle', 'square', 'decimal', 'lower-roman', 'upper-roman', 'lower-alpha', 'upper-alpha' ); if (! preg_match( // '/^([0-8]{1}|none|disc|circle|square|decimal|lower-roman|upper-roman|lower-alpha|upper-alpha)/', '/^([0-8]{1}|\w*)/', $prm, $pat)) return FALSE; return isset($subset[$pat[1]]) ? $subset[$pat[1]]: $pat[1]; } function bbp_color(&$n, &$prm) { static $subset = array( 'black' => '#000000', 'blue' => '#0000FF', 'brown' => '#A52A2A', 'cyan' => '#00FFFF', 'darkblue' => '#00008B', 'darkred' => '#8B0000', 'green' => '#008000', 'indigo' => '#4B0082', 'olive' => '#808000', 'orange' => '#FFA500', 'red' => '#FF0000', 'violet' => '#EE82EE', 'white' => '#FFFFFF', 'yellow' => '#FFFF00', 'aqua' => '#00FFFF', 'fuchsia' => '#FF00FF', 'grey' => '#808080', 'lime' => '#00FF00', 'maroon' => '#800000', 'navy' => '#000080', 'purple' => '#800080', 'silver' => '#C0C0C0', 'teal' => '#008080' ); if (! preg_match( // '/^"?(#[0-9]{6}|black|blue|brown|cyan|darkblue|darkred|green|indigo|olive|orange|red|violet|white|yellow|aqua|fuchsia|grey|lime|maroon|navy|purple|silver|teal)"?/is', '/^"?(#[0-9A-F]{6}|\w*)"?/is', $prm, $pat)) return FALSE; return isset($subset[$pat[1]]) ? $subset[$pat[1]]: $pat[1]; } function bbp_thtd(&$n, &$prm) { static $lprm = array( 'cs' => array('/^([0-9]+)$/is', ' colspan='), 'rs' => array('/^([0-9]+)$/is', ' rowspan='), 'h' => array('/^([0-9]+%?)$/is', ' height='), 'w' => array('/^([0-9]+%?)$/is', ' width='), 'ga' => array('/^(l|c|r)$/is', ' align='), 'va' => array('/^(t|m|b)$/is', ' valign='), 'nw' => array('', ' nowrap'), 'bc' => array('/^(#[0-9A-F]{6}|\w*)$/is', ' bgcolor='), ); static $sub = array( 'l' => 'left', 'r' => 'right', 'c' => 'center', 'm' => 'middle', 't' => 'top', 'b' => 'bottom', ); return bbp_short_args( $prm, $lprm, $sub); } function bbp_tr(&$n, &$prm) { static $lprm = array( 'ga' => array('/^(l|c|r)$/is', ' align='), 'va' => array('/^(t|m|b)$/is', ' valign='), 'bc' => array('/^(#[0-9A-F]{6}|\w*)$/is', ' bgcolor='), ); static $sub = array( 'l' => 'left', 'r' => 'right', 'c' => 'center', 'm' => 'middle', 't' => 'top', 'b' => 'bottom', ); return bbp_short_args( $prm, $lprm, $sub); } function bbp_table(&$n, &$prm) { static $lprm = array( 'b' => array('/^([0-9]+?)$/is', ' border='), 'cp' => array('/^([0-9]+?)$/is', ' cellpadding='), 'cs' => array('/^([0-9]+?)$/is', ' cellspacing='), 'h' => array('/^([0-9]+%?)$/is', ' height='), 'w' => array('/^([0-9]+%?)$/is', ' width='), 'ga' => array('/^(l|c|r)$/is', ' align='), 'va' => array('/^(t|m|b)$/is', ' valign='), 'bc' => array('/^(#[0-9A-F]{6}|\w*)$/is', ' bgcolor='), ); static $sub = array( 'l' => 'left', 'r' => 'right', 'c' => 'center', 'm' => 'middle', 't' => 'top', 'b' => 'bottom', ); return bbp_short_args( $prm, $lprm, $sub); } function bbp_short_args(& $prm, & $lprm, & $sub) { $args = explode(';', str_replace('"', '', $prm)); $out = ''; foreach ( $args as $arg) { $a = explode(':', $arg); if (isset($lprm[$a[0]])) { if (isset($a[1]) ) { if (preg_match($lprm[$a[0]][0], $a[1], $pat) > 0) $out .= $lprm[$a[0]][1].'"'.(isset($sub[$pat[1]])?$sub[$pat[1]]:$pat[1]).'"'; //echo "Для маски {$lprm[$a[0]][0]} в строке поиска {$a[1]} найдено ".preg_match($lprm[$a[0]][0], $a[1], $pat)."совпадений<br>"; //echo 'Контент: '.nl2br(print_r($pat, true)).'<br>'; } else $out .= $lprm[$a[0]][1]; } } return $out; } // ТОЧКА ВХОДА В ПАРЗЕР BB-кодов function filter_bb($str, $smiles = false, $content = NULL) { global $bb_list1a, $bb_list1b; // Преформат: выкидываем лишние \n из сложных выражений // Фактически мы выкидываем br после закрывающих // тегов $str = preg_replace('/[\r|\n]{2}+\[(\*|\/)/', "[$1", $str); // $str = preg_replace('#(\[(?:\w|/\w|/|\*).*?\])[\r|\n]{2}#', "$1", $str); // разобьем строку на составляющие подстроки и теги if ($content == NULL) $content = preg_split('#(\[(?:\w|/\w|/|\*).*?\])#mis', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE ); // echo 'Контент: '.nl2br(print_r($content, true)).'<br>'; // вызовем рекурсивную функцию обработки c с последющей заменой // проигнорированных спецтегов if ($smiles) { global $smiles; return str_replace($smiles['s'], $smiles['r'], bb_rcd($content, 'start')); } else return bb_rcd($content, 'start'); } // РЕКУРСИВНАЯ ФУНКЦИЯ ДЕКОДИРОВАНИЯ С ИСПОЛЬЗОВНИЕМ МАССИВА ПОДСТРОК function bb_rcd(& $content, $openkey='') { global $bb_list1, $bb_list2, $bb_const; $out = ""; $opentag = str_replace('=', '', $openkey); while (true) { if (empty($content)) return $out; $elm = array_shift( $content); // echo "<br>Вход: $openkey; элемент: $elm<br>"; if ($elm[0] == '[') // && $elm[1] !='*') // найден bb-код (игнорим списочный [*]) { $match_count = preg_match( '#^\[(/?)((?:[A-Za-z]+|[\*_]||))(\d*)([=:]?)(.*?)]$#i', $elm, $matches); // $matches[0] - копия входящей строки // $matches[1] - '/' если закрывающий тег, иначе '' // $matches[2] - слово кода // $matches[3] - цифра сразу за кодом // $matches[4] - разделители '=' или ':' // $matches[5] - параметр // echo 'Массив разбора тега:<br>'.nl2br(print_r($matches, true)).'<br>'; if (! $match_count) { $out .= $elm; continue; } $bb_prm = $matches[5]; $bb_wrd = strtolower(trim($matches[2])); $bb_dlm = $matches[4] == '' ? '' : '='; $bb_key = $bb_wrd.$bb_dlm; // ключ в массиве $vl =& $bb_list2[$bb_key]; if ($matches[1] != '/') // тег не закрывающийся { if ( empty($bb_wrd)) continue; // тег пуст, игнорим // Проверим наличие тега в массиве допустимых //echo '<br>Проверка тега: '. $bb_wrd.$bb_dlm . '<br>'; //echo "Ключ: ".$bb_key.'<br>'; if (! isset($bb_list2[$bb_key]) ) // тег не описан, смотрим в массив одиночных тегов { $out .= isset($bb_list1[$bb_key]) ? $bb_list1[$bb_key]: $elm; continue; } // Проверим ограничения на позицию элемента //echo "Текущий открытый тег: ". $opentag.'<br>'; if ( !empty($vl[4])) { if ( strpos($vl[4], "|$opentag|") === FALSE ) // если вложенный элемент вложен неправильно { //echo "|$opentag| нет в {$vl[4]}, выход!<br>"; $out .= bb_invalid($elm); continue; } if ( !empty($vl[5]) && strpos($vl[5], "|$opentag|") !== FALSE) { array_unshift($content, $elm); //echo "Автозакрытие: $opentag и выход<br>"; return $out; // закрываем текущий уровень вложенности } // else echo "Автозакрытие невозможно: |$opentag| нет в {$vl[5]}<br>"; } // Проверим соответствие формата ожидаемому if ( @function_exists($vl[1]) === TRUE ) // если присутствует функция-валидатор { //echo "Есть функция-валидатор: ". $vl[1].'<br>'; $bb_prm = $vl[1]($matches[3], $bb_prm); if ($bb_prm === FALSE) { $out .= bb_invalid($elm); continue; } } $out .= str_replace('$', $matches[3], $bb_list2[$bb_key][0].$bb_prm.$bb_list2[$bb_key][2]. bb_rcd($content, $bb_key). $bb_list2[$bb_key][3] ); //echo "Out: $out<br>"; } else // закрывающий тег { //echo "Слово закрывающегося тега: $bb_wrd, слово открытого тега: $opentag.<br>"; if ($bb_wrd == $opentag) return $out; // полное совпадение, выходим else { if ( empty($bb_wrd)) // тег автозакрытия [/] { if ( ! empty($bb_list2[$opentag][4])) // открытый тег вложенный array_unshift($content, $elm); // сохраняем тег автозакрытия // - это вызовет последовательное закрытие вложенных тегов до закрытия контейнера // echo "Автозакрытие тега: $opentag<br>"; return $out; } if ( empty($vl[4]) && strpos(isset($vl[5]) ? $vl[5]:'', "|$opentag|") !== FALSE ) // тег не является вложенным, возможно автозакрытие { array_unshift($content, $elm); // echo "Автозакрытие тега: $opentag<br>"; return $out; } // else echo "Автозакрытие невозможно: |$opentag| нет в {$vl[5]}<br>"; $out.= bb_invalid($elm); } //echo "Закрывающий html для $openkey: ".htmlspecialchars($bb_list2[$openkey][3]).'<br>'; } } else $out .= nl2br($elm); } } function bb_invalid($str) { return '<font color="red">' .$str. '</font>'; } ?> Тестовое файло: PHP: <?php include 'bbsm.php'; $str = '[list][*]Во-первых:[url="/main?l=auth#art"]ссылка 1[/url][*]Во вторых: [b]:ЖЫРНЫЙ ШРИФТ[/b][*]в третьих - вложенный список[list=4][*]первый пункт[*]второй пункт[*]третий[/list][/list]'; echo $str.'<br>'; //echo nl2br(htmlspecialchars(my_decode_bb($str))); echo "\n"; echo '<br>Превью<br>'; echo "\n"; echo filter_bb($str); echo "\n"; $str = '[table=b:1;cp:0;cs:0;bc:#EEEEEE][tr][th="cs:2;va:m;ga:c;bc:lightblue;w:100%;h:100"]Заголовок[tr][td=rs]строка 1, ячейка 1[td]строка 1, ячейка 2[tr=bc][td]строка 2, ячейка 2[/table]'; echo "\n"; echo $str.'<br>'; echo "\n"; echo '<br>Превью<br>'; echo "\n"; echo filter_bb($str); echo "\n"; $str = '[h]Заголовок 1[/h][h2]Заголовок 2[/h2][h3=center]Заголовок 3[/h3]'; echo "\n"; echo $str.'<br>'; echo "\n"; echo '<br>Превью<br>'; echo "\n"; echo filter_bb($str); echo "\n"; $str = '[sl]текст в квадратных скобках[sr]'; echo "\n"; echo $str.'<br>'; echo "\n"; echo '<br>Превью<br>'; echo "\n"; echo filter_bb($str); echo "\n"; echo '<br><br>'; $str = '[p=center]'. '[table=b:1;w][tr][th=cs:4;bc:#EEEEEE][b]Смайлики[/b]'. '[tr][td]:)[td=ga]:)[td]:-)[td=ga]:-)'. '[tr][td];)[td=ga];)[td];-)[td=ga];-)'. '[tr][td];([td=ga]:([td];-([td=ga]:-('. '[tr][td]:D[td=ga]:D[td]:-D[td=ga]:-D'. '[tr][td]:o[td=ga]:o[td]:-o[td=ga]:-o'. '[tr][td]:p[td=ga]:p[td]:-p[td=ga]:-p'. '[tr][td=cs]:confused:[td=ga]:confused:'. '[tr][td=cs]:cool:[td=ga]:cool:'. '[tr][td=cs]:rolleyes:[td=ga]:rolleyes:'. '[tr][td=cs]:eek:[td=ga]:eek:'. '[tr][td=cs]:mad:[td=ga]:mad:'. '[/table]'. '[/p]'. ''; echo "\n"; echo $str.'<br>'; echo "\n"; echo '<br>Превью<br>'; echo "\n"; echo filter_bb($str, true); echo "\n"; ?>
ёпта, ктож для создания таблиц юзает ббкоды?? для таких дел обычно вводят теги типа HTML: содержимое обработывают регулярками или домом... [quote]$str = '[p=center]'. '[table=b:1;w][tr][th=cs:4;bc:#EEEEEE]Смайлики'. '[tr][td]:)[td=ga]:)[td]:-)[td=ga]:-)'. '[tr][td];)[td=ga];)[td];-)[td=ga];-)'. '[tr][td];([td=ga]:([td];-([td=ga]:-('. '[tr][td]:D[td=ga]:D[td]:-D[td=ga]:-D'. '[tr][td]:o[td=ga]:o[td]:-o[td=ga]:-o'. '[tr][td]:p[td=ga]:p[td]:-p[td=ga]:-p'. '[tr][td=cs]:confused:[td=ga]:confused:'. '[tr][td=cs]:cool:[td=ga]:cool:'. '[tr][td=cs]:rolleyes:[td=ga]:rolleyes:'. '[tr][td=cs]:eek:[td=ga]:eek:'. '[tr][td=cs]:mad:[td=ga]:mad:'. '[/table]'. '[/p]'. '';[/quote] убил ..
Вопрос в другом. как сделать этот код безопасным, без применения автоматов, пулеметов и т.п. PHP: function parseBBcode($var) { $search = array( '/\[b\](.*?)\[\/b\]/is', '/\[i\](.*?)\[\/i\]/is', '/\[u\](.*?)\[\/u\]/is', '/\[img\](.*?)\[\/img\]/is', '/\[quote\](.*?)\[\/quote\]/is', '/\[url\](.*?)\[\/url\]/is', '/\[url\=(.*?)\](.*?)\[\/url\]/is', '/\[youtube\](.*?)\[\/youtube\]/is' ); $replace = array( '<strong>$1</strong>', '<em>$1</em>', '<u>$1</u>', '<img src="$1" />', '<div class=quote>$1</div>', '<noindex><a target=_blank rel="nofollow" href="$1">$1</a></noindex>', '<noindex><a target=_blank rel="nofollow" href="$1">$2</a></noindex>', '<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/$1&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/$1&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>' ); $var = preg_replace ($search, $replace, $var); return $var; }
в подготовке статей и текстов юзерами - очень может быть. Чушь Имхо, лучший шаблонизатор - strtr. Достаточно для упихания контента в тематический шаблон. Все остальное - хня.
Читал многа статей, где многа букофф. Долго думал. Об стену убеватся не пришлось. Ладно, все это лирика, но с чего вы решили, что ваш скрипт подвержен подобным атакам? Давайте разберемся. Чтоб получить ключ /e, нужно смодифицировать паттерны поиска, не более и не менее. У вас они статические, так какого дьявола беспокоиться? Беспокоиться надо имхо исключительно в том случае, если паттерн поиска является продуктом вычислений с использованием переменных, которые в теории могут содержать начинку от GET, POST и COOKIE. Мнение экспертов весьма интересно будет увидеть.