Создание серверных приложений на языке PERL

         

П2.3.2 Простые операторы


Последовательность простых операторов может следовать за отдельным модификатором. В Perl-е простыми модификаторами являются:
if (EXPR)
unless (EXPR)
while (EXPR)
until (EXPR) В операторах while и until проверка условия происходит перед выполнением тела блока, за исключением одного случая, когда используется do-оператор:
do {

$_ = <STDIN>;

...

} until $_ eq ".\n";в котором проверка условия происходит после выполнения блока. Операторы цикла, которые будут описаны далее, не будут работать в этой конструкции, так как отсутствует метка цикла.



П2.3.3 Составные операторы


if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK eslif (EXPR) BLOCK else BLOCK
LABEL: while (EXPR) BLOCK
LABEL: while (EXPR) BLOCK continue BLOCK
LABEL: for (EXPR; EXPR; EXPR;...) BLOCK
LABEL: foreach VAR(LIST) BLOCK
LABEL: BLOCK continue BLOCK

В отличие от C и Pascal все определяется в терминах блоков, а не операторов: то есть фигурные скобки являются обязательными. Метка состоит из идентификатора и двоеточия. Она ставится в начале цикла и служит указателем для операторов цикла next, last и redo (их описание смотри ниже). Если это continue блок, то он выполняется перед тем, как условие будет проверено снова, как третья часть for оператора в C. Правильность условия может зависеть от результатов выполнения блока, например: $i = 1;

while ($i < 10){

...

} continue {

$i++;

}или, что тоже самое: for ($i = 1; $i < 10; $i++;) {

...

}Foreach цикл присваивает переменной по очереди каждое значение из списка и выполняет над ней все команды из блока. Переменная является локальной и существует только в пределах данного цикла. Если список является массивом, то его можно изменять в цикле, посредством операций над переменной. Если переменная опускается, то по умолчанию в качестве нее используется $_. foreach \$elem(@elements) \{\$elem = \$elem * 2;\}-- цикл по всему содержимому массива @items. Пример: for ((1,2,3,4,5,6,7,8,9,10,'boom')) {

print $_,"\n"; sleep(1); }

for (1..15) { print "Merry Christmas\n"; }

foreach $item (split(/[\/\*\\n]/,$ENV{'TERMCAP'})) {

print "Item: $item\n"; }Блок семантически эквивалентен циклу, который исполняется один раз. Поэтому в него можно включать операторы контроля цикла, чтобы выйти из него или запустить его еще раз.





П2.3.4.1 Термы и операторы списка


Операторы в Perl-е имеют различный приоритет. Операторы, заимствованные из C, сохранили между собой ту же иерархию, что и в C. Термы имеют самый большой приоритет, они содержат переменные, кавычки, выражения в скобках, функции с их параметрами. Если за списковым оператором ( например, print()) или унарным оператором ( например, chdir()) следует список аргументов, заключенный в скобки, то эта последовательность имеет самый высокий приоритет, подобно функции с аргументами. Аналогично термам обрабатываются последовательности do{} и eval{}.



П2.3.4.2 Оператор ``стрелка''


Также, как в С и С++ ``->'' является инфиксным оператором ссылки. Если правая часть является [...] или {...} подпрограммой, тогда левая часть должна быть символьной ссылкой на массив или хэш. Если правая часть - это имя метода или скалярная переменная содержащая имя метода, то левая часть должна быть объектом или именем класса.



П2.3.4.3 Операторы ++ и - -


Эти операторы работают также как и в С. То есть, если они стоят перед переменной, то они увеличивают или уменьшают переменную до возвращения значения. Если они стоят после переменной, то увеличение или уменьшение переменной происходит после возврата значения. Если переменная содержит в себе число или употребляется в скалярном контексте, то использование ++ дает обычное увеличение значения. Если же переменная употреблялась только в строковом контексте, не является пустой строкой и содержит символы a-z,A-Z,0..9, то происходит строковое увеличение значения переменной:
print ++($foo = '99'); - напечатает 100
print ++($foo = 'a0'); - напечатает a1
print ++($foo = 'Az'); - напечатает Ba
print ++($foo = 'zz'); - напечатает aaa



П2.3.4.4 Экспоненциальный оператор


В Perl-е двойная звездочка ** является экспоненциальным оператором. Он требует к себе даже больше внимания, чем унарный минус: -2**4 это -(2**4), но не (-2)**4.



П2.3.4.5 Символьные унарные операторы


Унарный ! означает логическое отрицание. Унарный минус, в случае числового значения переменной, обозначает обычное арифметическое отрицание. Если операндом является идентификатор, то возвращается строка, состоящая из знака минус и идентификатора. Если строка начинается со знака + или -, то возвращается строка, начинающаяся с противоположного знака. Унарная тильда ``~'' обозначает побитовое отрицание.
Унарный плюс не имеет влияния даже на строки. Он используется для отделения имя функции от выражения заключенного в скобки, которое иначе рассматривается как список аргументов. rand (10) * 20; - (rand10) * 20;

rand +(10) * 20; - rand(10 * 20);Унарный бэкслэш ``'' обозначает ссылку на то, что стоит за ним.



П2.3.4.6 Операторы связки


Знак равенства с тильдой ``=~''связывает выражение слева с определенным шаблоном. Некоторые операторы обрабатывают и модифицируют переменную $_. Эти же операции иногда желательно бывает выполнить над другой переменной. Правый аргумент это образец поиска, подстановки или трансляции, левый аргумент - это то, что должно быть подставлено вместо $_. Возвращаемая величина показывает успех операции. Бинарное ``!~'' это тоже самое, что и ``=~'', только возвращаемая величина является отрицательной в логическом смысле.



П2.3.4.7 Бинарные операторы


Звездочка * - умножение двух чисел. Cлэш / - деление числа на число. Процент % - вычисляет модуль двух чисел, x - оператор повторения. В скалярном контексте возвращает строку, состоящую из многократно повторенного левого операнда, причем повторяется он то количество раз, которое стоит справа. В списковом контексте он многократно повторяет список. print 'a' x 80; напечатает букву a 80 раз.
@ones = (1) x 80; массив из восьмидесяти единиц.
@ones = (5) x @ones сделает все элементы равными пяти.
Бинарный плюс - операция сложения двух чисел.
Бинарный минус - операция вычитания двух чисел.
Бинарная точка - конкатенация строк.



П2.3.4.8 Операторы сдвига


Двоичный сдвиг осуществляется, как и во многих других языках программирования, с помощью операторов ``<<'' и ``>>''. При применении этих операторов значения левых аргументов сдвигаются в соответствующую сторону на количество разрядов, указанное в правых аргументах. Аргументы должны быть целочисленными.



П2.3.4.9 Операторы сравнения


``<'' - возвращает TRUE если левый аргумент численно меньше, чем правый.
``>'' - возвращает TRUE если правый аргумент численно меньше, чем левый.
``<='' - возвращает TRUE если правый аргумент численно меньше или равен левому.
``>='' - возвращает TRUE если левый аргумент численно меньше или равен правому.
``gt'' - возвращает TRUE если левый аргумент меньше (в строковом контексте), чем правый.
``lt'' - возвращает TRUE если правый аргумент меньше (в строковом контексте), чем левый.
На поведение операторов lt и gt влияют установки системного языка, если операционная система способна работать с несколькими языками. По этой причине операторы должны корректно работать со строками на языках, отличных от US ASCII, что в системе UNIX задается указанием свойств LC_COLLATE системного locale.



П2.3.4.10 Операторы эквивалентности


== возвращает TRUE, если левый аргумент численно эквивалентен правому.
!= возвращает TRUE, если левый аргумент численно неэквивалентен правому.
<=> возвращает -1, 0 или 1 в зависимости от того, численно меньше, равен или больше левый аргумент правого.
eq возвращает TRUE, если левый аргумент эквивалентен правому (в строковом контексте).
ne возвращает TRUE, если левый аргумент неэквивалентен правому (в строковом контексте).
cmp возвращает -1, 0 или 1 в зависимости от того, меньше равен или больше левый аргумент правого (в строковом контексте).



П2.3.4.11 Побитовое И, побитовое ИЛИ и Исключающее ИЛИ


Бинарное & возвращает объединенные побитово операнды.
Бинарное | возвращает перемноженные побитово операнды.
Бинарное ^ возвращает исключенные побитово операнды.



П2.3.4.12 Логическое И и логическое ИЛИ


Бинарное && - логическое И. Если левый аргумент FALSE, то правый не проверяется.
Бинарное || - логическое ИЛИ. Если левый аргумент TRUE, то правый аргумент не проверяется.
||''и && отличаются от подобных операторов в \verbC| тем, что вместо 0 или 1 они возвращают последнюю обработанную величину. Таким образом, наиболее удобным способом определить домашний каталог пользователя из переменной окружения HOME будет (на практике такой способ определения домашнего каталога пользователя не рекомендуется): $home = $ENV{'HOME'} || $ENV{'LOGDIR'} ||

(getpwuid($<))[7] || die "You're homeless!\n";В качестве более удобной для чтения альтернативы Perl поддерживает операторы and и or, которые будут описаны далее. Их приоритет ниже, однако их можно с удобством использовать, не расставляя скобки, после операторов, аргументами которых являются списки: unlink "alpha", "beta", "gamma"

or gripe(), next LINE;Если писать в стиле C, то это может быть записано так: unlink("alpha", "beta", "gamma")

|| (gripe(), next LINE);



П2.3.4.13 Оператор диапазона


.. - оператор диапазона. Реально это два разных оператора, в зависимости от контекста. В списковом контексте он работает как оператор диапазона от левого аргумента до правого. for (1..10) {

#code

}В скалярном контексте он возвращает булевское значение. Если левый операнд TRUE, то .. принимает значение TRUE, если правый операнд тоже TRUE. if (101..200) { print 'hi;)';}- напечатает вторую сотню строк



П2.3.4.14 Условный оператор


?: также как и в C является условным оператором. Он работает подобно if-then-else. Если аргумент перед ? - TRUE, то возвращается аргумент перед :, в противоположном случае возвращается аргумент после :. Скалярный или списковый контекст второго и третьего аргументов передается по наследству. ($a_or_b ? $a : $b) = $c;



П2.3.4.15 Операторы присваивания


= - обычный оператор присваивания. Вообще операторы присваивания работают также как и в C. $a += 2; - то же самое, что и $a = $a + 2; Можно использовать следующие сокращения: **= += *= &= <<= &&=

-= /= |= >>= ||=

.= %= ^= x=($a += 2) *= 3; - то же самое, что и : $a = $a + 2; $a = $a * 3;



П2.3.4.16 Оператор ``запятая''


, - оператор запятая или comma-оператор. В скалярном контексте он обрабатывает левый аргумент и отбрасывает его значение, потом обрабатывает правый аргумент и возвращает его величину. В этом он подобен comma-оператору из C. В списковом контексте он играет роль разделителя аргументов и вставляет оба аргумента в список. => является синонимом comma-оператора.



П2.3.4.17 Логическое НЕ


Унарное NOT возвращает отрицание аргумента. Оно эквивалентно !, за исключением более низкого приоритета.



П2.3.4.18 Логическое И, ИЛИ и Исключающее ИЛИ


and возвращает конъюнкцию двух выражений. Он эквивалентен &&, за исключением более низкого приоритета. or возвращает дизъюнкцию аргументов. Он эквивалентен ||, за исключением более низкого приоритета. xor (eXclusive OR) - исключающее ИЛИ, возвращает истину, если истинен ровно один из аргументов.



П2.3.4.19 Оператор чтения из файла


В Perl есть несколько операций ввода-вывода. Для вывода из файла используется команда <>. open(STDIN,"/etc/passwd");

while ($string = <STDIN>)

{

@a = split(/[:]/,$string);

}Внутри этих скобок стоит дескриптор файла. Считывание происходит построчно. В конце файла <STDIN> принимает значение FALSE и цикл while завершается. По умолчанию считывание происходит в переменную $_. Нулевой дескриптор файла используется также как в sed и awk, то есть считывается поток из файлов перечисленных в командной строке.



П2.3.4.20 Оператор замены строки


Оператор s/PATTERN/REPLACEMENT/egimosx производит поиск строки, соответствующей шаблону PATTERN и если строка найдена, то подстановку на ее место текста REPLACEMENT. Возвращает количество произведенных подстановок. Если перед этим не использовался оператор =~ или !~ для определения переменной, которая будет обрабатываться, то будет модифицироваться переменная $_. Этот оператор используется со следующими опциями:

e интерпретирует правую часть как выражение.

g производит подстановку на место каждой строки, соответствующей шаблону.

i производит поиск различающий большие и маленькие буквы.

m обрабатывает строку, как состоящую из нескольких строк.

o происходит подстановка только на место первой встреченной строки.

s обрабатывает строку, как состоящую только из одной строки.

x использует расширенные регулярные выражения. Например: $path =~ s|/usr/local/bin|/usr/bin|;

($foo = $bar) =~ s/this/that/o;

$count = ($paragraf =~ s/Mister\b/Mr./gm);



П2.3.4.21 Оператор замены множества символов


tr/SEARCHLIST/REPLACEMENTLIST/cds y/SEARCHLIST/REPLACEMENTLIST/cds Заменяет все найденные символы из множества символов SEARCHLIST на соответствующие символы из множества символов REPLACEMENTLIST. Возвращает число символов, которые были заменены или удалены. Если посредством операторов =~, !~ не была указана никакая строка, то обрабатывается переменная $_. y является синонимом tr. Если SEARCHLIST заключен в скобки, то REPLACEMENTLIST тоже заключается в скобки, которые могут отличаться от тех, в которые заключается шаблон, например: tr[A-Z][a-z]

tr(+-*/)/ABCD/Этот оператор употребляется со следующими опциями:

c заменяет символы, которые не входят во множество SEARCHLIST на REPLACEMENTLIST, например: tr/a-zA-Z/ /cs;заменит неалфавитные символы.

d Стирает символы, которые ни на что не заменяются.

s Переводит последовательность символов, которые заменяются на один и тот же символ в один символ. Например: $a = 'CCCCCCCCC';

$a =~ tr/C/D/s;теперь $a = 'D'



П2.4.1.1 Основные понятия


В предыдущих версиях Perl была реализована возможность только символьных ссылок. Perl версии 5 и выше позволяет использовать не только символьные ссылки на переменные, но и ``жесткие'' ссылки на любые данные. Так как любой скаляр может быть ссылкой, а массивы и хэши состоят из скаляров, то можно с легкостью организовать массив массивов, массив хэшей, хэш массивов и так далее. ``Жесткие'' ссылки следят за счетчиком ссылки и как только счетчик становится равным нулю, автоматически удаляют ссылку. Символьные ссылки содержат только имя переменной, также как символьная ссылка файловой системы содержит просто имя файла. Ссылки могут быть созданы несколькими способами:

Используя бэкслэш оператор перед переменной, подпрограммой или простой константой. (Это работает почти как & - создается еще одна ссылка, так как одна уже существует в символьной таблице.) $varref = \$foo;

$arref = @ARGV;

$hashref = \%ENV;

$coderef = \&handler;

Ссылка на массив может быть создана с использованием квадратных скобок: $arrayref = [1,2,['a','b','c']];По адресу $arrayref[2][1] будет храниться значение b. Ссылка на произвольный хэш может быть создана с использованием фигурных скобок: $hashref = {

'Earth' => 'Moon',

'Jupiter' => 'Kallisto',

...

};

Ссылка на подпрограмму может быть создана с использованием слова sub, без определения имени подпрограммы: $coderef = sub { print "Hello!\n" };

Ссылки часто возвращаются конструкторами. Объекты Perl на самом деле являются ссылками на специальную сущность, которая знает, какой пакет ассоциировать с объектом. Конструкторы это специальные подпрограммы, которые умеют создавать эту ассоциацию. Чтобы извлечь информацию, на которую указывает ссылка, тоже существует несколько методов:

Можно сделать идентификатор ссылки частью имени переменной или подпрограммы: $bar = $$scalarref;

push(@$arrayref,$filename);

$$arrayref[0] = "January";

$$hashref{"key"} = "value";

&$coderef(1,2,3);

$refrefref = \\\"how are you?";


print $$$$refrefref;- напечатает ``how are you?''.
Нужно понимать, что раскрытие ссылки имеет более высокий приоритет, чем извлечение значения переменной. Можно поступить как и в предыдущем случае, но заключить выражение после знака $в фигурные скобки. Приведенный пример тогда будет выглядеть таким образом: $bar = ${$scalarref};

push(@{$arrayref},$filename);

${$arrayref}[0] = "January";

${$hashref}{"key"} = "value";

&{$coderef}(1,2,3);В данном случае использование фигурных скобок ничего не меняет, но в общем случае в скобках может стоять произвольное выражение, даже подпрограмма: &{ $dispatch{$index} }(1,2,3);

В случае массива или хэша можно использовать такую запись: $arrayref->[0] = "January";

$hashref->{"key"} = "value";Левая часть должна быть выражением, возвращающим ссылку, возможно также являющуимся раскрытием ссылки: $array[$x]->{"foo"}->[0] = "January";

Если ссылка является ссылкой на объект, то раскрытие данных происходит также, как уже было описано выше. Функция ref() может быть использована для определения типа объекта, на который указывает ссылка. Функция bless() может быть использована для ассоциирования ссылки с пакетом, функционирующим как объектный класс.


П2.4.1.2 Символьные ссылки


Мы рассмотрели, что происходит, если величина, используемая в качестве ссылки, не была определена ранее. Что же происходит, если она уже определена и не является жесткой ссылкой? В таком случае она обрабатывается как символьная ссылка. То есть значение скаляра рассматривается как имя переменной, а не прямая ссылка на переменную. ¯

$name = "foo";

$$name = 1; - то же самое, что $foo = 1;

${$name} = 2; - то же самое, что $foo = 2;

${$name x 2 } = 3; -то же самое, что $foofoo = 3;

$name->[0] = 4; -то же самое, что $foo[0] = 4;

@$name = (); - обнуляет массив @foo

&$name(); - вызывает &foo



П2.4.2 Регулярные выражения


Perl позволяет использовать регулярные выражения. Для того чтобы пояснить, что же представляет из себя регулярное выражение приведем несколько примеров:
/SWAP.*/ - соответствуют все слова начинающиеся со SWAP и заканчивающихся произвольным набором символов. Точка обозначает произвольный символ, звездочка - то, что символ, стоящий перед ней, входит в слово 0 и более раз. Все метасимволы, которые будут описаны ниже, бозначают вхождение того, что стоит перед ними.
/\w*/ - соответствуют слова состоящие только из алфавитных, цифровых символов и символа подчерк. \w - соответствует алфавитным, цифровым символам и символу подчерк, звездочка - тому, что эти символы могут входить произволное количество раз. Здесь мы приведем только основные метасимволы. Для более подробной информации смотрите соответствующие страницы man по Perl. ¯

* соответствует 0 или более вхождений

+ соответствует 1 или более вхождений

? соответствует 1 или 0 вхождений

{n} соответствует ровно n вхождений

{n,} соответствует по крайней мере n вхождений

{n,m} соответствует по крайней мере n,

но не более m вхождений

Метасимвол * эквивалентен {0,}, + эквивалентен {1,} и ? эквивалентен {0,1}. Ограничений на величину m и n нет. Эта стандартная конструкция работает в ``жадном'' режиме, то есть: регулярному выражению a.*b будет соответствовать всевозможный набор слов начинающихся с символа a и кончающихся символом b, в том числе слова типа abcab. В таких словах есть подпоследовательности символов, которые также удовлетворяют условиям регулярного выражения. Если после каждого из описанных метасимволов поставить знак ?, то подобные последовательности будут опускаться. Шаблоны обрабатываются как строка в двойных кавычках, поэтому приведенные ниже последовательности также будут обрабатываться: ¯

\l - передвижение на символ вниз

\u - передвижение на символ вверх

А также все перечисленные ранее бакслэш-последовательности. В Perl-е определены также: ¯

\w - соответствуют алфавитные и цифровые


символы а также символ подчерк

\$W - соответствуют все символы не входящие

во множество символов w

\s - символы пробела, табуляции, возврата каретки

\S - все символы не входящие во множество символов

s

\d - цифровые символы

\D - нецифровые символы

Обратите внимание, что \w отмечает только отдельные символы, а не все слово. Чтобы отметить все слово нужно использовать \w+. Также определены следующие команды: ¯

\b - соответствуют границы слова

\B - соответствуют не-границы слова

\A - соответствуют только начало строки

\Z - соответствуют только конец строки

При использовании конструкции типа ( ... ), \<digit> подставляет подстроку из скобок с номером digit. Можно использовать скобки для отделения подшаблона. Если в скобках имеется более, чем 9 подстрок, то переменные $10, $11, ... содержат соответствующие подстроки. $+ возвращает то, чему соответствует последняя конструкция в скобках. $& возвращает подставленную строку. $` возвращает все перед подставленной строкой, $' возвращает все после подставленной строки. $_ = 'abcdefghi';

/def/;

print "$`:$&:$'\n"; - напечатает abc:def:ghiНа этом мы закончим описание регулярных выражений, для более подробной информации читайте manual page.


П2.4.3 Зарезервированные переменные


В Perl есть имена имеющие специальное значение. Многие из них аналогичны зарезервированным именам в shell.
Если вы хотите использовать длинные имена переменных, в заголовке программы требуется сказать:
use English;
Многие переменные доступны только для чтения, то есть при попытке присвоения такой переменной какого-либо значения напрямую или по ссылке происходит ошибка.

$_ В эту переменную по умолчанию происходит ввод, присваивание, в нее складываются результаты поиска по заданному образцу. while(<>){...}или, что то же самое: while($_= <>) {...}

$<digit> Эта переменная была описана в предыдущем параграфе. Она доступна только для чтения, так же как и переменные $&, $`, $' и $+.

$. Эта переменная содержит номер строки, которая была почитана последней из файла, который был прочитан последним. Она также доступна только для чтения.

$/ Содержит символ по которому разделяются вводимые записи. По умолчанию содержит символ перевода строки. Она похожа на переменную RS из awk.

$| По умолчанию имеет значение 0. Если содержит ненулевое значение, то происходит сброс буферов каждый раз после осуществления вывода (на печать, на экран и т.д.).

$, Содержит символ-разделитель полей для оператора печати. Подобна переменной OFS в awk.

$ Содержит символ-разделитель записей для оператора печати. Подобна переменной ORS в awk. (Вы можете определить $ вместо того, чтобы печатать n в конце печати.)

$" Подобна переменной $,. Но используется при обращении к списку величин в двойных кавычках (или другой строке, которая требует интерпретации). По умолчанию содержит символ пробел.

$; Содержит символ-разделитель для эмуляции многомерных хэшей. Если ссылаться на такой элемент хэша как $foo{$a,$b,$c} то реально это будет происходить так: $foo{join($;,$a,$b,$c)}. Не путайте с @foo{$a,$b,$c}, так как это тоже самое, что($foo{$a},$foo{$b},$foo{$c}). По умолчанию содержит значение \034 такое же как переменная SUBSEP в awk.

$# Формат для печати чисел. Подобна переменной OFMT в awk. Первоначально содержит значение %.20g.

$% Содержит номер текущей выводимой страницы.

$= Содержит длину текущей страницы (количество печатных срок), обычно содержит значение 60.

$- Содержит значение, определяющее количество оставшихся на странице строк, например количество еще не напечатанных строк для печатного канала вывода.

$~ Содержит имя текущего формата сообщений. Обычно имя дескриптора файла.

$^ Содержит имя текущего формата заголовка страницы. Обычно содержит имя дескриптора файла с добавлением в конце _TOP

$: Содержит множество символов после которых вывод сроки может быть прерван и начат снова после перевода строки.

$! Если эта переменная используется в числовом контексте, то содержит текущее значение errno (номер ошибки) со всеми обычными сообщениями. В строковом контексте содержит соответствующее системное сообщение об ошибке.

$@ Содержит сообщение о синтаксической ошибке, допущенной во время исполнения последней команды eval(). Если содержит значение 0, то команда была исполнена корректно. Но заметьте, что сообщения не накапливаются в этой переменной.

$$ Содержит идентификатор текущего процесса.

$< Содержит идентификатор пользователя (UID), которому принадлежит текущий процесс.

$> Содержит эффективный UID текущего процесса.

$( Содержит идентификатор группы (GID) пользователя, которому принадлежит текущий процесс.

$) Содержит эффективный GID текущего процесса.


$0 Содержит имя файла, в котором находится исполняемая программа.

$ARGV Содержит имя текущего файла, из которого происходит чтение.

@ARGV Содержит массив аргументов командной строки, которые были переданы программе.

@INC Содержит список точек входа в программу, в которых используются конструкции do EXPR, require и use.

%INC Содержит входы для каждого файла, который включается посредством использования операторов do или require. Ключами являются имена файлов, а значениями места их расположения.

%ENV Содержит текущее окружение процесса. Изменением содержимого хэша можно изменить окружение порожденного (дочернего) процесса.

%SIG Этот хэш используется для установки обработчиков различных сигналов. Например: sub handler {

local($sig) = @_;

print "Caught a SIG$sig - shutting down\n";

close(LOG);

exit(0);

}

$SIG{'INT'} = 'handler';

$SIG{'QUIT'} = 'handler';

...

$SIG{'INT'} = 'DEFAULT';

$SIG{'QUIT'} = 'IGNORE';


П2.4.4 Встроенные функции


abs VALUE Возвращает абсолютное значение аргумента.

accept NEWSOCKET, GENERICSOCKET подобно системному вызову accept(2) ждет соединения. Возвращает запакованный адрес, если соединение произошло успешно и FALSE в противоположном случае.

atan2 Y,X Возвращает arctg(Y/X).

bind SOCKET, NAME Привязывает сетевой адрес к сокету, также как системный вызов bind в OS UNIX или любой другой системе, поддерживающей BSD Sockets. Если привязка произошла успешно, возвращает TRUE, в противном случае - FALSE. Переменная NAME должна содержать запакованный адрес, соответствующего для сокета типа. Тип адреса для разных видов сокетов определяется в терминах языка C структурой sockaddr, которая представляет собой абстрактный тип, содержащий все данные, необходимые для сокета.

binmode FILEHANDLE Позволяет читать или писать файл с соответствующим дескриптором в бинарном режиме.

bless REF, PACKAGE Эта функция присоединяет объект на который указывает ссылка REF, к пакету PACKAGE, если он определен, если же он опущен, то к текущему пакету. Для удобства возвращает ссылку, так как bless() часто является последним оператором в конструкторе.

caller EXPR Возвращает контекст текущего вызова подпрограммы. В скалярном контексте возвращает TRUE, если мы находимся внутри подпрограммы, eval() или require(). FALSE в противоположном случае. В списковом контексте возвращает: ($package, $filename, $line) = caller;С аргументом EXPR возвращает более сложную информацию, которая используется отладчиком для печати карты стека. Значение EXPR отмечает глубину стека до текущей записи. ($package, $filename, $line,

$subroutine, $hasargs, $wantargs) = caller($i);

chdir EXPR Изменяет текущую директорию на указанную в EXPR, если это возможно. Если EXPR опущено, то устанавливает в качестве текущей директории домашнюю директорию. Возвращает TRUE в случае успеха и FALSE иначе.

chmod LIST Изменяет права доступа к файлам указанным в LIST. Первым аргументом должна быть маска доступа в цифровом формате. Возвращает число файлов права доступа к которым были успешно сменены. $cnt = chmod 0700 'foo','bar';


chmod 700 @executables;

chown LIST Изменяет хозяина или группу, которой принадлежит список файлов. Первыми двумя аргументами должны быть uid и gid. Возвращает количество успешных изменений.

chr NUMBER Возвращает символ, представленный номером NUMBER в наборе символов. Например, chr(65) вернет A.

close FILEHANDLE Закрывает файл с дескриптором FILEHANDLE. Для более подробной информации читайте manual page. open(OUTPUT '/usr/home/petrov');

...

close OUTPUT;

closedir DIRHANDLE Закрывает каталог открытый вызовом opendir().

connect SOCKET,NAME Пытается соединиться с удаленным сокетом (по аналогии с системным вызовом). Возвращает TRUE в случае успешного соединения и FALSE в противоположном случае. Переменная NAME должна содержать запакованный адрес соответствующего данному сокету типа.

cos EXPR Возвращает косинус EXPR, выраженного в радианах. Если EXPR опущено, возвращает косинус $_.

dbmopen ASSOC, DBNAME, MODE Связывает dbm(3) или ndbm(3) файл с ассоциативным массивом. ASSOC - имя ассоциативного массива. DBNAME - имя базы данных (без .dir или .pag расширения). Если база данных не существует, то она создается с правами доступа указанными в MODE. dbmopen(%HIST,'/usr/lib/news/history', 0600);

while (($key, $val) = each %HIST){

print $key, '=', unpack('L',$val),\n;}

dbmclose(%HIST);

dbmclose ASSOC Прерывает связь между файлом и ассоциативным массивом.

defined EXPR Возвращает TRUE или FALSE, в зависимости от того определено значение EXPR или нет. Многие операции возвращают неопределенное значение в случае конца файла, неинициализированной переменной, системной ошибки или при подобной ситуации. Если речь идет о хэше, то defined покажет только определены ли ли величины, ничего не говоря о существовании ключей. Для определения существования ключей используется функция exists().

delete EXPR Стирает указанную величину. Возвращает удаленную величину или значение не определено в случае, если удаление не произошло. foreach $key (keys %array) {

delete $array{$key};

}Но более быстро то же самое можно сделать используя функцию undef().

die LIST Вне eval() печатает значение LIST в STDERR и выходит из программы с текущим значением $!. Если значение $! есть ноль, то принимает значение $? >> 8. Если значение $? >> 8 есть ноль, то принимает значение 255. Внутри eval() сообщение об ошибке помещается в переменную $@ и eval() прерывается с неопределенным значением. open(FL, "/root/rm-rf") || die "Can't open file.\n";



do BLOCK Функцией не является. Возвращает значение последней операции внутри блока.

do EXPR Использует величину EXPR как имя файла и далее запускает содержимое этого файла, как программу на Perl. Обычно это используется для включения библиотечных подпрограмм. do 'stat.pl';Это то же самое, что: eval 'cat stat.pl';Однако подключать библиотечные модули более удобно используя use и require.

each ASSOC_ARRAY Возвращает массив из двух элементов, содержащий ключ и значение из хэша, причем по очереди перебирает все пары ($key, $value). while (($key,$value) = each %ENV){

print " $key = $value \n";

}

eof FILEHANDLE Возвращает 1, если следующее считывание возвращает конец файла или если FILEHANDLE не был открыт. При опущении аргумента eof обрабатывает последний файл, из которого происходило считывание. Но на практике эта функция редко используется, так как в Perl-е операторы чтения возвращают неопределенное значение в конце файла.

eval EXPR EXPR выполняется как маленькая программа в контексте основной программы. Определенные переменные и подпрограммы остаются определенными и в дальнейшем. Возвращается значение, которое возникает при обработке последнего выражения. Если EXPR опущено, то обрабатывается $_.

exec LIST Исполняет внешнюю программу и НИКОГДА не возвращает управление. На самом деле (в UNIX) производится системный вызов семейства exec, который подменяет программу, исполняющуюся в рамках текущего процесса. Если LIST представляет собой список из более, чем одного аргумента, то вызывается execvp(3) с аргументами из LIST. Если аргумент только один, то он проверяется на метасимволы shell. Если они присутствуют, то он далее передается /bin/sh -c для обработки. Если же их нет, то аргумент передается напрямую execvp, который более эффективен.

exists EXPR Возвращает TRUE, если в хэше есть ключи и даже в том случае, когда значения VALUE не определены.

exit EXPR Обрабатывает EXPR и осуществляет немедленный выход с полученной величиной. $ans = <STDIN>;

exit 0 if $ans =~ /^[Xx]/;Если EXPR опущено, то осуществляет выход с нулевым статусом.

exp EXPR Возвращает е (основание натурального логарифма e = 2.718281828...) в степени EXPR. По умолчанию обрабатывается $_.

fork Делает системный вызов fork(2). Возвращает pid (идентификатор процесса) дочернего процесса родительскому процессу и 0 дочернему процессу. Значение не определено в случае неуспешного завершения команды. Неуспех может произойти, например, в случае установки в системе ограничения на количество процессов данного пользователя. Вот небольшой пример использования этой функции. unless ($pid = fork) {



unless (fork) {

exec "what you really wanna do";

die "no exec";

some_perl_code_here;

exit 0;

}

exit 0;

}

waitpid($pid,0);

getc FILEHANDLE Возвращает следующий символ из файла чтения, присоединенный к FILEHANDLE или пустую строку в случае конца файла. Если FILEHANDLE опущен, то считывание происходит из STDIN.

goto LABEL Эта функция осуществляет переход на точку программы LABEL и продолжает выполнение программы с этой точки. Точка не может находиться внутри подпрограммы или foreach цикла, так как в этих случаях требуется предварительная инициализация. Использовать в качестве LABEL выражение не рекомендуется, хотя такая возможность и предоставляется.

grep BLOCK, LIST

grep EXPR, LIST Обрабатывает BLOCK или EXPR для каждого элемента LIST и возвращает список элементов для которых значение выражения TRUE. В скалярном контексте возвращает число элементов для которых EXPR TRUE.

hex EXPR Возвращает десятичное значение EXPR, интерпретируемого как шестнадцатеричная строка. По умолчанию обрабатывает переменную $_.

kill LIST Посылает сигнал списку процессов LIST, первым элементом списка должен быть номер сигнала. Возвращает число процессов, которым сигнал был послан успешно. В отличие от shell, если номер сигнала отрицателен, то он посылается группе процессов.

int EXPR Возвращает целую часть EXPR, если EXPR опущено, то обрабатывает переменную $_.

join EXPR,LIST Соединяет в единую строку строки из LIST. При этом в качестве разделителей между элементами LIST ставит значение EXPR. Например: $_ = join( ':',$login,$passwd,

$uid,$gid,$gcos,$home,$shell);

keys ASSOC_ARRAY Возвращает обычный массив, состоящий из ключей ассоциативного массива ASSOC_ARRAY. В скалярном контексте возвращает число ключей. @keys = keys %ENV;

length EXPR Возвращает длину EXPR в символах. По умолчанию обрабатывает переменную $_.

link OLDFILE,NEWFILE Создает файл NEWFILE, присоединенный к файлу OLDFILE. (В OS UNIX создание нескольких имен для одного файла) Возвращает 1 в случае успеха и 0 иначе.

listen SOCKET, QUEUESIZE Делает то же самое, что и одноименный системный вызов. Возвращает TRUE в случае успеха, FALSE иначе.

local EXPR На самом деле гораздо эффективнее использовать функцию my. Функция local делает перечисленные переменные локальными в блоке, подпрограмме, eval или do. Если переменных более, чем одна, то они должны объединяться скобками. sub RANGEVAL{



local($min,$max,$thunk) = @_;

local $result = '';

local $i;

for ($i = $min; $i < $max; $i++) {

$result = eval $thunk;

}

$result;

}

log EXPR Возвращает натуральный логарифм EXPR, по умолчанию обрабатывает переменную $_.

map EXPR,LIST Подставляет каждый элемент из списка LIST в EXPR (которое может быть блоком) и возвращает список полученных после обработки величин. @chars = map(chr, @nums);

mkdir FILENAME,MODE Создает директорию с именем FILENAME и правами доступа указанными в переменной MODE. В случае успеха возвращает 1, в противном случае возвращает 0 и устанавливает значение переменной $!(errno).

my EXPR Эта функция (так же как и описанная ранее функция local) делает перечисленные переменные локальными в пределах блока, подпрограммы, eval или do. Если список состоит более чем из одного элемента, то он должен быть заключен в скобки. Все элементы в списке должны быть фактическими параметрами. В отличие от local, переменные локализованные функцией my не видны снаружи блока, подпрограммы или другой конструкции, внутри которой my употребляется.

next LABEL Употребляется подобно continue оператору в C - запускает следующую итерацию цикла. line: while (<STDIN>) {

next line if /^#/;

...

}

oct EXPR Возвращает десятичное значение EXPR, интерпретируемого как строка в восьмеричном формате. (Если строка начинается с 0x, то интерпретируется, как строка в шестнадцатеричном формате.)

open FILEHANDLE,EXPR Открывает файл, имя которого описано в переменной EXPR и привязывает его к FILEHANDLE. Если EXPR опущено, то переменная с таким же именем как FILEHANDLE содержит имя файла. Если имя файла начинается со знака: ¯

< файл открывается на чтение.

> файл открывается на запись.

>> файл открывается для добавления.

| имя файла расценивается как команда,

с которой будет организован программный канал,

то есть вывод в дескриптор FILEHANDLE будет

передаваться на вход программе EXPR.

Если знак | указывается после имени команды, то вывод этой команды будет ассоциирован с дескриптором FILEHANDLE, из которого будет производиться чтение. Интересно, что нельзя открыть двойной программный канал, то есть ассоциировать ввод и вывод команды с дескриптором файла (что соответствовало бы системному вызову popen в UNIX).

В случае, когда имя файла оканчивается вертикальной чертой, оно расценивается как имя команды, вывод которой будет интерпретироваться как ввод из файла (аналог функции popen(3)). open(LOG, '>>/usr/spool/news/twitlog');



open DIRHANDLE,EXPR Открывает директорию с именем EXPR, возвращает TRUE в случае успеха.

ord EXPR Возвращает числовое значение в таблице ASCII первого символа EXPR. По умолчанию обрабатывает переменную $_.

print FILEHANDLE,LIST Печатает строку или несколько строк, разделенных запятой. FILEHANDLE может быть именем скалярной переменной, содержащей дескриптор файла. Если эта переменная опущена то печать идет в выбранный канал вывода. Если переменная LIST тоже опущена, то печатает переменную $_ в STDOUT.

printf FILEHANDLE, LIST Эквивалентно print FILEHANDLE, sprintf(LIST). Первый аргумент LIST интерпретируется как формат печати.

rand EXPR Возвращает выбранное случайным способом значение между 0 и EXPR. EXPR должно быть положительным. По умолчанию производит выборку в диапазоне между 0 и 1. (Замечание: если ваша функция постоянно возвращает слишком большие или слишком малые значения, то скорее всего была допущена ошибка при компиляции вашей версии Perl. Было установлено неверное значение RANDBITS.)

read FILEHANDLE,SCALAR,LENGTH,OFFSET Считывает LENGTH байт данных из FILEHANDLE в переменную SCALAR. Возвращает число считанных байт или неопределенное значение в случае ошибки. Если вы хотите считать данные не с начала строки, то для этого нужно установить значение переменной OFFSET.

readlink EXPR Возвращает значение символьной ссылки, если она существует. Если же ее нет, то выдает fatal error и устанавливает значение переменной $!. По умолчанию обрабатывает переменную $_.

redo LABEL Перезапускает цикл без повторной обработки условия. Блок continue, если он есть не исполняется. Если LABEL опущена, то команда выполняется для внутреннего цикла. line: while(<STDIN>) {

while ($_ ne '\') {

if (ord $_ < 86) {

...

}

redo line;

}

print;

}

ref EXPR Возвращает TRUE, если EXPR является ссылкой и FALSE в противоположном случае. Полученное значение зависит от типа объекта на который указывает ссылка. Существует несколько встроенных типов данных:

REF SCALAR ARRAY HASH CODE GLOB Если объект, на который указывает ссылка, находится в пакете (package), то в таком случае возвращается имя пакета. if (ref($r) eq "HASH") {



print " Это ссылка на ассоциативный массив.\n";

}

if (!ref($r)) {

print " А это не ссылка вовсе! \n";

require EXPR Используется для подключения модулей. require "oraperl.pm";

reset EXPR Обычно используется в continue блоке в конце цикла для переустановки значений переменных. EXPR интерпретируется как список отдельных символов. Значения переменных и массивов, имена которых начинаются с одного из этих символов списка переустанавливаются. Например: ¯

reset 'X' переустановит все X переменные

reset 'a-z' переустановит все переменные,

имена которых состоят из маленьких букв.

rm FILENAME Удаляет файл или директорию с заданным именем. Возвращает 1 в случае успеха, 0 в противоположном случае и устанавливает значение переменной $!. По умолчанию обрабатывает аргумент $_.

scalar EXPR Выражение будет трактоваться в скалярном контексте. Возвращает значение EXPR.

seek FILEHANDLE, POSITION, WHENCE Позволяет установить курсор в файле, определенном в переменной FILEHANDLE, на позицию POSITION в режиме, указанном в переменной WHENCE. Если переменная WHENCE содержит значение 0, то позиция отсчитывается от начала файла, если 1 то от текущей позиции и если 2, то от конца файла. Возвращает 1 в случае успеха и 0 иначе.

select FILEHANDLE Возвращает текущий выбранный FILEHANDLE. Направляет вывод в FILEHANDLE.

select RBITS,WBITS,EBITS,TIMEOUT Вызывает системный вызов select(2) с определенной аргументами битовой маской.

shift ARRAY Сдвигает массив ARRAY влево с удалением первого элемента и возвращает удаленный элемент. Если в массиве нет элементов, то возвращает неопределенное значение. Если ARRAY опущен, то обрабатывает массив @ARGV в главной программе и массив @_ в подпрограммах.

sin EXPR Возвращает синус выражения EXPR (выраженного в радианах). Если аргумент опущен, то обрабатывается переменная $_.

sleep EXPR Дает процессу команду остановки на EXPR секунд. Если аргумент опущен, то процесс зависает навсегда. В таком случае ``сон'' можно прервать, послав ему сигнал. Возвращает число секунд, в течение которых процесс был в состоянии остановки.

socket SOCKET,DOMAIN,TYPE,PROTOCOL Создает сокет и привязывает его к дескриптору файла SOCKET. Остальные параметры описываются так же, как и в одноименном системном вызове. В начале программы необходимо написать use Socket;.

sort SUBROUTINE,LIST Сортирует аргументы из LIST и возвращает отсортированный список. Если список является массивом, то несуществующие элементы массива не учитываются и не возвращаются. Ниже приведено несколько примеров. @articles = sort @files;- Лексическая сортировка без использования подпрограммы. @articles = sort{$a cmp $b} @files;- То же самое, но с использованием подпрограммы. @articles = sort{$a <=> $b} @files;- Численная сортировка по возрастанию.

splice ARRAY,OFFSET,LENGTH,LIST Удаляет из массива ARRAY элементы, отмеченные в переменных OFFSET и LENGTH и заменяет их элементами списка LIST, если таковые имеются. Возвращает удаленные из массива элементы. Длина массива растет или уменьшается, если это необходимо. Если переменная LENGTH опущена, то удаляет все, начиная с OFFSET.

split /PATTERN/,EXPR,LIMIT Разбивает строку на массив строк и возвращает его. В скалярном контексте возвращает число полученных полей и помещает полученный массив в @_. Если EXPR опущено то разбивается строка $_. Если PATTERN тоже опущен, то разбиение происходит по символу пробел. Символы, указанные в PATTERN, служат разделителями для полей. Разделители могут быть длиннее, чем один символ. Если переменная LIMIT задана и имеет неотрицательное значение, то разбиение будет происходить на число полей не более указанного в LIMIT. Если переменная не определена, то пустые поля отбрасываются, если имеет отрицательное значение, то это интерпретируется Perl-ом, как отсутствие ограничения на длину возвращаемого массива. Если шаблону соответствует пустая строка, то EXPR будет разбито на отдельные символы. Например: print join(':',split(/ */,'hi there'));напечатает строку h:i:t:h:e:r:e.

sqrt EXPR Возвращает корень квадратный из значения EXPR. По умолчанию обрабатывает переменную $_.

system LIST Делает то же самое, что и функция exec LIST, за одним исключением: вместо того, чтобы просто начать выполнять программу , как это делает exec, system делает fork и порождает еще один процесс, причем родительский процесс ждет завершения дочернего.

tell FULEHANDLE Возвращает текущую позицию курсора в файле FILEHANDLE. Если аргумент опущен, то обрабатывает файл, который читался последним.

tie VARIABLE,PACKAGENAME,LIST Привязывает переменную к пакету, который будет заносить значения в эту переменную. Переменная VARIABLE содержит имя переменной, переменная PACKAGENAME содержит имя пакета. Дополнительные аргументы передаются методу new этого пакета. Обычно это такие аргументы, которые в дальнейшем могут быть переданы в качестве параметров dbm_open() функции из C. tie(%HIST, NDBM_File,'/usr/lib/news/history', 1, 0);



while(($key,$val) = each %HIST) {

print $key, '= ', unpack('L',$val),"\n";

}

untie(%HIST);Пакет, реализующий ассоциативный массив, должен содержать следующие методы:
TIEHASH objectname, LIST
DESTROY this
FETCH this, key
STORE this, key, value
DELETE this, key
EXISTS this, key
FIRSTKEY this
NEXTKEY this, lastkey
Пакет, реализующий обычный массив, должен содержать следующие методы:
TIEARRAY objectname, LIST
DESTROY this
FETCH this, key
STORE this, key, value
Пакет, реализующий скаляры, должен содержать следующие методы :
TIESCALAR objectname, LIST
DESTROY this
FETCH this
STORE this, value

truncate FILEHANDLE, LENGTH Обрезает файл FILEHANDLE до заданной длины.

undef EXPR Делает значение EXPR неопределенной величиной, в случае, когда аргумент опущен ничего не меняет. Не следует пытаться применять эту функцию к зарезервированным переменным, потому что результат может оказаться непредсказуемым.

unlink LIST Удаляет список файлов и возвращает число удачно удаленных файлов. Если вы не являетесь суперпользователем, то эта функция не может удалять каталоги. Даже в случае, когда программа запускается с привилегиями суперпользователя, будьте осторожны, лучше использовать функцию rmdir.

untie VARIABLE Разрывает связь между переменной и пакетом.

unshift ARRAY, LIST Производит действие противоположное действию функции shift. Присоединяет LIST к началу массива ARRAY и возвращает новое количество элементов в массиве.

use Module LIST Осуществляет присоединение модуля к программе. use strict qw(subs,vars,refs);

values ASSOC_ARRAY Возвращает обычный массив, состоящий из значений ассоциативного массива ASSOC_ARRAY. В скалярном контексте возвращает число элементов полученного массива. Элементы массива могут располагаться в произвольном порядке.

wantarray Возвращает TRUE, если контекст исполняющейся подпрограммы списковый, FALSE в противоположном случае.

write создает запись (возможно состоящую из нескольких строк) в соответствующем файле, используя формат ассоциированный с этим файлом. Формат для текущего канала вывода может быть установлен посредством присваивания переменной $~{ } имени формата.


П2.4.5.1 Подпрограммы


Описать и использовать подпрограмму можно несколькими способами:

sub NAME; - подразумевает описание в дальнейшем тела подпрограммы. sub NAME BLOCK - непосредственное описание. $subref = sub BLOCK - анонимное описание. use PACKAGE qw(NAME1, NAME2, NAME3) - включение подпрограмм из модулей. Вызвать подпрограмму можно тоже несколькими способами:

&NAME(LIST) - скобки обязательны для & формы. NAME(LIST) - & не обязательно со скобками. NAME LIST - скобки можно опустить в случае предварительного описания или включения подпрограммы из модуля. Аргументы передаются подпрограмме в виде локального массива @_, его элементы являются ссылками на реальные скалярные параметры. Подпрограмма возвращает значение, полученное в результате исполнения последнего оператора подпрограммы. Как уже говорилось, подпрограмма вызывается использованием префикса & перед ее именем, в Perl 5 этот префикс не обязателен. Пример: sub MAX {

my $max = pop(@_);

foreach $foo (@_) {

$max = $foo if $max < $foo;

}

$max;

}

...

$bestmark = &MAX(1,2,3,4,5);Подпрограмма может вызываться рекурсивно. Если подпрограмма вызывается с использованием & формы, то список аргументов необязателен. Если вы хотите создать внутри модуля его собственную, невидимую снаружи подпрограмму, то описание должно быть анонимным: my $subref = sub {...}

&$subref(1,2,3);



П2.4.5.2 Пакеты


Perl поддерживает механизм альтернативного именного пространства для каждого отдельного пакета. Обычная программа является пакетом с именем main. Можно ссылаться на переменные или дескрипторы файлов из других пакетов посредством использования префикса перед именем переменной, состоящего из имени пакета и двойного двоеточия: $Package::Variable. Если имя пакета нулевое, то предполагается использование переменной из main пакета. То есть $::sail эквивалентно $main::sail. Пакеты могут включать в себя другие пакеты, в таком случае чтобы обратиться к переменной нужно применить описанное обозначение рекурсивно: $OUTER::INNER::var.
В пакете могут содержаться только переменные, чьи имена начинаются с буквы или подчерка, остальные переменные содержатся в пакете main. Кроме того зарезервированные переменные, как то STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC и SIG также содержатся в главном пакете. package mypack;

sub main::mysub {

...

}



П2.4.5.3 Таблицы символов


Таблицы символов пакета хранятся в ассоциативном массиве с тем же именем и двойным двоеточием в конце. Для пакетов включенных в пакет имя символьной таблицы составляется аналогичным образом: %OUTER::INNER::.



П2.4.5.4 Конструкторы и деструкторы пакетов


Существует две функции специального вида - конструкторы и деструкторы. Это BEGIN и END программы в их описании необязательно использование sub. Подпрограмма BEGIN исполняется сразу, как только это возможно, то есть в момент, когда она полностью определена, даже перед тем как обрабатывается остаток содержащего файла. В файле может быть несколько блоков BEGIN. Они исполняются в порядке определения.
Подпрограмма END исполняется в самом конце. В файле может содержаться несколько END блоков, они исполняются в обратном порядке.



П2.4.5.5 Классы


В Perl 5 нет специального синтаксиса для описания классов, но пакеты могут функционировать как классы, если они содержат подпрограммы функционирующие как методы. Такие пакеты могут также брать некоторые методы из других пакетов-классов. Для этого необходимо перечислить имена других пакетов в массиве @ISA.



П2.4.5.6 Модули


В Perl 5 понятие пакетов расширено в понятие модулей. Модули это пакеты находящиеся в одноименном файле, включенном в библиотеку. Модули подключаются следующим образом: use Module; или use Module LIST;Это эквивалентно: BEGIN { require "Module.pm"; import Module; }Все модули имеют расширение .pm. Если именное пространство модуля пересекается с именным пространством основной программы то всегда используется use, если не пересекается то можно использовать require.
Стандартные модули Perl описаны в документации.



П2.5.1 Объекты


В отличие от C++, Perl не имеет специального синтаксиса для описания конструкторов. Конструктор, как уже говорилось раньше, это просто подпрограмма, которая возвращает ссылку ассоциированную с классом (как правило с тем, где определена подпрограмма). Например, типичный конструктор: package Critter;

sub new { bless {} }{} создает ссылку на анонимный хэш.
В пределах класса методы как правило работают с обычными ссылками. Конструктор может привязать объект к другому классу, в таком случае предыдущая привязка бывает забыта, так как объект не может принадлежать одновременно нескольким классам.



П2.5.2 Классы


В отличие от C++, Perl не имеет специального синтаксиса для описания классов. Классом является пакет, чьи подпрограммы выступают в качестве методов. Для каждого пакета определен специальный массив @ISA, в котором перечислены пакеты, подключенные к данному пакету. Таким образом в Perl реализован механизм наследования методов. Метод, принадлежащий другому объекту, подключается как подпрограмма.



П2.5.3 Методы


В Perl-е метод имеет синтаксис простой подпрограммы. В качестве первого аргумента метода выступает объект или пакет. Существует два типа методов: статические и виртуальные методы.
Статические методы имеют первым аргументом имя класса. Они обеспечивают функциональность для класса в целом, а не для отдельных объектов принадлежащих классу. Конструкторы являются, как правило, статическими методами. Многие статические методы просто игнорируют свой первый аргумент, так как заранее знают, какому пакету они принадлежат. Другой способ использования статических методов состоит в том, что метод работает с объектом, используя имя: sub find {

my ($class, $name) = @_;

$objtable{$name};

}Виртуальные методы имеют первым аргументом ссылку на объект. Обычно они помещают эту ссылку в переменную self или this и в дальнейшем используют ее как обычную ссылку. sub display {

my $self = shift;

my @keys = @_ ? @_ : sort keys %$self;

foreach $key (@keys) {

print "\t$key => $self ->{$key}\n";

}

}



П2.5.4 Вызов метода


Существует два способа обратиться к методу. Во-первых, можно вызвать его просто как подпрограмму. Но в таком случае не работает механизм наследования. Второй способ лучше просто проиллюстрировать примерами. $fred = find Critter "Fred";

display $fred, 'Height', 'Weight';Это можно записать так: display {find Critter "Fred"} 'Height', 'Weight';



П2.5.5 Деструкторы


Когда удаляется последняя ссылка на объект, этот объект автоматически удаляется. Это может произойти даже после завершения программы, если ссылки на объект содержались в глобальных переменных. Если необходимо контролировать процесс удаления объекта, можно определить в объекте специальный метод, называемый деструктором. Деструктор объекта (в отличие от C++) имеет фиксированное имя DESTROY и вызывается перед удалением объекта. В нем можно реализовать дополнительные процедуры, необходимые для корректного завершения (например, удаление временных файлов, используемых объектом).



П2.5 Объектная ориентация


Понятие объектной ориентации зиждется на трех простых определениях:

Объект это просто ссылка. Класс это просто пакет, который содержит методы для работы с объектными ссылками. Метод это просто подпрограмма, которая имеет своим первым аргументом объектную ссылку (или имя пакета для статического метода).



Пару слов от автора


Что меня заставило взятся за этот нелегкий труд написания данного учебного пособия. Ну во первых то что практически НЕТ

ничего по CGI-програмированию на русском

языке, а большинству тех,кто хотел бы изучить CGI, документация на английском

в отличии от тех немногих типа меня практически недоступна для понимания.Чтоб помочь им преодолеть этот в первую очередь языковый барьер я и сел писать эту хренотень...

Еще причина ,отчасти перекликающаяся с первой, это то что когда говорят об интернет-программировании

обычно излагают HTML со всеми тэгами, которые всем уже по ночам в кошмарах снятся ,ну а после чего начинают долго охать и ахать над прелестями

нового аппаратно и платформо-независимого,переносимого,безопасного.....и.т.д. языка Java.Иногда в еще и могут тонким краешком затронуть JavaScript.Видя эту не побоюсь этого слова безнадежную

ситуацию, я как доблестный CGI-программист решил хоть что-то поправить к лучшему. Если у меня это хоть немного удалось, то напишите мне. Если также у вас есть какие-то вопросы -тоже пишите, я с радостью постараюсь ответить на них всех.

Леша.

paaa@uic.nnov.ru

http://www.uic.nnov.ru/~paaa/cgi-bin/contact.cgi



Переменные среды CGI


Предыдущий скрипт не содержал ничего особенно замечательного,так просто вываливал HTMLый текст который благополучно и отбражался на екране браузера.Но По настоящему мощь придает CGI возможность обработки параметров,которые переданы скрипту.например вы можете набрать

http://www.somehost.ru/somedir/cgi-bin/my_cgi.cgi?param=value

то есть вы хотите чтоб скрипт my_cgi.cgi

обработал для вас параметер param

со значением value (ну это например) или когда вы заполнили запрос в форме (в например yahoo

или altavista).Ну это с точки зрения пользователя... А на сервере при запуске CGI-скрипта сервер формирует среду окружения в которой скрипт может найти всю доступную информацию о HTTP-соединении и о запросе.

Вот эти переменные:

REQUEST_METHOD

Это одно из самых главных поле используемое для определения метода запроса HTTP Протокол HTTP

использует методы GET и POST

для запроса к серверу.Они отличаются тем что при методе GET

запрос является как-бы частью URL

т.е. http://www..../myscript.cgi?request а при методе POST данные передаются в теле HTTP-запроса (при GET

тело запроса пусто) и следовательно для CGI тоже есть различие при GET запрос идет в переменную QUERY_STRING а при POST подается на STDIN

скрипта.

Пример:REQUEST_METHOD=GET

QUERY_STRING

Это строка запроса при методе GET. Вам всем известно что запрос из формы кодируется браузером поскольку не все символы разрешены в URL некоторые имеют специальное назначение. Теперь о методе urlencode: неплохо бы чисто формально напомнить,что все пробелы заменяются в URL на знак '+', а все специальные и непечатные символы на последовательность %hh ,где hh-шестнадцатиричный код символа,разделитель полей формы знак '&',так что при обработке форм надо произвести декодирование.

Пример:QUERY_STRING= name=quake+doomer&age=20&hobby=games

CONTENT_LENGTH

Длина в байтах тела запроса.При методе запроса POST необходимо считать со стандартного входа STDIN

CONTENT_LENGTH байт,а потом производить их обработку.Обычно методом POST пользуются для передачи форм,содержащих потенциально большие области ввода текста TEXTAREA.При этом методе нет никаких ограничений,а при методе GET существуют ограничения на длину URL .


Пример:CONTENT_LENGTH=31

CONTENT_TYPE

Тип тела запроса( для форм кодированых выше указаным образом он application/x-www-form-urlencoded)

GATEWAY_INTERFACE

Версия протокола CGI.

Пример:GATEWAY_INTERFACE=CGI/1.1

REMOTE_ADDR

IP-Адрес удаленого хоста,делающего данный запрос.

Пример:REMOTE_ADDR=139.142.24.157

REMOTE_HOST

Если запрашивающий хост имеет доменное имя,то эта переменная содержит его, в противном случае -тот же самый IP-адресс что и REMOTE_ADDR

Пример:REMOTE_HOST=idsoftware.com

SCRIPT_NAME

Имя скрипта,исполизованое в запросе.Для получения реального пути на сервере используйте SCRIPT_FILENAME

Пример:SCRIPT_NAME=/~paaa/guestbook.cgi

SCRIPT_FILENAME

Имя файла скрипта на сервере.

Пример:SCRIPT_FILENAME=/home/p/paaa/public_html/cgi-bin/guestbook.cgi

SERVER_NAME

Имя серера ,чаще всего доменное как www.microsoft.com ,но в редких случаях за неимением такового может быть IP-адресом как 157.151.74.254

Пример:SERVER_NAME=www.uic.nnov.ru

SERVER_PORT

TCP-Порт сервера используюшийся для соединения .По умолчаниию HTTP-порт 80, хотя может быть в некоторых случаях другим.

Пример:SERVER_PORT=80

SERVER_PROTOCOL

Версия протокола сервера.

Пример:SERVER_PROTOCOL=HTTP/1.1

SERVER_SOFTWARE

Програмное обеспечение сервера.

Пример:Apache/1.0

AUTH_TYPE, REMOTE_USER

Эти переменные определены в том случае,когда запрошеный ресурс требует аутентификации пользователя.

Переменные заголовка HTTP-запроса.

За исключением тех строк из заголовка HTTP-запроса которые были включены в другие переменные,сервер приделывает строкам префикс HTTP_ и заменяет знаки '-' на '_':

HTTP_ACCEPT

Давая запрос на сервер браузер обычно расчитывает получить информацию определеного формата,и для этого он в заголовке запроса указывает поле Accept:,Отсюда скрипту поступает cписок тех MIME,которые браузер готов принять в качестве ответа от сервера.

Пример:HTTP_ACCEPT=text/html,text/plain,image/gif

HTTP_USER_AGENT

Браузер обычно посылает на сервер и информацию о себе,чтоб базируясь на знании особеностей и недостатков конкретных браузеров CGI-скрипт мог выдать информацию с учетом этого. Например,разные браузеры могут поддерживать или не поддерживать какие-то HTMLые тэги.



Пример:HTTP_USER_AGENT=Mozila/2.01 Gold(Win95;I)

Ну, начнем применять на практике усвоеные уроки.



#!/usr/bin/perl #vars.cgi sub urldecode{ #очень полезная функция декодирования local($val)=@_; #запроса,будет почти в каждой вашей CGI-программе $val=~s/\+/ /g; $val=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge; return $val; } print "Content-Type: text/html\n\n"; print "<HTML><HEAD><TITLE>CGI-Variables</TITLE></HEAD>\n"; print "<BODY>\n"; print "Enter here something:<ISINDEX><BR>\n"; print "Your request is:$ENV{'REQUEST_STRING'}<BR>\n"; print "Decoded request is:urldecode($ENV{'REQUEST_STRING'})<BR>\n"; print "<HR>\n"; print "Variables:<BR>\n"; print "<I><B>REQUEST_METHOD</B></I>=$ENV{'REQUEST_METHOD'}<BR>\n"; print "<I><B>QUERY_STRING</B></I>=$ENV{'QUERY_STRING'}<BR>\n"; print "<I><B>CONTENT_LENGTH</B></I>=$ENV{'CONTENT_LENGTH'}<BR>\n"; print "<I><B>CONTENT_TYPE</B></I>=$ENV{'CONTENT_TYPE'}<BR>\n"; print "<I><B>GATEWAY_INTERFACE</B></I>=$ENV{'GATEWAY_INTERFACE'}<BR>\n"; print "<I><B>REMOTE_ADDR</B></I>=$ENV{'REMOTE_ADDR'}<BR>\n"; print "<I><B>REMOTE_HOST</B></I>=$ENV{'REMOTE_HOST'}<BR>\n"; print "<I><B>SCRIPT_NAME</B></I>=$ENV{'SCRIPT_NAME'}<BR>\n"; print "<I><B>SCRIPT_FILENAME</B></I>=$ENV{'SCRIPT_FILENAME'}<BR>\n"; print "<I><B>SERVER_NAME</B></I>=$ENV{'SERVER_NAME'}<BR>\n"; print "<I><B>SERVER_PORT</B></I>=$ENV{'SERVER_PORT'}<BR>\n"; print "<I><B>SERVER_PROTOCOL</B></I>=$ENV{'SERVER_PROTOCOL'}<BR>\n"; print "<I><B>SERVER_SOFTWARE</B></I>=$ENV{'SERVER_SOFTWARE'}<BR>\n"; print "<I><B>HTTP_ACCEPT</B></I>=$ENV{'HTTP_ACCEPT'}<BR>\n"; print "<I><B>HTTP_USER_AGENT</B></I>=$ENV{'HTTP_USER_AGENT'}<BR>\n"; print "<HR>\n"; print "All enviroment:<BR>\n"; foreach $env_var (keys %ENV){ print "<I>$env_var=$ENV{$env_var}</I><BR>\n"; } print "</BODY></HTML>\n";

Так как все ваши .cgi -файлы должны быть исполняемыми то чтоб облегчить себе жизнь заведите себе в директории cgi-bin командный файл mkcgi ,содержащий



chmod +x *.cgi

и сделайте его в свою очередь исполняемым chmod +x mkcgi -он сильно упростит вам жизнь.

Ну а теперь запускайте скрипт......

Изучив информацию,выдаваемую данным скриптом вы сможете лучше ориентироваться в переменных окружения CGI.


Perl+Windows


Как прикрутить perl к винде, чтобы можно было скрипты выполнять локально?


У меня перл от Activestate, как мне поставить такой-то модуль?


А из браузера как смотреть на вывод скрипта? Почему-то показывается исходник.


Как заставить работать связку perl + MySQL под виндой?



Q: Как прикрутить perl к винде, чтобы можно было скрипты выполнять локально?

A: www.activestate.com, download perl. Устанавливаете, и запускаете:

perl myscript.pl

Q: У меня перл от Activestate, как мне поставить такой-то модуль?

A1: ppm

ppm> install

A2: www.activestate.com/packages/zips/

Hаходите нужный архив, скачиваете, читаете readme.

Если нужного модуля нет - идёте на CPAN, ищете его там, пытаетесь понять, как

его прикрутить. С некоторой вероятностью он чисто перловый, и тогда есть шанс,

что просто положив его в директорию с модулями, вы получите работающий модуль.

Если же у него есть С-часть, ставите MS Visual C, и мучаетесь, мучаетесь...

Q: А из браузера как смотреть на вывод скрипта? Почему-то показывается

исходник.

A: Потому что между браузером и perl должен стоять сервер, который и

запускает скрипт на выполнение, отдавая результат браузеру. Сервер не

обязательно подразумевает под собой отдельный компьютер - вы можете поставить

себе программу, и обращаться к ней через браузер, наблюдая за работой

скриптов. Вариантов масса:

Apache-W32, www.apache.org

Personal Web Server из поставки Win9x

Sambar, www.sambar.com

Устанавливаете сервер, и либо указываете в настройках сервера ассоциацию на

файлы cgi и pl - запуск perl.exe, либо устанавливаете такую ассоциацию на эти

файлы в windows.

Q: Как заставить работать связку perl + MySQL под виндой?

A: Скачать дистрибутив MySQL с сайта (www.mysql.com), установить необходимые модули - DBI и DBD:MySQL.

Неплохой тьюториал по установке Perl+Apache+MySql

http://userguide.webservis.ru/



Постраничный вывод новостей с разбиением по датам


Предположим есть файл news.dat со строками(не суть что разделитель, разделитель определяется переменной $/, которую можно в начале кода переопределить) вида:

20010717<A href="http://www.netoscope.ru/news/" target=_new>news1</a>&nbsp;&nbsp;&nbsp;&nbsp;[Нетоскоп] 20010717<A href="http://www.utro.ru/news/" target=_new>news2</a>&nbsp;&nbsp;&nbsp;&nbsp;[Утро] 20010718<A href="http://www.compulenta.ru/" target=_new>news3</a>&nbsp;&nbsp;&nbsp;&nbsp;[Компьюлента] 20010718<A href="http://www.compulenta.ru" target=_new>news4</a>&nbsp;&nbsp;&nbsp;&nbsp;[Компьюлента] 20010718<A href="http://www.kommersant.ru/news/" target=_new>news5</a>&nbsp;&nbsp;&nbsp;&nbsp;[КоммерсантЪ] 20010719<A href="http://www.echo.msk.ru/7news/" target=_new>news6</a>&nbsp;&nbsp;&nbsp;&nbsp;[Эхо Москвы] 20010719<A href="http://www.echo.msk.ru/7news/" target=_new>news7</a>&nbsp;&nbsp;&nbsp;&nbsp;[Эхо Москвы]

где даты поставлены задом наперед, сначала год, затем месяц, затем день, так сравнивать легче, ибо год максимален, месяц тоже максимален, и деть тоже максимален. Иначе для сортировки по дате пришлось бы вводить двенадцатиричную систему счисления для месяцев и затем 60-тиричную систему счисления для часов, минут и секунд.

Приведенная ниже программа позволяет реализовать постраничный вывод текста, с линейкой прокрутки текста наподобие результатов, выдаваемых обычными поисковиками:

#!/usr/bin/perl -wT print "content-type: text/html\n\n"; use CGI 'param'; $pos = param('pos'); $n = 5; $k = 5; $url = "q.pl"; open F, "<news.dat"; @mass=<F>; close F;

@m1=grep{!$_{$_}++} map{/^(\d\d\d\d\d\d\d\d)/} @mass;

foreach $u(0 .. $#m1){ foreach $n(@mass){ chomp $m1[$u]; push @{$ha{$m1[$u]}}, $n if($n=~m/^$m1[$u]/) } } print "<a name=top>"; for $k(reverse sort keys %ha){ $k=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; push(@re, " <a href=\"#$k\">$k</a> "); } print "<center>"; &res(@re); print "</center>"; for $k(reverse sort keys %ha){ $m=$k; $m=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; $tr="<b><a name=\"$m\">$m</b> <a href=\"#top\">top</a><ul>"; foreach $im(@{$ha{$k}}){ $im=~s!$k|<br>!!; $tr.="<li>$im";} $tr.="</ul>"; push @res, "$tr\n"; } push @res, ""; &res(@res); sub res{ local @res=@_; if($#res>$n-1){ print "<p><center><font size=-1><b>"; foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); } foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->') {push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } } print $back[$#back]; print @nach; foreach $elem1(@vtoroj){ if ($elem1/$n<=$pos/$n+$k && $res[$#res] ne '<!--end-->'){ print " | <a href=\"$url?pos=$elem1\">".($elem1/$n+1)."<\/a> \n"; } if($#vtoroj > $k-1 && $res[$#res] ne '<!--end-->'){ push(@back1, "<a href=\"$url?pos=".($elem1)."\">>><\/a>") } } print "$back1[0]</b></font></center>"; } $#pervij=-1; $#vtoroj=-1; $#back=-1; $#nach=-1; $#back1=-1; print "<p>"; for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]} }


Разберем работу программы:

@m1=grep{!$_{$_}++} map{/^(\d\d\d\d\d\d\d\d)/} @mass;

составляем массив цифр, т.е. массив дат, map{/^(\d\d\d\d\d\d\d\d)/} @ mass составляет список цифр, указанных в регулярном выражении. Следующая строчка grep{!$_{$_}++} - убирает одинаковые даты, т.к. в списке новостей может быть несколько новостей за один день. Получаем массив @m1 с днями, которые были с новостями.

foreach $u(0 .. $#m1){ foreach $n(@mass){ chomp $m1[$u]; push @{$ha{$m1[$u]}}, $n if($n=~m/^$m1[$u]/) } }

создаем хеш массивов @{$ha{$m1[$u]}}, в которых определенному дню будет соответствовать несколько новостей.

for $k(reverse sort keys %ha){ $k=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; push(@re, " <a href=\"#$k\">$k</a> "); } print "<center>"; &res(@re); print "</center>";

выводим линейку дат, если при выводе 5 дней(значение числа дней содержится в переменной $n = 5;) число новостей таково, что будет помещаться на более чем одной странички, вобщем для быстрой навигации.

for $k(reverse sort keys %ha){ $m=$k; $m=~s|^(\d\d\d\d)(\d\d)(\d\d)|$3\.$2\.$1|; $tr="<b><a name=\"$m\">$m</b> <a href=\"#top\">top</a><ul>"; foreach $im(@{$ha{$k}}){ $im=~s!$k|<br>!!; $tr.="<li>$im";} $tr.="</ul>"; push @res, "$tr\n"; } push @res, ""; &res(@res);

выводим из хеша список новостей по одной штуке, независимо от даты. Далее следует код вывода линейки прокрутки для постраничного вывода результатов.

sub res{ local @res=@_; if($#res>$n-1){ print "<p><center><font size=-1><b>"; foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); } foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->') {push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } } print $back[$#back]; print @nach; foreach $elem1(@vtoroj){ if ($elem1/$n<=$pos/$n+$k && $res[$#res] ne '<!--end-->'){ print " | <a href=\"$url?pos=$elem1\">".($elem1/$n+1)."<\/a> \n"; } if($#vtoroj > $k-1 && $res[$#res] ne '<!--end-->'){ push(@back1, "<a href=\"$url?pos=".($elem1)."\">>><\/a>") } } print "$back1[0]</b></font></center>"; } $#pervij=-1; $#vtoroj=-1; $#back=-1; $#nach=-1; $#back1=-1; print "<p>"; for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]} }



локализуем массив @res: local @res=@_; - получили массив, переданный попрограмме. Далее if($#res>$n-1){blah blah blah} если число элементов массива больше, чем 5, то показываем строчку прокрутки.

Разбиваем массив @res на массивы до текущей страницы(@pervij) и после текущей страницы(@vtoroj):

foreach($j=0; $j<=$#res; $j++){ push(@pervij,"$j") if($j<=$pos && $j % $n == 0); push(@vtoroj,"$j") if($j>=$pos+$n && $j % $n == 0); }

размерность массивов @pervij и @vtoroj кратна(кратность определяется оператором %) числу $n, т.е. это массивы до текущей страницы и после текущей страницы, в броузере, если пользователь находится допустим на 10 странице результатов до текущей все то, что до цифры без ссылки, после текужей это все то, что после цифры без ссылки, включая линейки прокрутки << и >>:



<< 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

| 10

| 11

| 12 >>



Эти массивы содержат число пятерок(для $n=5;) элементов массива @res.

foreach $elem(@pervij){ if($elem/$n>=$pervij[$#pervij]/$n-$k && $res[$#res] ne '<!--end-->'){ if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->') {push(@nach ,($elem/$n+1));} else{ push(@nach, " <a href=\"$url?pos=$elem\">".($elem/$n+1)."<\/a> |\n");} } if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") } }

Цикл для показа элементов предыдущих страниц << 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

т.е. если $elem/$n>=$pervij[$#pervij]/$n-$k, то это значит, что выбираются страницы элементов до текущей позиции, включая е?, т.е. 2, 3, 4, 5 и 6 - цифра 7 это текущая позиция, которая определяется условием if($elem==$pervij[$#pervij] && $res[$#res] ne '<!--end-->'). Зачем тут стоит <!--end--> будет видно позднее в разборе админской части этой ленты новостей.

Условие

if($#pervij > $k && $res[$#res] ne '<!--end-->'){ push(@back, "<a href=\"$url?pos=".($pos-$n)."\"><<<\/a>") }



значит что если существуют элементы массива @pervij больше, чем $k=5, то для таких елементов нужно ставить знички прокрутки << и >>. Для массива @vtoroj условия определяются аналогичным образом, учитывая, что элементы для него должны быть больше определенного числа $pos, которое определяет текущее значение показываемой пятерки дат. Вывод самих новостей осуществляется циклом

for ($i=$pos; $i<$pos+$n; $i++) { print $res[$i]}

который берет элементы массива $res[$i] до элемента $n, т.е. допустим пользователь находится на странице 10, значит должен производится вывод новостей с 50 по 55-ю включительно.

Вывод результатов помещен в подпрограмму, т.е. существует некая переносимость кода из одного скрипта в другой. В скрипте подпрограмма используется дважды, когда нужно вывести число дат по $n штук и когда нужно вывести сами новости в количестве $n штук на страничку.

Автор: Dmitriy Kuvshinov

E-mail: dmitriy@genphys.phys.msu.su

URL: http://genphys.phys.msu.su/~dmitriy/perl/


Практические примеры программирования cgi-скриптов на Perl: работа с файлами и каталогами.


Прислал: OlegTr [ 12.03.2001 @ 08:39 ]
Раздел:: [ Статьи по Perl ]



Права Доступа


Я бы ни за что не написал этот раздел,если бы он не был так важен.Сидя в пределах своей домашней директории и занимаясь только тем,что качаете с Инета всякую херню,вы возможно и не задавались некоторыми вопросами....а зря.......... Ведь немного надо,чтоб попортить нервы начинающему CGI -програмисту.

Одна из таких вещей это права доступа......

Начнем с того ,что в системе Unix каждый пользователь имеет свой идентификатор- число,уникально идентифицирующее его в этой системе.(Мой логин paaa а ему соответсвует число 1818).Это число внутреннее для операционной системы,для пользования оно представлено как логин,который и соответствует пользователю.

Только не надо думать о пользователе,как о конкретном человеке сидящим за клавиатурой, пользователем может быть и какой-нибудь процесс.Важно отметить что пользователь-это определенная область прав доступа,которая ему соответствует.(Вы например не можете удалить файлы из каталога другого пользователя). Это и дает возможность стабильной работы всей системы.

Итак есть идентификатор пользователя.Также имеется идентификатор группы.

Группа служит для выделения пользователей по группам. Например у пользователей группы users (Обычные пользователи) не такие права как у группы wheels (административная группа).

Каждый процесс который вами запущен(Будь то Netscape,терминал,или текстовый редактор)получают ваши идентификаторы пользователя и группы. таким образом исполняются от вашего имени.

Теперь рассмотрим повнимательней файловую систему.В Unix с файлом связано много характеристик. Во-первых в системе нет "ничьих" файлов ,все файлы имеют владельца-пользователя и владельца-группу. Любой файл который вы создаете автоматически получает ваш идентификатор.По этому система очень легко отслеживает, чьи это файлы и каталоги.

Следующее новшество по сравнению с DOS это права доступа к файлу.Их может сменить только тот пользователь которому принадлежит файл,или супервизор.(Это в отличии от DOS где каждая дрянь типа вируса может снять атрибут readonly)


Права доступа задаются обычно числом в восьмеричном коде и разбиты на 3 части по 3 бита: Каждая часть задает права доступа для конкретной группы:

1я -права доступа для пользователя,которому принадлежит файл
2я -для группы которой принадлежит файл
3я -для всех остальных
В каждой такой категории выделяются 3 права: Право на чтение,Право на запись,и право на исполнение. (все права и аттрибуты очень наглядно показаваютя командой ls с ключом -l) Так как исполнять каталоги бессмыслено,то право на исполнение для них означает право обращатся к файлам из этого каталога.

Бит Описание
8 Право на чтение для пользователя
7 Право на запись для пользователя
6 Право на исполнение для пользователя
5 Право на чтение для группы
4 Право на запись для группы
3 Право на исполнение для группы
2 Право на чтение для всех остальных
1 Право на запись для всех остальных
0 Право на исполнение для всех остальных
Изменяются права командой chmod,ее синтаксис такой:

chmod [u|g|o]{+|-}{r|w|x} file

chmod number file

,где u-user,g-group,o-other,r-read,w-write,x-execute;--удалить,+-установить

Примеры:

chmod +r file.txt #разрешает всем право на чтения файла

chmod u+w file.txt #устанавливает для владельца файла право на запись в него

chmod +x gbook.cgi #право на исполнение для всех,как для ползователя,группы,и для других

chmod 0777 cgi-bin #Разрешает самые широкие права доступа для cgi-bin

Приоткрытии файла программой,операционная система сравнивает идентификатор пользователя с идентификатором пользователя владельца файла, если они равны,то действуют права пользователя,если не равны то сравниваются идентификаторы группы,если и они не равны,то действуют права доступа для остальных

остальных.В том случае если у процесса нет достаточных прав,система возвращает ошибку. Следует заметить ,что для супервизора root права доступа не проверяются.

Можно выполнить скрипт,только если есть права на его исполнение. Вот почему следует давать chmod +x *.cgi иначе ваши скрипты станут просто недоступными. Но и это еще не все.....



Ваш скрипт может обращатся к вашим файлам ( например ведет базу данных гостевой книги). Все выглядит нормально,но только ничего не работает,файл в который вы намеревались писать, не открывается,знакомая проблема ;(( ?.Так вот чтобы вы не мучались в догадках Ваш скрипт не может получить доступ к вашим файлам,потому что он выполняется не вами (не с вашим идентификатором), а от имени nobody (непривелигированый пользователь).Это мера предосторожности направлена на то, чтоб скрипты ,взбесившись из-за неправильно переданых параметров(или вообще от глюков) не могли ничего повредить ценного и важного на сервере.

Поэтому к тем файлам,к которым скрипт по смыслу должен обращатся нужно присвоить самые широкие права доступа 0777

Например в случае гостевой книги chmod 0777 guestbook.dat

Если также важно чтоб скрипты могли заводить новые файлы в cgi-bin то надо дать также права на это chmod 0777 cgi-bin

Если вы видите что ваш скрипт не может обратится к какому-то файлу,то это в 99% случаев из-за вашей забывчивости.!!!

На самый крайний случай воспользуйтесь setuid-скриптами (к этому делу ,если вы на это решились,отнеситесь ОЧЕНЬ серьезно,так как целые тома по безопасности в Unix посвящены именно setuid-скриптам). Хочу сразу предупредить ,сам я таких не писал,да и вам не особенно советую.Но для общего как говорится развития,имейте в виду следующую информацыю.

Кроме указания прав доступа,существуют специальные биты у файла.Это биты установки пользователя и группы. Когда процесс выполняется(простой процесс) то его реальный и эффективный идентификаторы пользователей совпадают,идентификаторы групп тоже. На самом деле значение имеют как раз эффективные значения пользователя и группы,они учавствуют в сравнении прав доступа. Нельзя ли их как-то изменить,когда уж совсем нужда заставит? Можно! .На этот вопрос дают ответ программы с установленым битом пользователя.Когда система запускает такую программу,она присваивает новому процессу не идентификатор того пользователя,что запустил ее, а идентификатор пользователя-владельца исполняемого файла.



Самый классический пример setuid-программ это программа passwd , предназначеная для смены пароля пользователя. Такие данные как пароль и прочие характеристики пользователей хранятся в специальном файле,который имеет огромное значение при входе в систему. Так как это системный файл,то открыть к нему доступ на запись всем-значит подвергнуть ВСЮ систему риску,ведь любое неправильное изменение его повлечет катастрофические последствия(в конце концов бывает просто хулиганство). Поэтому доступ к этому файлу закрыт для всех пользователей.А что если надо сменить пароль?

Запускаем программу passwd ,если глянуть на ее аттрибуты ,то видно что она принадлежит root -супервизору, и еще имеет установленый бит setuid. Так корректно обходится эта проблема.

Если вы все-же решили попытаться ,то знайте ,что сделать программу setuid можно

коммандой : chmod +s myprogramm

И как всгда Примерчик напоследок:

Эта программа выдает содержимое вашей директории public_html в том случае,если она доступна для чтения,и для каждого файла указывает ,можно ли его читать,писать и исполнять. Попробуйте ее сделать setuid и посмотрите как изменится результат.



#!/usr/bin/perl #listmydir.cgi print "Content-Type: text/html\n\n"; if(!(-r '..')){ print ".. is not allowed for reading ;)))))\n"; } else{ @list=glob('../*'); foreach(@list){ print "<A href=\"$_\">$_</A>"; print "&nbsp;readable" if -r; print "&nbsp;writable" if -w; print "&nbsp;executable" if -x; print "<BR>\n"; } }


Права доступа к файлам и скриптам


Правильная настройка прав доступа к файлам имеет очень важное значение. От этого зависит безопасность вашего сайта. Кроме того, неправильно настроенные права доступа могут служить причиной ошибок в работе ваших программ и веб страниц.

Настраивая права доступа к файлам, вы должны знать, под какими именами веб сервер выполняет ваши программы и считывает веб страницы. Все CGI-программы, а также asp-страницы выполняются с именами пользователя и группы - владельца сайта.

Все остальное - HTML страницы, программы mod_perl, mod_php, java-сервлеты, jsp-страницы, ... - выполняется с именами пользователя и группы www. SSI-страницы вызываются под именами www.www. Однако запускаемые из SSI-страниц CGI-скрипты имеют имя и группу владельца сайта.

Исходя из этих сведений и настраиваются права доступа: Те файлы и скрипты, которые запускаются под именем www.www, должны иметь признаки чтения всеми. Если это исполняемые файлы (mod_perl), то должны еще быть и признаки выполнения всеми. Файлы, выполняемые под вашими именами пользователя и группы, не обязаны содержать признаки чтения и выполнения всеми. Вы можете даже убрать разрешение чтения/выполнения членами вашей группы (FTP-пользователями вашего сайта). В этом случае вы полностью застрахованы от того, что ваш файл прочитают посторонние пользователи. Вы можете смело располагать прямо в файле такие сведения, например, как пароли доступа к базам данных. Кроме суперпользователя root и самого веб сервера, эти файлы сможете прочитать или исполнить только вы сами. Если файл создан не вами, а одним из ваших FTP-пользователей, то имя владельца не будет совпадать с тем, под которым его будет запускать веб сервер. В этом случае признак чтения (и исполнения, если требуется) должен быть проставлен для группы тоже. Но открывать чтение (и исполнение) для всех в этом случае все равно не требуется.

Варианты настройки прав доступа к различным типам файлов вы можете проследить из следующей таблицы.

CGI Perlrwx --- ---700user.user
rwx r-x ---750
CGI Pythonrwx --- ---700user.user
rwx r-x ---750
CGI TCLrwx --- ---700user.user
rwx r-x ---750
CGI PHPrw- --- ---600user.user
rw- r-- ---640
ASP (VBScript,JavaScript)rw- --- ---600user.user
rw- r-- ---640
ASP (PerlScript)rw- r-- r--644www.www
Java сервлетыrw- r-- r--644www.www
JSP-страницыrw- r-- r--644www.www
HTML-страницыrw- r-- r--644www.www
SSI-страницыrw- r-- r--644www.www
mod_php скриптыrw- r-- r--644www.www
mod_perl скриптыrwx r-x r-x755www.www



Прекрасный язык Perl


Вы наверное обратили свое внимание что CGI скрипты пишутся обычно на языке Perl (Practical Extraction and Report Language)- очень удобном языке,впитавшем из других все лучшие черты.Может у вас возникнуть сомнение :Ну вот!Изучать новый язык программирования!? Спешу вас успокоить,изучение Perl не будет в тягость (я сужу по своему опыту!). Вы даже сами не заметите как выучите его.Если вы хоть когда-нибудь программировали скажем на C и использовали утилиту grep для поиска регулярных выражений в тексте,то вам будет еще легче.Мое изучение Perl

началось с того что я скачал Perl

под Windows (фирмы ActiveWare) и изучения той HTMLой документации которая к нему прилагалась хватило чтоб этот язык стал моим любимым....

Все в нем сделано для удобства программиста (в отличии например от Java;( )

Начнем с переменных,они в Perl

бывают 3х типов скаларные,списковые(массивы)

и хэши(ассоциативные массивы). Для указания компилятору(да и для немалого удобства программиста) перед именем скалярной переменной стоит знак '$' перед массивом '@',перед хешем '%'. т.е. например $scalar_var,@array_var,%hash_var

Скалярные переменные могут быть как числовые так и строковые,но это не надо указывать Perl сам по контексту в зависимости от операций может привести одно к другому.

Например: "123"+"4" будет 127 (или "127") так как операция '+' действует над числами а вот если применить операцию конкатенации строк '.'

то строковое "test" . 1 будет "test1"

Ну а вот операции над скалярными переменными:

Операцыи Описание Пример
+ - * / % Арифметические print 2*7+4/(8%3);

print int(127/15); #целая часть

** Возведение в степень print 2**16;
++ -- Инкремент-декремент $i++;
& | ^ ~ << >> Побитовые $x=3;$y=4;

print $x|$y;

print $x&$y;

== != < > <= >= <=> Числовые операции сравнения if($x==9){print "Ok!";}
eq ne lt gt le ge cmp стрковые операции сравнения if($game eq 'doom'){print "You are doomer!\n";}
|| && ! Логические if(($x==9)||($game eq 'doom')){print "hello you!\n";}
?: Условный оператор $x=($game eq 'quake'?9:8);
, Последовательное вычисление $x=10,$y=20;
. Конкатенация $x='http://'.'www.uic.nnov.ru';
x Повторение $x='1234'x5; #$x='12341234123412341234'
=~ Сопоставление с образцом if($url=~/http/){print "HTTP";}
!~ То же но с отрицанием if($url!~/http/){print "No HTTP";}
= += -= *= /= %= **= |= &= ^= ~= <<= >>= .= x= Присваивание $x+=$y;
   
<
Пусь это будет вам справочником ,да кстати насчет строк,вы заметили,что они могут быть в двойных и одинарных кавычках, разница между ними состоит в том ,что в одинарных не осуществляется подстановка переменных, а в двойных осущестляется, Например:



$x='qwerty'; print 'my var is $x'; #выведет my var is $x print "my var is $x"; #выведет my var is qwerty

Списки: Спискочные переменные начинаются с символа '@'

конструируются следующим образом



@List1=(1,2,5,70); @List2=(12,23,@List1); #12,23,1,2,5,70 @Rgb=($r,$g,$b);

Также можно список использовать как lvalue:



@List=(1,2,3..8,15); ($x,$y,$z)=@List; #$x=1,$y=2,$z=3 ($x,$y,$z,@list2)=@List; #$x=1,$y=2,$z=3,@list2=(4,5,6,7,8,15); ($r,$g,$b)=@Rgb;

Можно обращаться к нескольким,выбраным элементам массива(срезу массива):



@list=(1..10); @list[2,3,5,9]=(100,200,300,400); #@list=(1,100,200,4,300,6,7,8,400,10) @list[1,10]=@list[10,1];#меняет местами элементы

Обратится к скаларному значению -элементу массива можно $имя_массива[индекс], сдесь обратите внимание на знак '$'- мы ведь обращаемся к скаляру-элементу.

Теперь немного о хешах:

хеш это такой массив который состоит из пар ключ-значение, весь хеш обозначается %хеш ,к отдельным элементам доступ $хеш{скалярное выражение} конструируется хеш так:



$my_hash{1}="doom"; $my_hash{'quake'}="www.idsoftware.com"; $my_hash{1+2}=100;

Хеш может быть также сконструирован из массива с четным числом элементов где пары превращаются в ключ-значение



%hash=(1,20,2,100);#аналогично $hash{1}=20;$hash{2}=100;

удаление из хеша -операция delete:



delete $hash{1};

есть функции выдающие ключи и значения соответственно.



%hash=(1,20,2,100,3,'doom'); @k=keys %hash; #@k=(1,2,3); @v=values %hash;#@v=(20,100,'doom');

Операторы:

Набор операторов в Perl Очень широк,многие из них прямые аналоги имеющихся в других языках,например if,for,while;но есть и значительные улучшения имеюшихся и конечно новые...

Тот же самый оператор if имеет две формы (как когда удобнее):





if(условие)оператор; оператор if условие;

В пару к оператору if имеется оператор unless : означающий if

с отрицанием:



unless(($method eq 'GET')||($method eq 'POST')){print "Unsupported method";} print "Ok" unless $x < $y;

Также в пару while существует until

синтаксис оператора for

полностью аналогичен C:



for($i=0;$i

новшеством(и приятным) является foreach позволяющий пройтись по всем элементам массива,присваивая по очереди его элементы какой-то переменной, его синтаксис такой:



foreach $переменная (@массив){ блок операторов; } или foreach (@массив){ операторы; }

Последний пример особенно важен для упрощения вашего тяжкого труда програмиста и демонтстрирует интересную особенность Perl-переменную по умолчанию $_: в оргомном количестве операторов и функций при опускании аргумента она подразумевается по умолчанию. Она также по умолчанию сопоставляется с регулярным выражением:



следующий пример @Data=<STDIN>; foreach(@Data){ chomp; print if /^From:/; } аналогичен такому: @Data=<STDIN>; foreach $_ (@Data){ chomp($_); print $_ if $_ =~ /^From:/;

как видите затраты труда значительно сокращаются,благодаря этому маленькому трюку. Регулярные выражения.

регулярное выражение записывается между двух слэшей /рег_выр/



if(/abc/){ print '$_ содержит abc\n'; }

это самый простой пример применения регулярного выражения а теперь посложнее вот тут в табличке (из того что я помню наизусть):

Символ Значение Пример применения
. Соответствует любому символу print if /ab.c/;
[мн-во симв] Соответствует любому символу из данного мн-ва /[abc]d/;#соответствует ad,bd,cd
[^мн-во] Отрицание мн-ва символов /[^xyz]/;#
(....) Группировка элементов(и также запоминание в переменных $1 $2 $3 ...) /(xyz)*/

/([abc].[^xy]qwerty)/
(..|..|..) Одна из альтернатив  
* повторение образца 0 или более раз /.*/;#соответствует всему
? Повторение 0 или 1 раз /(http:\/\/)?.*\.cgi/
+ Повторение 1 или более раз  
{n,m} повторение от n до m раз  
{n} повторение точно n раз  
{n,} повторение n и более раз  
Спец символы:    
\t \r \n ... Управляющие символы:табуляции,возврат каретки,перевод строки.....  
\d Соответствует цифре,Аналог [0-9]  
\D Соответствует нецифровому симсволу,аналог[^0-9]  
\w Соответствует букве  
\W Соответствует небуквеному символу  
\s Соответствует пробельным символам(пробелы,табуляции,новые строки..)  
\S Соответствует непробельному символу  
\b Соответствует границе слова $test1="this is test";

$test2="wise";

if($test1=~/\bis\b/){print "1";}#соответствует

if($test2=~/\bis\b/){print "2";}#нет
\B Соответствует не границе слова /\Bis\B/ соответсвует 'wise' но не 'is'
<


Для того чтоб поместить в регулярное выражение любой специальный символ,поставьте реред ним обратный слэш Заставить Perl игнорировать регистр можно поставив i после регулярного выражения



print "Are you sure?:"; $answer=<STDIN>; if($answer=~/Y/i){ #че-нибудь сделаем... }

Полезные функции.

В Perl очень много различных функций ,как говорится на все случаи жизни,все о них я конечно не опишу,но обо многих. Начну с тех,которые больше относятся к операторам. Операция замены s/рег.выражение/строка/ игнорировать регистр - опция i

глобальная(по всей строке) замена -опция g; Пример:



$x="This is test"; $x=~s/ /_/g; print $x; #This_is_test

Очень полезная опция у s/// e -она означает что вторая строка не строка а выражение, результат которого и будет подставлен. Например,у вас есть файл в котором все записи о возрасте через год надо менять



open OLD,"oldfile.txt" || die "Cannot open oldfile.txt $!\n"; open NEW,">newfile.txt" || die "Cannot open newfile.txt $!\n"; foreach(){ s/(\d+)(\s+год)/($1+1).$2/gie; s/(\d+)(\s+лет)/($1+1).$2/gie; print NEW $_; } close NEW; close OLD;

или более показательным примером послужит функция urldecode,которая будет встречатся в каждой вашей программе,обрабатывающей формы:



sub urldecode{ local($val)=@_; $val=~s/\+/ /g; $val=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge; return $val; }

Также важным удобством в Perl являются операции для работы с файлами для выполнения схожих функций в других языках приходиться проделывать огромную массу работы. Аргументами могут быть как Файловые переменные,так и строки,представляющие имя файла.

Операция Описание Пример использоввания
-r Доступен для чтения unless(-r "myfile"){print "Cannot read myfile\n";}
-w Доступен для записи  
-x Для исполнения  
-o Принадлежит пользователю if(-o "index.htm"){chmod 0777,"index.htm";}
-R Доступен для чтения реальным

пользователем,а не только "эффективным".

Имеет значения для set-uid -скриптов
if(-r FILE){unless(-R FILE){die "Its not allowed to read this\n";}}
-W Доступен для записи реальным пользователем  
-X Доступен для исполнения реальным пользователем  
-O Принадлежит реальному пользователю  
-e Файл или каталог Существует unless(-e $htmlfile){

open HTML,">$htmlfile";

print HTMLFILE "<HTML><BODY></BODY></HTML>";

close HTMLFILE;

}
-z Существует,но имеет нулевую длину if(-z 'tmpfile'){unlink 'tmpfile';}
-s Размер файла в байтах system "rar m -m5 archive.rar $myfile" if -s $myfile > 1000;
-f Файл существует и является простым файлом  
-d Файл существует и является каталогом if(-d 'public_html'){chdir 'public_html';}
-l Символической ссылкой  
-p Каналом FIFO  
-u Имеет бит установки пользователя  
-g Имеет бит установки группы  
-k Установлен sticky-бит  
-t Является терминальным устройством  
-M Время с последнего изменения (в днях) while(defiled($file=glob('*'))){

 if(-M $file >= 7.0){

  unlink($file);#удаляем слишком старые файлы

  }

}
-A Время последнего доступа(в днях) if(-A "$ENV{'HOME'}/public_html/index.html"
-C Время последнего обновления файлового индекса(в днях)  
     
<


Еще есть и другие

функция open открывает файл



open ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,"имя файла"; # открыть файл для чтения open ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,">имя файла"; #для записи open ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,">>имя файла";#для записи в конец open ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,"+

Что какается открытия файлов,то вам как програмистам все очевидно, но с коммандами тоже все здорово,что пояснит хороший пример(из практики):



open MAIL,"|mail paaa@uic.nnov.ru";#Пошлем информацию по почте print MAIL "Hello\n"; print MAIL "...\n"; print MAIL "...\n"; close MAIL;

когда вы открыли файл вы можете считать из него строку в скалярную переменную Вот так:$str=<FILE>

избавиться от символа новой строки на конце поможет функция chomp, ведь этот символ может помешаться например в имени файла или при выводе на экран



print "Введите имя файла:"; $fname=<STDIN>; chomp($fname); open F,$fname || die "Cannot open $fname $!\n"; .....

Если также подставить списочную переменную,то получим список строк файла от текущей строки и до конца



print "Что искать:"; $search=<STDIN>; chomp($search); @L=<F>; foreach(@L){ print if /$search/; } а можно и так: print "Что искать:"; $search=<STDIN>; chomp($search); foreach(<F>){ print if /$search/; }

бинарный файл можно читать и писать функциями sysread и syswrite:

sysread ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт

syswrite ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт

функции split и join: @Список=split /рег.выр/,$скаляр;

$скаляр=join строка,@Список;



#Разбить строку слов,разделенных пробелами в список вы можете @WordList=split / /,$String; #После обработки снова обьединить $String=join ' ',@WordList;

Встроеные функции Perl можно вызывать со скобками или без (как вам удобно), скобки программисты указывают или для красоты,или чаще,что устранить возможную неоднозначность в выраженнии:



printf "x=%d",$x; printf ("x=%d",$x);#аналогично



Надеюсь что я вас позабавил примерами функций ;).

Примеры применения Perl для различных нужд...

Следующая программа переводит текстовый файл в формат HTML (вспомните сколько хлопот вам доставит отлов во всем файле '<', '>' и '&' чтоб заменить их на &tl; , &gt; и &amp;

а как неплохо чтоб автоматически все http://www.... превратились в <A href="http://www...." >http://www....</A>)



#!/usr/bin/perl #txt2html die "Usage: txt2html Infile OutFile\n" unless(@ARGV); open IN,"$ARGV[0]" || die "Cannot open $ARGV[0] $! \n"; open OUT,">$ARGV[1]" || die "Cannot open $ARGV[1] $! \n"; while(<IN>){ s/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g; s/\n/<BR>\n/g; s/(http:\/\/\S+)/<A href="$1">$1<\/A>/g; print OUT $_; } close IN; close OUT;

Более подробную информацию о Perl вы можете получить по адресам:

http://www.perl.com

http://www.metronet.com/0/perlinfo/perl5/manual/perl.html

http://www.ActiveWare.com/


Рассмотрим сценарий регистрации пользователя на


Рассмотрим сценарий регистрации пользователя на веб-сервере.Имя пользователя и его пароль записываются в текстовый файл и используются для его последующей аутентификации.
#!/usr/local/bin/perl #Объявляем глобальные переменные.
$request=$ENV{'REQUEST_METHOD'}; $content=$ENV{'CONTENT_LENGTH'}; $basedir="http://www.mydomain.com/~"; $userdir="f:/home";
#Подпрограммы для декодирования данных из формы.
sub urldecode { local($val)=@_; $val=~ s/\+/ /g; $val=~ s/%[0-9a-hA-H] {2}/pack('C',hex($1))/ge; return $val; }
sub strhtml { local($val)=@_; $val=~s//>/g; $val=~s/(http:\/\/\+S)/<A href="$1">$1<\/A>/g; return $val; } ######################################################################
if ($request eq 'GET') { $query=$ENV{'QUERY_STRING'}; } else { sysread(STDIN,$query,$content); }
#Генерируем форму,если никакие данные не введены. print "Content-type:text/html\n\n"; print <<HTML_gen; <HTML><BODY bgcolor="e6e8fa">
HTML_gen
if ($query eq '') { print <<HTML; <h2 align=center><font color="ff0000">Registration.</font></h2> <p><font face="serif" size=2> Please,fill in the form below. <p>After registration you will receive your personal directory and unique URL.Fill all fields carefully. Form fields marked as <font color="ff0000">*</font>are required.</font> <p><FORM ACTION="../cgi-bin/addlogin.cgi" METHOD="POST" name="reg"> <center><TABLE BGCOLOR="bfbfbf"> <TR><td><font color="ff0000">*</font> <TD><b>Login:</b><TD><INPUT TYPE="text" NAME="login" SIZE="20"> <TR><td><font color="ff0000">*</font> <TD><b>Password:</b> <TD><INPUT TYPE="password" NAME="pass" SIZE="20"> <TR><td><font color="ff0000">*</font><TD><b>E-mail:</b> <TD><INPUT TYPE="text" NAME="email" SIZE="20"> <TR><TD colspan=3><p><center> <INPUT TYPE="submit" VALUE="Submit"></center> </TABLE></center> </FORM> HTML


#Декодируем поля формы
else { foreach (@fields=split(/&/,$query)) { if (/^login=(.*)/) { $login=&urldecode ($1); } if (/^pass=(.*)/) { $password=&urldecode ($1); } if (/^email=(.*)/) { $email=&urldecode ($1); } }
#Проверяем, не существует ли данное имя в системе. open(INFO,"login.txt") ||die; @data=<INFO>;#Читаем строки в массив. close(INFO);
foreach $string(@data) { @item=split(/&/,$string);#Разбиваем строку на части. foreach (@item) { if ($item[0] eq $login) { #Сравниваем полученное имя с первым полем файла #для каждой строки и если такое найдено выдаем #ошибку. print <<HTML; <h2 align=center><font color="ff0000">Error!</font></h2>
<p><center><b>The name <font color="ff0000">$login</font> already exists in the system. <p>Please,go back and choose another name.</b>
<p><form><input type="button" value="Back" onClick="history.back()"></form>
</center>
HTML exit; } } }
#Если имя не найдено,открываем базу данных и добавляем информацию.
if ($item[0] ne $login) { open(DATA,">>login.txt"); $string=join('&',$login,$password,$email,scalar localtime,$ENV {'REMOTE_ADDR'}; print DATA "$string\n"; close(DATA);
#Создаем домашний каталог пользователя и переходим в него.
mkdir("$userdir/$login",0700); chdir("$userdir/login"); opendir(USER,"$userdir/$login");
#Помещаем файл index.html в каталог пользователя.
open(IN,">$userdir/$login/index.html"); print IN "This is the test!\n"; close(IN); closedir(USER);
#Содержание файла может быть любым,это только для примера.
#Генерируем ответ пользователю.
print <<HTML; <p><h1 align=center><font color="ff0000">Congratulations!</font></h1>
<p><b>Your registration was successful and your data were added to our database.Thank you for your time.</b>
<p><center><b><font color="ff0000">
You entered:</font>(print this page and keep it in safe place)</b>
<p><table>
<tr><td><b>Your login name:</b><td><font color="0000ff">$login</font>
<tr><td><b>Your password:</b><td><font color="0000ff">$password</font>
<tr><td><b>Your e-mail address:</b><td><font color="0000ff">$email</font>
</table></center>
HTML } }
Скрипт выдает ответ в виде html-страницы,содержащей всю информацию,введенную пользователем.

Начало скрипта можно взять из


Рассмотрим пример открытия и чтения каталога и вывод списка файлов,содержащихся в нем. Начало скрипта можно взять из предыдущего примера.Предположим,что пользователь,зарегистрированный на веб-сервере,хочет войти в свой домашний каталог.
#!/usr/local/bin/perl #Объявляем глобальные переменные.
$request=$ENV{'REQUEST_METHOD'}; $content=$ENV{'CONTENT_LENGTH'}; $basedir="http://www.mydomain.com/~"; $file="login.txt"; $url="http://www.mydomain.com"; $dir="f:/home/"; $cgi="f:/usr/local/apache/cgi-bin";
#Подпрограммы для декодирования данных из формы.
sub urldecode { local($val)=@_; $val=~ s/\+/ /g; $val=~ s/%[0-9a-hA-H] {2}/pack('C',hex($1))/ge; return $val; }
sub strhtml { local($val)=@_; $val=~s//>/g; $val=~s/(http:\/\/\+S)/<A href="$1">$1<\/A>/g; return $val; } ######################################################################
if ($request eq 'GET') { $query=$ENV{'QUERY_STRING'}; } else { sysread(STDIN,$query,$content); }
#Генерируем форму,если никакие данные не введены. print "Content-type:text/html\n\n"; print <<HTML_gen; <HTML><BODY bgcolor="e6e8fa">
HTML_gen
if ($query eq '') { print "Content-type:text/html\n\n"; print <<HTML; <HTML><HEAD>
</HEAD><BODY bgcolor="e6e8fa">
<FORM ACTION="../cgi-bin/fileman.cgi" name="form1" METHOD="POST">
<h2 align=center><font color="ff0000">System login.</font></h2>
<p><center>Please,enter your login name and password: <p><TABLE BGCOLOR="cccccc">
<tr><td colspan=2 align=center bgcolor="99cccc"><b><font color="ff0000">
I am registered user</font></b>
<TR><TD><p><b>Login:</b><TD><INPUT TYPE="text" NAME="login" SIZE="20">
<TR><TD><p><b>Password:</b><TD><INPUT TYPE="password" NAME="pass" SIZE="20">


<tr><td colspan=2 align=center><input type=submit value="Submit"></center>
HTML } #Если информация получена,декодируем поля формы.
else { foreach (@fields=split(/&/,$query)) { if (/^login=(.*)/) { $login=&urldecode ($1); } if (/^pass=(.*)/) { $password=&urldecode ($1); } }
#Открываем базу данных и проверяем логин и пароль. open(INFO,$file) ||die; @data=; close(INFO);
foreach $string(@data) { @item=split(/&/,$string); foreach (@item) { if (($item[0] eq $login) && ($item[1] eq $password)) {
#Если все нормально,переходим в пользовательский каталог.
print "Content-type:text/html\n\n"; print <<HTML; <html><body bgcolor="e6e8fa">
#Приветствуем пользователя. <p><h2 align=center><font color="ff0000">Hello,$login!</font></h2>
<p><center> Welcome to your home directory! <p>Your URL is <a href="$basedir$login">$basedir$login.</a></center>
HTML
######################### # Directories list # #########################
$userdir=$dir.$login; chdir ("$userdir");
#Открываем каталог и читаем список файлов в массив. opendir(DIR,"$userdir") || die "Cannot open $userdir!"; while (@files=readdir(DIR)) {
#Если каталог содержит подкаталоги,выводим их отдельно,а также не показываем #каталоги "." и ".." Печатаем шапку таблицы. print <<HTML; <p><center>
<table bgcolor=\"bfbfbf\" width=600 border cellspacing=0 cellpadding=0 nowrap>
<tr><td colspan=5 align=center nowrap><b><font color="ff0000">Directories</font></b></td></tr>
<tr><td>.</td><td align=center><b>List</b></td><td><b>Size</b><td><td><b>Last accessed</b></td><td><b>Last modified</b></td>
HTML foreach $file(@files) {


#Стстистика файлов-размер,время последнего обращения и модификации. $size=(stat("$userdir/$file"))[7]; $atime=localtime((stat("$userdir/$file"))[8]); $mtime=localtime((stat("$userdir/$file"))[9]);
#Печатаем список подкаталогов. if ( -d "$userdir/$file" && "$file" ne "." && "$file" ne "..") {
print "<tr><td width=30><img src=\"$url/image/folder.gif\"></td><td width=100 align=left>$file</td>\n"; print "<td width=50>",$size,"</td><td width=200>",$atime,"</td><td width=200>",$mtime,"</td></tr>\n"; } } print "</table>\n";
################ # Files list # ################
# Ту же операцию проводим для файлов.Печатаем шапку таблицы. print <<HTML; <p><table bgcolor=\"bfbfbf\" width=600 border cellspacing=0 cellpadding=0>
<tr><td colspan=5 align=center><b><font color="ff0000">Files</font></b></td></tr>
<tr><td>.</td><td><b>List</b><td><b>Size</b><td><b>Last accessed</b><td><b>Last modified</b></tr>
HTML
foreach $file(@files) { $size=(stat("$userdir/$file"))[7]; $atime=localtime((stat("$userdir/$file"))[8]); $mtime=localtime((stat("$userdir/$file"))[9]);
if (!-d "$userdir/$file" && "$file" ne "." && "$file" ne "..") { push (@dir,"$userdir/$file");#Помещаем найденные файлы в массив $number=@dir; #Подсчитываем их количество.
#Выдаем информацию. print "<tr><td width=30><img src=\"$url/image/page.gif\"></td><td width=100><a href=\"$basedir$login/$file\">",$file,"</a></td>\n"; print "<td width=50>",$size ,"</td>\n"; print "<td width=200>",$atime,"</td><td width=200>",$mtime,"</td></tr>\n"; } } print "</table>\n"; print "<p><center><b><font color=\"0000ff\">There are ",$number," files in this directory.</b></font></center>\n"; }
Надеюсь,я объяснил все достаточно подробно.Я выбрал намеренно сложные примеры,чтобы показать все операции,которые можно производить с файлами и каталогами.Файлы еще можно загружать на сервер через веб.Этому посвящен следующий раздел.

Примеры функций, разное


Как округлить число?


Как получить текущую дату и время?


Функция time() возвращает время с точностью до секунды. Как работать с меньшими промежутками?


Как по дате вычислить день недели?


Как, зная дату и время, получить количество секунд, прошедших до этого времени с 1970 года (unix-time format)?


Можно ли сделать GUI-интерфейс в перловой программе, или вывод в GUI-окно ее результатов?


Как устроить загрузку файла с удаленного сервера? Проще говоря, скачать скриптом файл с http или ftp


Как передать из одного скрипта данные другому скрипту методом GET, вроде бы понятно. А как передавать данные методом POST?


Как создавать графические файлы на лету? Как наложить число на картинку(счетчик)?



Q: Как округлить число?

A: sprintf("%3.2f",$i)

Здесь 3 - кол-во знаков до запятой, 2 - после запятой.

Q: Как получить текущую дату и время?

A: Функция time() возвращает время в unix-формате - количество секунд,

прошедших с 1 января 1970 года. Функция localtime() возвращает дату и время.

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

контексте - строку определенного формата. Подробнее см. perldoc -f localtime

Q: Функция time() возвращает время с точностью до секунды. Как работать с

меньшими промежутками?

A: Time::HiRes

Q:Как по дате вычислить день недели?

A1: perldoc -f localtime

A2: Date::Calc

Q: Как, зная дату и время, получить количество секунд, прошедших до этого

времени с 1970 года (unix-time format)?

A: Time::Local

Q: Можно ли сделать GUI-интерфейс в перловой программе, или вывод в GUI-окно

ее результатов?

A: модуль Tk. он и под windows, и под linux есть - можно писать GUI-программы

для разных платформ.

Q: Как устроить загрузку файла с удаленного сервера? Проще говоря, скачать

скриптом файл с http или ftp

A: LWP, Net::Ftp

Q: Как передать из одного скрипта данные другому скрипту методом GET, вроде

бы понятно. А как передавать данные методом POST?

A: Внимательно почитать документацию о LWP::UserAgent и HTTP::Request


+ perldoc lwpcook

Q: Как создавать графические файлы на лету?

A: модуль GD, или внешние программы: Imagemagick, fly,..

Примеры скриптов


Как одновременно поставить куки и сделать редирект?


Вечная тема - закачка файла на сервер(upload).



Q: Как одновременно поставить куки и сделать редирект?

A:

sub ReLocate

{

my($url,$cookie)=@_;

print "Status: 302 Moved\n";

if ($cookie ne '') { print "Set-Cookie: $cookie\n" }

print "Location: $url\n\n";

}
Примечание:

Не забудьте, что URL должен быть полным, частичные "не прокатывают" под некоторыми ОС и веб-серверами.

Q: Вечная тема - закачка файла на сервер(upload).

A:
#!/usr/bin/perl # используйте -T для CGI-скриптов

$SIG{ALRM} = sub { die "$0 timed out" }; # эти 2 строки не работают под

alarm 900; # Windows, но они необязательны

use strict; # спасает от глупых ошибок

use Fcntl; # O_EXCL, O_CREAT и O_WRONLY

use CGI qw (:standard); # читайте "perldoc CGI"

use CGI::Carp qw (fatalsToBrowser); # вывод ошибок к browser-у

$CGI::POST_MAX = 131072; # максимальный ввод = 128 KB

my $foto = param ('foto'); # имя файла и одноврем. handle

my $DIR = '/home/alex/pics' # не забудьте "chmod 777 pics"

my $JS = " // JavaScript-функция для пред-

// варительной проверки формы

function check (form)

{

if (form.elements['foto'].value.length < 4)// foto должно быть заполнено

{

alert ('A gde zhe foto?'); // показать JavaScript-окошко

form.elements['foto'].select (); // выделить текст в поле foto

form.elements['foto'].focus (); // и прыгнуть туда курсором

return false; // false запретит browser-у

} // отправлять данные к серверу

return true; // все OK - можно отправлять

}";

print header (-type => 'text/html; charset=koi8-r'),

start_html (-title => 'МИСС ИHТЕРHЕТ', # напечатать заголовок и $JS

-script => $JS);

# regex внизу проверяет, есть ли .gif или .jp(e)g в конце и кладет имя

# файла в $1

if ($foto !~ /([\w-]+ \. (?: gif | jpe?g ))$/ix) #только имя,путь выкидывается

{

print h1 ('Отправьте нам фото!'), #start_form работать не будет

start_multipart_form (-onsubmit => 'return check (this)'),

filefield (-name => 'foto'),

submit (-value => 'Go baby go!'), # напечатать форму с кнопкой

Программа вывода номеров журнала


Еще один пример использования хеша массивов для вывода содержания журнала за несколько лет календарем. Есть директория с файлами содержания журнала по номерам вида:

1.1996.txt

2.1996.txt

3.1996.txt

4.1996.txt

5.1996.txt

...

и т.д. до

5.2001.txt

где первая цифра в названии файла это содержание журнала за данный месяц, а вторая это год.

Читаем эту директорию в массив и вызываем подпрограмму:

while(<$dir/journal/*.txt>){push(@files, $_)}

&calendar;

sub calendar{

print qq~<center><font><b>Содержание

по номерам</b></font><p></center>~;

@year1=grep{!$test{$_}++ if(/^(\d+)$/)} #выделяет число лет, за которые есть номера журнала

#и заодно удаляет одинаковыен года, т.к.

#на каждый год приходится не больше 12

#файлов: 1.1996, 2.1996, 3.1996...

map{/\.(\d+)/, $_} @files; #выделяет года и заносит их во временный массив

foreach $line(@year1){ #цикл по годам.

foreach $files(@files){

push @{$numbers{$line}}, $files if($files=~m/$line/);

#здесь производится заполнение хеша массивов ключами,

#которые являются годами, а значениями хешей буду являться

#массивы номеров журнала за данный год, который является ключом.

#т.е. в результате должно получиться что-то вида:

#%hash = (

# 1996 => ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],

# 1997 => ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],

# ...

# 2001 => ["1", "2", "3", "4", "5"] #до пятого номера потому, что

#шестой номер на момент написания этого

#примера еще не вышел.

#);

}

}

print "<center><table>"; #открываем табличку для вывода результатов

for $key (sort keys %numbers){#цикл по отсортированным в порядке возрастания годам


print "<tr><td><font size=\"1\"><b>$key: </b></font>"; #печатаем год

foreach $elem(@{$numbers{$key}}){ # вытаскиваем массив номеров журнала из хеша, ключем

#которому должен являться определенный год

if($elem=~m/\/(\d+).(\d+)\.txt/){$nj=$1; $yj=$2;

if($nj eq $nomer && $yj eq $year){#текущий номер для просмотра выделяем красным:

$temp1=qq~<font size="1" color=red><b>$nj</a> </b></font>\n~;

push(@results123, $temp);

}

else{#остальные выделяем ссылкой

$temp2=qq~<font size="1"><b><a

href="$url?month=$nj&year=$yj" class="menu">$nj</a>

</b></font>\n~;

push(@results123, $temp2)

}

}

}

#дальнейшая конструкция называется преобразованием Рэндела

#Шварца, смысл которой заключается

#в том, чтобы отсортировать массив номеров журнала по возрастанию,

#т.к. при извлечении из хеша они будут выстраиваться в порядке

#1,11,12,2,3,4...

@sort123= map{ $_ -> [1]}

sort{$a->[0] <=> $b->[0]}

map{[/>(\d+)<\/a>/, $_]} @results123;

print @sort123; #печатаем табличку номеров журнала за 1995 год

print "</td></tr>";#закрываем строку таблички

#обнуляем временные массивы

$#results123=-1;

$#sort123-1;

#возвращаемся наверх и начинаем печатать строчку

#таблицы для следующих номеров следующего года.

}

print qq~</table></center>~;

}

Все вышеописанное выглядит в виде html примерно так:

Содержание по номерам

1995: 1

1996: 1

2

3

4

5

6

7

8

9

10

11

12

1997: 1

2

3

4

5

6

7

8

9

10

11

12

1998: 1

2

3

4

5

6

7

8

9

10

11

12

1999: 1

2

3

4

5

6

7

8

9

10

11

12

2000: 1

2

3

4

5

6

7

8

9

10

11

12

2001: 1

2

3

4

5


Протокол HTTP





Что такое протокол HTTP и для чего он нужен, я думаю расказывать не нужно, поэтому сразу приступим к более подробному рассмотрению. Какое отношение HTTP протокол имеет к Perl? Да самое прямое. Без знания HTTP протокола, нельзя написать практически никакого CGI скрипта.

Итак, договоримся о терминах.
Веб-сервер - програмное обеспечение, которое следит за 80 (возможны и другие варианты, но данный наиболее популярен) портом и в случае обнаружения запроса, выдает некоторую информацию (сообщение об ошибке, html документ).
Клиент - программное обеспечение осуществляющее подключение к 80 порту сервера и посылающее туда запрос.

Помимо выдачи статичных документов, веб-серверы умеют выдавать результаты работы скрипта. т.е. если клиент запрашивает документ, который на самом деле является CGI скриптом, то веб-сервер запускает этот скрипт на выполнение, а всю информацию полученную со стандартного выхода скрипта, перенаправляет клиенту.

В процессе прочтения данного документа, вам наверно захочется попробовать все предложенные примеры. Используйте для этого любой telnet клиент. Просто соединитесь с 80 портом сервера, на котором расположен ваш любимый сайт.

Взаимодействие, между веб-сервером и клиентом просто до неприличия. Клиент посылает запрос состоящий из заголовка и (иногда) тела, а веб-сервер выдает ответ, который так же состоит из заголовка и тела. Рассмотрим более детально, как же выглядят эти запросы и ответы.



Любой запрос начинается строкой:

МЕТОД РЕСУРС HTTP/версия


МЕТОД - один из поддерживаемых веб-сервером методов. Наиболее распространены:

GET - в этом случае выдается запрошенный ресурс. Самый старый и самый распространенный метод.

HEAD - в этом случае, выдается только заголовок документа. Из заголовка можно узнать существует ли документ, его размер и еще некоторую информацию, о которой ниже. Данный метод, как правило, используется для проверки ссылок и кеширующими системами.

POST - аналогичен методу GET, но не только запрашивает ресурс, но и передает ему некоторую информацию. Если ресурс - CGI скрипт, то информация поступает на его стандартный ввод. Метод GET тоже умеет передавать информацию для CGI скриптов, но передает он ее в самом имени ресурса. Дело в том, что если мы вызовем CGI скрипт таким образом:



script.cgi?ПАРАМЕТРЫ



то веб-сервер запустит на выполнение script.cgi, а тот в свою очередь сможет заполучить ПАРАМЕТРЫ. А вот о том, откуда он их получит, позже.

Кроме вышеперечисленных методов, существуют еще методы PUT - для сохранения данных в указанном ресурсе и DELETE - для удаления указанного ресурса. Как правило они не поддерживаются веб-серверами, сами понимаете почему.

Теперь пример запроса:

GET /~user/cgi-bin/test.pl HTTP/1.0

Это конечно самый простой пример. Обычно, запрос выглядит гораздо сложнее и состоит из нескольких строк. Чтобы веб-сервер знал, что ввод данных закончен, нужно послать ему пустую строку. Т.е в данном примере, нужно нажать Enter два раза (один раз - переход на новую строчку, второй раз - пустая строка).

Если вы запрашиваете главную страницу сайта (т.е. в браузере это www.perl.ru) запрос будет выглядеть так:

GET / HTTP/1.0

Практически все переданные данные можно узнать непосредственно в скрипте на перле. Для этого служит массив %ENV, в котором хранятся так называемые переменные среды CGI. Например:

$ENV{REQUEST_METHOD} = GET

$ENV{QUERY_STRING} = те самые
параметры (script.cgi?параметры)

Узнать все пременные очень просто:

foreach (keys %ENV){
 print "$_ = $ENV{$_}\n";
}

Какую же еще информацию, мы можем передавать веб-серверу?

ПолеПримерОписание
Date:Date: Sun, 30 Dec 2000 23:59:59 GMTДата запроса.
MIME-version:MIME-version: 1.0Версия MIME.
Pragma:Pragma: no-cacheИнформация для шлюзов и прокси-серверов.
Authorization:Authorization: Basic QWxhZGRpbj pvcGVuIHNlc2FtZQ==Информация для авторизации.
From:From: Pupkin@mail.rue-mail пользователя браузера.
If-Modified-Since:If-Modified-Since: Sun, 30 Dec 2000 23:59:59 GMTИспользуется при методе GET. Документ возвращается только в том случае, если он изменился с указанного момента. Как правило браузер, запрашивает документ подобным образом, если копия документа содержится у него в кеше. И соответственно выдает пользователю информацию из кеша или обновленный документ.
Referer:Referer: http://www.perl.ru/URL предшествующего ресурса. Именно по нему на некоторых сайтах определяется, насколько хорошо их рекламирует тот или иной ресурс.
User-Agent:User-Agent: Mozilla/5.0Имя клиента. Может стоять что угодно, но некоторые, особенно гадкие сервера, не выдают страницы "не браузерам".
Host:Host: vasya.narod.ruИмя хоста. Дело в том, что в сети существует очень большое количество виртуальных серверов, т.е. серверов с разными именами, но одним IP адресом. Именно по этой переменной веб-сервер определяет какую же информацию вам дать.
Accept: Accept: text/htmlУказывает серверу, выдавать только данные указанного типа.
Вот основные и наиболее часто используемые данные, передаваемые веб-серверу.

Теперь пара примеров запросов:

GET /cgi-bin/test.cgi?name=Vasily&age=18 HTTP/1.0
User-Agent: Mozilla/5.0

И тоже, но методом POST

POST /~user/cgi-bin/test.cgi HTTP/1.0
User-Agent: Mozilla/5.0
Accept: text/html
Accept: image/gif
Content-Type: application/x-www-form-urlencoded
Content-Length: 18

name=Vasily
&age=18

Теперь рассмотрим, что же отвечает веб-сервер. Ответ веб-сервера выглядит следующим образом:

HTTP/ВЕРСИЯ КОД_ОТВЕТА ФРАЗА_ОТВЕТА

КОД_ОТВЕТА - 3-хзначное число. Указывает что все прошло успешно (200) или код ошибки.

ФРАЗА_ОТВЕТА - Тот же код но по-русски (шучу, по-английски)

Пример:

HTTP/1.1 200 OK




Дальше идет информация, которая различна для разных запросов. Как правило, это опять таки дата, тип сервера и т.д. Иногда веб-сервер может поместить в заголовок ответа следующую строчку:

Location: http://www.perl.ru/

Она указывает браузеру, что нужно немедленно идти по этому адресу, что собственно они все успешно и делают.
Далее я перечислю коды ответа браузера и их значения.

Обязательно должна присутствовать строчка:

Content-Type: text/html

указывающая тип переданных данных.

Ну и напоследок, список кодов возвращаемых веб-серверами и их значений

 Код статуса  Значение 
200OK
201Успешная команда POST
202Запрос принят
203    Запрос GET или HEAD выполнен
204Запрос выполнен но нет содержимого
300Ресурс обнаружен в нескольких местах
301Ресурс удален навсегда
302Ресурс отсутствует временно
304Ресурс был изменен
400Плохой запрос от клиента
401Неавторизованный запрос
402Необходима оплата за ресурс
403Доступ Запрещен
404Ресурс не найден
405Метод не применим для данного ресурса
406Недопустимый тип ресурса
410Ресурс Недоступен
500Внутренняя ошибка сервера
501Метод не выполнен
502Неисправный шлюз либо перегруз сервера
503Сервер недоступен/тайм-аут шлюза
504Вторичный шлюз/тайм-аут сервера
Philip A. Koryaka

e-mail:flp@mail.ru

Copyright c 2001


Рабочие программы, использующие регулярные выражения


В принципе регулярные выражениея это вовсе не вещь в себе, хотя иногда и может встретится задача, фактически полностью реализуемая при помощи regex. Ниже приведены программы, иллюстрирующие использование реглуярных выражений:



Работа с cookies на Perl


Материал взят с сайта http://spgroup.km.ru/

Cookies - небольшие файлы сохраняемые на машине клиента, позволяющие хранить персональную информацию для каждого пользователя на стороне клиента. В Perl для работы с Cookies используется модуль CGI::Cookie

С помощью Cookies Вы можете сохранять на стороне клиента информацию ввиде ключ-занчение. В какой-то степени Cookies можно сравнивать с передачей параметров запроса методом POST, но передаваемые значения в случае Cookies будут храниться на компьютере пользователя, что позволяет идентифицировать любого клиента, зашедшего на Ваш сайт второй или более раз.

В основном Cookies применяются для аутентификации пользователя ресурса. Т.е. в Cookies можно хранить имя пользователя, пароль, или идентификатор сессии пользователя. Таким образом, зарегистрированный на вашем сайте пользователь может входить в свою область идентификации не вводя каждый раз пароль.

Единтефикация пользователя, конечно, не единственное применение Cookies. Уважаемый читатель может пользоваться Cookies для каких-то своих, ему ведомых целей.

Итак, как можно (и нужно) работать с Cookies на Perl?

Во-первых, для работы необходимо подключить модуль:

use CGI::Cookie;

Этот модуль позволит Вам получить доступ для манипуляций с Cookies.

Вторым шагом может служить запись Cookies:

Сначала надо создать Cookie:

$c = new CGI::Cookie(-name => 'SOMENAME',

    -value => 'SOMEVALUE',

    -expires => '+3M',

    -domain => '.someserver.com',

    -path => '/cgi-bin'

    -secure => 1

);

Ключи -name и -value передают пользователю данные которые Вы хотите записать пользователю в формате Ключ - Значение соответственно.

Ключ -expires указывает время жизни Cookie на машине пользователя. В данном примере время жизни 3 месяца. Если время жизни устанавливается в ноль то Cookie существует только тогда, когда запущен браузер и не записывается на диск. После закрытия браузера такой Cookie аннулируется.


Ключ -domain указывает полное или частичное имя сервера, для которого Cookie имеет силу. Браузер возвратит Cookie любому хосту, который соответствует полному или частичному имени указанному в этом ключе. На-пример, если Вы укажете имя домена .somesrver.com, то Cookie будет возвращено любому поддомену этого домена, будь то www.somesrver.com или vasya.somesrver.com. Если же этот ключ не определен, то будет установлено имя хоста по умолчанию, с которого был записан Cookie.

Ключ -path служит для указания пути к скриптам которые используют этот Cookie. Если Вы указываете путь /cgi-bin, то все скрипты в этом каталоге и в его подкаталогах получат Cookie, но скрипты расположенные в других каталогах, не являющихся подкаталогами /cgi-bin этот Cookie не получат.

Если установлен ключ -secure, то Ваш Cookie будет передаваться только по протоколу SSL. По обычному HTTP протоколу он передаваться не будет.

Дальше нобходимо передать созданный Cookie браузеру пользователя:


print header(-cookie=>$c);

Теперь как получить Cookie...



%cookies = fetch CGI::Cookie;

В результате этой операции мы получим хэш со значениями переданного от пользователя Cookie. Далее мы можем манипулировать полученными значениями


$SOMECOOKIE = $cookies{'SOMENAME'}->value;

После этой операции переменная $SOMECOOKIE будет иметь значение 'SOMEVALUE'.