Данная работа написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал WEB-сервером, а я, соответственно, WEB-мастером. Учиться принято на чужих ошибках и опыте, поэтому предлагаю Вашему вниманию свой опыт изучения Перла.
Сразу нужно пояснить, для кого это все написано. Если Ваш сервер работает на платформе UNIX, то это я должен читать Вашу статью. Уменяжеустановлен Windows NT workstation 4.0 (RUS) плюс Service Pack 3. Когда пришло время сделать из компьютера WEB-сервер, я было кинулся ко встроенным Службам узла WEB, но быстро понял, что это мне не нравится (почему ?). И тут один добрый человек посоветовал поставить Xitami WEB Server от iMatix Corporation (http://www.imatix.com/), который и стоит по сей день.
Что касается самого Перла, то здесь несколько сложнее. Покопавшись по различным Перловым серверам (www.perl.org , www.perl.com ) я узнал, что версий Перла настолько много, что выбрать что-нибудь конкретное довольно сложно. При этом каких-нибудь вразумительных рекомендаций по поводу выбора той или иной версии нигде нет. Перепробовав почти все версии для Windows, я остановил свой выбор на Active Perl (http://www.activestate.com/).
Человеку, избалованному всякими Виндовозами и Дельфями, писать программы на Перл довольно непривычно, поэтому настоятельно рекомендую сразу установить Perl Builder. Взять его можно на www.solutionsoft.com. Там лежала тридцатидневная Демо версия.
Ну, думаю, пора переходить непосредственно к делу. В общем случае, скрипт на Перл, как и любая другая программа, работает так:
получает данные
обрабатывает данные
выдает результаты
Передать данные скрипту можно двумя методами - 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";
#if you want multi-selects to goto into an array change to:
#$field{$name} .= "\0$val";
}
}
}
return 1;
}
Второй этап работы скрипта - обработка данных - полностью на Ваше усмотрение. Проверяйте полученные данные на правильность, пишите их в файл, делайте что хотите.
И, наконец, Вам нужно выдать какие-то результаты броузеру клиента, причем так, чтобы броузер правильно их отобразил. То есть, выдавать результаты нужно в HTML. Это делается просто: (тоже можно по-разному)
print 'Content-type: text/html', "/n/n"; #обязательнаястрока
print '
Вполе Category Выввели: ', $Category, '
',"\n"
Все это касается скриптов, получающих данные из формы на странице HTML. При этом страница с формой - отдельно, скрипт - отдельно. Можно сделать красивее и удобнее: объединить страницу и скрипт в единое целое. Для этого скрипт пишется по схеме:
При первом запуске скрипт рисует HTML страницу с формой и ссылкой в тэге ACTION на самого себя. Первый запуск определяется по отсутствию входных данных.
Если входные данные есть, то получаем их, обрабатываем и выдаем результаты.
Пример:
#! 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>мнепонравилось :-)</small></p>
</div><div align="left"><p><small></small><input type="radio" name="RadioButton"
value="Bad"><small>мненепонравилось :-( </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"