Практический Перл для начинающего

СОДЕРЖАНИЕ: Данная работа написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал 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; #обязательнаястрока

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/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;

# Закрываем файл с записями гостевой книги.

Список литературы

Александр Боровский . Практический Перл для начинающего.

Скачать архив с текстом документа