Данная статья написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал WEB-сервером, только я, соответственно, WEB-мастером. Учиться принято на чужих ошибках также эксперименте, поэтому советую Вашему заботе свой эксперимент изучения Перла.

Сразу нужно пояснить, для кого это все написано. если Ваш сервер трудится на платформе UNIX, то это мы вынужден произносить Вашу статью. У меня же установлен Windows NT workstation 4.0 (RUS) плюс Service Pack 3. В какое время пришло пора сделать из компьютера WEB-сервер, мы было кинулся ко встроенным Службам узла WEB, но спешно осознал, что это мне никак не нравится (почему ?). И тут один добродушный индивид посоветовал поставить Xitami WEB Server от iMatix Corporation (www.imatix.com), какой также стоит по этот сутки.

Что дотрагивается самого Перла, то тут несколько сложнее. Покопавшись по различным Перловым серверам (www.perl.org , www.perl.com ) мы узнал, что версий Перла настолько немало, что выбрать что-нибудь конкретное достаточно сложно. При этом каких-нибудь вразумительных рекомендаций по поводу избрания той либо иной версии нигде нет. Перепробовав приблизительно все версии для Windows, мы остановил свой избрание на Active Perl.

Человеку, избалованному каждыми Виндовозами также Дельфями, строчить программы на Перл достаточно непривычно, поэтому настоятельно рекомендую разом установить Perl Builder. Взять его можно на www.solutionsoft.com. Там лежала тридцатидневная Демо разновидность.

Ну, думаю, пора переходить непосредственно к занятию. В общем случае, скрипт на Перл, как также любая другая программа, трудится так:

  1. получает данные
  2. обрабатывает данные
  3. выдает результаты

Передать данные скрипту можно дублем методами - GET также POST. Разность между ними в том, что при использовании GET данные безостановочно бездельничают в строке адреса браузера, напимер:

httр://treagraf.tasur.edu.ru/cgi-bin/price.pl?Category=POWER&Description=varta

В этом случае скрипт B_price.pl берет данные в переменной окружения QUERY-STRING.

$data=$ENV{'QUERY_STRING'};

При использовании метода POST данные передаются на стандартный вход скрипта. Длинна блока данных берется в переменной CONTENT_LENGTH:

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

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

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

http://treagraf.tasur.edu.ru/cgi-bin/B_price.pl?Category=%C2%E8%E4%E5%EE&Description=%E0%E1%E2%E3

Это значит:

http://treagraf.tasur.edu.ru/cgi-bin/B_price.pl?Category=Видео&Description=абвг

Декодировать строку запросов в главный однажды лучше самому. На задача "а как?" есть множество ответов, переписывать которые нет смысла. Приведу лишь только малый образец:

Заменяем знаки (+) на пробелы

$query = s/\+/ /g;

Потом заменяем все сочетания знака (%), позже которого следуют шестнадцатиричные цифры, на соответствующий символ ASCII

$query = s/%([0-9A-H]{2})/pack('C', hex($1))/eg;

Я использую тем, что советует Perl Builder:

#! E:\perl5\bin\perl &GetFormInput; # вызов подпрограммы получения данных $Category = $field{'Category'}; # приобретаем данные из поля Category $Description = $field{'Description'}; # приобретаем данные из поля Description $Page = $field{'Page'}; # приобретаем данные из поля Page

В конце скрипта размещаем подпрограмму "прозрачного" чтения данных.

sub GetFormInput { (*fval) = @_ if @_ ; local ($buf); if ($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN,$buf,$ENV{'CONTENT_LENGTH'}); } else { $buf=$ENV{'QUERY_STRING'}; } if ($buf eq "") { return 0 ; } else { @fval=split(/&/,$buf); foreach $i (0 .. $#fval){ ($name,$val)=split (/=/,$fval[$i],2); $val=tr/+/ /; $val= s/%(..)/pack("c",hex($1))/ge; $name=tr/+/ /; $name= s/%(..)/pack("c",hex($1))/ge; if (!defined($field{$name})) { $field{$name}=$val; } else { $field{$name} .= ",$val"; } } } return 1; }

Второй этап труда скрипта - отделка данных - полностью на Ваше усмотрение. Проверяйте полученные данные на правильность, пишите их в файл, делайте что хотите.

И, в конце концов, Вам нужно выдать какие-то результаты броузеру заказчика, причем так, чтобы броузер правильно их отобразил. То есть, выдавать результаты нужно в HTML. Это делается просто: (тоже можно по-разному)

print 'Content-type: text/html', "/n/n"; #обязательная строкаprint '

В поле Category Вы ввели: ', $Category, '

',"\n"

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

  1. При главном запуске скрипт рисует HTML страницу с формой также ссылкой в тэге ACTION на самого себя. Первый запуск определяется по неимению входных данных.
  2. Если входные данные есть, то приобретаем их, обрабатываем также выдаем результаты.

Пример:

#! E:\perl5\bin\perl if (($ENV{'QUERY_STRING'} eq '') or ($ENV{CONTENT_LENGTH}=0) ) { # генерируем страницу с формой } else {# приобретаем данные, обрабатываем также выдаем результат}

Гостевая книга

Общий алгоритм труда гостевой книги таков:

1. если посетитель хочет сделать запись в книгу, то
1.1 Получаем данные
1.2 Записываем их в файл либо в базу данных
1.3 Говорим спасибо на HTML также советуем чтить другие записи
2. если посетитель хочет чтить записи в книге, то
2.1 Читаем записи из файла либо из базы данных
2.2 Выводим их красиво в HTML

Для удобства восприятия мы оформил пункты 1 также 2 отдельными скриптами add_guestbook.pl также read_guestbook.pl соответственно. Сообщения гостевой книги хранятся в текстовом файле построчно, т.е. на каждую запись - строка. Так сделано для удобства чтения этого файла. Пример одной записи:

Sat Dec 5 13:31:20 1998&Наташа&студентка&Good&Для истока хорошо. Успехов на данном поприще Вам, Александр!&нету@пока&194.226.60.34

Вот описание полей рассматриваемой гостевой книги.
Name - имя, фамилия, отчество, кличка - на усмотрение посетителя
Work - профессия, семейство занятий
RadioButton - три кнопки: понравилось (Good), никак не понравилось (Bad), пофигу (Different)
Text - text box комментариев также примечаний
Email - обратный адрес

add_guestbook.pl - запись в книгу

#! e:\perl5\perl # Первая строка, как обычно require "ssi-pl.pl"; # Я использую навигационную панель в виде SSI-включения. Для этого используется модуль ssi-pl.pl if (($ENV{'QUERY_STRING'} eq '') or ($ENV{CONTENT_LENGTH}=0) ) { # если нет входных данных, то генерируем страницу с формой print <<head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"><meta name="GENERATOR" content="Microsoft FrontPage 3.0"><title>Книга жалоб также предложений</title></head><body background="../images/background_new.jpg"><div align="left"><table border="0" width="630" height="49"> <tr> <td width="200" height="45"></td> <td width="430" height="45"><p align="center"><img src="../images/guestbook.GIF" alt="Книга жалоб" WIDTH="258" HEIGHT="60"></td> </tr></table></div><div align="left"><table border="0" width="630" height="53" cellspacing="0" cellpadding="0"> <tr> <td width="200" height="260" valign="top"> <p align="center">HTML DoInclude("_menu.htm"); # Это SSI-включение навигационной панели. print <<HTML; </p> <p align="left"> </td> <td width="10" height="53" valign="top"></td> <td width="410" height="53" valign="top"><table border="1" width="100%" cellspacing="0" cellpadding="0"> <tr> <td width="100%"><form name="GuestBook" method="POST" action="add_guestbook.pl"> <div align="left"><p><small>Я, <input type="text" name="Name" size="20"></small>, <small>по профессии бесхитростный </small><input type="text" name="Work" size="20">, <small>посетив этот сервер также ознакомившись с представленными на нем материалами, хочу выразить свои чувства , эмоции следующими приличными словами:</small></p> </div><div align="left"><p><small> </small><input type="radio" value="Good" checked name="RadioButton"><small>мне понравилось Smile happy</small></p> </div><div align="left"><p><small> </small><input type="radio" name="RadioButton" value="Bad"><small>мне никак не понравилось Smile sad </small></p> </div><div align="left"><p> <input type="radio" name="RadioButton" value="Different"><small>мне пофигу :-| </small></p> </div><div align="left"><p><small>В дополнение к сказанному хочу так же сказать: </small></p> </div><div align="left"><p><textarea rows="4" name="Text" cols="30"></textarea></p> </div><div align="left"><p><small>Прошу принять к рассмотрению мое заявление также незамедлительно принять мерки. Решение по моему заявлению направить письменно на мой электрический адрес </small><input type="text" name="Email" size="20"><small>.</small></p> </div><div align="center"><center><p><input src="../images/send.JPG" name="Send" alt="Послать" border="0" type="image" WIDTH="53" HEIGHT="21">    <a href="read_guestbook.pl"><img src="../images/read.jpg" alt="Почитать" border="0" WIDTH="63" HEIGHT="21"></a></p> </center></div> </form> </td> </tr> </table> </td> <td width="10" height="53" valign="top"></td> </tr></table></div></body></html>HTML die; } # Нынче приобретаем входные данные. &GetFormInput; $Name = $field{'Name'} ; $Work = $field{'Work'} ; $RadioButton = $field{'RadioButton'} ; $Text = $field{'Text'} ; $Email = $field{'Email'} ; $Send = $field{'Send'} ; # это поле никак не используется # Проверяем, заполнены ли обязательные поля. # если нет - генерируем HTML страницу с прошением заполнить нужные поля. if ($Name eq '' || $Email eq '' || $Text eq '') { print <<HTML; Content-type: text/html <html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"><meta name="GENERATOR" content="Microsoft FrontPage 3.0"><title>Книга жалоб также предложений - ошибка</title></head><body background="../images/background_new.jpg"><div align="left"><table border="0" width="630" height="49"> <tr> <td width="200" height="45"></td> <td width="430" height="45"><p align="center"><img src="../images/guestbook.GIF" alt="Книга жалоб" WIDTH="258" HEIGHT="60"></td> </tr></table></div><div align="left"><table border="0" width="630" height="53" cellspacing="0" cellpadding="0"> <tr> <td width="200" height="260" valign="top"><p align="center">HTML DoInclude("D:/InetPub/wwwroot/_menu.htm"); print <<HTML; </p> <p align="left"> </td> <td width="10" height="53" valign="top"></td> <td width="410" height="53" valign="top"><p align="left"><small>Вы никак не указали свое имя, E-mail, или никак не заполнили самолично текст Вашего отзыва. Вернитесь, пожалуйста, на страницу формы также заполните требуемые поля.</small></p> <p align="center"><a href="add_guestbook.pl">Назад</a> </td> </tr></table></div><table> <tr> <td width="10" height="53" valign="top"></td> </tr></table></body></html>HTML } else # все данные правильно введены { # если все поля заполнены правильно, то затеваем их обрабатывать. $Text=tr/\r\n/ /; #заменяем перевод строки на пробел # если в текстовом поле формы (text box) посетитель нажимал Enter, # то нужно убрать символы перевода строки, чтобы можно было записать # все поля формы в одну строку файла. if ($Work eq '') {$Work=' '}; #если пусто - то пробел # если поле никак не заполнено, то оно равно пробелу. $Name=s/&/ /g; $Work=s/&/ /g; $Text=s/&/ /g; $Email=s/&/ /g; # если посетитель использовал символ &, то заменяем его на пробел, # поскольку этот символ мы будем использовать для деления наших полей в файле. open(OutFile, ">>guestbook.txt") || die; # Вскрываем файл для прибавления. $Time=localtime; #получаем время # Получаем пора заполнения гостевой книги. $line=join('&', $Time, $Name, $Work, $RadioButton, $Text, $Email, $ENV{REMOTE_HOST}); # И, в конце концов, слепляем все поля формы в одну строку. На каждый приключение добавляем в конце # IP адрес посетителя, взятый из переменных окружения. print OutFile "$line\n"; close OutFile; # Записываем полученную строку в файл также закрываем его. # Осталось только сказать посетителю спасибо. # выводим сообщение о успехе print "Content-type: text/html\n\n"; print "<html>\n" ; print "\n" ; print "<head>\n" ; print '<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">'."\n" ; print '<meta name="GENERATOR" content="Microsoft FrontPage 3.0">'."\n" ; print "<title>Книга жалоб также предложений</title>\n" ; print "</head>\n" ; print "\n" ; print '<body background="../images/background_new.jpg">'."\n" ; print '<div align="left">'."\n" ; print "\n" ; print '<table border="0" width="630" height="49">'."\n" ; print " <tr>\n" ; print ' <td width="200" height="45"></td>'."\n" ; print ' <td width="430" height="45"><p align="center">'; print '<img src="../images/guestbook.GIF" alt="Книга жалоб" WIDTH="258" HEIGHT="60"></td>'."\n" ; print " </tr>\n" ; print "</table>\n" ; print '</div><div align="left">'."\n" ; print "\n" ; print '<table border="0" width="630" height="53" cellspacing="0" cellpadding="0">'."\n" ; print " <tr>\n" ; print ' <td width="200" height="260" valign="top"><p align="center">'."\n" ; DoInclude("D:/InetPub/wwwroot/_menu.htm"); print ' <p align="left"> </td>'."\n" ; print ' <td width="10" height="53" valign="top"></td>'."\n" ; print ' <td width="410" height="53" valign="top"><p align="center"><small>Ваши данные'."\n" ; print " приняты. Спасибо.</small></p>\n" ; print ' <p align="center"><a href="read_guestbook.pl">'; print '<img src="../images/read.jpg" alt="Почитать" border="0" WIDTH="63" HEIGHT="21"></a> </td>'."\n" ; print " </tr>\n" ; print "</table>\n" ; print "</div>\n" ; print "\n" ; print "<table>\n" ; print " <tr>\n" ; print ' <td width="10" height="53" valign="top"></td>'."\n" ; print " </tr>\n" ; print "</table>\n" ; print "</body>\n" ; print "</html>\n" ; } # Не забываем подпрограмму разбора данных из формы. sub GetFormInput { (*fval) = @_ if @_ ; local ($buf); if ($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN,$buf,$ENV{'CONTENT_LENGTH'}); } else { $buf=$ENV{'QUERY_STRING'}; } if ($buf eq "") { return 0 ; } else { @fval=split(/&/,$buf); foreach $i (0 .. $#fval){ ($name,$val)=split (/=/,$fval[$i],2); $val=tr/+/ /; $val= s/%(..)/pack("c",hex($1))/ge; $name=tr/+/ /; $name= s/%(..)/pack("c",hex($1))/ge; if (!defined($field{$name})) { $field{$name}=$val; } else { $field{$name} .= ",$val"; #if you want multi-selects to goto into an array change to: #$field{$name} .= "\0$val"; } } } return 1; }

Вот также все. Пример труда описанного скрипта можно посмотреть на http://treagraf.tasur.edu.ru/cgi-bin/add_guestbook.pl

read_guestbook.pl - чтение книги

#! e:\perl5\perl # Первая строка, как обычно require "ssi-pl.pl"; # Я использую навигационную панель в виде SSI-включения. Для этого используется модуль ssi-pl.pl open(InFile, "guestbook.txt") || die; # Вскрываем файл с записями гостевой книги. @lines=<InFile>; # Читаем строки в массив. # Выдаем шапку HTML страницы. print <<HTML; Content-type: text/html <html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"><meta name="GENERATOR" content="Microsoft FrontPage 3.0"><title>Книга жалоб также предложений - нам пишут</title></head><body background="../images/background_new.jpg"><div align="left"><table border="0" width="630" height="49"> <tr> <td width="200" height="45"></td> <td width="430" height="45"><p align="center"><img src="../images/guestbook.GIF" alt="Книга жалоб" WIDTH="258" HEIGHT="60"></td> </tr></table></div><div align="left"><table border="0" width="630" height="53" cellspacing="0" cellpadding="0"> <tr> <td width="200" height="260" valign="top"><p align="center"><small>HTML DoInclude("D:/InetPub/wwwroot/_menu.htm"); print <<HTML; </p> <p align="left"> </td> <td width="10" height="53" valign="top"></td> <td width="410" height="53" valign="top"><p align="center">Нам пишут:</p> <table border="0" width="100%" cellspacing="0" cellpadding="0">HTML # Нынче выводим записи в невидимой (в смысле, рамка никак не видима) таблице. # Чтобы свежие записи отображать первыми, обрабатываем массив строк с конца. for ($i=$#lines; $i>=$[; $i--) #обрабатываем строки файла с конца { # Делим строку на элементы @item=split('&', $lines[$i]); #разделяем на элементы # Нынче заменяем HTML тэги в записи (на приключение какого-нибудь хитрого юзера) foreach (@item) { $_=s/</</g; $_=s/>/>/g; } # Приступаем непосредственно к заключению записей в HTML print "<tr>\n"; print '<td width="100%"><dl>'."\n"; # В зависимости от поля, в каком месте посетителю предлагался избрание понравилось - никак не понравилось, # рисуем картинку с радостной либо грустной мордочкой соответственно. В качестве ALT тэга # картинки пропишем IP адрес посетителя. print '<dt><img src="../images/'.$item[3].'.gif" width="31" height="31" alt="'; priny $item[6].'" align="absbottom"'."\n"; # Выводим остальные поля. print 'align="absmiddle"><small>'.' '.$item[4]."</small></dt>\n"; print '<dt><small>'.$item[1].',  '.$item[2]."</small></dt>\n"; print '<dt><a href="mailto:'.$item[5].'"><small>'.$item[5].'</small></a></dt>'."\n"; print '<dt><small>'.$item[0]."</small></dt>\n"; print "</dl>\n"; print "</td>\n"; print "</tr>\n"; } # Осталось вывести окончание HTML print <<HTML; </table> </td> <td width="10" height="53" valign="top"></td> </tr></table></div></body></html>HTML close InFile; # Закрываем файл с записями гостевой книги.