Первый сайт на Perl

       

Пример создания собственного CGI-сценария



Пример создания собственного CGI-сценария

Программа должна декодировать полученные данные, проверять заполнение обязательных полей формы и правильность подтверждения пароля, в зависимости от результатов проверки формировать документ для отсылки клиенту. Сохраним сценарий в файле /cgi-bin/registrar, cgi. Полный маршрут к данному файлу определяется параметрами конфигурации Web-сервера. Местоположение каталога cgi-bin обычно указывается относительно корня дерева документов Web-сервера, а не корневого каталога файловой системы. Например, если корнем является каталог /home/httpd/htmi/, то файл сценария будет иметь маршрутное ИМЯ /home/httpd/html/cgi-bin

/registrar.cgi, которое в запросе клиента будет указано как /cgi-bin /registrar.cgi. В первом приближении текст сценария может выглядеть следующим образом.

#!/usr/bin/perl

print "Content-type:text/html\n\n"; $method = $ENV{'REQUEST_METHOD'}; if ($method eq "GET") { ^

$form_data = $ENV{'QUERY_STRING'}; } else {

read (STDIN, $form_data, $ENV{'CONTENT_LENGTH'}); }

$form_data =~ s/%(..)/pack ("C", hex ($l))/eg; $form_data =~ tr/+/ /; @pairs = split (/&/, $form_data); foreach $pair (Spairs) {

($name, $value)=split(/=/,$pair);

$FORM{$name}=$value;

Проверка заполнения обязательных полей

if (!$FORM{'regname'} I I !$FORM{'passwordl'}) { print «goback

<html>



<head><title>Невведенные данные </title></head>

<body><h2>Извините, Вы пропустили обязательные данные</п2>

<br>

<а href=" ">Попробуйте еше раз, пожалуйста</а>

</body>

</html> goback ;}

#Проверка правильности ввода пароля elsif ($FORM{'passwordl 1 } eq $FORM{'password2'}){ print«confirmation <htrml>

<head><title>no3flpaBnHeM!</titlex/head> <Ьойу><h2>Поздравляем! </h2><br>

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

</body>


Рис 15.5. Подтверждение регистрации
В противном случае формируется HTML-документ, предлагающий ввести пароль повторно (Рисунок 15.6). Этот новый документ содержит форму, в состав которой входят два видимых поля типа "password" — для ввода и подтверждения пароля, и скрытые поля типа "hidden" — для сохранения остальных данных, введенных при заполнении исходной формы. Каждое скрытое поле новой формы наследует у соответствующего поля исходной формы атрибуты name и value. Если эти данные не сохранить, то их придется вводить заново, принуждая пользователя повторно выполнять уже сделанную работу. Информация, сохраненная в скрытых полях, невидима пользователю и недоступна для изменения.
Рис 15.6. Повторное приглашение для ввода пароля
Культура Perl допускает различные уровни владения языком. В рассмотренном варианте использован минимальный набор средств. Очевидно, что часть кода, например, декодирование, требуется при обработке не только данной, но и любой другой формы. Естественным шагом в развитии исходного варианта сценария является выделение этой части в отдельную подпрограмму и предоставление доступа к ней другим сценариям. Для этого преобразуем исходный текст в соответствии с планом, изложенным в примере 15.7.
1. Часть исходного кода может быть использована другими CGI-программами. Преобразуем ее в отдельный модуль, сохраняемый в файле CGI__UTILS.pm.
package CGI_UTILS; require Exporter;
@ISA = qw(Exporter);
^EXPORT = qw(print_header process_input);
# Подпрограмма вывода заголовка ответа sub print_header {
print "Content-type: text/html\n\n"; } .
# Подпрограмма декодирования данных форьы sub process_input {
my ($form_ref)=(?_.;
my ($ form_data,@pai rs);
my ($temp)="";
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN,$form_data,$ENV{'CONTENT_LENGTH'}); } else {
$form_data=$ENV{'QUERY_STRING'}; }
$form_data=~s/%(..)/pack("c",hex($1))/ge; $form_data=~tr/+/ /; $form_data=~s/\n/\0/g; @pairs=split(/&/,$form_data); foreach $item(@pairs) {


($name,$value)=spl£t (/=/,$item) ; if (!defined($forih_ref->{$name})) <
$ form_ref->{Sname}=$value; } else {
$form_ref->{$name} .= "\0$value"; } }
foreach $item (sort keys %$form_ref) { $temp.=$item."=".$form_ref->{$item}."&";} return($temp); } 1;
2. Текст основного сценария обработки формы registrar.cgi преобразуем следующим образом:
#!/usr/bin/perl use cgi_utils;
my 8FORM, $file_rec; $file_rec=&process_input(\%FORM); ^Проверка заполнения обязательных полей
#if {$FORM{'regname'} eq "" $FORM{'passwordl'} eq "") { if (!$FORM{'regname'} !$FORMTpasswordl'}) {
print "Location: /goback.html\n\n"; }
#Проверка правильности ввода пароля
elsif ($FORM{'passwordl'} eq $FORM{'password2'}}{
print "Location: /confirmation.html\n\n";
open (OUTF, "»users");
print OUTF $file_rec, H \n";
close OUTF }
else {
&print_header; print«new_form
<html>
<head><title>Ошибка при вводе пароля</titlex/head>
<ЬойухпЗ>Введенные Вами значения пароля не совпадают
<br><forro method="get" action="/cgi-bin/registrar.cgi">
<pre>
Введите пароль: <input type="password" name="passwordl">
Подтвердите пароль: <input type="password" name="password2">
</pre> new_form / foreach $key ( keys %FORM) {
if ($key ne "passwordl" && $key ne "password2") {
print "<input type=\"hidden\' J name=$key value=$FORM{$key}>\n";
} } print«EndOfHTML
<br><br>
<input type="submit" value="OK">
<input type="reset" value="Отменить">
</form>
</body>
</html> EndOfHTML
} exit
3. В исходном варианте сценария в качестве ответов сервера при получении неполных данных и для подтверждения регистрации пользователя формируются виртуальные HTML-документы. В этом нет необходимости, так как они содержат только статическую информацию. Соответствующие фрагменты сценария преобразуем в HTML-код ротовых документов, которые сохраним в отдельных файлах. В основном сценарии в качестве ответа сервера возвращаются ссылки на эти документы.


Файл confirmation. html содержит документ, посылаемый клиенту в качестве сообщения об успешной регистрации:
<html>
<head><title>Пoздpaвляeм!</title></head> <body><h2>Пoздpaвляeм! </h2><br>
Ваша регистрация прошла успешно. Вы можете пользоваться нашей библиотекой. ..- -
<br>
Спасибо за внимание.
</body>
</html>
Файл goback.html содержит документ, посылаемый клиенту при получении неполных данных:
<html>
<head><title>Heпoлныe данные</^^1ех/пеай>
<body><h2>HsBHHMTe, Вы пропустили обязательные данные</h2>
<br>
<а href=" ">Попробуйте еще раз, пожалуйста </а>
</body>
</htral>
В приведенном тексте появились некоторые новые элементы, которые необходимо пояснить.
Подпрограмма process_input модуля cgi_utiis.pm передает декодированные данные через вызываемый по ссылке параметр — ассоциативный массив. [Кроме того, она возвращает при помощи функции return () те же данные, но в виде строки, состоящей из пар имя=значение, разделенных символом "&". Обратите внимание на то, как подпрограмма вызывается в основной программе:
$file_rec=sprocess_input(\%FORM);
В качестве аргумента ей передается ссылка на ассоциативный массив. В тексте подпрограммы появилась проверка наличия полей формы с совпадающими именами и разными значениями:
if (!defined($form_ref->{$name})) {
$form_ref->{$name}=$value; }
else { }}
Этот фрагмент необходим для того, чтобы правильно обработать следующую ситуацию из нашего примера. Выбраны несколько переключателей, определяющих языки, которыми владеет пользователь: русский, английский, французский. Так как соответствующие элементы формы имеют одинаковые имена name=language, то без проверки в ассоциативный массив %fcrm_ref, куда помещаются обработанные данные, попадет только информация от последнего обработанного Элемента name=language value=french. В Подобном случае обычное присваивание заменяется операцией присваивания с конкатенацией
$form_ref->{$name} .= "\0$value",
которая к переменной $fom_ref->{$name) добавляет нулевой символ и значение $value.
В основной программе registrar.cgi обратим внимание на то, как передается ссылка на готовый HTML-документ. Для этого вместо заголовка content-type: text/html выводится заголовок Location: URL, сообщающий серверу адрес документа.
Еще один новый элемент в основной программе — сохранение данных в файле с именем users.  


Содержание раздела