Приложение 3. Основы CGI/Perl

Программы, написанные на языке скриптов Perl, синтаксически похожи на программы, написанные на языке Cи. Рассмотрим простой пример вывода строк:

#!/usr/local/bin/perl –w

print("Hello, world\n"); #пример3.1-вывод строк

print "I live in Minsk,\n", "I work hire", "\n";

print ('Hello, world\n');

Будет выведено:

Hello, world

I live in Minsk,

I work hire

Hello, world \n

Программы main(), как в языке Си, здесь нет. Комментарием в Perl является все, что следует за «решеткой» (#), вплоть до конца строки. Строка в одинарных ковычках рассматривается как массив символов, при этом символы \n будут выведены как обычные символы, а не как символ конца строки.

В системе UNIX при вызове Perl через CGI первая строка должна иметь вид комментария, в котором системе указывается путь к интерпретатору perl.exe. Аналогично, в системе Windows указывается свой путь, в котором прямой слэш ‘/’ может быть заменен на обратный ‘\’, например c:\perl5\bin\perl.

Чтобы выполнить программу, создаем файл pr31.pl и наберем строку вызова интерпретатора: perl pr31.pl

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

Рассмотрим второй пример ввода и вывода значений строковых переменных:

#!/usr/local/bin/perl -w

#пример3.2- ввод и вывод строк

# -w режим отображения предупреждений об ошибках

print "What is yure name?:";

$who =<STDIN>;

$where = 'Минск';

print "My name is $who,\n"; # представимся

print "I live in \t$where\n",

Будет выведено:

What is yure name?:valera

My name is valera,

I live in Минск

Для ввода строкового значения используется дескриптор стандартного файла <STDIN> . Если строка еще не образована, то Perl останавливается и ждет до тех пор, пока не будут введены информация и вслед за ней символ перехода на новую строку.

Типы данных

Perl оперирует следующими типами данных - скалярами, массивами, ассоциативными массивами (хешами). Особенностью Perl является то, что типы применяемых переменных не объявляются.

Их названия начинаются со знака $ - для скалярных переменных, @ -для массивов, % - хешей. Имена $varName и @varName различны.

Скалярные переменные могут принимать числовые и строковые значения, например

#Пример 3.3 : Вывод значений переменных

$str=”Результат:”;

$a = 2;

$b = 6;

$c = $a . $b; # ”.” — операция конкатенации двух строк

$d = $c / 2;

print $str, $d; # — результат равен 13

Будет выведено:

Результат:13

Массив — это список скаляров. Каждый элемент массива — это скалярная переменная, которой можно присваивать значение. Все массивы в языке Perl— динамические. О проблемах распределения памяти заботится интерпретатор. Рассмотрим пример:

#Ghbvth 3.4 : Вывод значений массивов

@emptyArray = ();

@numberArray = (12, 014, 0x0c, 34.34, 23.3E-3);

@stringArray = ("This", "is", 'an', "array", 'of', "strings");

@mixedArray = ("This ", 10, " is ", 'a', " mixed array ", ' of ', " items");

print "Here is an empty array:" . @emptyArray ."\n";

print @numberArray; print "\n";

print @stringArray; print "\n";

print @mixedArray; print "\n";

 

Будет выведено:

Here is an empty array:0

12121234.340.0233

Thisisanarrayofstrings

This 10 is a mixed array of items

Здесь символ "\n" выводится отдельно от массива. Если вместо этого использовать контактенацию и вывести print @numberArray . "\n";, то Perl истолкует @numberArray в скалярном контексте и выведет не элементы массива, а их число. Так и происходит вывод массива @emptyArray, в результате чего выводится число элементов 0.

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

@array = (1..5);

$numberOfElements = @array;

$doubleTheSize = 2 * @array;

print "The number of array elements is: " . $numberOfElements . "\n";

print "Double the number of array elements is: " . $doubleTheSize . "\n";

Будет выведено:

The number of array elements is: 5

Double the number of array elements is:10

Два массива можно объединить в одном:

@smallArrayOne = (5..10);

@smallArrayTwo = (1..5);

@largeArray = (@smallArrayOne, @smallArrayTwo);

print @largeArray;

Будет выведено:

Как и в C++, нумерация элементов массива начинается с нуля, однако здесь можно использовать отрицательные индексы, чтобы вести отсчет от конца массива. Например:

@array = (1..5);

print @array; print "\n";

print $array[-1]; print $array[-2];

print $array[-3]; print $array[-4];

print $array[-5]; print "\n";

Будет выведено:

Можно использовать подмассивы данного массива:

@array = ("One", "Two", "Three", "Four");

($first, $third) = @array[0, 2];

@half = @array[2, 3];

print("\@array=@array\n");

print("\$first=$first \$third=$third\n");

print("\@half=@half\n");

@array[0, 3] = @array[3, 0];

print("\@array=@array\n");

Будет выведено:

@array=One Two Three Four

$first=One $third=Three

@half=Three Four

@array=Four Two Three One

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

@A=(1,2,3);

@B = (4, 5, 6);

@C = (7, 8, 9);

@D = (@A, @B, @C);

print @D;

Результирующий массив D будет содержать числовые значения от 1 до 9

Встроенная функция qw() используется для объединения нескольких скалярных значений в массив например:

@passwords = qw(pas1 pas2 pas3);

Проведя такую операцию, затем можно обращаться к каждому из скаляров с помощью индексных ссылок. В рассматриваемом примере $passwords[0] имеет значение pas1, $passwords[1] — pas2, а $passwords[2] —pas3.

Вcтроенная функция sort(() использует массивы как аргументы и возвращает массив, в отсортированном виде. Результатом операции print sort(‘Beta’,’Gamma’,’Alpha’); будет последовательность AlphaBetaGamma. Функция join() имеет два входных параметра — строку и массив строк. Она возвращает строку, которая состоит из всех элементов массива, разделенных значением входной строки, т. е. print join (‘:’,’Name’,’Address’,’Phone’); и выдает на печать Name : Address : Phone. Функцию push() можно использовать, чтобы добавить к уже существующему массиву какой-нибудь элемент, не создавая при этом дополнительный массив. Например:

#Пример 3.10 : добавление элемента в массив

@b = (”Beta”, ”Gamma”, ”Alpha”);

push @b, ”Tetta”; # добавим в массив @b новый элемент

@w = sort @b; # отсортируем массив @b по алфавиту

$i=0; # инициализируем переменную $c

foreach (@w) {

print ”$w[$i]\n”; # выведем отсортированные значения

$i++;

}

Будет выведено:

Alpha

Beta

Gamma

Tetta

Как ранее указывалось, дескриптор <STDIN> возвращает в скалярном виде значение введенной строки. Примененный массиву, он каждому его отдельному элементу присваивает значение очередной введенной строки, пока не будет введен признак конца файла Ctrl+Z. Таким образом, если ввести три строки и операцию конца файла [Ctrl + Z], то массив будет состоять из трех элементов, которые являются строками и заканчиваются символами перехода на новую строку.

#!/usr/local/bin/perl -w

#пример3.12- ввод и вывод строк

print "Enter an array elements:";

@a =<STDIN>;

print "Array: @a \n";

Будет выведено:

Enter an array elements: aaaa<ввод>

bbbb<ввод>

cccc<ввод>

Ctrl+Z

Array: aaaa

bbbb

cccc

Ассоциированные массивы

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

%associativeArray = ("Jack A.", "Dec 2", "Joe B.",

"June 2", "Jane C.", "Feb 13");

$associativeArray{"Jennifer S."} = "Mar 20";

print "Joe's birthday is: " . $associativeArray{"Joe B."} . "\n";

print "Jennifer's birthday is: " . $associativeArray{"Jennifer S."} . "\n";

Будет выведено:

Joe's birthday is: June 2

Jennifer's birthday is: Mar 20

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

%fruit=(”Green”,”Apple”,”Orange”,”Orange”,”Yellow”,”Banana”);

print $fruit{”Yellow”};

В результате из-за структуры АМ «ключ, значение», получается «Banana». Ключом также является «Green», которому будет соответствовать элемент массива «Apple».

Ассоциативные массивы (АМ) упрощают работу программистов с базами данных (БД). Для лучшего понимания использования АМ следует сопоставить ключи с ID в таблицах реляционных баз данных, которые представляют собой практически одно и то же. Рассмотрим пример.

%Folk = ('BG', 'Bill Gates',

'PR', 'SuperProgramer',

'DS', 'Djon Smith');

%State = ('BG', 'California',

'PR', 'Minsk',

'DS', 'Washington' );

%Job = ('BG', 'work in Microsoft',

'PR', 'work as programmer',

'DS', 'work as writer');

 

foreach $person ('PR', 'BG', 'DS') {

print "My name is $Folk{$person},\n",

"I live in $State{$person},\n",

"I $Job{$person} there.\n\n";

}

Будет выведено:

My name is SuperProgramer,

I live in Minsk,

I work as programmer there.

 

My name is Bill Gates,

I live in California,

I work in Microsoft there.

 

My name is Djon Smith,

I live in Washington,

I work as writer there.

Содержимое массивов можно представить и в другой форме, например : %Job = (‘BG’ => ‘work in Microsoft’, ‘PR’ => ‘work as programmer’, ‘DS’ => ‘work as writer’);

Индексы и элементы массива можно заключать как в апострофы, так и в кавычки. Чтобы перебрать все значения АМ, можно использовать оператор цикла foreach. Можно обращаться к ключам и значениям с помощью операторов keys и values.

Специальный ассоциативный массив %ENV хранит содержимое всех переменных, индексированных по имени. Так, %ENV{‘PATH’} возвращает текущее значение пути поиска. Существует также функция each, приводящая список, который состоит из двух элементов — ключа и значения. При каждом следующем вызове она возвращает новую пару, например

while (($key,$value) = each %ENV) {

print ”$key = $value\n”;

}

Строки

Двойные ковычки в строках

@array = (1..5);

print "@array\n";

Будет выведено:

1 2 3 4 5

Если вы хотите вывести значение переменной, а затем добавить символы в конце с помощью кода:

$word = "large";

print "He was a $wordr fellow.";

Будет выведено:

He was a fellow.

Переменная $wordr трактуется неправильно, если вы хотите вывести строку "He was a larger fellow". Эта проблема может быть исправлена с помощью операции кантактенации следующим образом:

$word = "large";

print "He was a " . $word . "r fellow.";

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

Использование специальной переменной $" при работе со строками. В следующем примере переменная $" = "," используется для вывода элементов массива, разделенных запятыми.

$" = ",";

@array = (1..5);

print "@array\n";

Будет выведено:

1,2,3,4,5

Вы можете использовать любой другой символ, например $" = "; " выведет точку с запятой и пробел.

Операторы

В языке Perl используются операторы, аналогичные используемым в C++. Например условные операторы имеют вид:

if (EXPR) {BLOCK}

if (EXPR){ BLOCK} else{ BLOCK}

if (EXPR) BLOCK elsif (EXPR) {BLOCK} else {BLOCK}

#Пример

$var = 1;

if ($var == 0)

{ print "\$var = 0\n"; }

elsif ($var == 1)

{ print "\$var = 1\n"; }

else

{ print "Не известное \$var\n"; }

Результат: $var = 1

В Perl используются следующие операторы циклов:

LABEL while (EXPR){ BLOCK}

LABEL while (EXPR) {BLOCK} continue{ BLOCK}

LABEL for (EXPR; EXPR; EXPR) {BLOCK}

LABEL foreach VAR (LIST) {BLOCK}

Цикл while выполняет BLOCK до тех пор пока EXPR = true. Блок после continue выполняется всегда перед вычислением выражения EXPR. Метка LABEL используется, чтобы пометить цикл, который надо прервать, и необходима при использовании внутри блока операторов next, last и redo. Если метка отсутствует, то эти операторы ссылаются на начало ближайшего цикла. Оператор next подобно оператору continue в Си переходит к началу текущего цикла.

M1:

while ($i < 6)

{ ++$i; # Увеличиваем счетчик на 1

next M1 if $i < 3; # Переходим в начало если $i < 3

++$i; # иначе увеличиваем счетчик еще раз на 1

}

continue

{ print "$i "; # Печатаем $i

}

Результат: 1 2 4 6

Оператор last - подобно оператору break в языке Си немедленно прерывает цикл. Оператор redo предписывает начать новый цикл не вычисляя EXPR и не выполняя блок continue.

Пример:

M1:

while ($i < 6)

{ ++$i; # Увеличиваем счетчик на 1

redo M1 if $i == 3; # Далее пропустить для $i = 3

++$i; # иначе увеличиваем счетчик еще раз на 1

}

continue { print "$i "; # Печатаем $i

}

Результат: 2 5 7

Оператор for полностью аналогичен оператору for в Си.

Цикл foreach имеет вид: LABEL foreach VAR (LIST) {BLOCK}

Переменной VAR присваивается поочередно каждый элемент списка LIST и выполняется блок. Вместо слова foreach можно писать просто for - это слова синонимы.

Пример:

@месяц = ("январь","февраль","март"); # Создали массив

foreach $i (@месяц)

{ print $i," "; # Печать $i

}

for $i (3,5,7)

{ print "$i "; }

Результат: январь февраль март

3 5 7

В Perl существует оператор goto.

Рассмотрим пример небольшой программы:

#!/usr/local/bin/perl

@passwords = qw (inet basic net);

print ”Enter the login: ”;

$login = <STDIN>;

chomp ($login);

if ($login eq ”Root”) {

print ”Hello, Administrator! Glad to see you again!\n ”;}

else { print ”Enter password: ”;

$pass = <STDIN>;

chomp ($pass);

$i = 0; $flag = ”no”;

while ($flag eq ”no”) {

if ($passwords[$i] eq $pass) {$flag = ”yes”;}

elseif ($i <2) {$i = $i + 1;}

else {print ”Incorrect password for $login, try again.\n”;

print ”Enter password: ”;

$pass = <STDIN>;

chomp ($pass);

$i = 0; }

}

}

В рассматриваемом случае массив @passwords включает три элемента: inet, basic, net. Команда qw(), заключающая их в скобки, освобождает от ввода кавычек, необходимого при использовании общепринятой конструкции вида @passwords = (”inet”, ”basic”, ”net”); Оператор print служит для вывода на экран символьной информации print ”Enter the login: ”.

Затем располагается оператор ввода строки с терминала, выполняющегося в Perl с помощью конструкции <STDIN>. Переменная $login содержит и завершающий символ строки, например, Root будет введено как Root\n. Чтобы убрать лишний символ, требуется функция chomp, которая в качестве своего единственного параметра принимает скалярную переменную и удаляет из нее завершающий символ перехода на новую строку, если этот символ там присутствует: chomp ($login);

Наличие значения переменной $pass среди элементов массива @passwords проверяет $passwords[$i] eq $pass. Следующая ниже операция сложения $i = $i + 1; увеличивает текущее значение счетчика.

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

Подпрограммы необходимо определить или объявить (декларировать):

sub имя; #- декларация. Определение ниже.

sub имя блок; #- Декларация и определение.

sub имя (прототипы) {блок;} #- То же, но с параметрами.

Вызов подпрограммы:

имя(список параметров); # символ '&' можно не указывать.

имя список; # Если подпрограмма уже декларирована.

&имя; # Параметры в @_

Все параметры передаются подпрограмме как массив @_ ,который содержит адреса параметров. Соответственно $_[0] - первый параметр, $_[1] - второй и т.д. Возвращаемое значение подпрограммы - результат последнего оператора. Можно возвращать значение используя return.

Для применения переменных, доступных только внутри блока или подпрограммы, необходимо определить их с помощью функции my(список). Если переменная одна, то скобки можно опустить.

# Программа вычисления факториала.

print fact(3); # вычислить факториал 3*2*1

sub fact # Определяем подпрограмму.

{ my $m; # private переменная

$m = $_[0];

return 1 if $m <= 1;

return($m * fact($m -1)); }

Функция my позволяет указывать начальные значения переменных: my(список) = выражение; Так в приведенном примере лучше было написать: my($m) = $_[0];

В Perl реализован механизм модулей - группы подпрограмм включенных в один файл. Начало модуля определяется директивой: packages имя_модуля;. Конец модуля это конец блока или файла. Головной модуль имеет по умолчанию имя main. На имя внутри модуля можно ссылаться, добавляя '::' после имени модуля. Например: $main::var1.Для импортирования подпрограмм из других модулей используйте: use модуль qw(подпрограмма1 подпрограмма2 );

В Perl используются конструкторы и деструкторы - подпрограммы, которые выполняются в момент создания (удаления) объекта. Для модуля это подпрограммы с именами BEGIN и END.

Perl библиотеки обычно поставляется с дистрибутивом Perl и разделяются на pragma библиотеки (директивы компилятору) и стандартные библиотеки. Pragma библиотеки используют так: use имя;

В стандартный набор входят следующие pragma библиотеки:

diagnostics - включить режим расширенной диагностики; integer - использовать целочисленную арифметику; overload - hежим переопределения операторов; sigtrap - режим слежения за прерываниями; strict -режим ограниченного использования "опасных" операторов; subs - режим обязательного декларирования подпрограмм.

Рассмотрим некоторые стандартные библиотеки: AnyDBM_File - возможность работы с разными типами баз данных. Carp - предупреждения об ошибках. Config - доступ к конфигурации Perl. Cwd - получить имя текущей рабочей директории. English - использовать длинные имена встроенных переменных. Env - импортировать имена переменных окружения. ExtUtils::MakeMaker - создает файл проекта Makefile. File::Basename -синтаксический разбор спецификации файла. File::Find - Быстрый поиск файлов по директориям. File::Path –создание/удаление директорий. Net::Ping - тест доступа к хосту. Socket - определение структур и констант. Подробное описание каждой библиотеки записано в самом файле.

Программисты, работающие с Perl, создали общедоступную библиотеку модулей CPAN. Она доступна через Интернет.

Файлы

Существует три способа открытия файла: для чтения (read), дополнения (append) и записи (write). Для режима read синтаксис операции открытия файла следующий: open (HANDLE,”filename.txt”);

В круглых скобках заключен дескриптор файла HANDLE и имя файла. Для считывания информации из файла выполняется так называемая операция ромба, обозначаемая символами (<>):

open (HANDLE,”filename.txt”);

while (<HANDLE>){

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

}

Отличие синтаксиса open() для операции записи заключается в том, что перед именем файла стоит символ (>). Этот символ сообщает, что следует создать указанный в кавычках файл и записать или обновить его содержимое. Чтобы записать в него информацию, нужно обратиться к помощи оператора print:

open (HANDLE,”>filename.txt”);

print HANDLE ”Записать этот текст в файл...”;

Режим добавления (Append) синтаксически выглядит так:

open (HANDLE,”>>filename.txt”);

print HANDLE ”Дописать этот текст в файл...”;

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

В случае успешного выполнения функция open() возвращают значение true, иначе — false. Закрыть файл можно с помощью функции close(HANDLE). Всякий раз при открытии файла разумно использовать вместе с оператором open() оператор die. Бывает, что файл по какой-то причине нельзя правильно открыть. В подобном случае оператор die прерывает выполнение программы и выдает сообщение об ошибке при открытии файла.

open (HANDLE,”>>f.txt”)||die”Ошибка добавления в файл $!\n”;

Функция die прерывает выполнение программы. Выдается сообщение об ошибке, а также информация о том, что ее вызвало. Perl сохраняет сведения о последней системной ошибке в специальной переменной $!. В синтаксисе используется «логическое ИЛИ» (||).

Проверка существования файла.

$filename = ”filename.txt”;

if (-e $filename) {

print ”Файл $filename уже существует\n”;}

else { print ”Файл $filename не найден\n”;}

Чтобы убедиться в наличии какого-либо файла и возможности чтения из него, нужно вместо операции -e выполнить -r, а в случае требования возможности записи —w. Можно проверить один и тот же файл на доступность чтения и записи информации:

$filename = <STDIN>;

chomp ($filename);# убрать символ новой строки

if (-r $filename && -w $filename) {

# файл существует, мы можем читать из него и записывать в него

}

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

@files = <*.txt>;

foreach (@files) {

print ”$_ is readable\n” if -r;

}

При большинстве подобных проверок, а их около 20, возвращается значение true или false.

При работе на Perl под управлением Windows нужно указывать полный путь к файлу (вместе с именем диска), над которым будут выполняться какие-либо действия, например:

open (HANDLE,”c:/scripts/newfile.txt”) || die ”Error opening c:/scripts/newfile.txt $!\n”;

close (HANDLE);

Common Gateway Interface

CGI представляет собой стандарт взаимодействия Web-сервера с прикладными программами, которые пользователь может выполнять на Web-сервере. Программы CGI можно писать на языках типа С++, Visual Basic, но при этом возникают проблемы их переносимости с одной серверной платформы на другую. Таких проблем с Perl нет, интерпретатор Perl существует практически на любой платформе.

Ниже будет показано, как реализовать диалог с посетителем Web-страницы. Будут рассмотрены вопросы создания программ типа гостевой книги на основе Perl. Необходимые Perl-программы можно загрузить из Internet. Вот несколько узлов: www.freescripts.com, www.scripts.ru.