http://www.nadomnik.by.ru/


Hello, Perl! Perl FAQ по-русски. Часть 8

Дмитрий Репин aka cmapuk[0nline]

Это последняя часть опуса "Hello, Perl!", посвященного "ЧастоЗадаваемымВопросам" по программированию на языке Perl.
В этой части мы рассмотрим несколько полезных, с моей точки зрения, модулей. На некоторых из них остановимся подробнее.

"Не виноватая я!..." Когда возникают ошибки в скрипте, может оказаться полезным действием проверка переменных окружения, состояния HTTP-заголовков и т.п. С проверкой переменных окружения сервера проблем возникнуть не должно.

#!/path/to/perl
print "Content-type:text/html\n\n";
grep print("$_=$ENV{$_}
"), keys %ENV;

С помощью LWP можно проверить и полный HTTP-ответ сервера клиенту. Эти данные можно взять из $result->status_line и $result->headers_as_string(). Но самое сложное - проверить, что передает броузер.

Для этого нам необходимо написать свой сервер. Нет ничего проще!

use Socket;
# Открываем потоковый (STREAM) сокет для протокола tcp
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
# Опции сокета. Чтобы не было тайм-аута между запусками сервера
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1);
# Привязываем дескриптор к порту и локальному адресу.
# Эта функция регистрирует сервер
bind(SOCK,sockaddr_in(80,INADDR_ANY));
# Ставим очередь на подключение с максимальным кол-вом подключений
listen(SOCK,SOMAXCONN);
print "Socket OK\n";
if(accept(CLNT,SOCK)){ # Если клиент с нами соединился
         print "Client accepted\n";
         open(F,">request.txt");
         while($line=){ # Читаем, что он пишет до "\n\n", и записываем в файл
                 $line=~s/\r//g;
                 last if $line eq "\n";
                 print F $line;
         }
         print "Client data OK\n";
         close(F);
         print CLNT "HTTP/1.0 200 OK Found\n". # Пишем ему ответ
                 "Accept-Ranges: bytes".
                 "Keep-Alive: timeout=15".
                 "Connection: Keep-Alive".
                 "Content-Length: 15".
                 "Content-type:text/plain\n\n".
                 "Hello!";
         print "Session finished";
         close(CLNT); # Закрываем все сокеты и выгружаемся
         close(SOCK);
         exit;
} # если вместо if(accept) while (и не закрывать сокет), то сервер не будет ждать
# запросов и по очереди их обрабатывать.


Теперь в файле request.txt лежит запрос, посланный броузером, и мы можем узнать, соответствует ли он принятым стандартам ;-). Ну и для примера напишем еще клиента для проверки ответа сервера, но уже с помощью IO::Socket;

use IO::Socket;


$sock=IO::Socket::INET->new(PeerAddr => '127.0.0.1',
                         PeerPort => 80,
                         Proto => 'tcp',
                         Type => SOCK_STREAM);
print $sock "GET / HTTP/1.0\n".
                 "User-Agent:Murzilla 3000\n".
                 "Connection: Keep-Alive\n\n";
open(F,">server_response.txt");
while($line=<$sock>){
         $line=~s/\r//g;
         next if $line eq "\n";
         print F $line;
}
close(F);
close($sock);

В файле server_response.txt будет ответ.

Теперь продолжим обзор других модулей.

Файловая рекурсия. Часто в программировании возникают задачи, требующие перебора целого дерева файлов. В этом случае без рекурсии обойтись практически невозможно. Что такое "рекурсия"?. Проще говоря, это когда какая-либо функция вызывает сама себя.

# %H - сложный многомерный хэш
hash_tree(\%H, 0); # Передаем ссылку в функцию и уровень вложенности 0
sub hash_tree{
         my($ref,$num)=@_;
         if(ref $ref){ # Если значение - ссылка, увеличиваем уровень на 1
                 $num++;
                 for(keys %$ref){ # И для каждого элемента по ссылке вызываем сами себя
                         hash_tree($ref,$num);
                 }
         }else{ # Если значение - не ссылка, пишем его со сдвигом слева,
                 # в зависимости от глубины вложенности $num
                 print ' ' x $num;
                 print "$ref\n";
         }
}

Чтобы не изобретать велосипед, для перебора файлового дерева можно воспользоваться модулем File::Recurse

use File::Recurse;
$MAX_DEPTH=100 # Глубина. По умолчанию - 100
$FOLLOW_SYMLINKS=0 # Следовать ли символическим ссылкам? По умолчанию - 0 (нет)
recurse { chmod 0666, $_ } "/home/users/vasya/public_files";

Опять картинки. Если вам нужно определить размер картинки или свойства GIF-файла или сграбить кучу картинок с сайта, то Вы можете воспльзоваться семейством модулей Image::***.

Image::Grab - Картинки из сети
Image::ParseGIF - Разбор гифа
Image::Size - Размер
Image::Magick - Рисовалка

Процессы. Для того чтобы манипулировать процессами, открывать файлы на запись и чтение (программы тоже), в Perl имеется множество возможностей. Кроме стандартного fork (который не работает в Win32) есть модули семейств IPC (InterProcessCommunication), Proc::***, Win32::Process, etc.

IPC::Open2 - Открытие (запуск) файла на чтение и запись
IPC::Open3 - То же, но еще с потоком для ошибок
Proc::Background - Процессы в "задней земле" ;-)
Proc::*** - Всяческие манипуляции с процессами
Win32::Process - Процессы в Win-системах
Parallel::ForkManager - Название говорит за себя

Вот пример, взятый из Perl CookBook, показывающий, как запустить приложение Perl/Tk без окна DOS

use Win32;
use Win32::Process;
Win32::Process::Create($Win32::-Process::Create::ProcessObj,
                         'd:\perl\bin\perl.exe', # Путь к Перлу
                         'perl ./GUIperldoc.pl', # Строка запуска "perl имяПрограммы"
                         0,DETACHED_PROCESS,".")||
                         die Win32::FormatMessage(Win32:-:GetLastError());

Снова про Сеть. Для получения какой-либо полезной информации из Сети, кроме различных модулей типа Mail::***, News::*** и т.п., в Perl имеются модули, являющиеся практически готовыми клиентскими программами, предоставляющими разработчику скриптов свой интерфейс. Я говорю о модулях семейств WebFetch::*** и WWW::Search::***. WebFetch - это модули для скачивания различных новостей и т.п. информации. Например, WebFetch:: DebianNews, WebFetch::PerlStruct и другие. Название расширения WebFetch::*** говорит само за себя. То же относится и к расширениям WWW::Search:::***.

WWW::Search::AltaVista - Работа с поисковиком
WWW::Search::Excite - - || -
WWW::Search::Google - - || -

Кроме того, модули WWW::*** помогут вам написать робота, работать с WWW-конференциями и т.д.

Проверим, есть ли в поисковике Altavista ссылки на perl.ru =)

use WWW::Search;
$search = new WWW::Search('AltaVista');
$search->native_query(WWW::Search-::escape_query("\"perl.ru\""));
while (my $result = $search->next_result()){
         print $result->title, "\n", $result->url, "\n\n";
}
Regexp. Для того чтобы создать регулярное выражение для определенного списка строк, можно это сделать вручную. Но если знаний в области regexp маловато и список слишком велик, то воспользуйтесь модулем Regex::PreSuf. Вот пример из документации по этому модулю:
use Regex::PreSuf;
$re = presuf(qw(foobar fooxar foozap));
print $re;

Еще один полезный модуль - Regexp::Shellish - регулярные выражения а-ля консоль. А вы не знали, что в консоли есть регексп? Теперь знаете ;-)

Работа с Win32. Для работы в Win32 есть большое семейство Win32::***. Кроме того, есть модули Win32API, Script, etc. Модули Win32::*** предоставляют широкий интерфейс для программирования приложений под эту ОС. Здесь есть возможности работы с реестром, WinAPI, OLE, DDE, ASP, ODBC, файловой системой, процессами, сервисами, возможности администрирования и многое другое. Модуль Script - это модуль для написания административных скриптов для управления логином системы, запуском приложений.

# Читаем Clipboard
use Win32::Clipboard;
$clp = Win32::Clipboard();
print "Clipboard: ", $clp->Get(), "\n";
# Ставим атрибуты файлам
use Win32::File;
SetAttributes($filename, HIDDEN);
# В Сети через Wininet.dll
use Win32::Internet;
$www = new Win32::Internet();
$url = $www->OpenURL("http://www.comprice.ru";);
$html = $url->ReadFile();
$url->Close();
# Список юзеров (текущий домен)
use Win32::NetAdmin qw(GetUsers);
my %users;
GetUsers("", FILTER_NORMAL_ACCOUNT , \%users);
grep print("User:$_ Name:$users{$_}\n"), keys %users;
# Список сервисов (NT only)
use Win32::Service;
GetServices("",\%servs);
grep print("Service:$_ Name:$servs{$_}\n"), keys %servs;
# Играем музыку
use Win32::Sound;
Win32::Sound::Volume('100%');
Win32::Sound::Play("supermusic.wav");
Win32::Sound::Stop();
# Работаем с MS Excel через OLE (Лучше Perl, чем экселевские макросы ;-))
use Win32::OLE;
$xlfile="E:\\Programming\\-Perl\\XL\\test.xls";
$xl=Win32::OLE->GetObject($xlfile);
$sheet=$xl->Worksheets(1);
$sheet->Cells(1,1)->{Value}="Hello,Perl!";
$sheet->Range("A2:C2")->{Value}=(["PerlFAQ", "by cmauk[0nline]" ,"cmapuk\@pisem.net"])
$sheet->SaveAs("newtest.xls");

Так что Perl - это не только Unix, как думают многие. C помощью этих модулей можно автоматизировать рабочие процессы (c Excel, Access и другие), администрирование и многое другое.

Всяко-разно

MP3::Tag - Модуль для манипуляций с тэгами в mp3-файлах. В этих тэгах содержится такая информация, как название композиции, автор и прочее. Если вы храните на сайте mp3-файлы - этот модуль вам будет полезным =).

use MP3::Tag;
$mp3 = MP3::Tag->new($filename);
$mp3->getTags;
print $mp3->{ID3v1}->song;
PostScript::*** - модули для работы с PostScript-файлами. Для тех, кто занимается паблишингом и не только.
Sort::*** - модули для всевозможной сортировки. Очень полезны.
@lines=("010 Vasya Pupkin user",
         "010 Pasha Urodov master",
         "010 Kevin Mitnikov admin",
         "010 Masha Pupkina user");
use Sort::Fields;
@sorted = fieldsort [3], @lines;
print join("\n",@sorted);

Вот так можно отсортировать строки по третьему слову, в данном случае по фамилии.

Spreadsheet::*** - Модули для работы с файлами Excel
Term::*** - Семейство модулей для работы с терминалом. Цветной вывод, чтение символа после нажатия клавиши и тому подобные возможности.
URI::*** - модули для манипуляций с адресами. Поиск адресов в тексте, разбор адреса, управление букмарками Нетскейпа и многое другое.
VRML::*** - Для тех, кто занимается моделированием виртуальной реальности на языке VRML. Есть возможности работать как с VRML1.0, так и с версией 2.0 этого языка.
XBase - Интерфейс к dbf-файлам баз данных. Простой и удобный интерфейс.
XML::*** - Большое семейство модулей для работы со стандартом XML.
XML::Generator - Генератор XML
XML::Parser - Парсер XML-данных
XML::Writer - Писать XML-файлы
use XML::Writer;use IO;
my $output = new IO::File(">output.xml");
my $writer = new XML::Writer(OUTPUT => $output);
$writer->startTag("hello",
         "class" => "simple");
$writer->characters("Hello, Perl!");
$writer->endTag("hello");
$writer->end();
$output->close();

Ну все. Хорошего понемножку. PerlFAQ по-русски версии 1.0 закончен. Жду предложений, пожеланий, критики и другой полезной информации на e-mail. В этой статье рассмотрены далеко не все вопросы о Perl, в частности о Regexp. Это оставим для следующих версий. А пока, присылайте комментарии.

Спасибо за внимание.

При написании статьи использовались материалы из документации Perldoc, книги "Perl Cook Book".

Источник: "Компьютер Price", http://www.comprice.ru

 


Copyright © "Internet Zone", http://www.izcity.com/, info@izcity.com