Войти
VTEM SlideshowVTEM SlideshowVTEM Slideshow


Организация "шаблонного" вывода в CGI-скриптах на Perl

 

Введение

Написать эту статью меня заставили попытки изменить один бесплатный скрипт-CGI гостевой книги под требования некого сайта. Нужно было сделать с ним - это везде изменить слова "гостевая книга" на "книга отзывов", и прописать определенные строки по центру. Но в даном скрипте оказалось четыре (!) блока вывода - один только для штатной ситуации ("Ваша запись была успешно добавлена...") и три - только для вывода разнообразных ошибок (отсутствует E-Mail, имя или текст). При этом текст данных блоков довольно крепко прописан в операторах print. Ясное дело, что пришлось попотеть.

Большинство хостеров дают веб-программисту предустановленные скрипты - различные гостевые книги, счетчики, доски объявлений и тому подобное. При этом у некоторых хостеров (а именно, TvoyHosting.com) данные скрипты очень хорошо настраиваются. Даже несмотря на то, что у мастера-веб, обычно, нет возможности редактировать код данных скриптов, веб-мастера могут изменить дизайн выводимых данными скриптами страничек, редактируя скрипты под дизайн Вашего сайта.

В данной статье разбирается суть шаблонного вывода, его преимущества использования и рассматривается, как организовать на практике данный вывод в Ваших скриптах на языке Perl, используя сильное средство данного языка - регулировка выражений.

 

1. Шаблоны вывода.

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

Настройка скрипта под конкретный сайт сводится к редактированию этих самых шаблонов, представляющих по своей сути HTML-страницы. Это дает несколько преимуществ по сравнению с редактированием кода:

1. настроить скрипт может любой, который не писал такой скрипт и не знает его "тонкостей", да и вообще не шарит в Perl-программировании; :-)

2. при настройке просто невозможно внести в код скрипта синтаксические ошибки, которые потом придется поискать;

3. наглядность редактирования, возможность просмотреть примерный результат сразу в браузере; к тому же, у web-мастера обычно уже есть макет страниц, в который он вставляет содержимое;

4. один скрипт можно использовать с разными вариантами вывода, "подставляя" ему различные шаблоны.

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

В некоторых скриптах, не использующих шаблоны, есть текстовые файлы, содержащие "верх" и "низ" страницы. Скрипт считывает такие файлы, вставляет между ними свой вывод ("зашитый" в скрипте) и выдает страницу клиенту. Это позволяет разрешить много трудностей с "подгонкой" скрипта, но не позволяет изменить формат самого вывода. Поэтому я считаю шаблоны более универсальным средством.

Для того, чтобы скрипт "знал", в какие места шаблона какаие данные нужно пихать, шаблон содержит определенные метки - зарезервированные последовательности символов. Перед выдачей страницы  скрипт заменяет такие последовательности конкретными данными. В качестве меток чаще применяются последовательности букв, "обрамленные" слева и справа хостинг для joomla определенными последовательностями символов, которые ведомо не могут встречаться в тексте HTML-шаблона. Часто такие метки делают на манер HTML-тэгов, например:

<--MESSAGE-->, <-NAME-> и т.п.

Это необязательно, хотя психологически привычнее. Далее в данной статье я буду употреблять метки вида <-XXX->, где XXX-последовательность символов, которую будем называть "имя метки".

В Perl есть довольно полезные средства для обработки шаблонов - операторы поиска и замены и регулярные выражения.

 

2. Создаем блок вывода

Предположим, что создаем скрипт добавления записи в гостевую книгу, который выдает пользователю страничку подтверждения, содержащую вбитые пользователем данные (имя, страна проживания, адрес e-mail и сообщение).

Простейший блок вывода такого скрипта может выглядеть так:


#Читаем файл шаблона
open TF,"<template.txt";
sysread TF,$t,-s TF;
close TF;
$t=~s/<-NAME->/$name/g;     #Подставляем значение <-NAME->
$t=~s/<-EMAIL->/$eml/g;     #Подставляем значение <-EMAIL->
$t=~s/<-COUNTRY->/$ctry/g;  #Подставляем значение <-COUNTRY->
$t=~s/<-MESSAGE->/$msg/g;   #Подставляем значение <-MESSAGE->
print "Content-Type: text/html\n\n";
print $t;

Здесь предполагается, что в файле template.txt хранится шаблон вывода, а в переменных $name, $eml, $ctry, $msg хранятся определенные значения полей. Четыре оператора замены заменяют метки на определенные им значения. Параметр g означает "глобальная замена", т.е. каждая такая метка будет заменена определенным значением по всему шаблону, сколько бы раз она не встречалась.

Данным образом, шаблон может выглядеть, примерно, так:


<HTML>
<HEAD>
<TITLE><-NAME->, Ваша запись была успешно добавлена</TITLE>
</HEAD>
<BODY>
<B><-NAME->, Ваша запись была успешно добавлена в Гостевую книгу.</B>
<HR>
<P>Вы ввели следующие данные:
<P><B>Имя:</B> <-NAME->
<p><B>E-Mail:</B> <A href="mailto:<-EMAIL->"><-EMAIL-></A>
<P><B>Страна:</B> <-COUNTRY->
<P><B>Текст сообщения:</B><I><-TEXT-></I>
</BODY></HTML>

В этом шаблоне метка <-NAME-> встречается три раза, и везде при выводе будет заменена именем человека, оставившего запись.

Несколько необычно выглядит метка <-EMAIL-> внутри тэга <A href=...>. Однако метки можно вставлять в ЛЮБОМ МЕСТЕ HTML-документа, т.к. они будут заменены значениями ДО того, как документ будет выдан клиентской программе.

 

3. Метки "высокого" и "низкого" уровня

Теперь рассмотрим ситуацию, с которой можно столкнуться при создании реальных скриптов.

Допустим, мы хотим, чтобы значение <-NAME-> было ссылкой на E-Mail человека - чтобы, щелкнув по имени, можно было написать ему письмо.

Для этого можно изменить одну строчку рассмотренного выше шаблона следующим образом:

<P><B>Имя:</B><A href="mailto:<-EMAIL->"><-NAME-></A>.

Но в этом случае, если человек не ввел свой E-Mail, ссылка будет "пустая" и это будет выглядеть несколько некрасиво. Если мы хотим, чтобы имя человека служило ссылкой только в том случае, если он ввел адрес E-Mail, а в противном случае было просто текстом, то это надо сделать в самом Perl-скрипте - чтобы переменная $name уже содержала ссылку, если это нужно.

 


#"Художественно обрабатываем" имя для вывода
if ($eml ne ""){$name="<A HREF=\"mailto:$eml\">$name</A>"};

Однако, в двух других случаях использования метки <-NAME-> (в тэге <TITLE> и сообщении о добавлении записи) нам в любом случае нужен текст, без ссылки. Для этого надо для разных потребностей "завести" две разные метки, скажем, <-NAME-> для "текстового" имени и <-A_NAME-> для ссылки.

Вообще, если какие-то введенные значения обрабатываются "для красоты", предпочтительно иметь два набора значений - "обработанных" ("высокого уровня") и "необработанных" ("низкого уровня"), т.к. "голые", необработанные введенные значения всегда могут пригодиться.

 

4. Вложенные шаблоны

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

Здесь нам понадобятся уже два шаблона - отдельно шаблон страницы и шаблон записи.

 


open TM,"<msg.txt"; # Загружаем шаблон сообщения
sysread TM,$tm,-s TM;
close TM;

open TP,"<page.txt"; # Загружаем шаблон страницы
sysread TP,$tp,-s TP;
close TP;


#В массивах $name[], $eml[], $text[] хранятся имя, электронный адрес
#и собственно оставленное сообщение. В переменной $num-кол-во
#сообщений.

$m=""; #Инициализируем переменную для сообщений
for ($i=$num;$i<=0;$i--){
$m1=$tm;
$m1=~s/<-NAME->/$name[$i]/g;
$m1=~s/<-EMAIL->/$eml[$i]/g;
$m1=~s/<-TEXT->/$text[$i]/g;
$m=$m.$m1; #Формируем список сообщений
};
#
$p=$tp;
$p=~s/<-MESSAGES->/$m/g;
#
# ... Подстановка других меток, если нужно
#
print "Content-Type: text/html\n\n";
print $p;

В шаблоне page.txt хранится общий вид выдаваемой страницы. В том месте, где скриптом должны быть вставлены сообщения, стоит метка <-MESSAGES-> На это место будет вставлено нужное количество сообщений, сформированных по шаблону msg.txt.

 

5. Обработка шаблонов для случаев, если имена меток заранее неизвестны

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

Соответственно, замена меток с "жесткими" именами, как мы делали до этого, в таких случаях невозможна, однако выход есть. Предположим, что набор параметров вывода лежит в хэше %PARAM; тогда блок вывода можно сделать так:


open TF,"<template.txt";
sysread TF,$t,-s TF;
close TF;
#
# ... Замена "жестких" меток, если необходимо
#
# А теперь меняем динамические метки
$t=~s/<-(.*)->/$PARAM{}/gie;
print "Content-Type: text/html\n\n";
print $t;

Если в процессе замены "динамических" меток в шаблоне будут встречены метки, для имен которых нет значений в хэше, на их место будет подставлено нулевое значение (метка просто исчезнет). Поэтому метки с "жесткими" именами надо обрабатывать до меток с динамическими именами.

 

6. Поддержка единых элементов дизайна для страниц и скриптов

Многие сайты используют SSI для вставки единых элементов оформления на все страницы. Это дает возможность быстрой полной смены дизайна при необходимости.

Как известно, в сгенерированных скриптами страницах директивы SSI не работают, а следовательно, не будут они работать и в шаблонах вывода CGI скриптов. Однако некоторые функции SSI можно "поручить" самим скриптам, благодаря чему в шаблонах можно будет использовать ссылки на те же общие фрагменты, которые используются в HTML-страницах через SSI.

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

В большинстве случаев достаточно обработки наиболее часто используемой директивы <!--#include virtual="..."-->

Для этого в блоке вывода можно предусмотреть приблизительно такой код:


$base="/usr/home/site"; #"Базовый" путь к сайту.

#Загружаем файл шаблона
open TF,"<template.txt";
sysread TF,$t,-s TF;
close TF;

#Обрабатываем "инклюды"
$t=~s/<!--#include virtual="(.*)"-->/getfile()/ge;
#
# ... Здесь, если нужно, обрабатываем другие метки
#

#выводим страницу клиенту
print "Content-Type: text/html\n\n";
print $t;

sub getfile{
if (substr($_[0],0,1) eq "/"){$fn=$base.$_[0];}
else {$fn=$_[0];};
open F,"<$fn";
sysread F,$t,-s F; close F; return $t;}

В этом фрагменте оператор ~s заменяет определенную вышеуказанной SSI-директиве конструкцию на значение функции getfile, которая возвращает содержимое нужного файла. Аргументом для функции служит путь к файлу, "извлекаемый" из "SSI-директивы". Если этот путь начинается со слэша '/' ("корневая папка сайта"), то в его начало добавляется базовый путь к сайту из переменной $base. Параметр e оператора ~s указывает на то, что заменяемая строка является функцией, значение которой надо использовать для замены.

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


Hosting tools

Who's Online

Сейчас 17 гостей и ни одного зарегистрированного пользователя на сайте