Шаг 156.
Создание собственного CGI-сценария (окончание)

    На этом шаге мы закончим создания сценария CGI.

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

  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,@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;
    

  2. Текст основного сценария обработки формы registrar.cgi преобразуем следующим образом: #! /usr/bin/perl
    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
    

  3. В исходном варианте сценария в качестве ответов сервера при получении неполных данных и для подтверждения регистрации пользователя формируются виртуальные HTML-документы. В этом нет необходимости, так как они содержат только статическую информацию. Соответствующие фрагменты сценария преобразуем в HTML-код готовых документов, которые сохраним в отдельных файлах. В основном сценарии в качестве ответа сервера возвращаются ссылки на эти документы.

        Файл 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";
которая к переменной $form_ref->{$name} добавляет нулевой символ и значение $value.

    В основной программе registrar.cgi обратим внимание на то, как передается ссылка на готовый HTML-документ. Для этого вместо заголовка content-type: text/html выводится заголовок Location: URL, сообщающий серверу адрес документа.

    Еще один новый элемент в основной программе - сохранение данных в файле с именем users.

    На следующем шаге мы рассмотрим модуль CGI.pm.




Предыдущий шаг Содержание Следующий шаг