23 мая 2011 г.

Парсер BBcode на PHP для нашего редактора (заключительная статья)

Здравствуйте! Сегодня я продолжу написание редактора, вернее скрипт, который будет переводить bb-код в нужный вид. В прошлой статье мы дописали наш редактор на javascript. Мы научили его вставлять необходимые теги в необходимое место. Теперь нам нужен скрипт на стороне сервера, который это будет сохранять в файл или базу данных, и еще один скрипт который все это будет переводить в надлежащий вид.
Я решил поступить следующим образом. Данные будут храниться в bbcode и парситься при выдаче. Чтобы при редактировании не надо было переводить из html опять в bbcode. Кто с этим не согласен, давайте поспорим. :)
Итак, я создаю файл save.php

<?php
$txt = htmlspecialchars($_POST['text']);
file_put_contents('for_pars.txt', $txt);
?>
<a href="pars.php">посмотреть результат</a>

Все данные я предварительно обрабатываю функцией htmlspecialchars(), и просто помещаю в текстовый файл for_parse.txt. После этих незамысловатых действий я предоставляю пользователю возможность просмотреть результат в том виде, в котором все это будет отображаться на сайте.
Теперь создаем следующий файл pars.php

<?php
$txt = file_get_contents('for_pars.txt');
 
function pars_bb($txt){
 $txt = str_replace('[b]', "<b>", $txt);
 $txt = str_replace('[/b]', "</b>", $txt);
 $txt = str_replace('[u]', "<u>", $txt);
 $txt = str_replace('[/u]', "</u>", $txt);
 $txt = str_replace('[i]', "<i>", $txt);
 $txt = str_replace('[/i]', "</i>", $txt);
 $txt = str_replace('[s]', "<span style=\"text-decoration: line-through;\">", $txt);
 $txt = str_replace('[/s]', "</span>", $txt);
 $txt = str_replace('[left]', "<div align=\"left\">", $txt);
 $txt = str_replace('[/left]', "</div>", $txt);
 $txt = str_replace('[center]', "<div align=\"center\">", $txt);
 $txt = str_replace('[/center]', "</div>", $txt);
 $txt = str_replace('[right]', "<div align=\"right\">", $txt);
 $txt = str_replace('[/right]', "</div>", $txt);
 
 preg_match_all('/\[link href=([^]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt = str_replace('[link href=' . $val . ']', '<a href="' . $val . '">', $txt);
  $i++;
 }
 
 preg_match_all('/\[image]([^[]*)\[\/image]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = str_replace('[image]'.$val.'[/image]', "<img src=\"$val\" />", $txt);
  $i++;
 }
 
 preg_match_all('/\[video]([^[]*)\[\/video]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = get_ifrm_src($val) ? str_replace('[video]'.$val.'[/video]', get_ifrm_src($val), $txt) : str_replace('[video]'.$val.'[/video]', "<a href=\"" . $val . "\">Ссылка на видео</a>", $txt);
  $i++;
 }
 
 preg_match_all('/\[email=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt = str_replace('[email='.$val.']', "<a href=\"mailto:$val\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[media]([^[]*)\[\/media]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = str_replace('[media]'.$val.'[/media]', "<a href=\"$val\">media</a>", $txt);
  $i++;
 }
 
 preg_match_all('/\[font=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[font='.$val.']', "<span style=\"font-family: $val;\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[size=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[size='.$val.']', "<font size=\"$val\">", $txt);
  $i++;
 }
 
 preg_match_all('/\[color=([^\]]*)]/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $key => $val)
   $txt =str_replace('[color='.$val.']', "<font color=\"$val\">", $txt);
  $i++;
 }
 
 $txt =str_replace('[/color]', "</font>", $txt);
 $txt =str_replace('[/size]', "</font>", $txt);
 $txt =str_replace('[/font]', "</span>", $txt);
 $txt =str_replace('[/code]', "</pre>", $txt);
 $txt =str_replace('[code]', "<pre>", $txt);
 $txt = str_replace('[quote]', "<div class=\"quote\">", $txt);
 $txt = str_replace('[/quote]', "</div>", $txt);
 $txt = str_replace('[/email]', "</a>", $txt);
 $txt = str_replace('[/link]', "</a>", $txt);
 $txt = str_replace('[indent]', "<div style=\"padding:20px\">", $txt);
 $txt = str_replace('[/indent]', "</div>", $txt);
 
 preg_match_all('/:(\w*):/i', $txt, $match);
 if(count($match[0]) > 0){
  foreach($match[1] as $val)
   $txt = file_exists("./images/$val.gif") ? str_replace(":$val:", "<img class=\"smile\" src=\"./images/$val.gif\" />", $txt) : $txt;
  $i++;
 }
 
 
 else $txt = find_video($txt);
 
 return $txt;
}
 
function get_ifrm_src($url){
 include('config.php');
 preg_match('/http:\/\/([^\/]*)\/(.*)/i', $url, $match);
 if(count($match[1]) == 0) return false;
 $pat = $pat_ar[$match[1]];
 $str = $pat['tpl'];
 $player = $pat['player'];
 if($str){
  preg_match($pat['pat'], $match[2], $s_match);
  if(count($s_match)){
   foreach($s_match as $key => $s_val)
    if($key) $str = str_replace('['.$key.']', "$s_val", $str);
   $str = str_replace("[url]", $str, $player);
  }
 }
 return $str == $pat['tpl'] ? false : $str;
}
 
function find_video($txt){
 include('config.php');
 if(count($pat_ar) == 0) return $txt;
 foreach($pat_ar as $val){
  if(preg_match_all($val['url_pat'], $txt, $match)){
   foreach($match[0] as $val)
    $txt = str_replace($val, (get_ifrm_src($val) ? get_ifrm_src($val) : $val), $txt);
  }
 }
 return $txt;
}
 
 
echo pars_bb($txt);
?>

И получился вот такой файл. Теперь настала пора его разобрать. Сначала мы считываем данные из файла, который содержит данные введенные пользователем в виде bbcode. И отображаем результат вызова функции pars_bb(), которой для парсинга мы передали данные пользователя.
Что же делает данная функция? Она по регулярным выражениям ищет находит то, что надо заменить и заменяет. Некоторые теги теги мы меняем, применяя простую функцию str_replace() без preg_match_all().
Дальше мы видим, что тег [video] у нас преобразуется не как все. А дело в том, что если видео вставлено с youtube, то оно заменяется фреймом с видео-плеером. В расчете на то, что подобные замены могут быть довольно-таки разные, я некоторые параметры вынес в отдельный файл config.php

<?php
$pat_ar = array();
$pat_ar['www.youtube.com'] = array('url_pat' => '/http:\/\/www.youtube.com[^\s]+/i', 'pat' => '/\?v=([^&]*)/i', 'tpl' => 'http://www.youtube.com/embed/[1]', 'player' => '<iframe width="425" height="349" src="[url]" frameborder="0" allowfullscreen></iframe>');
?>

Взглянув, на файл конфигурации и функции, которые его применяют, сразу становится ясно, что и для чего необходимо. Думаю, что здесь ничего объяснять не надо. Конечно, если у кого-то возникнут вопросы, спрашивайте, буду отвечать. Если кто-то желает посмотреть все файлы, то их можно скачать одним архивом здесь.

До новых встреч!

2 комментария:

  1. Игорь спасибо, давно ищу редактор но прикрутить ни как не удавалось буду читать что интересного ты выложил на своем блоге еще раз спасибо.

    ОтветитьУдалить
  2. Скачал архив. Запустил через апач файл textarea.html, открылась стр где можно вводить текс. Но при попытке форматировать его (выделяю текс, нажимаю жирный текст ни чего не происходит и не выделяю текст нажимаю на кнопки они не работают... как заставить их работать? )

    ОтветитьУдалить