WebClub - Всероссийский Клуб Веб-разработчиков
WebClub.RU » Архив » Практический Перл для начинающего

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


Дата публикации: 17-03-2013

Данная статья написана для людей, которым в силу непреодолимых обстоятельств приспичило срочно изучить Перл. Для меня таким обстоятельством стало то, что мой компьютер стал 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 (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"
    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;
# Закрываем файл с записями гостевой книги.

Популярное

Не так давно в сети появился новый сервис, под названием Dead Man Zero. Этот сервис сделал...
Рынок социальных площадок уже давно стал стабильным. Несмотря на то, что время от времени...
Artisteer 4 – единственный в своем роде продукт, позволяющий автоматизировать работу над созданием...
Февраль 2017 (3)
Январь 2017 (1)
Август 2016 (1)
Май 2016 (2)
Ноябрь 2015 (1)
Октябрь 2015 (1)

Карта сайта: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41

Друзья сайта

Хотите продать свой сайт?
- Мы быстро и удобно для Вас сможем его купить:
  • Заявка на продажу сайта
  • Раcсматриваем цены на каждый сайт в индивидуальном порядке.

    Случайная цитата

    Неизвестный автор:

    "Решение всех жизненных проблем находится в интернете. Надо только уметь хорошо искать."

    Опрос

    Какой антивирус Вы используете?

    Kaspersky Antivirus
    NOD32
    Norton Antivirus
    Dr.Web
    Panda
    Аvast!
    ClamWin
    Другой...