На этом шаге мы закончим создания сценария CGI.
Культура Perl допускает различные уровни владения языком. В рассмотренном варианте использован минимальный набор средств. Очевидно, что часть кода, например, декодирование, требуется при обработке не только данной, но и любой другой формы. Естественным шагом в развитии исходного варианта сценария является выделение этой части в отдельную подпрограмму и предоставление доступа к ней другим сценариям. Для этого преобразуем исходный текст в соответствии с ниже изложенным планом.
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,@pairs); 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))/eg; $form_data =~ tr/+/ /; $form_data =~ s/\n/\0/g; @pairs = split (/&/, $form_data); foreach $item (@pairs) { ($name, $value)=split(/=/,$item); if (!defined($form_ref->{$name})) { $form_ref->{$name}=$value; } else { $form_ref->{$name} .= "\0$value"; } } foreach $item (sort keys %$form_ref) { $temp.=$item."=".$form_ref->{$item}."&"; } return($temp); } 1;
use CGI_UTILS; my %FORM, $file_rec; $file_rec=&process_input (\%FORM); #Проверка заполнения обязательных полей if (!$FORM{'regname'} || !$FORM{'password1'}) { print "Location: /goback.html\n\n"; } #Проверка правильности ввода пароля elsif ( $FORM{'password1'} eq $FORM{'password2'}) { print "Location: /confirmation.html\n\n"; open (OUTF, ">>users"); print OUTF $file_rec, "\n"; close OUTF; } else { &print_header; print <<new_form <html> <head><title>Ошибка при вводе пароля</title></head> <body><h3>Bвeденные Вами значения пароля не совпадают</h3> <br><form method="get" action="/cgi-bin/registrar.cgi"> <pre> Введите пароль: <input type="password" name="password1"> Подтвердите пароль: <input type="password" name="password2"> </pre> new_form ; foreach $key (keys %FORM) { if ($key ne "password1" && $key ne "password2") { print "<input type=\"hidden\" name=$key value=$FORM{$key}>\n"; } } print <<EndOfHTML <br><br> <input type="submit" value="OK"> <input type="reset" value="Отменить"> </form></body></html> EndOfHTML ;} exit
Файл confirmation.html содержит документ, посылаемый клиенту в качестве сообщения об успешной регистрации:
<html> <head><title>Поздравляем!</title></head> <body><h2>Поздравляем!</h2><br> Ваша регистрация прошл успешно. Вы можете пользоваться нашей библиотекой.<br> Спасибо за внимание. </body></html>
Файл goback.html содержит документ, посылаемый клиенту при получении неполных данных:
<html> <head><title>Неполные данные</title></head> <body><h2>Извините, Вы пропустили обязательные данные</h2> <br> Попробуйте еще раз, пожалуйста. </body></html>
В приведенном тексте появились некоторые новые элементы, которые необходимо пояснить.
Подпрограмма process_input модуля cgi_utils.pm передает декодированные данные через вызываемый по ссылке параметр - ассоциативный массив. Кроме того, она возвращает при помощи функции return() те же данные, но в виде строки, состоящей из пар имя=значение, разделенных символом "&". Обратите внимание на то, как подпрограмма вызывается в основной программе:
$file_rec=&process_input (\%FORM);
В качестве аргумента ей передается ссылка на ассоциативный массив. В тексте подпрограммы появилась проверка наличия полей формы с совпадающими именами и разными значениями:
if (!defined($form_ref->{$name})) { $form_ref->{$name}=$value; } else { $form_ref->{$name} .= "\0$value"; }
Этот фрагмент необходим для того, чтобы правильно обработать следующую ситуацию из нашего примера. Выбраны несколько переключателей, определяющих языки, которыми владеет пользователь: русский, английский, французский. Так как соответствующие элементы формы имеют одинаковые имена name=language, то без проверки в ассоциативный массив %form_ref, куда помещаются обработанные данные, попадет только информация от последнего обработанного элемента name=language value=french. В подобном случае обычное присваивание заменяется операцией присваивания с конкатенацией
$form_ref->{$name} .= "\0$value";
В основной программе registrar.cgi обратим внимание на то, как передается ссылка на готовый HTML-документ. Для этого вместо заголовка content-type: text/html выводится заголовок Location: URL, сообщающий серверу адрес документа.
Еще один новый элемент в основной программе - сохранение данных в файле с именем users.
На следующем шаге мы рассмотрим модуль CGI.pm.