Язык программирования Perl является основным средством разработки CGI-скриптов для Web-узлов. Его не применяют только там, где требуется высокая эффективность кода и нет стандартных библиотек для Perl.
Perl как язык разработки скриптов имеет ряд преимуществ. Перечислим их в порядке значимости:
Все это делает программное обеспечение, написанное на Perl, мобильным, а разработку программ — быстрой и простой.
У программы на языке Perl нет жестко заданной структуры. Точнее
сказать, программист не обязан ее соблюдать. Если же он захочет, чтобы
интерпретатор контролировал объявление и использование переменных и
конструкций языка, то при помощи класса strict он может такой контроль
установить.
Программа на Perl состоит из операторов языка, которые должны заканчиваться символом ";". Например:
print "Привет, Perl.";
В общем случае операторы делятся на простые и составные. Простой оператор —
это оператор print, например, а составной — while():
while() {s/</lt;/g; s/>/gt;/g; print $_;};
Программа на Perl исполняется интерпретатором Perl. Есть и компиляторы с этого языка, но они используются реже. При программировании CGI-скриптов в Unix интерпретатор вызывается из того же файла, который содержит программу, например:
#!/usr/local/bin/perl print "Привет, Perl.";
В данном случае первая строка — это вызов интерпретатора с указанием полного пути к нему от корневого каталога файловой системы.
Вообще говоря, символ "#" — это символ начала комментария в Perl. Последовательность символов от символа "#" до конца строки рассматривается как комментарий. Часто в качестве комментария используют целые строки. В этом случае символ "#" ставится в первой позиции строки:
#!/usr/local/bin/perl # #Печатаем HTML-заголовок # print "Content-type: text/html\n\n"; # #Содержание документа # print "Perl и CGI.";
Данный пример демонстрирует не только использование комментариев, но еще и формирование HTTP-заголовка. Без этого заголовка система выдаст сообщение о внутренней ошибке сервера, а в файле журнала ошибок появится запись о неправильном заголовке.
В последнее время основным рабочим местом авторов HTML-страниц и
CGI-скриптов стали системы на платформе Windows. Как известно, конец
строки в Windows и в Unix обозначается разными последовательностями
неотображаемых символов. Если автор использует текстовый редактор в
Windows, а потом как binary копирует файл в Unix, то эти символы
передаются. Сервер начинает сообщать об ошибках, которые автору не
видны. В таком случае можно сделать следующее: либо копировать
программы как char, тогда происходит перекодировка, либо использовать
"умные" текстовые редакторы.
Удобна также и Samba, которая позволяет редактировать "по месту" из Windows в Unix.
Основная цель создания CGI-скрипта — обработка данных запроса пользователя и формирование отклика сервера на этот запрос. Можно рассматривать и другие задачи, которые позволяют решать CGI-скрипты, но эта задача — главная. Скрипт должен формировать не просто отклик, а HTTP-отклик. Это означает, что он должен сформировать заголовок и тело HTTP-сообщения, которые отделяются друг от друга пустой строкой.
Проще всего реализовать такой отклик с помощью команды print:
#!/usr/local/bin/perl print "Content-type: text/html\n\n"; print "<HTML><HEAD></HEAD><BODY>"; print "<H1>Perl и CGI.</H1>"; print "</BODY></HTML>";
Первая строчка определяет заголовок HTTP-отклика и пустую строку
(два символа "\n\n"). Остальные операторы print формируют тело
сообщения. Оператор print пишет в print можно использовать для
вывода данных в любой файл. Если имя файла не указано, то вывод
осуществляется в
Скрипт порождается сервером в некоторой операционной среде. Эта
среда называется окружением (environment). Частью окружения являются
так называемые
В Perl существует встроенный системный массив %ENV. Символ "%" перед именем массива означает, что это массив
ассоциативный, т.е. значение элемента массива может быть выбрано путем
указания ключа, с которым оно связано. Например, нужно определить метод
доступа к скрипту:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "REQUEST_METHOD:$ENV{REQUEST_METHOD}";
В данном контексте символ "$" перед именем массива не должен вводить в заблуждение. Обращение происходит к элементу ассоциативного массива. Это скаляр, поэтому и применяется символ "$". Ключ, по которому выбирается значение, указан в фигурных скобках.
Очень полезен скрипт распечатки всех perlenv2.htm ). Обычно этот отчет получают при отладке
HTML-форм:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
foreach $hkey (keys %ENV)
{
print "$hkey:$ENV{$hkey}"\n;
}
Этот простой скрипт распечатывает значения всех foreach.
В этом цикле переменная цикла hkey
пробегает по всем уникальным ключам (именам keys.
Когда пользователь работает с операционной средой в режиме удаленного алфавитно-цифрового монитора, он пользуется услугами оболочки (shell). Команды в операционной среде в этом случае вводятся в командной строке, и за каждой из команд может тянуться шлейф аргументов. Эти аргументы и называются аргументами командной строки.
CGI-скрипт вызывается не из оболочки, а загружается HTTP-сервером.
Если необходимо воспользоваться аргументами командной строки, то сервер
должен породить данную командную строку тоже. В CGI это делается только
для запросов ISINDEX. В таком случае скрипт вызывается через URI типа:
http://my.intuit.ru/directory/
script?arg1+arg2+arg3
В этой записи arg1+arg2+arg3 — аргументы командной строки скрипта, т.е.
данный URI равнозначен вводу в командной строке команды:
host>script arg1 arg2 arg3
Для приема этих аргументов достаточно воспользоваться скриптом типа:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
foreach $arg (@ARGV)
{
print "$arg\n";
}
В данном случае мы просто их распечатаем. Программа будет выбирать
по одному аргументу из системного массива аргументов командной строки @ARGV и помещать их в переменную $arg, а затем печатать.
В принципе, аргументы попадают и в , т.к. при запросе типа ISINDEX применяется метод GET. Но
тогда придется данную переменную разбирать. Аргументы командной строки
уже сделали эту работу за программиста.
Поток STDIN. В Perl применяется то же самое имя.
Для построчного чтения входного потока в Perl применяется пара символов "<>". Простая программа, читающая входной поток, может выглядеть следующим образом:
#!/usr/local/bin/perl
while(< >)
{
print $_;
}
В данном примере две скобки подряд определяют чтение из потока $_ обозначает
системную переменную, в которую по умолчанию помещается каждая
считанная из
Согласно спецификации CGI, скрипт получает данные через POST. Приведенный выше пример работы со EOF (End
of file, конец файла). Цикл while в этом случае будет бесконечным.
Скрипт сам определяет точное количество байтов, которые он должен
прочитать из CONTENT_LENGTH ( perlm1.htm ):
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "CONTENT_LENGTH=$ENV{CONTENT_LENGTH}";
Когда число байтов для чтения из потока read:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "CONTENT_LENGTH=$ENV{CONTENT_LENGTH}\n";
read STDIN,$query,$ENV{CONTENT_LENGTH};
print "Query:$query.";
После выполнения этих несложных операций в переменную $query будет
занесено содержание
В Perl существует довольно своеобразный набор типов данных: скаляры,
одномерные массивы (массивы), ассоциативные массивы (хешированные
таблицы или хеши), глобальные символы, ссылки. Обычно первых трех для
CGI-программирования вполне хватает. Ссылки применяют в совокупности со
стандартными библиотеками и вместо функции отложенного выполнения eval.
Глобальные символы нужны при работе с файлами или для межпроцессного
обмена данными при открытии каналов (потоков данных) через дескрипторы.
Скаляры — это все, что нельзя записать в виде массива или структуры. Числа всех типов и строки символов относятся к скалярному типу. Скаляр обозначается символом "$" перед именем. Примеры скаляров:
$a = 1; $b = 2.5; $str = "это строка символов";
Массивы — это множество элементов, причем все элементы могут быть
разнородными. В Perl нет понятия массива чисел или массива строк.
Массив не может быть многомерным. Можно реализовать
@a = (1,2,3); @b = (4,5,6,2.5,"test"); @c = (@a,@b); @in = $q = $c[3]; # 4
Индексирование элементов массива начинается с цифры 0. Поэтому в
нашем примере четвертый элемент массива с будет индексироваться как $c[3].
Ассоциативные массивы — это двухколоночная таблица. Первая колонка — ключ, а вторая колонка — связанное с ним значение. Ассоциативные массивы называют еще хешированными таблицами или просто хешами. Дело в том, что значение можно извлечь из таблицы прямо, указав ключ. При этом используется алгоритм хеширования по ключу.
Для краткости будем называть ассоциативный массив хешем. Обозначается переменная типа хеш символом "%" перед именем. Примеры хешей и обращений к их элементам:
%a = ("test",1,"test2",2);
$c = $a{test}; # $c=1
В первом случае хеш инициируется как обычный массив. Во втором
примере мы выбираем значение определенным ключом " test ". Результат этой
операции, скаляр, помещается в переменную $c.
Указатели — это аналог адресных указателей в С. Указатель обозначается символом "\" перед именем переменной:
$a = 1; $p = \$a; @b = (1,2,3); $p = \@b; $p = \%c;
Обращения к значениям, выбранным указателем, являются аналогом применения
функции eval (отложенное исполнение):
%a = ("test",1,"test2",2);
$p = \%a;
$c = $$p{"test"};
где вместо " а " используется $p.
Последнее, что мы рассмотрим — это дескрипторы потоков данных. Дескриптор потока указывает на структуру, которая описывает механизм обмена данными, например, с файлом. Применяются такие дескрипторы в функциях чтения и записи данных и в межпроцессном обмене:
open IN; read IN,$p,500; close IN;
В данном случае IN — дескриптор файла.
Самым интересным средством Perl является механизм регулярных
выражений, сравнение с образцом и подстановки, которые он унаследовал
от таких типичных для Unix-систем утилит, как awk и sed.
Операция сопоставления с образцом задается как "=~":
$query =~ /target/;
В данном случае в скаляре $query отыскивается подстрока
" target ". С
операцией "=~" связано два действия по умолчанию. Во-первых, операция
сопоставления в полной форме будет записана как
$query =~ m/target/;
То есть перед шаблоном используется префикс m. Во-вторых, если
опустить $query, то образец будет сопоставляться с содержанием
системной переменной $_:
/target/;
Операция "=~" возвращает значение "истина"( true ), если образец был
найден, и "ложь"( false ), в противном случае. Из этого следует, что
данную операцию можно использовать в операторах ветвления:
if($query =~ /target/)
{
print $query;
}
В данном случае, если образец содержится в $query, то запрос печатается,
не содержится — пропускается при печати.
При сопоставлении с образцом одновременно осуществляется разбор
запроса: шаблон попадает в переменную $_, часть строки до найденного
шаблона — в $`, а после образца — $'. Но для программирования разбора
данных из формы больше подойдет следующий пример ( perlexp1.htm ):
http://intuit.ru/scripts/ script?n1=v1n2=v2n3=v3 ... ($v1,$v2,$v3) = ($query =~ /^n1=(.+)n2=(.+)n3=(.+)$/); print $v1,$v2,$v3;
В переменные $v1 — $v3 будут записаны значения полей n1-n3,
соответственно. При этом символ "^" означает, что весь шаблон должен
стоять вплотную к началу строки. Символ "$" в конце шаблона означает,
что шаблон должен распространяться на всю строку до конца. Символ "."
означает любой символ, входящий в таблицу символов, "+" означает любое
количество этих символов, но не менее одного.
Еще более мощным средством является подстановка, которая базируется
на s%
$query =~ s/intuit/ruru/;
В данном случае, если в строке будет найден шаблон intuit, он будет
заменен на ruru. Наиболее очевидной областью применения подстановки
является перекодировка запросов form-urlencoded:
$query =~ s/%(.{2})/pack('c',hex($1))/eg;
Спецсимволы и символы из второй половины таблицы ASCII при передаче трансформируются в шестнадцатеричные описания байтов (две цифры), следующие после символа "%".
Под управлением потоком вычислений понимают способность программы в
зависимости от условий выполнять те или иные части кода и повторять
различные части кода. Для этой цели в Perl включены такие операторы как goto, next, last, redo, if, while, for, foreach и другие.
Оператор goto позволяет перейти к исполнению оператора Perl,
выделенного меткой, которая указывается в качестве аргумента оператора goto:
while()
{
if(/the end/) {goto out;};
}
out: print "the_end\n";
В данном случае выход из цикла осуществляется по оператору goto.
Вслед за всеми современными учебниками, напомним, что использование goto — это плохой стиль программирования. Метка в Perl задается как
строка, за которой вплотную следует символ двоеточия(":").
В нашем примере встретилось еще несколько while. While определяет
цикл, который исполняется до тех пор, пока значение выражения,
указанного в качестве аргумента оператора while, — "истина". Пример:
while(not($line =~ /the_end/))
{
$line = <>;
print "No\n";
}
print "the_end\n";
В данном случае оператор goto не используется. Выход из цикла
осуществляется по условию вхождения подстроки the_end в строку ввода.
Вхождение проверяется путем сопоставления с образцом. Входная строка
считывается из <> ).
Оператор for — это традиционный оператор цикла. Типовая схема
применения данного оператора может быть показана на следующем примере:
for($i=0;$i<CONTENT_LENGTH;$i++)
{
$query[$i] = getc;
}
$q = join (@query);
print $q;
Здесь данные в цикле считываются посимвольно из @query. Число символов,
которые нужно считать,
определяется переменной окружения CONTENT_LENGTH. После завершения
ввода массив объединяется в строку $q при помощи функции join. Наиболее
типичной ошибкой при использовании оператора for является отсутствие
символа " $ " у переменной цикла. Все три аргумента оператора for могут быть выражениями соответствующего типа.
Оператор foreach позволяет организовать цикл путем перебора
элементов списка. В качестве такого списка можно использовать массив:
foreach $arg (@ARGV)
{
print $arg;
}
В данном случае переменная цикла $arg пробегает по всем аргументам
командной строки скрипта, которые задаются встроенным массивом @ARGV.
Аналогично можно пройти и по всем переменным окружения:
foreach $arg (keys %ENV)
{
print "$arg:$ENV{$arg}\n";
}
Отличие данного примера от предыдущего заключается в том, что
переменные окружения представляют собой хеш. Поэтому сначала получаем
массив ключей (имен переменных окружения), переменная $arg пробегает по
этому массиву, и в цикле печатаются пары "имя переменной — значение
переменной".
После goto и операторов цикла следует остановиться
на операторе if.
Данный оператор позволяет организовать ветвление программы или, как это
еще называют, условное исполнение отдельных ее частей. Примером может
служить скрипт обработки данных, которые могут доставляться как по
методу GET, так и по методу POST:
if ($ENV{REQUEST_METHOD} =~ /POST/)
{
read STDIN,$query,$ENV{CONTENT_LENGTH};
}
else
{
$query = $ENV{QUERY_STRING};
}
В данном случае анализируется значение . В зависимости от ее значения либо включается чтение
данных из .
Если оператор goto не применять (концепция структурного
программирования), то при работе с циклами нужно обрабатывать ситуации
пропуска конца тела цикла и досрочного выхода из тела цикла. Пропуск
операторов конца тела цикла осуществляется при помощи оператора next:
foreach $arg (@strings)
{
if(!($ENV{REMOTE_HOST} =~ /\.intuit\.ru/))
next;
print $arg;
}
Здесь фрагмент скрипта печатает значения массива @string, только
если скрипт вызван с компьютера из домена intuit.ru. Машина
пользователя будет прописана в этом домене только в том случае, если
она прописана в nslookup ).
Досрочный выход из тела цикла производится по оператору last. Обычно
такой выход осуществляется по некоторому событию:
open IN,"<cont.txt";
while()
{
if($_ =~ /index\.htm/) last;
#разбор строки
}
close IN;
В данном примере скрипт считывает строки из файла счетчика посещений. Если в строке встречается имя файла "index.htm", то происходит досрочный выход из цикла.
Оператор redo применяется для повторения последней итерации цикла.
Например, если есть вложенные циклы while, которые выполняют одинаковые
последовательности операторов, то внутренний из них можно заменить на
оператор if с redo.
При выполнении различных операций в CGI-скриптах часто приходится работать с файловой системой Web-узла. Perl обеспечивает довольно разнообразный инструментарий для такой работы. Условно его можно разбить на четыре части:
Для работы с файлами в Perl применяют несколько встроенных функций.
Открывают файл функцией open. При этом для указания действий с записями
файла используют префиксы:
open IN,"<test.txt"; # открыть файл на чтение open IN,">test.txt"; # открыть файл на запись open IN,"+<test.txt"; # открыть файл на чтение и запись open IN,">>test.txt"; # открыть файл на модификацию (добавление)
Закрывают файл при помощи функции close:
close IN;
Для чтения записей из файла используют либо чтение потоком — <file>,
либо функцию read:
while(<IN>)
{
print $_;
}
read STDIN, $query, $ENV{CONTENT_LENGTH};
В первом случае данные построчно считываются из файла IN и
распечатываются в поток read $ENV{CONTENT_LENGTH} байтов. Для обработки потока timeout.
Для работы с каталогами используют ряд встроенных функций: opendir, readdir, closedir. Первая открывает дескриптор файла каталога, вторая
позволяет читать записи из файла каталога, третья закрывает дескриптор
файла каталога:
opendir DIR,"/usr/user";
while($_=readdir(DIR))
{
next if -d;
print $_;
}
closedir DIR;
В данном примере распечатываются названия файлов из каталога
"/usr/users". При этом имена каталогов не распечатываются. Такое
поведение скрипта определяется модификатором if в операторе next.
Одним из замечательных свойств командных языков является возможность
использования конвейеров. Они организуются путем перенаправления
open FILTER,"<cat;more>";
нельзя. С точки зрения логики, при такой форме записи один
дескриптор файла будет связан с разными потоками. Кроме того, поток
#!/usr/local/bin/perl use IPC::Open2; use FileHandle; $pid = open2(\*RDR,\*WRD,"cat"); WRD->autoflush(); print WRD "test\n"; $got = <RDR>; print "Это \$got:$got";
В данном случае для открытия канала связи между процессами
используется функция open2. Ей необходимы три аргумента: указатель на
дескриптор потока для чтения ( \*RDR ), указатель на дескриптор потока
для записи ( \*WRD ) и строка внешней программы-фильтра ( "cat" ). Вместо cat можно указать любое множество команд, организованных в виде
конвейера. Команда print посылает данные в этот конвейер, а команда ""
считывает из него данные.
Пусть и не очень часто, но все-таки приходится при разработке CGI-скриптов пользоваться возможностью обращения из скрипта к серверу, установленному на другом компьютере. При работе в сетях TCP/IP для этой цели используют библиотеку сокетов (Berkeley sockets) TCP/IP. Сокет — это пара "IP-адрес — номер порта". При программировании речь, конечно, будет идти о структуре данных, которая позволяет передать/принять данные с удаленного компьютера.
IP-адрес в сокете отвечает за доступ к определенному компьютеру в Internet. В общем случае IP-адреса закрепляются не за отдельными компьютерами, а за сетевыми интерфейсами. Один сетевой интерфейс может иметь несколько IP-адресов. Эта возможность используется при организации виртуальных Web-узлов.
Порт — это виртуальный канал приема/передачи данных, в котором
происходит обслуживание приходящих из сети запросов. Этот канал
обозначается цифрой. Первые 256 каналов — это
Порты бывают двух типов, TCP и UDP (
Кроме TCP/IP существуют еще и другие виды сокетов, поэтому при
программировании нужно указывать
#!/usr/local/bin/perl
use IO::Socket;
$remote = IO::Socket::INET->new(
Proto=>"tcp",
PeerAddr=>"localhost",
PeerPort=>"80"
) or die "No service";
$remote->autoflush(1);
print $remote "HEAD / HTTP/1.0\n\n";
while()
{
print;
}
-close $remote;
В данном примере используется пакет Socket из библиотеки IO
(Interpretive Operation, работа в режиме интерпретации) (оператор use ).
В третьей строчке примера происходит открытие дескриптора для сокета.
Затем этот дескриптор применяется как обычный дескриптор файла, который
открыт для записи и чтения.
Прежде чем писать данные в сокет, обычно отменяют буферизацию
( autoflush(1) — выталкиваем по одному байту). Делается это для того,
чтобы данные сразу уходили на сервер. В противном случае сервер может
разорвать соединение, не дождавшись запроса.
Оператор print демонстрирует запрос по протоколу HTTP 1.0 к
HTTP-серверу. В этом запросе просто считывается документ из корня
каталога HTTP-сервера. Обычно это файл index.html. Чтение отклика
происходит в цикле while. После считывания отклика socket закрывается
по функции -close.
Интерпретируемые языки программирования имеют две особенности, которых нет у компилируемых языков:
С точки зрения эффективности кода это, конечно, не лучшие решения. Рекурсия может приводить к различного рода переполнениям, что, в свою очередь, вызывает крах программы, а отложенное исполнение не позволяет заранее оптимизировать код и в ряде случаев может приводить к рекурсивному вызову интерпретатора. Тем не менее изящность этих механизмов не может оставить программиста равнодушным.
Отложенное исполнение в Perl применяется в случае подстановки, в том числе рекурсивной
$sm =~ s/%(.{2})/pack('c',hex($1))/eg;
и в случае использования операции eval. Алгоритм работы этой
операции достаточно прозрачен. В качестве аргумента в eval передается
строка, которая затем рассматривается как Perl-программа. Для
программирования из Web-браузера на Perl можно написать, например,
такой скрипт:
#!/usr/local/bin/perl
read STDIN,$query,$ENV{CONTENT_LENGTH};
$query =~ s/%(.{2})/pack('c',hex($1))/ge;
$query =~ tr/+/ /ge;
$query =~ s/f=//;
eval $query;
Функция read в этом примере обеспечивает считывание данных из потока
стандартного ввода скрипта. Операция рекурсивной подстановки позволяет
преобразовать текст программ из формата form-urlencoded в ascii.
Функция транслитерации tr заменяет символ "+" пробелом. Операция
подстановки, следующая за транслитерацией, удаляет из кода программы
имя поля и символ "=". Операция eval позволяет исполнить этот код. При
этом предполагается, что данные передаются из формы с единственным
полем типа textarea с именем "f".
Справедливости ради следует заметить, что в операции транслитерации кроме символа "+" нужно указать еще и другие символы, которые могут оказаться в коде программы. Например, если ввод кода осуществляется из браузера в среде MS-Windows, то при каждом переводе строки будет генерироваться символ "0D", который интерпретатор Perl для среды Unix не распознает.
Программировать на Perl без применения дополнительных библиотек
довольно сложно. В сети существует библиотека
CPAN( http://www.perl.com/CPAN/ ). CPAN — это огромное хранилище
полезного программного обеспечения. Для программирования CGI-скриптов в
этой библиотеке имеются модули CGI-программирования. В последних
версиях вместе с дистрибутивом Perl поставляется модуль CGI.pm. Но даже
если этого модуля нет, его просто нужно скачать из CPAN.
Установка модуля в Perl довольно проста. Требуется выполнить следующие действия:
edu>ftp ftp.perl.com
edu>gzip -d имя_модуля
Makefile.pl и выполняют генерацию файлов
для edu>perl Makefile.pl
edu>make; make test; make install
Теперь модуль установлен в Perl-каталог, и на него настроены все пути. С этого момента программы могут использовать функции из установленного модуля.
Включать функции из модуля в программу на Perl можно при помощи
оператора use. Например, для получения имени текущего каталога
используют функцию getcwd() из библиотеки Cwd:
#!/usr/local/bin/perl use Cwd; $dir = getcwd(); opendir DIR,$dir; .... closedir DIR;
При организации конвейеров также применяются модули из библиотеки. Стандартные библиотеки обычно поставляются вместе с дистрибутивом Perl и устанавливаются при его сборке.
Язык программирования Perl является основным средством разработки CGI-скриптов для Web-узлов. Его не применяют только там, где требуется высокая эффективность кода и нет стандартных библиотек для Perl.
Perl как язык разработки скриптов имеет ряд преимуществ. Перечислим их в порядке значимости:
Все это делает программное обеспечение, написанное на Perl, мобильным, а разработку программ — быстрой и простой.
У программы на языке Perl нет жестко заданной структуры. Точнее
сказать, программист не обязан ее соблюдать. Если же он захочет, чтобы
интерпретатор контролировал объявление и использование переменных и
конструкций языка, то при помощи класса strict он может такой контроль
установить.
Программа на Perl состоит из операторов языка, которые должны заканчиваться символом ";". Например:
print "Привет, Perl.";
В общем случае операторы делятся на простые и составные. Простой оператор —
это оператор print, например, а составной — while():
while() {s/</lt;/g; s/>/gt;/g; print $_;};
Программа на Perl исполняется интерпретатором Perl. Есть и компиляторы с этого языка, но они используются реже. При программировании CGI-скриптов в Unix интерпретатор вызывается из того же файла, который содержит программу, например:
#!/usr/local/bin/perl print "Привет, Perl.";
В данном случае первая строка — это вызов интерпретатора с указанием полного пути к нему от корневого каталога файловой системы.
Вообще говоря, символ "#" — это символ начала комментария в Perl. Последовательность символов от символа "#" до конца строки рассматривается как комментарий. Часто в качестве комментария используют целые строки. В этом случае символ "#" ставится в первой позиции строки:
#!/usr/local/bin/perl # #Печатаем HTML-заголовок # print "Content-type: text/html\n\n"; # #Содержание документа # print "Perl и CGI.";
Данный пример демонстрирует не только использование комментариев, но еще и формирование HTTP-заголовка. Без этого заголовка система выдаст сообщение о внутренней ошибке сервера, а в файле журнала ошибок появится запись о неправильном заголовке.
В последнее время основным рабочим местом авторов HTML-страниц и
CGI-скриптов стали системы на платформе Windows. Как известно, конец
строки в Windows и в Unix обозначается разными последовательностями
неотображаемых символов. Если автор использует текстовый редактор в
Windows, а потом как binary копирует файл в Unix, то эти символы
передаются. Сервер начинает сообщать об ошибках, которые автору не
видны. В таком случае можно сделать следующее: либо копировать
программы как char, тогда происходит перекодировка, либо использовать
"умные" текстовые редакторы.
Удобна также и Samba, которая позволяет редактировать "по месту" из Windows в Unix.
Основная цель создания CGI-скрипта — обработка данных запроса пользователя и формирование отклика сервера на этот запрос. Можно рассматривать и другие задачи, которые позволяют решать CGI-скрипты, но эта задача — главная. Скрипт должен формировать не просто отклик, а HTTP-отклик. Это означает, что он должен сформировать заголовок и тело HTTP-сообщения, которые отделяются друг от друга пустой строкой.
Проще всего реализовать такой отклик с помощью команды print:
#!/usr/local/bin/perl print "Content-type: text/html\n\n"; print "<HTML><HEAD></HEAD><BODY>"; print "<H1>Perl и CGI.</H1>"; print "</BODY></HTML>";
Первая строчка определяет заголовок HTTP-отклика и пустую строку
(два символа "\n\n"). Остальные операторы print формируют тело
сообщения. Оператор print пишет в print можно использовать для
вывода данных в любой файл. Если имя файла не указано, то вывод
осуществляется в
Скрипт порождается сервером в некоторой операционной среде. Эта
среда называется окружением (environment). Частью окружения являются
так называемые
В Perl существует встроенный системный массив %ENV. Символ "%" перед именем массива означает, что это массив
ассоциативный, т.е. значение элемента массива может быть выбрано путем
указания ключа, с которым оно связано. Например, нужно определить метод
доступа к скрипту:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "REQUEST_METHOD:$ENV{REQUEST_METHOD}";
В данном контексте символ "$" перед именем массива не должен вводить в заблуждение. Обращение происходит к элементу ассоциативного массива. Это скаляр, поэтому и применяется символ "$". Ключ, по которому выбирается значение, указан в фигурных скобках.
Очень полезен скрипт распечатки всех perlenv2.htm ). Обычно этот отчет получают при отладке
HTML-форм:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
foreach $hkey (keys %ENV)
{
print "$hkey:$ENV{$hkey}"\n;
}
Этот простой скрипт распечатывает значения всех foreach.
В этом цикле переменная цикла hkey
пробегает по всем уникальным ключам (именам keys.
Когда пользователь работает с операционной средой в режиме удаленного алфавитно-цифрового монитора, он пользуется услугами оболочки (shell). Команды в операционной среде в этом случае вводятся в командной строке, и за каждой из команд может тянуться шлейф аргументов. Эти аргументы и называются аргументами командной строки.
CGI-скрипт вызывается не из оболочки, а загружается HTTP-сервером.
Если необходимо воспользоваться аргументами командной строки, то сервер
должен породить данную командную строку тоже. В CGI это делается только
для запросов ISINDEX. В таком случае скрипт вызывается через URI типа:
http://my.intuit.ru/directory/
script?arg1+arg2+arg3
В этой записи arg1+arg2+arg3 — аргументы командной строки скрипта, т.е.
данный URI равнозначен вводу в командной строке команды:
host>script arg1 arg2 arg3
Для приема этих аргументов достаточно воспользоваться скриптом типа:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
foreach $arg (@ARGV)
{
print "$arg\n";
}
В данном случае мы просто их распечатаем. Программа будет выбирать
по одному аргументу из системного массива аргументов командной строки @ARGV и помещать их в переменную $arg, а затем печатать.
В принципе, аргументы попадают и в , т.к. при запросе типа ISINDEX применяется метод GET. Но
тогда придется данную переменную разбирать. Аргументы командной строки
уже сделали эту работу за программиста.
Поток STDIN. В Perl применяется то же самое имя.
Для построчного чтения входного потока в Perl применяется пара символов "<>". Простая программа, читающая входной поток, может выглядеть следующим образом:
#!/usr/local/bin/perl
while(< >)
{
print $_;
}
В данном примере две скобки подряд определяют чтение из потока $_ обозначает
системную переменную, в которую по умолчанию помещается каждая
считанная из
Согласно спецификации CGI, скрипт получает данные через POST. Приведенный выше пример работы со EOF (End
of file, конец файла). Цикл while в этом случае будет бесконечным.
Скрипт сам определяет точное количество байтов, которые он должен
прочитать из CONTENT_LENGTH ( perlm1.htm ):
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "CONTENT_LENGTH=$ENV{CONTENT_LENGTH}";
Когда число байтов для чтения из потока read:
#!/usr/local/bin/perl
print "Content-type: text/plain\n\n";
print "CONTENT_LENGTH=$ENV{CONTENT_LENGTH}\n";
read STDIN,$query,$ENV{CONTENT_LENGTH};
print "Query:$query.";
После выполнения этих несложных операций в переменную $query будет
занесено содержание
В Perl существует довольно своеобразный набор типов данных: скаляры,
одномерные массивы (массивы), ассоциативные массивы (хешированные
таблицы или хеши), глобальные символы, ссылки. Обычно первых трех для
CGI-программирования вполне хватает. Ссылки применяют в совокупности со
стандартными библиотеками и вместо функции отложенного выполнения eval.
Глобальные символы нужны при работе с файлами или для межпроцессного
обмена данными при открытии каналов (потоков данных) через дескрипторы.
Скаляры — это все, что нельзя записать в виде массива или структуры. Числа всех типов и строки символов относятся к скалярному типу. Скаляр обозначается символом "$" перед именем. Примеры скаляров:
$a = 1; $b = 2.5; $str = "это строка символов";
Массивы — это множество элементов, причем все элементы могут быть
разнородными. В Perl нет понятия массива чисел или массива строк.
Массив не может быть многомерным. Можно реализовать
@a = (1,2,3); @b = (4,5,6,2.5,"test"); @c = (@a,@b); @in = $q = $c[3]; # 4
Индексирование элементов массива начинается с цифры 0. Поэтому в
нашем примере четвертый элемент массива с будет индексироваться как $c[3].
Ассоциативные массивы — это двухколоночная таблица. Первая колонка — ключ, а вторая колонка — связанное с ним значение. Ассоциативные массивы называют еще хешированными таблицами или просто хешами. Дело в том, что значение можно извлечь из таблицы прямо, указав ключ. При этом используется алгоритм хеширования по ключу.
Для краткости будем называть ассоциативный массив хешем. Обозначается переменная типа хеш символом "%" перед именем. Примеры хешей и обращений к их элементам:
%a = ("test",1,"test2",2);
$c = $a{test}; # $c=1
В первом случае хеш инициируется как обычный массив. Во втором
примере мы выбираем значение определенным ключом " test ". Результат этой
операции, скаляр, помещается в переменную $c.
Указатели — это аналог адресных указателей в С. Указатель обозначается символом "\" перед именем переменной:
$a = 1; $p = \$a; @b = (1,2,3); $p = \@b; $p = \%c;
Обращения к значениям, выбранным указателем, являются аналогом применения
функции eval (отложенное исполнение):
%a = ("test",1,"test2",2);
$p = \%a;
$c = $$p{"test"};
где вместо " а " используется $p.
Последнее, что мы рассмотрим — это дескрипторы потоков данных. Дескриптор потока указывает на структуру, которая описывает механизм обмена данными, например, с файлом. Применяются такие дескрипторы в функциях чтения и записи данных и в межпроцессном обмене:
open IN; read IN,$p,500; close IN;
В данном случае IN — дескриптор файла.
Самым интересным средством Perl является механизм регулярных
выражений, сравнение с образцом и подстановки, которые он унаследовал
от таких типичных для Unix-систем утилит, как awk и sed.
Операция сопоставления с образцом задается как "=~":
$query =~ /target/;
В данном случае в скаляре $query отыскивается подстрока
" target ". С
операцией "=~" связано два действия по умолчанию. Во-первых, операция
сопоставления в полной форме будет записана как
$query =~ m/target/;
То есть перед шаблоном используется префикс m. Во-вторых, если
опустить $query, то образец будет сопоставляться с содержанием
системной переменной $_:
/target/;
Операция "=~" возвращает значение "истина"( true ), если образец был
найден, и "ложь"( false ), в противном случае. Из этого следует, что
данную операцию можно использовать в операторах ветвления:
if($query =~ /target/)
{
print $query;
}
В данном случае, если образец содержится в $query, то запрос печатается,
не содержится — пропускается при печати.
При сопоставлении с образцом одновременно осуществляется разбор
запроса: шаблон попадает в переменную $_, часть строки до найденного
шаблона — в $`, а после образца — $'. Но для программирования разбора
данных из формы больше подойдет следующий пример ( perlexp1.htm ):
http://intuit.ru/scripts/ script?n1=v1n2=v2n3=v3 ... ($v1,$v2,$v3) = ($query =~ /^n1=(.+)n2=(.+)n3=(.+)$/); print $v1,$v2,$v3;
В переменные $v1 — $v3 будут записаны значения полей n1-n3,
соответственно. При этом символ "^" означает, что весь шаблон должен
стоять вплотную к началу строки. Символ "$" в конце шаблона означает,
что шаблон должен распространяться на всю строку до конца. Символ "."
означает любой символ, входящий в таблицу символов, "+" означает любое
количество этих символов, но не менее одного.
Еще более мощным средством является подстановка, которая базируется
на s%
$query =~ s/intuit/ruru/;
В данном случае, если в строке будет найден шаблон intuit, он будет
заменен на ruru. Наиболее очевидной областью применения подстановки
является перекодировка запросов form-urlencoded:
$query =~ s/%(.{2})/pack('c',hex($1))/eg;
Спецсимволы и символы из второй половины таблицы ASCII при передаче трансформируются в шестнадцатеричные описания байтов (две цифры), следующие после символа "%".
Под управлением потоком вычислений понимают способность программы в
зависимости от условий выполнять те или иные части кода и повторять
различные части кода. Для этой цели в Perl включены такие операторы как goto, next, last, redo, if, while, for, foreach и другие.
Оператор goto позволяет перейти к исполнению оператора Perl,
выделенного меткой, которая указывается в качестве аргумента оператора goto:
while()
{
if(/the end/) {goto out;};
}
out: print "the_end\n";
В данном случае выход из цикла осуществляется по оператору goto.
Вслед за всеми современными учебниками, напомним, что использование goto — это плохой стиль программирования. Метка в Perl задается как
строка, за которой вплотную следует символ двоеточия(":").
В нашем примере встретилось еще несколько while. While определяет
цикл, который исполняется до тех пор, пока значение выражения,
указанного в качестве аргумента оператора while, — "истина". Пример:
while(not($line =~ /the_end/))
{
$line = <>;
print "No\n";
}
print "the_end\n";
В данном случае оператор goto не используется. Выход из цикла
осуществляется по условию вхождения подстроки the_end в строку ввода.
Вхождение проверяется путем сопоставления с образцом. Входная строка
считывается из <> ).
Оператор for — это традиционный оператор цикла. Типовая схема
применения данного оператора может быть показана на следующем примере:
for($i=0;$i<CONTENT_LENGTH;$i++)
{
$query[$i] = getc;
}
$q = join (@query);
print $q;
Здесь данные в цикле считываются посимвольно из @query. Число символов,
которые нужно считать,
определяется переменной окружения CONTENT_LENGTH. После завершения
ввода массив объединяется в строку $q при помощи функции join. Наиболее
типичной ошибкой при использовании оператора for является отсутствие
символа " $ " у переменной цикла. Все три аргумента оператора for могут быть выражениями соответствующего типа.
Оператор foreach позволяет организовать цикл путем перебора
элементов списка. В качестве такого списка можно использовать массив:
foreach $arg (@ARGV)
{
print $arg;
}
В данном случае переменная цикла $arg пробегает по всем аргументам
командной строки скрипта, которые задаются встроенным массивом @ARGV.
Аналогично можно пройти и по всем переменным окружения:
foreach $arg (keys %ENV)
{
print "$arg:$ENV{$arg}\n";
}
Отличие данного примера от предыдущего заключается в том, что
переменные окружения представляют собой хеш. Поэтому сначала получаем
массив ключей (имен переменных окружения), переменная $arg пробегает по
этому массиву, и в цикле печатаются пары "имя переменной — значение
переменной".
После goto и операторов цикла следует остановиться
на операторе if.
Данный оператор позволяет организовать ветвление программы или, как это
еще называют, условное исполнение отдельных ее частей. Примером может
служить скрипт обработки данных, которые могут доставляться как по
методу GET, так и по методу POST:
if ($ENV{REQUEST_METHOD} =~ /POST/)
{
read STDIN,$query,$ENV{CONTENT_LENGTH};
}
else
{
$query = $ENV{QUERY_STRING};
}
В данном случае анализируется значение . В зависимости от ее значения либо включается чтение
данных из .
Если оператор goto не применять (концепция структурного
программирования), то при работе с циклами нужно обрабатывать ситуации
пропуска конца тела цикла и досрочного выхода из тела цикла. Пропуск
операторов конца тела цикла осуществляется при помощи оператора next:
foreach $arg (@strings)
{
if(!($ENV{REMOTE_HOST} =~ /\.intuit\.ru/))
next;
print $arg;
}
Здесь фрагмент скрипта печатает значения массива @string, только
если скрипт вызван с компьютера из домена intuit.ru. Машина
пользователя будет прописана в этом домене только в том случае, если
она прописана в nslookup ).
Досрочный выход из тела цикла производится по оператору last. Обычно
такой выход осуществляется по некоторому событию:
open IN,"<cont.txt";
while()
{
if($_ =~ /index\.htm/) last;
#разбор строки
}
close IN;
В данном примере скрипт считывает строки из файла счетчика посещений. Если в строке встречается имя файла "index.htm", то происходит досрочный выход из цикла.
Оператор redo применяется для повторения последней итерации цикла.
Например, если есть вложенные циклы while, которые выполняют одинаковые
последовательности операторов, то внутренний из них можно заменить на
оператор if с redo.
При выполнении различных операций в CGI-скриптах часто приходится работать с файловой системой Web-узла. Perl обеспечивает довольно разнообразный инструментарий для такой работы. Условно его можно разбить на четыре части:
Для работы с файлами в Perl применяют несколько встроенных функций.
Открывают файл функцией open. При этом для указания действий с записями
файла используют префиксы:
open IN,"<test.txt"; # открыть файл на чтение open IN,">test.txt"; # открыть файл на запись open IN,"+<test.txt"; # открыть файл на чтение и запись open IN,">>test.txt"; # открыть файл на модификацию (добавление)
Закрывают файл при помощи функции close:
close IN;
Для чтения записей из файла используют либо чтение потоком — <file>,
либо функцию read:
while(<IN>)
{
print $_;
}
read STDIN, $query, $ENV{CONTENT_LENGTH};
В первом случае данные построчно считываются из файла IN и
распечатываются в поток read $ENV{CONTENT_LENGTH} байтов. Для обработки потока timeout.
Для работы с каталогами используют ряд встроенных функций: opendir, readdir, closedir. Первая открывает дескриптор файла каталога, вторая
позволяет читать записи из файла каталога, третья закрывает дескриптор
файла каталога:
opendir DIR,"/usr/user";
while($_=readdir(DIR))
{
next if -d;
print $_;
}
closedir DIR;
В данном примере распечатываются названия файлов из каталога
"/usr/users". При этом имена каталогов не распечатываются. Такое
поведение скрипта определяется модификатором if в операторе next.
Одним из замечательных свойств командных языков является возможность
использования конвейеров. Они организуются путем перенаправления
open FILTER,"<cat;more>";
нельзя. С точки зрения логики, при такой форме записи один
дескриптор файла будет связан с разными потоками. Кроме того, поток
#!/usr/local/bin/perl use IPC::Open2; use FileHandle; $pid = open2(\*RDR,\*WRD,"cat"); WRD->autoflush(); print WRD "test\n"; $got = <RDR>; print "Это \$got:$got";
В данном случае для открытия канала связи между процессами
используется функция open2. Ей необходимы три аргумента: указатель на
дескриптор потока для чтения ( \*RDR ), указатель на дескриптор потока
для записи ( \*WRD ) и строка внешней программы-фильтра ( "cat" ). Вместо cat можно указать любое множество команд, организованных в виде
конвейера. Команда print посылает данные в этот конвейер, а команда ""
считывает из него данные.
Пусть и не очень часто, но все-таки приходится при разработке CGI-скриптов пользоваться возможностью обращения из скрипта к серверу, установленному на другом компьютере. При работе в сетях TCP/IP для этой цели используют библиотеку сокетов (Berkeley sockets) TCP/IP. Сокет — это пара "IP-адрес — номер порта". При программировании речь, конечно, будет идти о структуре данных, которая позволяет передать/принять данные с удаленного компьютера.
IP-адрес в сокете отвечает за доступ к определенному компьютеру в Internet. В общем случае IP-адреса закрепляются не за отдельными компьютерами, а за сетевыми интерфейсами. Один сетевой интерфейс может иметь несколько IP-адресов. Эта возможность используется при организации виртуальных Web-узлов.
Порт — это виртуальный канал приема/передачи данных, в котором
происходит обслуживание приходящих из сети запросов. Этот канал
обозначается цифрой. Первые 256 каналов — это
Порты бывают двух типов, TCP и UDP (
Кроме TCP/IP существуют еще и другие виды сокетов, поэтому при
программировании нужно указывать
#!/usr/local/bin/perl
use IO::Socket;
$remote = IO::Socket::INET->new(
Proto=>"tcp",
PeerAddr=>"localhost",
PeerPort=>"80"
) or die "No service";
$remote->autoflush(1);
print $remote "HEAD / HTTP/1.0\n\n";
while()
{
print;
}
-close $remote;
В данном примере используется пакет Socket из библиотеки IO
(Interpretive Operation, работа в режиме интерпретации) (оператор use ).
В третьей строчке примера происходит открытие дескриптора для сокета.
Затем этот дескриптор применяется как обычный дескриптор файла, который
открыт для записи и чтения.
Прежде чем писать данные в сокет, обычно отменяют буферизацию
( autoflush(1) — выталкиваем по одному байту). Делается это для того,
чтобы данные сразу уходили на сервер. В противном случае сервер может
разорвать соединение, не дождавшись запроса.
Оператор print демонстрирует запрос по протоколу HTTP 1.0 к
HTTP-серверу. В этом запросе просто считывается документ из корня
каталога HTTP-сервера. Обычно это файл index.html. Чтение отклика
происходит в цикле while. После считывания отклика socket закрывается
по функции -close.
Интерпретируемые языки программирования имеют две особенности, которых нет у компилируемых языков:
С точки зрения эффективности кода это, конечно, не лучшие решения. Рекурсия может приводить к различного рода переполнениям, что, в свою очередь, вызывает крах программы, а отложенное исполнение не позволяет заранее оптимизировать код и в ряде случаев может приводить к рекурсивному вызову интерпретатора. Тем не менее изящность этих механизмов не может оставить программиста равнодушным.
Отложенное исполнение в Perl применяется в случае подстановки, в том числе рекурсивной
$sm =~ s/%(.{2})/pack('c',hex($1))/eg;
и в случае использования операции eval. Алгоритм работы этой
операции достаточно прозрачен. В качестве аргумента в eval передается
строка, которая затем рассматривается как Perl-программа. Для
программирования из Web-браузера на Perl можно написать, например,
такой скрипт:
#!/usr/local/bin/perl
read STDIN,$query,$ENV{CONTENT_LENGTH};
$query =~ s/%(.{2})/pack('c',hex($1))/ge;
$query =~ tr/+/ /ge;
$query =~ s/f=//;
eval $query;
Функция read в этом примере обеспечивает считывание данных из потока
стандартного ввода скрипта. Операция рекурсивной подстановки позволяет
преобразовать текст программ из формата form-urlencoded в ascii.
Функция транслитерации tr заменяет символ "+" пробелом. Операция
подстановки, следующая за транслитерацией, удаляет из кода программы
имя поля и символ "=". Операция eval позволяет исполнить этот код. При
этом предполагается, что данные передаются из формы с единственным
полем типа textarea с именем "f".
Справедливости ради следует заметить, что в операции транслитерации кроме символа "+" нужно указать еще и другие символы, которые могут оказаться в коде программы. Например, если ввод кода осуществляется из браузера в среде MS-Windows, то при каждом переводе строки будет генерироваться символ "0D", который интерпретатор Perl для среды Unix не распознает.
Программировать на Perl без применения дополнительных библиотек
довольно сложно. В сети существует библиотека
CPAN( http://www.perl.com/CPAN/ ). CPAN — это огромное хранилище
полезного программного обеспечения. Для программирования CGI-скриптов в
этой библиотеке имеются модули CGI-программирования. В последних
версиях вместе с дистрибутивом Perl поставляется модуль CGI.pm. Но даже
если этого модуля нет, его просто нужно скачать из CPAN.
Установка модуля в Perl довольно проста. Требуется выполнить следующие действия:
edu>ftp ftp.perl.com
edu>gzip -d имя_модуля
Makefile.pl и выполняют генерацию файлов
для edu>perl Makefile.pl
edu>make; make test; make install
Теперь модуль установлен в Perl-каталог, и на него настроены все пути. С этого момента программы могут использовать функции из установленного модуля.
Включать функции из модуля в программу на Perl можно при помощи
оператора use. Например, для получения имени текущего каталога
используют функцию getcwd() из библиотеки Cwd:
#!/usr/local/bin/perl use Cwd; $dir = getcwd(); opendir DIR,$dir; .... closedir DIR;
При организации конвейеров также применяются модули из библиотеки. Стандартные библиотеки обычно поставляются вместе с дистрибутивом Perl и устанавливаются при его сборке.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.