В предыдущем номере журнала читатели познакомились с базовыми понятиями и структурами языка создания Web-программ – Perl («Мир ПК», б№8/99, с. 68). Ниже будут рассмотрены более сложные его механизмы.

Дескриптор каталога

Для названий дескрипторов каталогов, так же как для дескрипторов файлов, нельзя выбирать зарезервированные слова, их рекомендуется набирать прописными буквами. Причем дескриптор файла FRED и дескриптор каталога FRED не связаны между собой. В Perl имеется несколько функций, позволяющих работать с каталогами. Можно создать каталог с помощью функции mkdir(), стереть – с использованием rmdir (), а для перемещения по дереву каталогов служит chdir().

Чтобы получить список файлов, находящихся в каком-либо каталоге, используются функции: opendir(), readdir() и closedir().Ниже приведена программа, показывающая, как вывести список всех Perl-программ, оканчивающихся на pl в текущем каталоге:

opendir(DIR, ”.”); # открыть каталог
@files = sort(grep(/pl$/, readdir(DIR)));
# массив файлов
closedir(DIR); 	# закрыть каталог
foreach (@files) { 
print(”$_
”) unless -d; # выводит список
файлов
}

Алгоритм ее работы таков:

  • открыть текущий каталог как дескриптор каталога с помощью функции DIR;
  • считать список файлов функцией readdir(), показать только оканчивающиеся на pl и затем отсортировать список и связать его с массивом @files;
  • закрыть каталог;
  • вывести содержимое массива на экран.

Функция chdir в Perl имеет один аргумент типа выражения. При его вычислении определяется имя текущего каталога. В случае его успешного изменения возвращается значение true, а при неудачном – false. Например, чтобы перейти в корень дерева каталогов и вывести там список всех файлов, нужно сделать следующее:

chdir (”/”) || die б”Невозможно перейти
в / ($!)”;
opendir(DIR, ”.”);
@files = sort(grep(/$_/, readdir(DIR)));
closedir(DIR);
foreach (@files) {    
print(”$_
”) unless -d;
}

Круглые скобки после chdir ставить необязательно.

Синтаксис функции создания каталога:

mkdir (DIRNAME, MODE), 

где DIRNAME – имя каталога, заключенное в кавычки, а MODE – права доступа. Так, чтобы создать каталог MYDIR, всем доступный и предоставляющий равные права, необходимо ввести команду

mkdir (”MYDIR”, 0777) || die б”Невозможно
создать MYDIR: $!”;

Если требуется удалить каталог, на помощь придет функция rmdir:

rmdir (”MYDIR”) || die ”Невозможно
удалить MYDIR: $!”;

Эта Unix-команда позволяет удалять только пустые каталоги. В Unix, как и в Windows NT, есть такое понятие, как право доступа к файлам и каталогам. С помощью функции chmod() можно устанавливать для файлов уникальные атрибуты. Например, чтобы сделать файлы «1.txt» и «2.txt» доступными для чтения и записи всем пользователям, нужно выполнить операцию

chmod  (0666, ”1.txt”, ”2.txt”);

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

Чтобы изменить права доступа к файлам «1.txt» и «2.txt» и проконтролировать ошибки, нужно использовать следующую конструкцию:

foreach $files (”1.txt”, ”2.txt”) {
unless chmod (0666, $files) {
warn ”Невозможно изменить права
доступа для $files.
$!”;
}
}

Каждый файл и каждый каталог обладают двумя параметрами – «владелец» и «группа», которые определяют, кому принадлежат права доступа, установленные для файла по категориям (чтение, запись и/или создание). Значения параметров выявляются при создании файла. Покажем, как можно изменять их для списка файлов. Первые два элемента списка должны представлять собой числовой UID (идентификатор пользователя) и GID (идентификатор группы):

$cnt = chown $uid, $gid, ‘foo’, ‘bar’;
chown $uid, $gid, @filenames;

Успешному выполнению операции соответствует ненулевое значение, равное числу файлов, принадлежность которых изменена (как в функции chmod). В листинге 1 приведен пример поиска нечисловых UID в файле passwd.

Листинг 1
print ”Пользователь: ”;
$user = ;
chop($user);
print ”Файлы: ”
$pattern = ;
chop($pattern);
open(pass, б‘/etc/passwdб’)
|| die б”Не могу открыть passwd:
$!
б”;
while () {
($login,$pass,$uid,$gid) =
split(/:/);
$uid{$login} = $uid;
$gid{$login} = $gid;
}
@ary = <${pattern}>;	# Получить имена
файлов
if ($uid{$user} eq б‘б’) {
die б”$user отсутствует в файле
passwdб”;
}
else {
chown $uid{$user}, $gid{$user},
@ary;
}

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

$cnt = unlink б‘1.txtб’, б‘2.txtб’, б‘3.txtб’;
или
@goners = (б‘1.txtб’, б‘2.txtб’, б‘3.txtб’);
unlink @goners;
или
	unlink <*.txt>;

Функция unlink() не позволяет убирать каталоги, если пользователь не обладает правами администратора системы. Учтите, что ее следует применять крайне осторожно, а при работе с каталогами целесообразно предпочесть rmdir ().

Чтобы переименовать файл, нужно воспользоваться функцией rename. При успешном выполнении она возвращает результат, равный 1, иначе 0. С помощью этой функции можно также переносить файлы из одного каталога в другой, например:

rename (б”e:/1.txtб”,б”d:/1.txtб”); 
или
rename (б”/docs/1.txtб”,б”/docs/add/1.txtб”);

Если же вы хотите просто переименовать какой-то файл, то пути к файлам должны совпадать, например:

rename (б”1.txtб”,б”2.txtб”);

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

Процедуры и функции

При создании программы разработчику, как правило, приходится писать в разных ее местах практически идентичные последовательности операторов, выполняющие одни и те же функции. В подобной ситуации очень могут помочь процедуры и функции, которые представляют собой самостоятельные фрагменты программы, оформленные особым образом и снабженные уникальным именем. Упоминание этого имени в тексте программы называется вызовом процедуры (функции). В Perl, как и в «классических» языках программирования, отличие функции от процедуры заключается в том, что в результате ее исполнения всегда получается единственное значение. Поэтому обращение к функции можно использовать в выражениях наряду с переменными. Далее будем называть функцию или процедуру общим именем «подпрограмма».

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

Ранее уже были описаны встроенные функции (подпрограммы), например chdir, print, mkdir, chomp, rmdir и другие. Теперь же рассмотрим функции, которые пользователь может определить самостоятельно. В Perl подпрограмма представляется конструкцией типа

sub название подпрограммы {
оператор_1;
оператор_2;
оператор_3;
оператор_4;
оператор_5;
...
}

Названием подпрограммы может быть любое имя. Подчеркнем, что могут одновременно существовать разные структуры программы с одинаковыми именами. Например, скалярная переменная $users, массив @users, хэш %users и подпрограмма &users. Подпрограммы могут находиться в любом месте текста программы, но обычно их размещают в конце. В теле подпрограммы можно обращаться к переменным, используемым в других частях программы, т. е. к глобальным, и присваивать им значения. Так, в следующем примере:

sub welcome {
print ”Welcome to CIA website!
”;
print ”––––––––––––––––
”;
print;
print ”Hello, $who
”;
}

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

$who = ”Michael Yevdokimov”;
&welcome;
или
$who = ”Michael Yevdokimov”;
welcome();

Одна подпрограмма может вызывать другую, та, в свою очередь, третью и т. д. Результат, полученный после вызова подпрограммы, называется возвращаемым значением. Он выходит вследствие выполнения оператора return или последнего вычисленного выражения. Вызов подпрограммы почти всегда является частью некоторого выражения, это хорошо видно на приведенных ниже примерах.

Пример 1
$a = 5; $b = 10;
$c = 3 * sum($a+$b);
print ”Результат = $c
”; # выводит Результат
= 45
sub sum {
return $a + $b;
}
Пример 2
$c = 3 * sum(5,10);
print ”Результат = $c
”; # выводит Результат
= 45
sub sum {
return $_[0] + $_[1];
}
Пример 3
@c = sum(5,10); # результат заносится в массив @c
print ”Первое значение: $c[0]; Второе: $c[1]
”;
sub sum {
return ($_[0],$_[1]);
}

На период выполнения подпрограммы значения элементов списка параметров, заключенных в круглые скобки, автоматически присваиваются специальной переменной @_. Подпрограмма может обратиться к ней и получить число аргументов и их значения. В двух последних примерах ссылка $_[0] представляет собой обращение к первому элементу массива @_. Переменная @_ является локальной для подпрограммы. Если же для нее установлено глобальное значение, то перед вызовом подпрограммы оно сохраняется, а после возврата восстанавливается.

Подпрограмма также может передавать параметры в другую подпрограмму, не «теряя» значения собственной переменной @_. Вложенный вызов подпрограммы точно так же пользуется уже своей переменной с именем @_.

Подсчитаем факториал числа 5 (листинг 2).

Листинг 2
print &factorial(1..5);
sub factorial{
$s=1;
foreach $_ (@_) {
# $s = $s * $_;
# $_++;		
$s *= $_;  # этой строчкой можно
заменить две предыдущие      
}
return $s;
}
Для сложения чисел от 1 до 5 вместо
$s *= $_ ;
вставим строку
$s += $_;

Если бы переменная с именем $s уже использовалась в программе, то при вызове подпрограммы &factorial ее значение было бы потеряно. А теперь рассмотрим, как этого можно избежать. Чтобы ограничить область действия переменной в пределах какой-либо подпрограммы, ее нужно заключить в круглые скобки, а слева от них написать my:

sub factorial {
my ($s);
$s = 0;
foreach $_ (@_) {
$s += $_;
}
return $s;
}

При этом текущее значение глобальной переменной $s запоминается, и после выполнения первого оператора в теле подпрограммы создается совершенно новая переменная с именем $s. При выходе из подпрограммы Perl восстанавливает предыдущее (глобальное) значение. Схема функционирует и в том случае, когда переменная $s является локальной, взятой из другой подпрограммы, вызывающей данную. Переменные могут иметь много вложенных локальных версий, но в каждый момент можно обращаться только к одной из них (листинг 3).

Листинг 3 
$s = ”something”;
print &factorial(1..5);
print ”$s
”;
sub factorial {
my($s)=1;	# инициализировать локальную переменную  если эту строчку закомментировать,
# то результатом будет вывод двух чисел,
# тогда как с операторомmy сначала будет
# выведена строка,а затем число
foreach $_ (@_) {
$s *= $_;
}
return ”$s
”;
}

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

В некоторых программах на Perl можно встретить функцию local. С ее помощью создаются так называемые «полулокальные» переменные. Приведем пример использования local в программе (листинг 4).

Листинг 4
$value = ”good”;
tellme();
spoof();
tellme();
sub spoof {	
local ($value) = ”bad”;
tellme();
}
sub tellme {
print ”It is $value!
”;
}

Переменная, созданная с помощью функции my, значение которой равно «bad», доступна только в пределах подпрограммы spoof(), а за ее пределами $value по-прежнему остается равной «good». Такой же она будет и в подпрограмме tellme(), вызванной из spoof(). При использовании функции local локальное значение $value = «bad» становится глобальным для всех остальных подпрограмм, запущенных из spoof(), в частности для tellme. Иначе говоря, локальные переменные доступны для функций, вызываемых из той подпрограммы, в которой они обюявлены.

Кроме того, операцию my можно использовать только для обюявления простых скалярных переменных, переменных-массивов и хэш-переменных с буквенно-цифровыми именами, тогда как для переменной, описанной с помощью local, подобные ограничения не установлены. Встроенные переменные Perl, такие как $_, @ARGV и #1, нельзя обюявлять с помощью my, а через local они работают прекрасно. Поскольку $_ используется в большинстве программ на Perl, целесообразно помещать строку

local $_;

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

Работа с базами данных

Основные принципы работы с базами данных на Perl описаны Брайаном Уилсоном (e-mail: brian.wilson@ netscapeworld.com) (см. «Мир ПК», № 11/97, с. 52). Если невозможно найти печатный вариант издания, то можно найти нужную статью на Web-сервере www. pcwold. ru.

CGI-программирование

В журнале «Мир ПК», № 8/97, с. 88 была опубликована статья А. и Г. Фроловых «Активный сервер Web: расширения CGI». Поскольку ее авторы в основном специализируются на программировании в Си/Си++, их работа также была ориентирована на разработчиков, использующих именно эти средства в сочетании с MS IIS (Microsoft Internet Information Server).

Рассмотрим ниже аналогичные возможности при программировании на Perl. Ниже будет показано, как реализовать диалог с посетителем Web-страницы или Web-узла, чтобы собирать различную информацию. Будут рассмотрены вопросы создания Perl-программ типа гостевой книги (рис. 1), списка рассылки новостей и простейшей системы идентификации посетителя.

Можно загрузить из Internet практически любые необходимые Perl-программы. Вот несколько узлов, на которых есть ПО на любой вкус: www.freescripts.com, www.scripts.ru, www.basicnet.sonnet.ru/download.

Как же работает механизм взаимодействия клиента с сервером, а конкретнее – с CGI-программой? Из приведенной на рис. 1 схемы видно, что пользователь сначала заполняет форму и подтверждает введенную им информацию нажатием соответствующей кнопки. Затем эти сведения из формы передаются на сервер.

HTML-код нашей формы гостевой книги выглядит следующим образом (листинг 5):

Листинг 5. Исходный текст HTML-формы
ГОСТЕВАЯ КНИГА

Ваше имя:
E-Mail:
Город:
Home Page URL:
Комментарии:

Из всех тегов, присутствующих здесь, непосредственно к форме относятся только

, ,