Модуль CGI.pm
Пример, рассмотренный выше, демонстрирует наивный подход, когда кажется, что все необходимые программы надо писать самостоятельно с самого начала. Но программирование CGI — это такая область, в которой Per] давно и активно применяется, и многое из того, что может потребоваться, уже давно кем-то написано. Надо только найти и использовать. В. данном разделе мы сделаем краткий обзор одного из таких готовых средств, предназначенных для поддержки разработки CGI-приложений.
Модуль CGI.pm, созданный Линкольном Штейном, входит в состав дистрибутивного комплекта Perl, начиная с версии 5.004, и его даже не нужно специально инсталлировать.
Этот модуль содержит большой набор функций для создания и обработки HTML-форм. Мы посвятили значительную часть предыдущего раздела изучению многочисленных тэгов, чтобы затем написать HTML-код для создания формы в примере 15.1. Модуль CGI позволяет сделать то же самое, но без использования HTML. С его помощью можно описать форму на языке Perl, используя вместо тэгов обращения к функциям модуля. В результате получится не документ HTML, а сценарий на языке Perl, который при вызове будет "на лету" генерировать HTML-форму и передавать серверу для отправки клиенту.
Модуль CGI является не просто модулем, а классом, что позволяет использовать преимущества объектно-ориентированного подхода. Модуль предоставляет пользователю на выбор два вида интерфейса с самим собой: процедурно-ориентированный и объектно-ориентированный.
При использовании процедурно-ориентированного способа работы с модулем CGI функции модуля нужно явным образом импортировать в пространство имен вызывающей программы, а затем обращаться к ним как обычно. В этом случае в вызывающей программе должны быть строки, аналогичные следующим:
#!/usr/bin/perl ; use CGI qw/:standard/; \ print header(), \
start_html('Пример формы'),
hi('Пример формы'),
Директива use импортирует в пространство имен вызывающей программы некоторый стандартный набор функций. Помимо него, существуют другие наборы функций модуля CGI. Их можно импортировать, указав имя соответствующего набора в списке импорта директивы use. Имена всех наборов можно просмотреть в файле CGI.pm, где они содержатся в хеш-массиве
%EXPORT_TAGS,
Функции header (), start_html О , hi () ЯВЛЯЮТСЯ функциями модуля CGI. Они будут рассмотрены ниже.
При использовании объектно-ориентированного интерфейса в директиве use вызывающей программы не нужно указывать список импортируемых имен функций. В этом случае взаимодействие с модулем CGI осуществляется через объект класса CGI, который нужно создать в вызывающей программе при помощи конструктора new (). Объектно-ориентированный вариант приведенного выше фрагмента выглядит следующим образом:
#!/usr/bin/perl
use CGI;
Squery = new CGI;
print $query->header(),
$query->start_html {'Пример формы'),
$query->hl ('Пример формы' ) ,
Замечание | |
Функции модуля CGI.pm являются методами класса CGI. Для того чтобы их можно было вызывать и как функции, и как методы, синтаксис не требует в качестве обязательного первого параметра указывать объект класса CGI. Поэтому в качестве функций к ним можно обращаться обычным образом, а как к объектам — только используя форму $object->method (). |
Будем для определенности использовать традиционный процедурно-ориентированный интерфейс. Рассмотрим следующий сценарий.
#!/usr/bin/perl
use CGI qw(:standard);
print header;
print start_html('Пример формы'),
h2('Регистрационная страница Клуба любителей фантастики'),
'Заполнив анкету, вы сможете пользоваться нашей электронной
"^библиотекой.',
br,
start_form,
"Введите регистрационное имя:",textfield('regname'),
P.
"Введите пароль: ", password_field(-name=>'passwordl',
-maxlength=>'8'),
Р,
"Подтвердите пароль: ", password_field(-name=>'password2',
-maxlength=>'8'),
Р/-
"Ваш возраст",
Р'
radio_group(-name=>'age',
-value=>['lt20','20_30', '30_50', 'gt50'],
-default=>'Lt20',
-labels=>{'It20'=>'flo 20', I 20_30'=>'20-30', 4> '30_50'=>'30-50','gt50'=>'старше 50'}),
br,br,
"На каких языках читаете:",
checkbox_group(-name=>'language', 4> -values=>
4>
['русский', 'английский' ,'французский', 'немецкий'],
^ -defaults=>['русский']), br,br,
" Какой формат данных является для Вас предпочтительным ", Ьг, popup_menu(-name=>'type',
-values=>['Plain text','PostScript','РОГ']), br,br, \
N
"Ваши любимые авторы:", x -~-_.
br,
textarea(-name=>'wish', -cols=>40, -rpws=>3),
br,
subrai t{-name=>'OK'), reset{-name=>'Отменить'),
end_form,
hr;
if (paramO) { print
"Ваше имя: ",em(param('regname')),
P,
"Ваш возраст: ", em(param('age')),
P, '
J
"Вычитаете на языках: ",em(join(", ",param('language'))),
P,
"Предпочтительный формат данных для Вас: ",em(param ('type')),
P,
"Ваши любимые авторы: ", em(join(", ",param('wish 1 ))),
hr; } print end_html;
Обсудим приведенный текст. Директива use, как мы отметили выше, осуществляет импорт стандартного набора функций модуля CGI.pm в пространство имен вызывающего пакета. В самом сценарии на месте тэгов исходного HTML-кода стоят обращения к функциям модуля: каждому тэгу соответствует вызов функции. Вызов функции модуля CGI можно осуществлять двумя способами: с использованием позиционных параметров print textfield('regname','начальное значение',50,80); с использованием именованных параметров
print textfield(-name=>'regname',
-default=>'начальное значение",
-size=>50,
-maxlength=>80);
Обработка позиционного параметра внутри функции зависит от его места в списке параметров. Обработка именованного параметра не зависит от его места в списке параметров. Функции модуля CGI могут иметь большое число параметров, порядок следования которых трудно запомнить, поэтому в этом модуле была реализована возможность вызова функций с именованными параметрами. Кроме того, применение именованных параметров делает текст программы более понятным. В тексте примера функции вызываются с именованными параметрами, если параметров больше одного. Познакомимся с функциями, использованными в примере.
print header(-type=>'image/gif',
-status=>'404 Not Found 1 );
Модуль CGI содержит методы (функции) для поддержки многих тэгов HTML2, HTML3, HTML4 и расширений, используемых в браузерах Netscape. Тэгам соответствуют одноименные методы модуля CGI.pm, имена которых записываются при помощи символов нижнего регистра. Если при этом возникают конфликты имен, в названия методов следует вводить символы верхнего регистра, как, например, в следующих случаях.
1. Название тэга <TR> совпадает с именем встроенной функции tr(). Имя соответствующего метода записывать в виде TR () или тг ().
2. Название тэга <PARAM> совпадает с именем собственного метода модуля CGI paramo. Для обозначения метода, соответствующего тэгу, использовать ИМЯ РАКАМ ().
3. Название тэга <SELECT> совпадает с именем встроенной функции select (). Для обозначения метода использовать имя Select ().
4. Название тэга <зив> совпадает с именем ключевого слова объявления функции sub. Для обозначения метода использовать имя sub ().
Тэгам, имеющим атрибуты, соответствуют методы, имеющие в качестве первого аргумента ссылку на анонимный хеш-массив. Ключами этого хеш-массива являются имена атрибутов тэга, а значениями — значения атрибутов.
Методы, соответствующие тэгам, и методы, предназначенные длячгенерирова-ния других элементов HTML-документа, возвращают строки, содержащие соответствующие элементы. Чтобы эти строки попали в создаваемый документ, их нужно вывести, как это делается в примере при помощи функции print.
В примере использованы следующие методы, соответствующие тэгам HTML.
Следующие функции используются для создания формы и ее элементов.
-action=>$action,
-encoding=>$encoding);
при помощи которых можно задать метод передачи формы Web-серверу (-method), программу, предназначенную для обработки формы (-action), и способ кодирования данных (-encoding). Все параметры являются необязательными. По умолчанию используются значения
method: POST;
action: данный сценарий;
encoding: application/x-www-form-urlencoded. П Функция end_form создает закрывающий тэг </FORM>.
textfieid (-name=>' field__name',
-default=>'starting value',
-size=>50,
-maxlength=>80);
Параметры соответствую^ атрибутам тэга. Обязательным является первый параметр. /
х. __ _ _^/
password_field(-name=>'secret',
-value=>'starting value',
-size=>8,
-maxlength=>12);
Параметры имеют тот же смысл, что и одноименные атрибуты соответствующего тэга. Обязательным является первый параметр.
radio_group(-name=>'group_name',
-values=>['bim',Jbam','bom'],
-default=>'bom',
-linebreak=>'true',
-lab.els=>\%labels) ;
Первый аргумент является обязательным, соответствует одноименному атрибуту тэга. Второй аргумент тоже обязательный и задает значения элементов. Эти значения отображаются в качестве названий кнопок. Он должен быть ссылкой на массив. Остальные аргументы являются необязательными. Третий аргумент задает кнопку, которая выбрана по умолчанию. Если значение четвертого аргумента 'true 1 , каждая следующая кнопка группы размещается в начале новой строки. Пятым аргументом является ссылка на хеш-массив, который связывает значения, присвоенные кнопкам, с метками, которые отображаются в виде названий кнопок. Если аргумент не задан, то в качестве названий отображаются сами значения.
checkbox_group(-name=>'group_name',
-values=>['bim','bam','bom'],
-default=>['bim','bom'],
-linebreak=>'true',
-labels=>\%labels);
Аргументы имеют тот же смысл, что и одноименные аргументы функции radio_group. Поскольку в группе переключателей можно одновременно выбрать несколько элементов, третий аргумент может быть или одиночным элементом, или ссылкой на массив, содержащий список значений, выбранных по умолчанию. Обязательными являются первый и второй аргументы.
popup_menu(-name=>'menu_name',
-values=>['bim', 'bam','bom'],
-default=>'bom r ,
-labels=>\%labels);
Первый аргумент задает имя меню. Второй аргумент является ссылкой на массив, содержащий список значений, присвоенных элементам меню. Первый и второй аргументы обязательны, остальные — нет. Третий аргумент задает элемент меню, выбранный по умолчанию. Четвертый 1 аргумент является ссылкой на хеш-массив. Хеш-массив значению каждого элемента меню ставит в соответствие строку, которая будет отображаться в меню для этого элемента. Если четвертый аргумент отсутствует, то для каждого элемента меню отображается его значение, заданное вторым аргументом.
textarea(-name=>'region',
-default=>'starting value',
-rows=>10,
-columns=>50);
Первый параметр, задающий имя элемента формы <ТЕХТДКЕА>, является обязательным, остальные — нет. Второй параметр задает строку, отображаемую по умолчанию. Третий и четвертый параметры задают соответственно число строк и столбцов, отображаемых в текстовом поле.
print $query->submit(-name=>'button_name', -value=>'value');
Первый параметр является необязательным. Он задает имя кнопки, которое отображается в качестве ее названия. Нужен только для переопределения названия Submit и в тех случаях, когда надо различать несколько имеющихся кнопок передачи. Второй параметр тоже необязательный. Он задает значение, которое посылается в строке запроса при щелчке на этой кнопке.
</HTML>.
Пример 15.8 содержит также код, который не связан с созданием формы Он состоит из одного условного оператора, в котором в качестве условия используется значение, возвращаемое функцией paramo. Эта функция используется также внутри блока условного оператора. Разберем для чего она применяется. При помощи функции paramo модуля CGI можно выполнить следующие действия.
Если сценарию переданы параметры в виде списка пар "имя=значение" функция paramo без аргументов возвращает список имен параметров сценария:
@names = param;
Функция paramo с единственным аргументом — именем параметра, возвращает значение этого параметра. Если параметру соответствует несколько значений, функция param о возвращает список этих значений:'
@values = param('language');
в противном случае — одно значение:
$value = param('regname');
param(-name => 'language', -values => ['russian', 'english', 'french']);
Можно задавать значения параметров, используя вызов функции param о в форме с позиционными параметрами, но тогда нужно знать порядок следования этих параметров:
param ('language', 'russian', 'english', 'french');
При помощи функции param о можно устанавливать начальные значения элементов формы или изменять ранее установленные значения.
Часть сценария, предшествующая условному оператору, предназначена для создания формы из примера 15.1. Заключительная часть, состоящая из условного оператора, обрабатывает заполненную и отправленную Web-серверу форму. Это происходит потому, что по умолчанию приложением, обрабатывающим форму, является данный сценарий (см. описание start__form). Таким образом, в одном сценарии содержится код, и создающий форму, и ее обрабатывающий.
Сохраним код, приведенный в примере 15.8, в файле welcome.cgi. Этот файл можно поместить на Web-сервере в стандартный каталог cgi-bin, предназначенный для хранения CGI-сценариев. Предположим, что Web-сервер имеет Internet-адрес www.klf.ru. Если из удаленного браузера послать запрос по адресу http://www.klf.ru/cgi-bin/welcome.cgi , то Web-сервер, получив запрос, выполнит сценарий welcome, cgi. Сценарий "на лету" создаст HTML-документ, содержащий форму, и передаст его Web-серверу, который отправит документ браузеру. Браузер, получив документ, отобразит его.
После заполнения формы и нажатия кнопки ОК данные формы будут вновь отправлены Web-серверу, который передаст их для обработки все тому же сценарию welcome.cgi. Сценарий "на лету" создаст новый HTML-документ с учетом полученных данных и через сервер направит его браузеру. Браузер отобразит новый документ.
Сценарий welcome.cgi можно передать для выполнения интерпретатору peri, а результат вывести в файл, чтобы посмотреть, как вызовы функций модуля CGI преобразуются в тэги HTML-документа. Документ HTML, созданный сценарием welcome.cgi, имеет следующий вид.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTMLXHEADXTITLE>npMMep <J>opMbi</TITLE> </HEADXBODY>
<Н2>Регистрационная страница Клуба любителей фантастики</Н2>
Заполнив анкету, вы сможете пользоваться нашей электронной библиотекой,
<BR>
<FORM METHOD="POST" ENCTYPE="application/x-www-form-urlencoded">
Введите регистрационное имя:<1ЫРит TYPE="text" NAME="regname" ><P>
Введите пароль: <INPUT TYPE="password" NAME="passwordl" MAXLENGTH=8><P>
Подтвердите пароль: <INPUT TYPE="password" NAME="password2" MAXLENGTH=8>
<Р>Ваш возраст<Р>
<INPUT TYPE="radio" NAME="age" VALUE="lt20" СНЕСКЕО>до 20
<INPUT TYPE="radio" NAME="age" VALUE="20_30">20-30
<INPUT TYPE="radio" NAME="age" VALUE="30_50">30-50
<INPUT TYPE="radio" NAME="age" VALUE="gt50">CTapnie 50
<BRXBR>Ha каких язьпсах читаете:
<INPUT TYPE="checkbox" NAME="language" УАШЕ="русский" СНЕСКЕП>русский
<INPUT TYPE="checkbox" NAME="language" УАШЕ="английский">английский
<INPUT TYPE="checkbox" NAME="language" УАьиЕ="французский">ф р анцузский
<INPUT TYPE="checkbox" NAME="language" VALDE="немецкий"Жемецкий
<BRXBR>
Какой формат данных является для Вас предпочтительным
<BRXSELECT NAME="type">
<OPTION VALUE="Plain text">Plain text
<OPTION VALUE="PostScript">PostScript
<OPTION VALUE="PDF">PDF
</SELECT>
<BRXBR>
Ваши любимые авторы:
<BRXTEXTAREA NAME="wish" ROWS=3 COLS=40X/TEXTAREA>
<BR>
<INPUT TYPE="sxobmit" NAME="OK" VALUE="OK">
<INPUT TYPE="reset" VALUE="Отменить">
<INPUT TYPE="hidden" NAME=".cgifields" VALUE="language">
<INPUT TYPE="hidden" NAME=".cgifields" VALUE="age">
</FORM>
<HRX/BODYX/HTML>
В действительности документ, созданный сценарием welcome. cgi, состоит из небольшого количества длинных строк, что связано с тем, как они формируются методами модуля CGI. Поэтому реально сформированный текст для удобства представлен в более структурированном виде. Но это единственное изменение, не влияющее на смысл автоматически созданного документа.