Веб-программирование. AJAX на Perl - это так просто!

Должен сказать, что у меня какая-то аллергия к PHP. Ну не люблю я этот язык. Многое в нём не кажется корявым, нелогичным, трудным для понимания. Что касается работы с базами данных, то до не столь давнего времени бедные программисты на PHP не имели универсального средства работы с ними: для каждой СУБД использовался свой собственный набор функций, начиная от подключения, заканчивая выполнением запросов, в том время как в Perl изначально использовался и используется стандартный и одинаковый для всех СУБД механизм DBI. Тем не менее, в среде веб-программистов у многих сложилось впечатление, что Perl - не для веб-програмирования, хотя Perl изначально предлагал намного более богатый список модулей-расширений, работающий с самыми разными библиотеками, и то, что не так давно появилось в PHP, было в Perl уже годы назад. Perl даже можно использовать в более тесной интеграции с веб-сервером apache как модуль mod_perl, точно также как это делается для PHP через модуль apache mod_php. Данная статья, даёт краткий обзор того, как можно использовать один из таких модулей-расширений, для лёгкого и быстрого написания Perl-скриптов для работы в веб с использованием техлогии AJAX.

В данной статье, мы рассмотрим работу модуля CGI::Ajax, который работает совместно с модулем CGI и для работы которого необходим модуль Class::Accessor. Все три модуля поставляются в составе всех популярных дистрибутивов. Например, для установки в Fedora/RHEL/CentOS или Oracle Linux достаточно выполнить команду:

yum install perl-CGI perl-CGI-Ajax perl-Class-Accessor

и менеджер пакетов установит всё что нужно для дальнейшей работы. Ещё одно замечение касается режима работы Perl при написании скриптов. В наших примерах мы будем использовать режим CGI, а не mod_perl, хотя думаю, что желающим не составит труда адаптировать всё для mod_perl, если у них вдруг появится такое желание. Пока же нам важно, чтобы ваш веб-сервер был корректно настроен для выполнения CGI скриптов. Для того, чтобы скрипты на языке Perl с расширением .pl принимались веб-сервером как CGI необходимо добавить следующую строку в настройки веб-сервера (либо в основной файл конфигурации, либо в файл с описанием виртуального хоста, либо даже в .htaccess если поддержка .htaccess включена):

AddHandler cgi-script .pl

Первый и простой скрипт из документации

Создайте файл test.pl следующего содержимого:

use strict;
use CGI;      # or any other CGI:: form handler/decoder
use CGI::Ajax;

my $cgi = new CGI;
my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );
print $pjx->build_html( $cgi, \&Show_HTML);

sub perl_func {
  my $input = shift;
  # do something with $input
  my $output = $input . " was the input!";
  return( $output );
}

sub Show_HTML {
  my $html = <<EOHTML;
           <HTML>
           <BODY>
             Enter something:
               <input type="text" name="val1" id="val1"
                onkeyup="exported_func( ['val1'], ['resultdiv'] );">
             <br>
             <div id="resultdiv"></div>
           </BODY>
           </HTML>
EOHTML
return $html;
}

Поместите скрипт в корневой каталог вашего сайта и откройте его в браузере. Например, если ваш сайт имеет имя mydomain.com, то наберите в браузере http://mydomain.com/test.pl. Вы должны увидеть на странице поле ввода. Если вы начнёте набирать в нём что-либо, вы увидите, что это же самое появляется на странице ниже. При этом, сама страница не перезагружается. Теперь о том, как это работает.

Наверное, вы уже пытались искать информацию об AJAX в Интернет. Количество кода, который нужно написать, чтобы всё заработало довольно велико. Кроме того, он труден для понимания и собственно к логике работы приложения не имеет никакого отношения. К счастью, всю выдачу служебного кода AJAX модуль CGI::Ajax берёт на себя. Мы можем не задумываться над тем как это устроено внутри, а заниматься лишь непосредственно логикой самого приложения. Итак:

use strict;
use CGI;      # or any other CGI:: form handler/decoder
use CGI::Ajax;

Первая строка устанавливает "строгий" или "ограниченный" режим функционирования скрипта на Perl. В этом режиме должно чётко соблюдаться объявление локальных и глобальных переменных, а также существуют и другие ограничения (отсылаю к руководству). В принципе, мы могли бы и не использовать такой режим, но часто его использование позволяет избежать путаницы, когда переменная с одним и тем же именем начинает использоваться глобально и в какой-либо функции, а вы потом недоумеваете, почему вдруг программа работает совершенно не так как ожидалось. Вторая и третья строки подключают модули для работы CGI и CGI::Ajax. Модуль CGI берёт на себя всю работу по инцициализации веб-окружения и переданных веб-серверу параметров, позволяя также выдавать и редактировать служебные и http-заголовки, куки и параметры POST и GET запросов. Модуль CGI::Ajax ещё и добавляет при этом возможность работы с AJAX

my $cgi = new CGI;
my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );
print $pjx->build_html( $cgi, \&Show_HTML);

Здесь в первых 2-х строках мы создаём экземляры переменных классов CGI и CGI::Ajax. В момент создания происходит их инициализации и задание неких начальных параметров. Для CGI::Ajax мы видим, что создаётся привязка JavaScript функции exported_func (о чём ниже) к функции Perl'а perl_func. И наконец, в 3-й строке происходит вызов метода класса CGI::Ajax с именем build_html, который предназначен для вывода HTML содержимого веб-странички. В качестве параметров передаются переменная класса CGI и ссылка на имя функции, которая собственно и отрисовывает веб-страницу.

sub perl_func {
  my $input = shift;
  # do something with $input
  my $output = $input . " was the input!";
  return( $output );
}

Это собственно та самая функция на языке Perl, которая будет вызвана при вводе какого-либо значения в поле ввода. Что интересно - эта функция будет вызвана как ОТДЕЛЬНЫЙ CGI-скрипт, в чём вы можете убедиться, просмотрев логи веб-сервера. Т.е. вы можете считать данную функцию совершенно независмым скриптом внутри основного скрипта. Это важный момент для понимания всей работы CGI::Ajax. Сама же функция в данном случае всё что делает - это принимает аргумент и добавляет к нему строку "was the input!", после чего возвращает полученную в итоге строку

sub Show_HTML {
  my $html = <<EOHTML;
           <HTML>
           <BODY>
             Enter something:
               <input type="text" name="val1" id="val1"
                onkeyup="exported_func( ['val1'], ['resultdiv'] );">
             <br>
             <div id="resultdiv"></div>
           </BODY>
           </HTML>
EOHTML
return $html;
}

Как я и писал выше, это функция, которая отрисовывает содержимое веб-странички. Как вы можете увидеть, функция выводит всего два видимых элемента: поле ввода с именем val1 и что более важно с таким же id, а также область (div), с id="resultdiv", в которой и будут отображаться результаты ввода и работы функции perl_func.

Но самая важная для понимания работы CGI::Ajax - это строка:

onkeyup="exported_func( ['val1'], ['resultdiv'] );">

В этой строке, для поля ввода val1 назначается обработчик события, возникающего при отпускании нажатой клавиши на клавиатуре - onkeyup. Такое назначение является работой языка JavaScript, поддержка которого встроена во все современные браузеры, ведь сам HTML - это только язык разметки текста, не более. Благодаря использованию CGI::Ajax вам даже на надо ничего знать про JavaScript - весь необходимый код будет создан автоматически, упоминание об этом даётся только для понимания сути того, что происходит. Далее, функции передаются два аргумента в квадратных скобках и одинарных кавычках (одинарных, потому что таково требование JavaScript). Первый аргумент - это id того элемента, событие которого будет обрабатывать функция, а второй - id элемента, в который будет помещён полученный в результате работы результат. Поскольку ранее мы говорили о привязке функции exported_func к perl_func, то соответственно происходит слеюущее: например мы вводим в поле ввода с клавиатуры цифру 1. Когда мы отпускаем кнопку с цифрой 1, случается событие onkeyup, которое подхватывается JavaScript, который далее передаёт управление функции exported_func. Данная функция, код которой автоматически генерируется CGI::Ajax, в свою очередь выполняет AJAX запрос, в результате которого выполняется функция perl_func (рассмотренная ранее) и возвращённый ей результат, функция exported_func размещает в div с id resultdiv.

Теперь, когда мы это всё рассмотрели, становится понятным, что многое всё-таки осталось "за кадром", но это-то и хорошо! Пусть болит голова у программистов на PHP, а мы пойдём другим путём! Осталось упомянуть несколько мелочей.

CGI::Ajax имеет своё мнение о выводимых заголовках, касаемо кодировки. Если вы выдали такие заголовки ранее, то не забудьте отключить их у CGI::Ajax, добавив после строки:

my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );
строку
$pjx->skip_header(1);

Если вам необходимо обрабатывать ввод в нескольких элементах ввода, вы можете видоизменить функцию exported_func, добавив аргументы:

onkeyup="exported_func(['val1','val2'], ['resultdiv1','resultdiv2']);"

А если вам необходимы разные функции-обработчики, добавляйте их при создании экземпляра класса CGI::Ajax:

my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func,
                         'exported_func2' => \&perl_func2);

Разумеется, что вы можете использовать AJAX не только для событий onkeyup. Разные элементы HTML могут генерировать разные события, полный перечень которых можно найти в руководстве по JavaScript.

Вот собственно и всё, что хотел сказать. Подробности вы можете найти на страницах man по CGI::Ajax. С вами был Виктор Вислобоков