Практический Перл для начинающего
СОДЕРЖАНИЕ: Данная работа написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал WEB-сервером, а я, соответственно, WEB-мастером. Учиться принято на чужих ошибках и опыте, поэтому предлагаю Вашему вниманию свой опыт изучения Перла.Данная работа написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал 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=POWERDescription=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%EEDescription=%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; #обязательнаястрока
Вполе 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) )
{
# Если нет входных данных, то генерируем страницу с формой
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/p>
div align=left
table border=0 width=630 height=49
tr
td width=200 height=45/td
td width=430 height=45p align=centerimg src=../images/p>
alt=Книгажалоб WIDTH=258 HEIGHT=60/td
/tr
/table
/divdiv 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=toptable border=1 width=100% cellspacing=0
cellpadding=0
tr
td width=100%form name=GuestBook method=POST action=add_guestbook.pl
div align=leftpsmallЯ, input type=text name=Name size=20/small, smallпо
профессиипростой /smallinput type=text name=Work size=20, smallпосетив
данный сервер и ознакомившись с представленными
на нем материалами, хочу выразить свои чувства и
эмоции следующими приличными словами:/small/p
/divdiv align=leftpsmall/smallinput type=radio value=Good checked
name=RadioButtonsmallмнепонравилось :-)/small/p
/divdiv align=leftpsmall/smallinput type=radio name=RadioButton
value=Badsmallмненепонравилось :-( /small/p
/divdiv align=leftpinput type=radio name=RadioButton value=Differentsmallмне
пофигу :-| /small/p
/divdiv align=leftpsmallВ дополнение к сказанному хочу
так же сказать:/small/p
/divdiv align=leftptextarea rows=4 name=Text cols=30/textarea/p
/divdiv align=leftpsmallПрошу принять к рассмотрению
мое заявление и незамедлительно принять меры.
Решение по моему заявлению направить письменно
намойэлектронныйадрес /smallinput type=text name=Email
size=20small./small/p
/divdiv align=centercenterpinput src=../images/p>
alt=Послать border=0 type=image WIDTH=53 HEIGHT=21 a
href=read_guestbook.plimg src=../images/p>
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/p>
div align=left
table border=0 width=630 height=49
tr
td width=200 height=45/td
td width=430 height=45p align=centerimg src=../images/p>
alt=Книгажалоб WIDTH=258 HEIGHT=60/td
/tr
/table
/divdiv align=left
table border=0 width=630 height=53 cellspacing=0 cellpadding=0
tr
td width=200 height=260 valign=topp 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=topp align=leftsmallВынеуказали
свое имя, E-mail, либо не заполнили сам текст Вашего
отзыва. Вернитесь, пожалуйста, на страницу формы
и заполните требуемые поля./small/p
p align=centera 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/p>
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=45p align=center;
print img src=../images/td.\n ;
print /tr\n ;
print /table\n ;
print /divdiv 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=topp 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=topp align=centersmallВашиданные.\n ;
print приняты. Спасибо./small/p\n ;
print p align=centera href=read_guestbook.pl;
print img src=../images/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/p>
div align=left
table border=0 width=630 height=49
tr
td width=200 height=45/td
td width=430 height=45p align=centerimg src=../images/p>
alt=Книгажалоб WIDTH=258 HEIGHT=60/td
/tr
/table
/divdiv align=left
table border=0 width=630 height=53 cellspacing=0 cellpadding=0
tr
td width=200 height=260 valign=topp align=centersmall
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=topp 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 dtimg src=../images/p>
priny $item[6]. align=absbottom.\n;
# Выводим остальные поля.
print align=absmiddlesmall. .$item[4]./small/dt\n;
print dtsmall.$item[1]., .$item[2]./small/dt\n;
print dta href=mailto:.$item[5].small.$item[5]./small/a/dt.\n;
print dtsmall.$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;
# Закрываем файл с записями гостевой книги.
Список литературы
Александр Боровский . Практический Перл для начинающего.