Perl для CGI / Введение |
||
Предисловие |
||
Программирование на Perl в простом компьютере (без серверного приложения) подобно написанию сценария для кинофильма. Вы можете написать прекрасный сюжет, даже шедевр, можете вложить туда всю свою душу и фантазию, но примут-ли этот сценарий на киностудии? Поймут-ли Вас, или понесете-ли вы туда его вообще? Вот так и программирование в среде CGI. Вы пишете программу в обычном текстовом редакторе без всякой поддержки со стороны транслятора и можете написать все что угодно. Вот только поймет-ли Вашу программу потом серверный Perl-интерпретатор? Не нужно боятся. Все CGI-программы этого сайта (ПерЧАТка, Барахолка, СКОБа, Почтовый робот, Каталог и другие) написаны именно на локальном компьютере, а отлаживались уже потом на сервере через простое dial-up соединение. Так что нет ничего невозможного. Если Вам что-то будет непонятно, или захочется что-то добавить, или просто возникнут вопросы, обращайтесь в соответствующий раздел форума, возможно там уже есть ответ на Ваш вопрос, а если нет, то думаю это самый быстрый способ его получить. Однако есть довольно простой способ облегчить себе жизнь. Если Вы работаете под управлением ОС Windows, то можете скачать Small HTTP Server (100Кб) для эмуляции HTTP-соединения (для этого нужно создать виртуальные хосты с привязкой к системному хосту (127.0.0.1), или вручную добавить в файл C:\Windows\system32\drivers\etc\hosts строки типа: 127.0.0.1 www.myhost.zone) и ActivePerl 5.6.1 (8645Кб). Так можно легко отлаживать Perl-программы, не выходя в интернет.
Дальнейший текст (кроме раздела MySQL, написанного С.А.Семищенко) написан автором, данные которого вы найдете ниже, с небольшими нашими дополнениями и исправлениями, под нашей редакцией. В первоисточнике он назывался: "Учебное пособие по CGI-программированию от Леши".
Пару слов от автора |
||
Что меня заставило взятся за этот нелегкий труд написания данного учебного пособия. Ну во первых то что практически НЕТ ничего по CGI-програмированию на русском языке, а большинству тех, кто хотел бы изучить CGI, документация на английском в отличии от тех немногих, типа меня, практически недоступна для понимания. Чтобы помочь им преодолеть этот, в первую очередь языковый, барьер я и сел писать эту книгу...
Еще причина, отчасти перекликающаяся с первой, это то что когда говорят об интернет-программировании обычно излагают HTML со всеми тэгами, которые всем уже по ночам в кошмарах снятся, ну а после чего начинают долго охать и ахать над прелестями нового аппаратно и платформо-независимого, переносимого, безопасного... и т.д. языка Java. Иногда еще могут тонким краешком затронуть JavaScript. Видя эту, не побоюсь этого слова, безнадежную ситуацию я, как доблестный CGI-программист, решил хоть что-то поправить к лучшему. Если у меня это хоть немного удалось, то напишите мне.
Если также у вас есть какие-то вопросы -тоже пишите, я с радостью постараюсь ответить на них.
Леша.
paaa@uic.nnov.ru
http://www.uic.nnov.ru/~paaa/cgi-bin/contact.cgi
Краткое лирическое отступление насчет CGI |
||
Итак что такое CGI-скрипты и вообще подобные вещи. Начнем с того что ваш браузер (когда вы набрали URL) соединяется по протоколу HTTP с указаным сервером и просит у него нужный файл, примерно так:
GET /~paaa/cgi-bin/guestbbok.cgi HTTP/1.0
Вот это самое главное в запросе. Ну тут дальше идет посылаемая браузером информация о себе и о том что более подробно ему надо (например Accept: */*). Ну и если запрошен простой файл например .html то если такой файл есть, сервер отошлет браузеру ответ:
HTTP/1.0 200 Okay
Content-Type: text/html
<HTML>
<BODY>
.......
</BODY></HTML>
В ответе, состоящем из заголовка и тела, в заголовке содержится код возврата и информация о типе содержимого. Далее после пустой строки (она нужна чтоб отделить заголовок от тела) идет информация из самого документа , по заданому URL <HTML><BODY>...
Вот в принципе и весь WWW. Ходишь от ссылки к ссылке...
А что если Нужно внести в этот
унылый процесс что-нибудь по
настоящему интерактивное,
динамическое, прекрасное и
великолепное? Что-ж есть ответ и на
этот вопрос. Просто если в
запрашиваемом URL указать
специальную программу (CGI,
программа Common Gateway Inteface - Общего
Шлюзового Интерфейса) и то что эта
прога выдаст то и отправиться
браузеру. Сервер запускает .cgi
программу и она например обработав
данные формы заносит вас
куда-нибудь в свою базу данных, а
вам сообщит что вы большой молодец
:)
Ну надеюсь я вас заинтриговал?
Введение |
||
Краткие сведения о том что надо знать чтоб писать CGI скрипты:
Ну во-первых надо знать что такое интернет и как он работает (а вы знаете? ;))) ). А так-же чуть-чуть умения програмировать (это самое главное).
На кого ориентировано данное учебное пособие -спросите вы? Ну в принципе на достаточно широкую аудиторию тех, кто занимается Интернет-программированием и кто хотел бы освоить премудрости интерфейса CGI. Данная книга будет весьма полезна для web-дизайнеров, системных администраторов интернет-серверов, программистов и для простых пользователей интернет, которые хотели бы сделать свой сайт по-настоящему достойным называться хорошим сайтом.
Так как интернет в основном строится на операционной системе UNIX , то изложеный здесь материал может быть без особых модификаций реализован на практически любой UNIX-системе. Кроме того, я также делаю предположение, что ваш web-сервер поддерживает интерфейс CGI и для вас эта поддержка включена. (на "халявных" серверах администраторы отключают CGI и SSI для пользовательских директорий - просто это такая политика - предоставлять только ОЧЕНЬ МИНИМАЛЬНЫЙ сервис. Правда в настоящее время появилось достаточно много бесплатных хостингов поддерживающих CGI и SSI, некоторые из них можно найти в лоцмане). Так что если вы хотите изучать CGI то вам нужет нормальный, полнофункциональный хостинг (или собственный сервер (см.начало статьи). Если же вы сами являетесь системным администратором на своем сервере, то для вас, естественно нет проблем, ведь включить CGI для какой-нибудь директории - это просто подправить одну строчку в файле конфигурации сервера.
Замечание: Если вы используете Windows NT, то материал данной книги вам будет тоже очень полезен, однако будьте готовы к тому что в некоторые скрипты придется вносить значительные изменения. В некоторых случаях, когда сказывается то, что возможности NT по работе с сетью намного хуже чем у UNIX, некоторые скрипты вовсе нельзя будет использовать.
Давайте вместе писанем какой нибудь простенький скриптик а потом я вам расскажу где здесь собака порылась... Ну сначала в своем домашнем каталоге создайте директорию cgi-bin:
cd public_html
mkdir cgi-bin
chmod 0777 cgi-bin
Последняя строчка будет очень важна. Далее возьмите текстовый редактор и наберите:
#!/usr/bin/perl
#first.cgi
print "Content-Type: text/html\n\n";
print "<HTML><BODY>";
print "<H1>Hello you!!!</H1>";
print "</BODY></HTML>";
Сохраните его в директории cgi-bin под именем first.cgi . Ну как сохранили? А теперь сделайте его исполняемым (ведь это программа):
chmod +x first.cgi
Ну вот, подходим к торжественному
моменту... наберите в строке
браузера
http://www.ваш.сервер.ru/~ваш_логин/cgi-bin/first.cgi
и посмотрите что будет. Будет одно
из двух: либо скрипт заработает и вы
увидите сгенерированую им
страничку (поздравляю, в нашем
полку прибыло!) либо Internal Server Error 500
-тогда не расстраивайтесь, вы что-то
сделали не так. Тогда Вам
пригодится пособие по ловле блох.
Ну во-первых проверку синтаксиса
можно осуществить следующим
образом:
perl -с first.cgi
Perl вам сразу выдаст либо сообщения об ошибках (ну бывает, точку с запятой пропустили, скобочки или кавычки забыли закрыть) это сразу по ходу дела поправимо. Более грубая с логической точки зрения это пропустить вывод пустой строки, которая отделяет заголовок от тела:
print "Content-Type:
text/html\n\n"; #Все Правильно
print "Content-Type: text/html\n"; #ОШИБКА!!!
Еще распространенная ошибка: в каком редакторе писали программу? В Windows Notepad или WordPad (Write)? Все правильно, только после сохранения вам надо заменить все Windows-символы перевода строки на Unix-символы. Дело в том, что в Windows перевод строки осуществляется сразу двумя символами, CrLf (коды 13 и 10 (\c\n)), а в Unix только Lf (10 (\n)). Perl будет интерпретировать до первого символа возврата каретки Cr, а дальше считывать программу не будет. Но преобразовать текст в Unix-формат очень просто, например при помощи FAR-менеджера. Открываете файл для редактирования по F4, далее нажимаете Сохранить как (Shift+F2) и указываете как Unix-текст. Ну и конечно после закачки на сервер нужно чтобы у Perl-программы были атрибуты 755. Кстати Perl-скрипты могут иметь расширение не только .cgi, но и .pl .
Разберем скрипт:
Первая строка #!/usr/bin/perl Просто
указывает где в системе расположен
компилятор Perl. Обычно он находится
/usr/bin/perl или /usr/local/bin/perl, выяснить это
можно одной из комманд which perl или
whereis perl ну или (что очень долго)
запустить полный поиск find / -name perl
-print. Вторая строка это просто
коментарий -вы можете тыкать что
угодно после знака #, однако я пишу
обычно во второй строке название
скрипта, что очень удобно. Затем
идет print "Content-Type: text/html\n\n"; Это
заголовок указывающий тип
содержимого. Все что скрипт
печатает в свой стандартный вывод
STDOUT идет на обработку к серверу.
Пустая строка отделяет заголовок
от тела, которое в нашем случае
представляет собой:
<HTML><BODY>
<H1>Hello you!!!</H1>
</BODY></HTML>
Сервер обработает ответ скрипта и на базе него сформирует и пошлет браузеру ответ. Сервер обычно не изменяет тела сообщения, он только дополняет заголовок нужными для работы протокола HTTP полями.
Ну вот азы уже освоены, все не так трудно и удручающе как могло показаться на первый взгляд. Вы теперь можете сами потренироваться в написании таких вот простеньких скриптов чтоб набить руку.
Переменные среды CGI |
||
Предыдущий скрипт не содержал ничего особенно замечательного, так просто вываливал HTMLый текст который благополучно и отбражался на экране браузера. Но настоящую мощь CGI придает возможность обработки параметров, которые переданы скрипту. Например вы можете набрать: http://www.somehost.ru/somedir/cgi-bin/my_cgi.cgi?param=value, то есть вы хотите чтоб скрипт my_cgi.cgi обработал для вас параметер param со значением value (ну это например) или когда вы заполнили запрос в форме (например yahoo или altavista). Это с точки зрения пользователя... А на сервере при запуске CGI-скрипта сервер формирует среду окружения в которой скрипт может найти всю доступную информацию о HTTP-соединении и о запросе. Вот эти переменные:
- REQUEST_METHOD - Это одно из самых главных полей используемое для определения метода запроса HTTP. Протокол HTTP использует методы GET и POST для запроса к серверу. Они отличаются тем что при методе GET запрос является как-бы частью URL т.е. http://www..../myscript.cgi?request, а при методе POST данные передаются в теле HTTP-запроса (при GET тело запроса пусто) и следовательно для CGI тоже есть различие. При GET запрос идет в переменную QUERY_STRING (на самом деле в $ENV{'QUERY_STRING'}, но пока это опустим для удобства описания), а при POST подается на STDIN скрипта. Пример: REQUEST_METHOD=GET
- QUERY_STRING - Это строка запроса при методе GET. Вам всем известно что запрос из формы кодируется браузером поскольку не все символы разрешены в URL некоторые имеют специальное назначение. Теперь о методе urlencode: неплохо бы чисто формально напомнить, что все пробелы заменяются в URL на знак '+', а все специальные и непечатные символы на последовательность %hh, где hh-шестнадцатиричный код символа, разделитель полей формы знак '&'. Так что при обработке форм надо произвести декодирование. Пример: QUERY_STRING= name=quake+doomer&age=20&hobby=games
- CONTENT_LENGTH - длина в байтах тела запроса. При методе запроса POST необходимо считать со стандартного входа STDIN CONTENT_LENGTH байт, а потом производить их обработку. Обычно методом POST пользуются для передачи форм, содержащих потенциально большие области ввода текста TEXTAREA. При этом методе нет никаких ограничений, а при методе GET существуют ограничения на длину URL . Пример: CONTENT_LENGTH=31
- CONTENT_TYPE - тип тела запроса (для форм кодированых выше указаным образом он application/x-www-form-urlencoded).
- GATEWAY_INTERFACE - версия протокола CGI. Пример: GATEWAY_INTERFACE=CGI/1.1
- REMOTE_ADDR - IP-Адрес удаленого хоста, делающего данный запрос. Пример: REMOTE_ADDR=139.142.24.157
- REMOTE_HOST - Если запрашивающий хост имеет доменное имя, то эта переменная содержит его, в противном случае -тот же самый IP-адрес что и REMOTE_ADDR. Пример: REMOTE_HOST=idsoftware.com
- SCRIPT_NAME - Имя скрипта, использованное в запросе. Для получения реального пути на сервере используйте SCRIPT_FILENAME. Пример: SCRIPT_NAME=/~paaa/guestbook.cgi
- SCRIPT_FILENAME - Имя файла скрипта на сервере. Пример: SCRIPT_FILENAME=/home/p/paaa/public_html/cgi-bin/guestbook.cgi
- SERVER_NAME - Имя сервера, чаще всего доменное как www.microsoft.com, но в редких случаях за неимением такового может быть DNS-адресом как 157.151.74.254 Пример: SERVER_NAME=www.uic.nnov.ru
- SERVER_PORT - TCP-Порт сервера используюшийся для соединения. По умолчаниию HTTP-порт 80, хотя может быть в некоторых случаях другим. Пример: SERVER_PORT=80
- SERVER_PROTOCOL - Версия протокола сервера. Пример: SERVER_PROTOCOL=HTTP/1.1
- SERVER_SOFTWARE - Програмное обеспечение сервера. Пример: Apache/1.0
- AUTH_TYPE, REMOTE_USER - Эти переменные определены в том случае, когда запрошеный ресурс требует аутентификации пользователя.
Переменные заголовка HTTP-запроса.
За исключением тех строк из заголовка HTTP-запроса которые были включены в другие переменные, сервер приделывает строкам префикс HTTP_ и заменяет знаки '-' на '_':
- HTTP_ACCEPT - Давая запрос на сервер браузер обычно расчитывает получить информацию определеного формата, и для этого он в заголовке запроса указывает поле Accept:. Отсюда скрипту поступает cписок тех MIME, которые браузер готов принять в качестве ответа от сервера. Пример: HTTP_ACCEPT=text/html,text/plain,image/gif
- HTTP_USER_AGENT - Браузер обычно посылает на сервер и информацию о себе, чтобы базируясь на знании особеностей и недостатков конкретных браузеров CGI-скрипт мог выдать информацию с учетом этого. Например, разные браузеры могут поддерживать или не поддерживать какие-то HTML-тэги. Пример: HTTP_USER_AGENT=Mozila/2.01 Gold(Win95;I)
- HTTP_HOST - Имя хоста к которому обращается браузер. Так как физически на одном сервере может находиться сразу много серверов (Виртуальные Хосты), то должен быть способ сообщить серверу к какому именно идет обращение. Скрипт же может тоже в зависимости от этой переменной производить различные действия, например если он используется на сайтах сразу нескольких виртуальных хостов. Пример: HTTP_HOST=www.nnov.city.ru
Ну,начнем применять на практике усвоеные уроки:
#!/usr/bin/perl
#vars.cgi
sub urldecode { #очень полезная функция
декодирования
local($val)=@_; #запроса,будет почти в
каждой вашей CGI-программе
$val=~s/\+/ /g;
$val=~s/%([0-9A-H]{2})/pack('C',hex($1))/ge;
return $val;
}
print "Content-Type: text/html\n\n";
print
"<HTML><HEAD><TITLE>CGI-Variables</TITLE></HEAD>\n";
print "<BODY>\n";
print "Enter here
something:<ISINDEX><BR>\n";
print "Your request
is:$ENV{'REQUEST_STRING'}<BR>\n";
print "Decoded request
is:urldecode($ENV{'REQUEST_STRING'})<BR>\n";
print "<HR>\n";
print "Variables:<BR>\n";
print
"<I><B>REQUEST_METHOD</B></I>=$ENV{'REQUEST_METHOD'}<BR>\n";
print
"<I><B>QUERY_STRING</B></I>=$ENV{'QUERY_STRING'}<BR>\n";
print
"<I><B>CONTENT_LENGTH</B></I>=$ENV{'CONTENT_LENGTH'}<BR>\n";
print
"<I><B>CONTENT_TYPE</B></I>=$ENV{'CONTENT_TYPE'}<BR>\n";
print
"<I><B>GATEWAY_INTERFACE</B></I>=$ENV{'GATEWAY_INTERFACE'}<BR>\n";
print
"<I><B>REMOTE_ADDR</B></I>=$ENV{'REMOTE_ADDR'}<BR>\n";
print
"<I><B>REMOTE_HOST</B></I>=$ENV{'REMOTE_HOST'}<BR>\n";
print
"<I><B>SCRIPT_NAME</B></I>=$ENV{'SCRIPT_NAME'}<BR>\n";
print
"<I><B>SCRIPT_FILENAME</B></I>=$ENV{'SCRIPT_FILENAME'}<BR>\n";
print
"<I><B>SERVER_NAME</B></I>=$ENV{'SERVER_NAME'}<BR>\n";
print
"<I><B>SERVER_PORT</B></I>=$ENV{'SERVER_PORT'}<BR>\n";
print
"<I><B>SERVER_PROTOCOL</B></I>=$ENV{'SERVER_PROTOCOL'}<BR>\n";
print
"<I><B>SERVER_SOFTWARE</B></I>=$ENV{'SERVER_SOFTWARE'}<BR>\n";
print
"<I><B>HTTP_ACCEPT</B></I>=$ENV{'HTTP_ACCEPT'}<BR>\n";
print
"<I><B>HTTP_USER_AGENT</B></I>=$ENV{'HTTP_USER_AGENT'}<BR>\n";
print
"<I><B>HTTP_HOST</B></I>=$ENV{'HTTP_HOST'}<BR>\n";
print "<HR>\n";
print "All enviroment:<BR>\n";
foreach $env_var (keys %ENV) {
print
"<I>$env_var=$ENV{$env_var}</I><BR>\n";
}
print "</BODY></HTML>\n";
Эта программа выдаст в ваш броузер значения всех системных переменных Perl.
Так как все ваши .cgi -файлы должны быть исполняемыми то чтоб облегчить себе жизнь заведите себе в директории cgi-bin командный файл mkcgi, содержащий:
#!/bin/sh
#mkcgi
chmod +x *.cgi
и сделайте его в свою очередь исполняемым chmod +x mkcgi -он сильно упростит вам жизнь.
Ну а теперь запускайте скрипт... Изучив информацию,выдаваемую данным скриптом вы сможете лучше ориентироваться в переменных окружения CGI.
Если до сих пор не поняли каким образом обрабатывать запросы HTTP при помощи Perl, то рассмотрим следующий пример:
#Config part
#query.pm
if ($ENV{'REQUEST_METHOD'} eq "GET") { # Если
REQUEST_METHOD=GET
$qs = $ENV{'QUERY_STRING'}; # то присваиваем
переменной $qs строку запроса QUERY_STRING
} elsif ($ENV{'REQUEST_METHOD'} eq "POST") { #
иначе если REQUEST_METHOD=POST
read(STDIN, $qs, $ENV{'CONTENT_LENGTH'}); # то
считываем в $qs значение STDIN, длиной
CONTENT_LENGTH
}
my @split = split (/&/, $qs); # в локальный (my)
массив @split считываем значения
foreach $split (@split) { # разделенные
ампресандом (&)
($query_key, $query_value) = split (/=/, $split);
$query_value =~ tr/+/ /;
$query_value =~ s/%([\dA-Fa-f][\dA-Fa-f])/ pack ("C",
hex ($1))/eg;
$query{$query_key} = $query_value;
}
sub header { # Эта процедура избавит от
написания стандартного заголовка
перед выводом в броузер
print "Content-type: text/html\n\n";
}
1; # завершаем модуль с кодом ошибки -
1 (все OK)
Напишите все это и сохраните в файле query.pm, сделав его доступным для чтения и записи (chmod 777). Это не обычная CGI-программа, а оверлейный модуль (PM-Perl Module). Он не исполняется самостоятельно, но может вызываться из CGI-скрипта строкой: require Name_module;. Такое построение программы оправдано когда в pm-модуле содержаться процедуры, необходимые в большинстве процедур, а CGI-сценарий вызывает его перед выполнением. В этом-же модуле можно указать конфигурационные переменные (типа вашего e-mail, путь к данным, опции и т.п.). Только-что написанный нами модуль удобно использовать во всех своих программах, ведь любой запрос декодируется и распределяется, при помощи него, в хэш-массив %query, откуда любое поле запроса можно считать из переменных типа: $query{'Name_value_request'}. В Windows файлы .pm должны иметь то же имя, что и .cgi-программы, их вызывающие. Рассмотрим это на следующем примере:
#!/usr/bin/perl
#print_request.cgi
require query; # Запрос модуля query.pm
&header; # вызов процедуры header из query.pm
для печати стандартного заголовка
print << "[END]"; # Выводить на
консоль все, до метки [END]
<HTML><BODY>
<P>
[END]
print "Имя: $query{'name'}<BR>"; #
Распечатать значение поля name из
запроса
print "Фамилия: $query{'fam'}";
print << "[END]";
</P>
</BODY></HTML>
[END]
Все. Сохраните это как print_request.cgi, в своей cgi-bin директории, сделайте его исполняемым и напишите в своем броузере в качестве URL-адреса: http://your_host/cgi-bin/print_request.cgi?name=Борис&fam=Ельцин. Поняли как все работает? Только что вы сделали GET-запрос к своему скрипту, который может передаваться с помощью тега <a> из html-документа. А теперь сделайте подобный запрос типа POST. Для этого создайте html-документ:
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1251">
</head>
<body>
<form
action="http://your_host/cgi-bin/print_request.cgi"
method="POST">
<p>Имя: <input type="text"
size="20" name="name"><br>
Фамилия: <input type="text"
size="20" name="fam"></p>
<p><input type="submit" name="B1"
value="Передать"></p>
</form>
</body>
</html>
После нажатия кнопки "Передать" ответ броузеру будет точно таким-же как и ответ при запросе GET (если в поле "Имя" введете "Борис", а в поле "Фамилия"-"Ельцин"), но способ передачи, как видите, разный. Впоследствии вы можете вернуться к этим примерам, но об обработке форм, и собственно об Perl будет рассказано в следующих разделах.