Все серверы могут предоставлять только статистические данные. Но бывает необходимость составлять страничку "на лету" или, например, управлять базами данных, посылать почту через web-страницы и т.д., вот как раз для этого и существует CGI. Вернее сам CGI не взаимодействует с базами данных и с почтой, а просто запускает прикладные программы и передаёт им данные. Программы, их ещё называют шлюзами, в свою очередь могут в соответствии полученных данных выполнять абсолютно любые действия, в том числе и вышеперечисленные.
Данные от сервера к программе передаются через командную строку или через переменные окружения, и поэтому программы могут быть написаны на любом языке программирования. Одним из самых популярных языков для создания CGI программ является Perl.
Вернее Perl является интерпретируемым языком, предназначенным для создания скриптов.
Основное различие скриптов от программы в том, что программа уже скомпилирована в двоичный код, а скрипт компилируется только перед выполнением. Удобство скриптов заключается в том, что они могут выполняться на любом компьютере вне зависимости от его архитектуры и операционной системы.
Perl(Practical Extraction and Report Language) является узкоспециализированным языком для обработки текста и составления отчетов. С помощью него можно открыть несколько файлов одновременно, прочитать оттуда данные, обработать и снова сохранить в файле. Perl является наилучшим и гибким инструментом для работы с текстом.
Поскольку Perl создан для многих разных операционных систем, в данном документе речь пойдет о Perl-е под Unix (я использую его клон Linux, дистрибутива Red Had). В принципе различий между ними мало, так что не будет хуже, если вы будете использовать, например Виндосовский. Проблем, честно говоря, у меня с установкой Perl-а не было, так как он поставился вместе с ОС. Достать его не проблема, например на:
www.perl.com - можно достать как документы (есть только одна проблема, они на английском, но кто им владеет, может подчеркнуть для себя много хорошего), также там можно достать и сам Perl под Unix.
http://ntperl.hip.com как и на www.ActiveState.com - можно достать Perl под Винду, во всяком случае так пишут в различных документах.
Поскольку Перл служит не только для работы с веб - страницами, а вообще с любыми текстами и файлами, мы пока будем писать программки, где вывод будет происходить на экран терминала.
Как во многих книгах, по программированию почему-то первая программа выводит на экран надпись "Hello world!!!", мы не будем отставать от них и напишем точно такую же программу:
#!/usr/bin/perl # -- This program prints "Hello world" -- print "Hello world!!! \n";
Можете напечатать эту программу в любом текстовом редакторе, и не забудьте сделать её запускаемой ( chmod +x имя_файла ). После этого попробуйте запустить её. Если она не вывела желаемого, а вывела что-нибудь вроде этого --- ,то попробуйте найти перл_интерпретатор таким образом ( find / -name perl),если всё же ничего не было найдено, то просто на просто у вас нет Perl-а или ваш администратор спрятал его от греха подальше. Если вы всё же нашли perl, тогда замените строку #!/usr/bin/perl на #!/_путь_/perl - эта строка показывает, где находится Перл.
Все что следует за знаком # - это комментарии, они игнорируются интерпретатором и служат только для нужд программиста.
Строка print "Hello world!!! \n"; - ну это и ежу понятно, что эта строка выводит саму надпись, символ \n переводит курсор на следующую строку.
Да, я совсем забыл сказать, что после каждого оператора надо ставить точку с запятой.
Ну, вот в принципе и все, что я вам хотел показать в этом шаге.
Переменных в перл, в отличии от таких языков, как С++ или Pascal, всего три типа. Они подразделяются на скаляры, массивы и хеши - так называемые ассоциативные массивы. Так как это средство для обработки текста, они не делятся на текстовые и численные, для перла это все равно.
Скаляры могут иметь только одно значение, они начинаются со знака "$".
Например:
$Var1 = " HeLLo All !!!! :- )))))))))";
Где Var1 - имя этой переменной, "=" в данном случае присваивает переменной значение "HeLLo All !!!! :- )))))))))".
Значение этой переменной можно вывести на экран таким образом:
$Var1 = " HeLLo All !!!! :- )))))))))"; print "Значение \$Var1 = $Var1";
Появиться результат:
Значение $Var1 = HeLLo All !!!! :- )))))))))
Обратите внимание на то, что перед первым $Var1 стоит знак "\", он сообщает компилятору, что следующее название переменной надо проигнорировать и вывести как обычную строку. После print текст может содержаться в двойных кавычках, если же вы напишите этот текст в одинарных кавычках (апострофах), то получится такой определённый казус:
Значение $Var1 = $Var1;
Если кто умеет программировать на SHELL под UNIX то, тот знает, что переменные и метасимволы в одинарных кавычках игнорируются. Раз уж мы начали говорить о строках, то надо еще сказать об обратном апострофе - так вот если вы заключите в них какую либо команду интерпретатора, то эта команда выполнится (примечание: если вы введете обычный текст, то эта строка пропускается интерпретатором)
Пример:
print "Сегодня: ",'date';
Результат:
Сегодня: Oct 28 16:36:10 YEKST 1999
Заметьте, что можно сочетать любые виды кавычек разделяя их запятой. Можно так же записывать переменные вне скобок и результат будет таким же, как если бы мы поставили в двойные кавычки, но есть некоторые различия, некоторые из них мы рассмотрим в этой главе.
Скалярам можно присвоить не только строки, но и числовое значение. Числа не заключаются в кавычки.
Пример:
$Var3 = 80; print "->$Var3<- ";
Результат:
->80<-
Если вы занесли в скаляр число, то с ним можно проделывать всяческие арифметические операции, но об этом попозже.
Массивы (списки скаляров) начинаются с символа "@" и могут содержать несколько значений.
Значения в массивы можно занести следующим образом:
@array = (1999,"Hello",'Привет',`date`);
Можно так же обращаться к отдельному элементу этого массива с помощью скаляров и это будет равносильно предыдущему варианту:
$array[0] = 1999; $array[1] = "Hello"; $array[2] = 'Привет'; $array[3] = `date`;
Здесь первый символ знак доллара, после идет имя этого массива, а потом в квадратных скобках указывается элемент, к которому вы хотите обратиться.
Если вы захотите вывести его, можно воспользоваться таким способом:
print "This array : @array";
Результат:
This array : 1999 Hello Привет Oct 28 16:36:10 YEKST 1999
элементы массива будут располагаться через пробелы, а если сделать так:
print "This array :",@array;
Результат:
This array :1999HelloПриветOct 28 16:36:10 YEKST 1999
между элементами пробелов нет. В массив можно включить другой массив или скаляр, присвоив элементу массива, другую переменную:
@mas2 = (@array," - массив в массиве, ", $var1,"- скаляр");
но если вы сделать таким образом:
@mas2[1] = @array;
то результатом этого будет присвоение @mas2[1] числа элементов массива @array, но если вы хотите все же включить @array в элемент массива, то поставьте его в двойные кавычки:
@mas2[1] = "@array";
Хеши(ассоциативные массивы) - это тот же самое что обыкновенный массив, но в нем чередуются названия и значения, то есть что-то вроде name:Sidorov, где name - название, а Sidorov - значение. Хеши в основном служат для создания текстовых баз данных. Они начинаются со знака "%". Инициировать их можно как обыкновенные массивы:
%hesh = ( 'name'," Sidorov ",'data_rozhdeniya',1900,'adress',"bomzh");
но есть и другие способы представления: через скаляры, к хешу можно обратиться следующим образом:
$hesh{name} = Sidorov;
$hesh{data_rozhdeniya} = 1900;
$hesh{adress} = bomzh;
- это будет равносильно вышеизложенному примеру. Но есть более удобные способы с помощью "=>" это выглядит примерно так:
%hesh = (name => "Sidorov", data_rozhdeniya =>1900, adress => "bomzh");
Так же в перле есть указатели на переменные, но в данном шаге они как видите, рассматриваться не будут.
Синтаксис:
if expression # Здесь expression - это условие
{:..}
else
{:..}
Нужно также сказать о блоке (операторных скобках), в перле блоком считается список выражений заключенный в фигурные скобки "{::..}".
if $var < 10
{ print "Ваша цифра меньше 10."; }
else
{ print "Ваша цифра больше или равна 10."; }
Поскольку мы еще не рассматривали операции ввода/вывода, то примеры получатся весьма глупыми, так как значение переменных уже известно. Но все-таки рассмотрим этот пример, здесь if проверяет условие, и если оно выполняется, то тогда выполняются выражения в блоке после if, а выражение в блоке после else игнорируются. Если же условие не верное, тогда выполняются выражения после else.
Если вы используете только один оператор, то не имеет смысла писать его в фигурных скобках, его можно записать таким образом.
print "Hello" if $var = 10;
Здесь оператор print пишется перед проверкой условия и точка с запятой между ними не ставится.
Ниже приведена таблица операторов отношений.
< меньше > больше <= меньше или равно >= больше или равно == равно != не равно
В перле проверять можно не только число, но и строки. Принцип, следующий и он прост, сравнивается каждый символ обоих строк по таблице кодировки.
"abc" == "abc" "abc" < "acb" "z" > "abc" "Z" < "z"
Но чтобы отличить отношение чисел от отношения строк используют другие операторы, они приведены ниже.
lt меньше gt больше le меньше или равно ge больше или равно eq равно ne не равно
Бывают ситуации, когда условие нужно несколько раз подряд, например:
if $var > 4
{
print "Это число меньше 8 и больше 4" if $var < 8;
}
Приведенный выше пример можно записать короче с помощью логических операторов, в данный момент используется оператор И.
print "Это число меньше 8 и больше 4" if $var > 4 && $var < 8;
В перле два логических оператора И - &&(AND), и ИЛИ - ||(OR);
Как и в других языках программирования в перле имеется несколько видов циклов. В этом шаге будет рассматриваться их синтаксис.
for (expression_1; expression_2; expression_3)
{ ::.. }
Где:
for( $fr = 0 ; $fr < 3 ; ++$fr )
{
print "->$fr<-/n";
}
Результат будет выглядеть так:
->0<- ->1<- ->2<-
Здесь expression_1 заменено на $fr = 0, как вы видите счетчиком, здесь служит скаляр $fr и ему присваивается начальное значение 0. Этот цикл будет работать пока выражение $fr < 3 будет выполнятся, если же нет, то он прервется. Шаг, с которым будет увеличиваться цикл, равен единице, это следует из выражения ++$fr (обратите внимание оператор ++ - инкремент, а также -- -декремент пишется перед переменной), которое можно заменить на более понятное $fr = $fr + 1;
Синтаксис:
foreach VAR ( ARRAY )
{------------}
Пример:
@array = ("one","two","three");
foreach $var (@array)
{
print "@var : ";
}
Результат:
one : two : three
Как видно из примера здесь каждое значение массива @array присваивается переменной $var. Можно также записать в таком виде:
foreach $var ("one","two","three")
{ ------- }
Это цикл работает, "пока" условие выполняется.
Синтаксис:
write (_EXP_)
{ ----------- }
Здесь _EXP_, условие, при котором цикл будет работать.
Пример:
$wr = 0;
write ( $wr < 6 )
{ print "->$wr<-\n";
$wr = $wr + 2;
}
Результат будет такой:
->0<- ->2<- ->4<-
Обратите внимание, что в цикле переменная $wr изменяется, если же она не будет изменяться, то цикл будет работать бесконечно но, слава богу, в юниксе есть такая команда как KILL, или сочетание клавиш Ctrl + C (это на случай если он у вас все-таки повис).
Если у вас в цикле должен повторяться только один оператор, то можно записать, к примеру, так:
++$var ( $var < 5 );
Оператор print пишется перед оператором цикла.
Существуют так же операторы управления циклом while:
Этот цикл противоположен циклу while, то есть он выполняется, пока условие не выполняется.
$wr = 0;
until ( $wr > 6 )
{ print "->$wr<-\n";
$wr = $wr + 2;
}
Этот оператор позволяет осуществить переход на указанное место. Поскольку я приверженец структурного программирования, то я советую не употреблять этот оператор в своих программах. Хотя в принципе он может понадобиться в некоторых случаях.
Формат следующий:
метка: .... goto метка;
Можно сделать переход к подпрограммам. Хотя подпрограммы мы будем рассматривать в следующих шагах, мы все-таки напишем его синтаксис:
goto $subroutine;
В этом шаге будут рассматриваться не только шаблоны (регулярные выражения), но и там где они используются, то есть, к примеру, в таких операторах, как поиск, замена и т.п. Именно этот раздел Перла больше всего пугает программистов, так как синтаксис шаблонов и операторов сильно отличается от таких языков как C. Возможно, далее сказанные слова вам не дадут представления о шаблонах, как и мне в начале изучения перла, но после разбора примеров других программистов я сориентировался. Надеюсь, вы поймете.
Оператор =~ наиболее важный для работы с шаблонами. Он связывает переменную, которая стоит перед ним, и шаблоном стоящим после него (он в принципе ничего не выполняет, кроме того, что привязывает переменную к оператору, который в свою очередь выполняет определенные действия над ним). Оператор != работает с точностью до наоборот.
Пример:
$var =~ /w+/
Здесь =~ привязывает переменной $var оператор /w+/, который выполняет поиск первого слова в этой переменной.
Найденный результат заносится в переменную типа $цифра, надо сказать что в эту переменную заносятся выражения попадающие под шаблон в круглых скобках. К примеру, можно написать такую программу:
$var = "Hello world!!!!"; $var =~ /Hello (\w+)/; printf "Результат: $1\n";
После запуска программы, она выдаст:
Результат: world
Здесь происходит поиск слова стоящего после слова Hello. Найденное слово заносится в переменную $1. Надо сказать, что оператор привязки может и не использоваться, тогда операторы будут брать данные из переменной $_.
Пример:
$_ = "Hello world!!!!"; /Hello (\w+)/; printf "Результат: $1\n";
Этот пример будет аналогичен вышеизложенному и результат будет точно такой же.
Я решил рассказать про оператор поиска, перед тем как начну рассказывать о шаблонах, так как надо хоть иметь представление о том, где они используются, да к тому же я их уже использовал его в предыдущих примерах.
Синтаксис:
m/шаблон/параметр
где место слово "параметр" ставятся параметры поиска:
| Параметр | Описание |
|---|---|
| g | Глобальный поиск. |
| i | Сравнение не зависит от регистра (верхний или нижний) |
| m | Строка многострочная |
| o | Однопроходная компиляция |
| s | Однострочная строка |
| x | Используются расширенные регулярные выражения. |
Хотя вы могли заметить из предыдущих примеров, что параметр можно не использовать, также можно не использовать m, а просто заключить шаблон между обратными бэкслэшами (деление). Как уже было сказано выше, результат поиска заносится в переменную типа $цифра.
Пример:
$var = "Hello world!!!!"; $var =~ /(\w+)(\w+)/; printf "Результат: $1 $2\n";
Результат:
Результат: Hello world
В случае удачного завершения операции возвращается true, а если ничего найти не удалось тогда false. К примеру:
if ( $var =~ /+w/ )
{ print "Найдено!!!\n"; }
else
{ print "Найдено!!!\n"; }
Прежде всего надо сказать, что шаблоны подобны двойным кавычкам, то есть в них допускается использование переменных и специальные символы (например \n - новая строка)
Шаблон не был бы шаблоном, если бы не метасимволы - символы обозначающие группы других символов. Имеются следующие метасимволы.
| \ | Отменяет действие следующего за ним метасимвола и считает его как обычный символ |
|---|---|
| () | Группировка. |
| . | Один произвольный символ. Кроме '\n' - конец строки. |
| $ | Конец строки |
| | | Альтернатива |
| ^ | Начало строки |
| [] | Множество символов. |
Рассмотрим для примера, метасимвол '()' - стоит оговорится, что при поиске, результат выражения будет содержаться именно в круглых скобках.
/Hello (\w+)/;
Здесь в круглых скобках используется метасимвол /w, он характеризует один алфавитно-цифровой символ. Знак '+' - модификатор, он характеризует число повторений метасимвола.
Имеются следующие модификаторы:
| * | Повторяется 0 или большее число раз |
|---|---|
| + | -//- 1 или большее число раз |
| ? | 1 или 0 раз |
| {n} | точно n раз |
| {n,m} | не меньше n, но и не больше m |
Как можно заметить, что все выражение '\w+', можно подставить в место любого слова (повторение буквенных символов и есть слово), то есть, имеется возможность сделать собственные универсальные шаблоны.
Для полного понятия рассмотрим еще несколько дополнительных метасимволов:
| \w | Алфавитно-цифровой или '_' символ |
|---|---|
| \W | не -//- |
| \s | один пробел |
| \S | один не пробел |
| \D | одна не цифра |
| \d | одна цифра |
| \b | Граница слова |
| \B | не граница слова |
| \A | начало строки |
| \Z | конец начало строки |
| \G | конец действия m//g |
Синтаксис следующий:
s/шаблон/подстановка/параметр
Оператор замены подобен оператору поиска, различие состоят в том, что у него используется еще один аргумент 'подстановка' - это выражение подставляется вместо найденного по шаблону выражения, так же существуют различия в параметрах:
| Параметр | Описание |
|---|---|
| g | Глобальный поиск. |
| i | Сравнение не зависит от регистра (верхний или нижний) |
| m | Строка многострочная |
| o | Однопроходная компиляция |
| s | Однострочная строка |
| x | Используются расширенные регулярные выражения. |
| e | Рассматривать правую часть как выражение |
Пример:
$var =~ s/привет/hello/;
здесь происходит замена слова 'привет' словом 'hello'. Также допускается использование метасимволов:
var =~ s/привет \w+/hello/;
в данном случае произойдет замена слова 'привет' и следующего за ним слова на слово 'hello'.
В случае удачного успешного завершения операции возвращается количество замен, а если ничего найти не удалось тогда false или 0.
Синтаксис:
tr/таблица1/ таблица2/параметры
В отличии от вышеизложенного оператора замены, этот оператор заменяет все символы выражения указанные в 'таблице1' на символы в 'таблице2'.
Имеет следующие параметры:
| c | Дополнение 'таблица1', то есть заменяются те символы, которые не стоят в 'таблица1', немного похожа на операцию NOT |
|---|---|
| d | Cтереть найденные, но не замененные символы |
| s | "сжать" повторяющиеся замененные символы, то есть если после замены в подряд идут несколько одинаковых символов, то они сжимаются в один. |
Пример:
$ var = "Hello All"; $ var =~ tr/l/L/; print "$var\n";
Получим:
HeLLo ALL.
Подпрограммой (процедурой) называется кусок программного кода, созданный для реализации конкретной задачи. Они дают возможность избегать повторного набора одних и тех же операторов. Вот к примеру:
$i = 5+6; print "Результат $i\n"; $i = 10+3; print "Результат $i\n "; $i = 6+1; print "Результат $i\n ";
Результат, как можно уже догадаться выглядит так:
Результат 11 Результат 13 Результат 7
Как вы видите здесь, повторяются практически все операции, и меняются только слагаемые.
Её можно уменьшить, применяя подпрограммы, но для начала посмотрим, как они определяются.
Синтаксис:
sub имя_подрограммы() #Если вашей подпрограмме не передаются параметры.
{ --БЛОК-- };
sub имя_подрограммы(тип переменных)
{ --БЛОК-- };
Здесь под словом 'тип переменных' понимается тип переменных, служащих для передачи данных подпрограмме. Хотя данные можно и не передавать, тогда 'тип переменных' можно упустить.
Одним важным примечанием является то, что вы можете определять подпрограммы перед главной программой, но вы можете писать процедуры и после программы предварительно указав вначале её описание, то есть тоже самое, но без 'блока'.
Пример:
sub AddingProc ( $$)
{
$i = $_[1] + $_[0];
print " Результат $i \n "
};
AddingProc(5,6);
AddingProc(10,3);
AddingProc(1,6);
Причем, как можно заметить, параметры программе передаются в массиве @_, где $_[0] и $_[1] являются его элементами. Здесь также присутствует описание передаваемых параметров, в данном случае это два скаляра, но могут и быть другие описания, например:
таких сочетаний вы можете придумать сколько угодно. Хотя есть некоторые неудобства в передаче параметров через массив @_, так как допустим, у вас передаются переменные типа @$, то идет зависимость местонахождения скаляра от размера идущего передним массива, это можно показать на таком примере:
sub TestProc( @$ )
{ print $_[3]; }
TestProc(("Test","Hello", "simply"),"scalar ");
Результат:
scalar
Ну здесь всё понятно, но если мы заделаем так:
sub TestProc( @$ )
{ print $_[3]; }
TestProc(("Test","Hello", "simply","array"),"scalar ");
То получим слово 'array', а поэтому если же вы будите пользоваться таким способом передачи данных в процедуру, тогда ставьте вперёд данные, размер которых известен, а только потом массивы, размер которых изменяется.
Можно так же передавать параметры через переменные, так как переменные описанные в главной программе считаются локальными, то есть значение этой переменной распространяется на все используемые подпрограммы. Так же предусмотрено использование не локальных, а переменных доступных только внутри блока. Это можно устроить с помощью функции my(список переменных), обратите внимание на то, что если у вас существуют локальные переменные с такими же именами, то они будут игнорироваться.
Приведем такой пример:
sub TestProc()
{
my($var);
print "$var";
}
$var = 10;
TestProc();
Результата здесь ни какого не будет, переменная $var в подпрограмме это не $var в главной программе.
Так же как и в других языках программирования, в перле можно работать с модулями. Модулем считается совокупность подпрограмм заключенных в один файл. Хотя в перле модули можно записать в один файл, это позволяет структурировать вашу программу. Так же это удобно когда программа становится очень большая, и её чтение становится затруднительным. Когда у вас есть подпрограммы, которые часто используются в разных программах, тогда можно использовать модуль как отдельный файл и экспортировать подпрограммы из него.
Пример:
package main;
{
print "Hello!!!!!!!!";
}
Давайте по подробнее рассмотрим этот пример. Здесь 'package' - идентификатор начала модуля, а 'main' - имя этого модуля, причем это имя зарезервировано и используется, как и название главного модуля, то есть если вы запустите скрипт, который состоит из одних модулей, то его выполнение начнётся именно с модуля main.
Пример:
package mod1;
{
@array = ('hello','bay','hay');
sub proc1
{
print "@array \n";
}
}
package main;
{
mod1::proc1;
print "@mod1::array \n";
}
Результат:
hello bay hay hello bay hay
Приведенный выше пример работает, если вы включили его в один файл. Так же есть ещё одно неудобство (по крайней мере, я не додумался, как это решить), модуль main надо описывать в самом конце файла, так как надо вперед описать другие модули. Вернемся к нашему примеру. Обратите внимание, как надо ссылаться на переменные и процедуры в другом модуле, здесь всё пишется как обычно, но к имени переменной в начало добавляется имя_модуля+'::'.
Модуль можно так же определить и внутри другого модуля, всё делается точно также, только обращение к его содержимому выглядит так:
имя_модуля::имя_подмодуля::переменные_или_продрограмма
Пожалуй, наиболее полезным является создание библиотек - файлов с заключенными в них модулями. Имеются так же стандартные библиотеки, в unix они содержатся в каталоге /usr/lib/perl/, и имеют расширение 'pm'. Вы можете записать туда свою библиотеку и использовать её. Вернемся к созданию библиотек. Создайте файл с расширением pm и поместите его в указанный выше каталог.
#--------------------------------------------------
# Главный файл можете поместить его куда хотите.
#--------------------------------------------------
use mod1; # Подключение библиотеки mod1
mdo1::proc1; # Использование подпрограммы из модуля mod1
proc2; # Почему то подпрограммы можно писать без ссылки на модуль
print "$mdo1::var1"; # Печать значения переменной и модуля
#----------END_FILE--------------------------------
#--------------------------------------------------
# Собственно сама библиотека, с именем файла
# mod1.pm, имя файла должно соответствовать
# названию модуля.
#--------------------------------------------------
package mdo1;
require Exporter; # Нужна для экспорта перемененных и подпрограм
@ISA = qw(Exporter); #
@EXPORT = qw(proc1 proc2); # Экспорт процедур
@EXPORT_OK = qw( $var1 ); # Экспорт переменных
$var1 = 10;
$var2 = 10;
sub proc1
{
print "Hello!!!!!!!!!!";
}
sub proc2
{
print "Привет!!!!!!!!";
}
#------------END_FILE------------------------------
В этом примере модуль не ограничивается блоком, так как начало файла является началом модуля, а конец - концом.