Сайт Попова Вадима Сергеевича
:::Рекомендую:::
стань партнером
::: Учебное пособие по CGI-программированию от Леши :::

Пару слов от автора
Краткое лирическое отступление насчет CGI
Итак ...приступим...
Переменные среды CGI
Прекрасный язык Perl
Заголовки запросов и ответов
Права Доступа
Генерация ответа
Обработка Форм
Изображения ismap
Анимация
Несколько советов по отладке
Trics and traps

Примеры приложений:

Кто посещает мою страничку?
Гостевая книга
Сщетчик посещений

Вместо заключения

Пару слов от автора

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

  Еще причина ,отчасти перекликающаяся с первой, это то что когда говорят об интернет-программировании обычно излагают HTML со всеми тэгами, которые всем уже по ночам в кошмарах снятся ,ну а после чего начинают долго охать и ахать над прелестями нового аппаратно и платформо-независимого, переносимого, безопасного.....и.т.д. языка Java.Иногда в еще и могут тонким краешком затронуть JavaScript.Видя эту не побоюсь этого слова безнадежную ситуацию, я как доблестный CGI-программист решил хоть что-то поправить к лучшему. Если у меня это хоть немного удалось, то напишите мне. Если также у вас есть какие-то вопросы - тоже пишите, я с радостью постараюсь ответить на них всех.

Леша: paaa@uic.nnov.ru

Краткое лирическое отступление насчет 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 то вам нужет нормальный ,полнофункциональный сервер. Если же вы сами являетесь системным администратором на своем сервере , то для вас, естественно нет проблем, ведь включить 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 - тогда не расстраивайтесь,вы что-то сделали не так.
Вам тогда пригодится пособие по ловле блох.

  Ну вопервых проверку синтаксиса можно осуществить следующим образом:

perl -с first.cgi

  Perl вам сразу выдаст либо сообщения об ошибках(ну бывает,точку с запятой пропустили, скобочки или кавычки забыли закрыть...) это сразу по ходу дела поправимо. Более грубая с логической точки зрения это пропустить вывод пустой строки, которая отделяет заголовок от тела:

print "Content-Type: text/html\n\n"; #Все Правильно
print "Content-Type: text/html\n";   #ОШИБКА!!!
Разберем скрипт:

  Первая строка #!/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 а при 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, но в редких случаях за неимением такового может быть IP-адресом как 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";

  Так как все ваши .cgi -файлы должны быть исполняемыми то чтоб облегчить себе жизнь заведите себе в директории cgi-bin командный файл mkcgi ,содержащий

#!/bin/sh
#mkcgi
chmod +x *.cgi
и сделайте его в свою очередь исполняемым chmod +x mkcgi -он сильно упростит вам жизнь.

  Ну а теперь запускайте скрипт......

  Изучив информацию,выдаваемую данным скриптом вы сможете лучше ориентироваться в переменных окружения CGI.

Прекрасный язык Perl

  Вы наверное обратили свое внимание что CGI скрипты пишутся обычно на языке Perl (Practical Extraction and Report Language)- очень удобном языке,впитавшем из других все лучшие черты.Может у вас возникнуть сомнение :Ну вот!Изучать новый язык программирования!? Спешу вас успокоить,изучение Perl не будет в тягость (я сужу по своему опыту!). Вы даже сами не заметите как выучите его.Если вы хоть когда-нибудь программировали скажем на C и использовали утилиту grep для поиска регулярных выражений в тексте,то вам будет еще легче. Для Perl родной платформой является Unix поэтому пользователям PC он мало известен. Мое целенаправленое доведение Perl до широкой публики началось с того что я скачал Perl под Windows (фирмы ActiveWare) К нему прилагается отличная гипертекстовая HTML-документация, даже быстрого просмотра которой хватит , чтобы начать хорошо и широко использовать его. Хоть он значительно уступает и по скорости и по эффективности своему Unix'ному аналогу, все равно самый лучший способ изучить язык это программировать на нем. Если вы как я дома используете большую часть времени не Windows а Unix то с изучением Perl у вас вообще не должно быть особых сложностей. Я же от себя могу сказать, что даже после небольшого опыта изучения его, он стал моим любимым языком программирования....

  Все в нем сделано для удобства программиста (в отличии например от Java)

  Начнем с переменных,они в Perl бывают 3х типов скаларные,списковые(массивы) и хэши(ассоциативные массивы). Для указания компилятору(да и для немалого удобства программиста) перед именем скалярной переменной стоит знак '$' перед массивом '@', перед хешем '%'.

например $scalar_var, @array_var, %hash_var

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

  Например: "123"+"4" будет 127 (или "127") так как операция '+' действует над числами, а вот если применить операцию конкатенации строк '.' то строковое "test" . 1 будет "test1"

  Ну а вот операции над скалярными переменными:

ОперацыиОписаниеПример
+ - * / %Арифметическиеprint 2*7+4/(8%3);
print int(127/15); #целая часть
**Возведение в степеньprint 2**16;
++ --Инкремент-декремент$i++;
& | ^ ~ << >>Побитовые$x=3;$y=4;
print $x|$y;
print $x&$y;
== != < > <= >= <=>Числовые операции сравненияif($x==9){print "Ok!";}
eq ne lt gt le ge cmpстрковые операции сравненияif($game eq 'doom'){print "You are doomer!\n";}
|| && !Логическиеif(($x==9)||($game eq 'doom')){print "hello you!\n";}
?:Условный оператор$x=($game eq 'quake'?9:8);
,Последовательное вычисление$x=10,$y=20;
.Конкатенация$x='http://'.'www.uic.nnov.ru';
xПовторение$x='1234'x5; #$x='12341234123412341234'
=~Сопоставление с образцомif($url=~/http/){print "HTTP";}
!~То же но с отрицаниемif($url!~/http/){print "No HTTP";}
= += -= *= /= %= **= |= &= ^= ~= <<= >>= .= x=Присваивание$x+=$y;

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

© Попов В.С. 2001, Мариуполь, Украина
800 x 600 IE5 best view.