Для журнала "Мой компьютер". В журнале публиковалось под названием "Perl'ы для веб-мастера".

Евгений Гривастов

CGI на Perl для вебмастера: практический курс

Вступление

Вы можете быть профессиональным вебмастером. Можете просто создавать и поддерживать свою домашнюю страницу. В определенный момент вы почувствуете, что возможностей html не хватает. Сайту нужна интерактивность, взаимодействие с посетителем. И тут вам на помощь прийдет Perl. Простой, и в то же время полнофункциональный, язык программирования. С помощью Perl можно создавать от простых CGI скриптов, до сложных программ, обрабатывающих данные и взаимодействующих с базами данных. С чего же начать? Вот об этом и рассказывает данная статья. Как решить основные задачи, стоящие перед вебмастером. Без необходимости многомесячного изучения языков программирования. В этой статье мы опустим длительное обучение теории и сразу перейдем к практике. Учиться будем в процессе создания скриптов, которые вы сможете с пользой использовать на своем сайте.

Глава 1. Основы.

Чтобы вы хоть немного могли понимать, о чем идет речь, некоторые начальные сведения "что есть что в Perl".

Имена скалярных переменных всегда начинаются со знака "$". Например: $ind. Скалярная переменная - это переменная, содержащая только одно значение. В отличие от массива, в котором содержится множество значений. Имя массива всегда начинается со знака "@". Например: @ind.

Комментарии начинаются со знака "#". Все, что идет в строке после этого знака, компилятор не замечает. Это справедливо для всех строк файла скрипта, кроме первой. Первая строка всегда содержит информацию, похожую на эту:

#!/usr/bin/perl

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

Заливать скрипты на сервер следует только в режиме txt, иначе они работать не будут. После заливки скрипту следует сделать права доступа 755 - это пометит скрипт как исполняемый файл.

Глава 2. Что необходимо знать о сервере

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

Прежде всего - это путь на Perl. Обычно он выглядит примерно так:
/usr/bin/perl
или так:
/usr/local/bin/perl

Еще необходимо знать полный путь на cgi-bin директорию вашего сервера и полный путь на директорию с файлами. Это не путь начинающийся с http. Это полный путь от корневой директории компьютера, на котором находится ваш сайт.

Чтобы иметь возможность отправлять из скрипта письма, понадобиться путь на sendmail. Обычно он выглядит примерно так:
/usr/sbin/sendmail

Глава 3. Инструменты.

Можно конечно писать Perl скрипты и в обычном Блокноте, входящим в состав Windows. Вы можете так и делать. (Более того - так удобно делать, когда надо просто что-то изменить в скрипте, подправить, и естьуверенность, что в результате этой правки не появится никаких ошибок.) Но все таки рекомендую потратить немного времени и места на винчестере, чтобы скачать из интернет и установить некоторые инструменты, которые помогут упростить программирование и отладку скриптов. Это во много раз упростит вам жизнь.

Прежде всего прийдется установить Perl для Windows.
Взять его можно по адресу http://www.activestate.com/ActivePerl/download.htm
либо выбрать другие варианты с сервера http://www.perl.com/

Для собственно программирования и отладки - самый удобный инструмент - это Perl Builder.
Взять последнюю версию можно здесь: http://www.solutionsoft.com/
Кроме возможности отладки и пошаговой отладки с возможностью просмотра на каждом шаге значений переменных, имеется автоматическая генерация стандартных скриптов.

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

Часть 1. Делаем счетчик посещений

Есть множество рейтингов, предоставляющих счетчики посешений, собирающих статистику. Взамен они требуют установить у вас на сайте свою кнопку. Но что делать, если вы не гонитесь за высоким положением в рейтинге? И не желаете вставлять в свою страницу кнопку рейтинга. Вам просто нужно считать посетителей и собирать некоторую статистику. Или почему бы не проконтролировать правильность информации, собранной чужим счетчиком. А может вы хотите создать собственный рейтинг. Ок, давайте сделаем сначала простейший счетчик, в последующем превратив его в систему сбора статистики и удобного просмотра собранной информации. Заодно и научим генерировать картинку счетчика.

Глава 4. Сделаем собственно простейший счетчик

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

Создайте два файла, назовите их например: count.cgi и count.txt. Второй из них пусть будет пустым. Первый - откройте в блокноте или в Perl Builder и введите следующий текст:

#!/usr/bin/perl

$namefile="count.txt";

open (COUNTFILE, "$namefile");
$count = <COUNTFILE>;
close(COUNTFILE);

chomp ($count);
$count=$count+1;

open (COUNTFILE, ">$namefile");
print COUNTFILE "$count";
close(COUNTFILE);

print "Content-Type: text/html\n\n";
print "$count";

exit;

Если вы набирали в Perl Builder, то вбрав в меню "Run/Debug -> Check Syntax With -w Flag", сможете сразу проверить скрипт на наличие ошибок. Если ошибки присутствуют - то Perl Builder выдаст соответствующие сообщения с номером строки, в которой содержится ошибка.

В первой строке скрипта вместо /usr/bin/perl укажите путь к Perl на сервере, на котором будет запускаться скрипт. Возможно он будет такой же, как написал я. Тогда ничего изменять не прийдется.

Поместите оба файла в cgi-bin директорию своего сервера. Не забудьте, что делать это надо в режиме txt! После этого назначьте права доступа для count.cgi - 755, а для count.txt - 666. Осталось вставить вызов скрипта в html страницу. Сделаем это с помощью строки:

<!--#exec cgi="/cgi-bin/count.cgi"-->

где /cgi-bin/count.cgi - это путь на скрипт от корня вашего сайта. Т.е. если полный путь на скрипт выглядит как http://your-domen.com/cgi-bin/count.cgi, то в вызове скрипта пишем /cgi-bin/count.cgi

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

То, что первая строка скрипта указывает, где искать собственно Perl - вы уже знаете.

Строка:

$namefile="count.txt";

помещаем в переменную $namefile имя файла count.txt

open (COUNTFILE, "$namefile");

открывает файл count.txt для чтения, связывая название файла с дескриптором COUNTFILE

$count = <COUNTFILE>;

считывает из файла последнее значение счетчика. Так как в первый раз считывать нечего, то в переменной $count появится значение 0

close(COUNTFILE);

закрывает файл

chomp ($count);

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

$count=1+$count;

увеличиваем значение счетчика на единицу

open (COUNTFILE, ">$namefile");

откроем файл count.cgi для записи, уничтожив его содержимое

print COUNTFILE "$count";

запишем в файл новое значение счетчика

close(COUNTFILE);

закроем файл

print "Content-Type: text/html\n\n";
print "$count";

отдадим новое значение счетчика в качестве результата работы скрипта, чтобы сервер включил это значение в состав html страницы

exit;

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

Глава 5. Небольшие усовершенствования нашего счетчика

Итак, мы научились считать заходы на нашу страницу. Однако не годится, что файл со значением счетчика лежит в директории cgi-bin. Давайте создадим на сайте отдельную директорию, назовем ее например mystat, куда и положим файл count.txt. Не забудьте назначить файлу права доступа 666. Возможно понадобится так же назначить права доступа и вновь созданной директории. Хотя обычно сервер сам заботиться об этом, но на всякий случай назначте директории mystat права доступа 666.

Теперь надо в нашем скрипте счетчика указать новый путь на файл count.txt. Помните строку

$namefile="count.txt";

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

Дабавим к названию файла полный путь к директории с файлами сервера (см. главу 2) и название директории, в которой этот файл у нас лежит. Например, если полный путь выглядит так:

/home2/your_domen/public_html/

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

$namefile="/home2/your_domen/public_html/mystat/count.txt";

Что будет, если зайти броузером на страницу со счетчиком и нажать "обновить"? Правильно - значение счетчика увеличится на единицу. Причем каждая новая загрузка страницы в броузер будет вызывать увеличение значения счетчика. Давайте научим наш счетчик отслеживать заходы подряд с одного IP адреса и не засчитывать такие заходы. Для этого создадим файл с названием, например, ip.txt и положим его в ту же директорию mystat на сервере. Назначим ему права доступа 666. В этом файле мы будем хранить IP адрес последнего посетителя, посчитанного счетчиком. Теперь осталось добавить соответствующую проверку в скрипт.

Прежде всего добавим переменную, в которой будет путь на файл

$nameipfile="/home2/your_domen/public_html/mystat/ip.txt";

Теперь нам надо получить собственно IP адрес посетителя. Содержится он в переменной $ENV{"REMOTE_ADDR"}, значение которой передается скрипту вместе запросом. Присвоим это значение переменной $ip:

$ip=$ENV{"REMOTE_ADDR"};

Теперь считаем из файла ip.txt значение последнего IP адреса, сравним его с полученным. Если они совпадают - то не засчитаем заход (завершив работу скрипта), если же не совпадают - увеличим значение счетчика и запишем новое значение IP адреса в файл ip.txt:

open (IPFILE, "$nameipfile");
$ipold = <IPFILE>;
close(IPFILE);

chomp ($ipold);

if ($ipold eq $ip) {
exit;
}

open (IPFILE, "$nameipfile");
print IPFILE "$ip";
close(IPFILE);

Теперь точность показаний счетчика стала немного выше. Но как он поведет себя, если на нашу страницу зайдет одновременно два посетителя. Одновременно две копии счетчика считают значение из файла, увеличат его и запишут обратно. В итоге получится значение меньшее, чем реальное количество заходов. Чтобы этого не допустить, необходимо разрешать доступ к файлу одновременно только одной копии скрипта. Сделать это можно с помощью функции flock. Функция flock позволяет заблокировать файл, связанный с дескриптором, от доступа из других скриптов. Немного изменим процесс работы с файлом count.txt:

open (COUNTFILE, "+<$namefile");
flock (COUNTFILE,2);
$count =readline(*COUNTFILE);
chomp ($count);
$count=1+$count;
seek (COUNTFILE,0,0);
truncate(COUNTFILE,0);
print COUNTFILE "$count";
close(COUNTFILE);

Теперь необходимые пояснения наших действий:

открываем файл для чтения и записи:

open (COUNTFILE, "+<$namefile");

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

flock (COUNTFILE,2);

считываем значение счетчика из файла

$count =readline(*COUNTFILE);

удаляем символ конца строки (если он случайно неизвестно откуда появился)

chomp ($count);

увеличиваем значение счетчика

$count=1+$count;

перемещаем указатель позиции в файле на его начало

seek (COUNTFILE,0,0);

усекаем длинну файла до текущей позиции (т.е. до начала файла - предыдущей строкой мы передвинули этот указатель на начало файла)

truncate(COUNTFILE,0);

записываем в файл новое значение счетчика

print COUNTFILE "$count";

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

close(COUNTFILE);

Итого, весь скрипт теперь будет иметь следующий вид:

#!/usr/bin/perl

$namefile="/home2/your_domen/public_html/mystat/count.txt";
$nameipfile="/home2/your_domen/public_html/mystat/ip.txt";
$ip=$ENV{"REMOTE_ADDR"};

open (IPFILE, "$nameipfile");
$ipold = <IPFILE>;
close(IPFILE);
chomp ($ipold);

if ($ipold eq $ip) {
exit;
}

open (IPFILE, "$nameipfile");
print IPFILE "$ip";
close(IPFILE);

open (COUNTFILE, "+<$namefile");
flock (COUNTFILE,2);
$count =readline(*COUNTFILE);
chomp ($count);
$count=1+$count;
seek (COUNTFILE,0,0);
truncate(COUNTFILE,0);
print COUNTFILE "$count";
close(COUNTFILE);

print "Content-Type: text/html\n\n";
print "$count";

exit;

(…продолжение следует…)