Сервер в кармане, или просто о сложном!

главная - Статьи - WWW (HTML, PHP и др.)

Парсер web страниц

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

Решить данную проблему, то есть полностью отделить код от дизайна, позволяет так называемый парсер. Парсер - это некоторый скрипт, который берет готовый дизайн и в специальным способом помеченные места подставляет некоторые значения. Сейчас мы напишем простейший парсер. Его я писал, когда у меня возникло желание сделать на своем сайте несколько разных дизайнов, причем каждый пользователь мог выбрать тот дизайн, который ему больше нравился.

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

Создайте в директории сайта следующие папки:

  • site_funcs - здесь мы будем размещать общие модули сайта
  • designs - здесь мы будем держать дизайны

В папке designs создайте файл design.htm будущего дизайна со следующим содержанием:

<html><head>
<title>Наш сайт :: {*title*}</title>
</head><body>
<table cellspacing="0" border="1" cellpadding="1" width="100%" height="100%">
<tr><td height="70" colspan="3">Тут всякие картинки будут</td></tr>
<tr><td height="20" align="center" colspan="3">{*menu*}</td></tr>
<tr valign="top">
    <td width="160" align="center">{*left*}</td>
    <td style="color:#888888; font-size: 8pt; font-weight: bold;">
    ::: {*title*}<br><br>{*main*}<br><br></td>
    <td width="160" align="center">{*right*}</td>
</tr>
</table>
</body></html>

Наш парсер будет заменять выражения {*имя_переменной*} на некоторые значения, которые будут определяться во время выполнения скрипта.

Теперь приступим к написанию собственно парсера. Создайте в папке site_funcs файл parse_funcs.php следующего содержания:

<?
$Designs=array(); // Элементы подстановки в дизайн
$DesignOut=''; // То, что будем выводить

function LoadDesign ($CurDesign='design.htm'){ // Загружаем выбранный дизайн
    global $DesignOut;
    //echo 'Start design loading';
    $FN='designs/'.$CurDesign;
    if (!file_exists($FN)) return false;
    $DesignOut=join('',File($FN));
    //echo 'Design loaded';
    return true;
}

function Parse ($n=1){ // Выполняет глобальную замену переменных {*...*} в дизайне на их значения, парсер одним словом. При необходимости делает замену нужное число раз (Если передать 0, то ничего не делает :) )
    global $Designs, $DesignOut;
    //echo 'Start parse';
    for ($i=0;$i<$n;$i++){
        foreach($Designs as $k=>$v){
            $DesignOut=str_replace("{*$k*}","$v",$DesignOut);
        }
    }
}
?>

Разберем работу данного скрипта. Сначала нам понадобятся несколько переменных. В переменной $DesignOut мы будем держать содержимое нашего файла дизайна, а в массиве $Designs будем держать имена переменных, используемых в файле дизайна и их значения. Имена переменных используются в качестве ключей массива, а в значениях массива хранятся значения наших переменных.

Функция LoadDesign загружает в переменную $DesignOut содержимое файла дизайна, по умолчанию это design.htm, но при вызове функции можно указать любой другой.

Теперь самое интересное, функция Parse. Сердце функции состоит всего из одного цикла:

foreach($Designs as $k=>$v){
    $DesignOut=str_replace("{*$k*}","$v",$DesignOut);
}

Этот цикл заменяет все вхождения переменных {*имя_переменной*} в строке $DesignOut на их значения из массива $Designs, причем имя_переменной это один из ключей массива $Designs. В самой функции есть еще один цикл, который выполняет описанный выше цикл n раз. Это нужно в том случае, если мы захотим в одной из переменных написать "Некоторый текст: {*text*}", а потом на место {*text*} вставить что-то еще. В этом случае нам надо сказать парсеру, чтобы он выполнил подстановку два раза.

Теперь нам надо написать простенький интерфейс для работы с парсером. Интерфейс будет состоять из набора функций, которые будут передавать значение в массив $Designs. Создайте в папке site_funcs файл design_funcs.php следующего содержания:

<?
$CurDes='main'; // Указатель дизайна по умолчанию

function With ($newdes){ // Выбирает дизайн по умолчанию
    global$CurDes;
    $CurDes=$newdes;
}

function PrClr ($text){ // Пишет в дизайн по умолчанию, предварительно очистив его
    global $CurDes,$Designs;
    $Designs[$CurDes]=$text;
}

function Pr ($text){ // Пишет в дизайн по умолчанию
    global $CurDes,$Designs;
    @$Designs[$CurDes].=$text;
}

function PrToClr ($des,$text){ // Пишет в указанный дизайн, предварительно очистив его
    global$Designs;
    $Designs[$des]=$text;
}

function PrTo ($des,$text){ // Пишет в указанный дизайн
    global $Designs;
    @$Designs[$des].=$text;
}

function Clr ($des){ // Очищает указанный дизайн
    global $Designs;
    $Designs[$des]='';
}
?>

В принципе в этом модуле нет ничего хитрого, это всего лишь набор функций облегчающих работу. Все это нужно, чтобы писать не $Designs['main'].='некоторый текст', а просто PrTo('main', 'некоторый текст').

Если мы в элемент дизайна ничего выводить не собираемся, то его нужно просто очистить, т.е. записать в него пустую строку. Если этого не сделать, то парсер эту переменную не заменит и в результате у вас на страничке выскочит {*переменная*}. Функция Clr() как раз и очищает дизайн. Функции PrTo() и PrToClr() пишут в указанный дизайн, отличие в том, что первая просто дописывает текст к тому, что есть, а вторая предварительно очищает выбранный дизайн. Pr() и PrClr() работают аналогично двум последним, с тем лишь отличием, что они пишут в предварительно выбранный элемент дизайна, который можно выбрать с помощью функции With(), в нашем случае по умолчанию это main.

Теперь можно приступить к созданию первой странички. В папке сайта создайте файл index.php следующего содержания:

<?
require_once 'site_funcs/parse_funcs.php';
require_once 'site_funcs/design_funcs.php';
LoadDesign();

PrToClr('menu','Меню, которого нет');
PrToClr('left','Левая часть');
Clr('right'); // В right ничего не пишем

PrToClr('title','Главная страничка');
PrToClr('text','некоторый текст');
Pr('Текст нашей страницы, который содержит в себе подтекст "{*text*}"');
With('left'); //Теперь функция Pr() будет писать в left
Pr('Пишем что-нибудь еще в left');

Parse(2);
echo $DesignOut;
?>

Как это работает думаю пояснять не стоит. Это примитивный пример. Поэкспериментируйте со значением, передаваемым парсеру. По хорошему первые 6 строк скрипта нужно отделить в отдельный файл инициализации, ведь по сути там ничего не меняется, и писать в каждом скрипте все это неразумно. Последние 2 строки нужно поместить в отдельную функцию, которая будет строить дизайн по частям, выводить его и завершать работу скрипта, у нас это будет DoDesign(). Эту функцию тоже не помешало бы положить в отдельный модуль, например в тот же parse_funcs.php. Таким образом последний файл примет вид:

<?
require 'init.php';

PrToClr('title','Главная страничка');
PrToClr('text','некоторый текст');
Pr('Текст нашей страницы, который содержит в себе подтекст "{*text*}"');
With('left'); //Теперь функция Pr() будет писать в left
Pr('Пишем что-нибудь еще в left');

DoDesign(2);
?>

Файл init.php будет содержать в себе:

<?
require_once 'site_funcs/parse_funcs.php';
require_once 'site_funcs/design_funcs.php';
LoadDesign();

PrToClr('menu','Меню, которого нет');
PrToClr('left','Левая часть');
Clr('right'); // В right ничего не пишем
?>

Функция DoDesign будет выглядеть примерно так

DoDesign($n=1){
   Parse($n);
   echo $DesignOut;
exit;
}

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

Автор: Gorinich, http://cngroup.ru/

Авторизуйтесь для добавления комментариев!


    забыли пароль?    новый пользователь?