Как работает CGI программа
CGI программа всегда размещается на диске сервера до ее выполнения. Web - сервер требует размещения CGI - приложения в директорию cgi-bin, однако системный администратор может выделить вам и другой каталог. Простейший способ вызова CGI программы состоит в указании броузеру URL этой программы. Например, если вы хотите выполнить программу test.pl на локальном web - сервере, вы должны ввести URL: http://localhost/cgi-bin/test.pl. Здесь cgi-bin представляет относительный адрес, к которому может добавляться остальной путь, напрмер: /usr/local/etc/httpd/cgi-bin/test.pl или /website/cgi-shl/test.pl.
Есть и другой способ вызова CGI программы. Вы можете поставить гиперссылку, например на кнопку формы
<A HREF="cgi-bin/test.pl">Click here to run a CGI program</A>
Информацию для CGI программы можно передать, добавляя ее к стандартному URL. Например <A HREF="cgi-bin/search.pl/root/document"> Search the Document Directory</A>
Информация о пути доступна через переменную окружения PATH_INFO.
Для поиска может быть использован знак вопроса
<A HREF="cgi-bin/search.pl?Wine+1993">Search for 1993 Wines</A>
Информация после знака вопроса доступна через переменную окружения QUERY_STRING.
Приведем пример простейшей CGI программы:
#!/usr/local/bin/perl -w
use strict;
print "Content-type: text/plain\n\n";
print "Hello, World.\n";
Файл test.pl с этой программой помещается в каталог cgi-bin web сервера. Затем задается URL вида: http://localhost/cgi-bin/test.pl
Результат: Hello, World.
При выполнении CGI программы автоматически открываются стандартные файлы STDIN - ввода информации из HTML формы, STDOUT - вывода в окно броузера, STDERR - вывода сообщений в log - файл сервера.
Первая строка вывода для CGI программы должна содержать заголовок HTTP, который сообщает броузеру клиента какой тип сообщения будет послан на STDOUT: print("Content Type: text/html\n\n");
Могут быть другие заголовки, например Location определяет какую из страниц открыть: print("Location: $nextPage\n\n");
CGI и переменные окружения
Переменные окружения доступны CGI программе через переменную %ENV. Могут использоваться следующие переменные окружения:
CONTENT_LENGTH - содержит длину записи, передаваемой скрипту через STDIN файл. Используется в методе POST.
CONTENT_TYPE - содержит тип данных, доступных через STDIN.
HTTP_ACCEPT - содержит лист MIME типов программ броузера
HTTP_USER_AGENT - тип броузера пользователя
HTTP_FROM - содержит email адрес пользователя.
PATH_TRANSTLATED - путь к скрипту
REMOTE_ADDR - числовой адрес пользователя
REMOTE_HOST - имя домена сайта из которого коннектится пользователь.
REMOTE_USER - имя пользователя.
REQUEST_METHOD - содержит метод "GET" или "POST"
SCRIPT_NAME - путь к скрипту.
SERVER_NAME имя хоста сервера.
SERVER_PORT -содержит прослушиваемый порт, стандартно 80.
SERVER_PROTOCOL имя протокола сервера.
Кодирование URL
Данные, поступившие из формы, имеют следующий вид:
<Имя1>=<Значение1>&<Имя2>=<Значение2>&<Имя3>=<Значение3>
ИмяX — имя элемента формы, определенное атрибутом NAME, а ЗначениеX — информация, введенная в соответствующее поле. Если в форме присутствует несколько элементов управления (поля ввода, ниспадающие списки, обычные списки, флажки, элементы выбора, кнопки), то пары <Имя>=<Значение> разделяются символом &.
Поскольку при использовании метода GET данные формы передаются как часть адреса URL, они не могут включать пробелы и другие специальные символы, применение которых в URL не допускается, а также символы, имеющие в URL другое назначение, например символ «косая черта» (/), причем последнее ограничение накладывается и при использовании метода POST. Web-браузер производит кодирование информации, представленной пользователем. Например, все символы пробелов заменяются на «+». Вместо управляющих символов ставится их шестнадцатеричный (HEX) эквивалент, вводимый после символа %. Например строка Ivan Ivankov [email protected] кодируется: Ivan+Ivankov+%[email protected] %3E. Символ < это %3C, символ > это %3E. CGI скрипт должен раскодировать информацию.
Работа с формами
Тег <INPUT> использует кнопку submit, чтобы переслать данные из формы в CGI программу. Например:
<INPUT TYPE=submit VALUE="Process Information">
Есть два способа передачи информации из формы:
<FORM METHOD =GET> и <FORM METHOD =POST>. Например: <FORM METHOD=get ACTION=/cgi-bin/gestbook.pl>
Метод GET добавляет данные из формы в конец URL, используемого в ACTION, разделяя их знаком вопроса. Эта информация помещается в переменную окружения QUERY_STRING и используется в CGI скриптом. Метод POST используется для больших форм и посылает скрипту информацию из формы, используя файл STDIN. Размер данных которые надо прочитать, определяется с помощью переменной CONTENT_LENGTH. По умолчанию используется метод пересылки данных METHOD=”GET”. Способ передачи данных помещается в переменную REQUEST_METHOD. Рассмотрим пример:
sub getFormData {
my($buffer) = "";
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
$buffer = $ENV{'QUERY_STRING'};#чтение из буфера в методе GET
}
else {#чтение из файла в методе POST
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}
}
В обоих случаях информация содержится в переменной $buffer .
Даннае из формы передаются в формате name=value, каждое поле разделяется амперсандом (&). Например
name=Ivan+Ivankov&age=34
Сначала разделим поля, используя & как разделитель:
name=Ivan+Ivankov
age=34
Затем разделим поля с помощью =:
Field Name: name Field Value: Ivan+Ivankov
Field Name: age Field Value: 34
В следующем примере объявим переменные, соответствующие полям формы, проинициализируем буфер, определим функцию getFormData(). Затем разделим строку с помощью функции split() и определим функцию декодирования decodeURL().
my(%frmFlds);
getFormData(\%frmFlds);
sub getFormData {
my($hashRef) = shift;
my($buffer) = "";
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
$buffer = $ENV{'QUERY_STRING'};
}
else {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}
foreach (split(/&/, $buffer)) {
my($key, $value) = split(/=/, $_);
$key = decodeURL($key);
$value = decodeURL($value);
%{$hashRef}->{$key} = $value;
}
}
sub decodeURL {
$_ = shift;
tr/+/ /;
s/%(..)/pack('c', hex($1))/eg;
return($_);
}
HTML-код нашей формы гостевой книги выглядит следующим образом:
<!-- Исходный текст HTML-формы-->
<FORM METHOD=”POST” ACTION=”/cgi-bin/guestbook.cgi”>
<BLOCKQUOTE>
<TABLE BORDER=”0” CELLPADDING=”0” CELLSPACING=”0”>
<TR> <TD COLSPAN=”2”>ГОСТЕВАЯ КНИГА<BR> <BR>
</TD> </TR>
<TR> <TD>Ваше имя: </TD>
<TD><INPUT TYPE=”text” NAME=”signer” SIZE=”40”></TD>
</TR>
<TR> <TD>E-Mail: </TD>
<TD><INPUT TYPE=”text” NAME=”email” SIZE=”40”></TD>
</TR>
<TR> <TD>Город: </TD>
<TD><INPUT TYPE=”text” NAME=”city” SIZE=”20”></TD>
</TR>
<TR> <TD>Home Page URL: </TD>
<TD> <INPUT TYPE=”text” NAME=”url” SIZE=”40” VALUE=”http://”>
</TD> </TR>
<TR>
<TD COLSPAN=”2”>Комментарии:<BR>
<TEXTAREA NAME=”comments” COLS=”40” ROWS=”4”>
</TEXTAREA><BR>
<INPUT TYPE=”submit” VALUE=”PostIt!”></TD>
</TR> </TABLE>
</BLOCKQUOTE>
</FORM>
Пользователь заполняет форму и подтверждает введенную им информацию нажатием кнопки submit. Затем сведения из формы передаются на сервер. К тегу <FORM> необходимо добавить два параметра: METHOD, обеспечивающий посылку данных, и ACTION, в котором хранится URL к CGI-программе. Метод POST более эффективен и надежен, чем GET. Например, формы, использующие поля <TEXTAREA>, позволяют пользователям вводить большое количество текста. Они должны всегда применять метод POST:
ACTION=”http://www.server.com/cgi-bin/script.cgi”
Практически во всех формах, которые приходится заполнять на тех или иных Web-узлах, присутствуют поля ввода и кнопки подтверждения. Все они создаются с помощью тега <INPUT>, который в отличие от <FORM> и <TEXTAREA> не имеет закрывающей пары. Тег <INPUT>, равно как и <FORM>, может содержать несколько атрибутов: NAME, TYPE и VALUE. Обязательными являются первые два:
<INPUT TYPE=”text” NAME=”email”VALUE=”@”>
<INPUT TYPE=”submit” NAME=”button”VALUE=”PostIt!”>
В результате отображения формы браузером первая строка образует поле для ввода информации (TYPE=«text»), а вторая — кнопку ее подтверждения (TYPE=«submit»). Можно также создать и кнопку сброса введенной информации в форме (TYPE=«reset»). Кроме TYPE используется NAME — второй важный параметр. Он придает каждому объекту формы свое уникальное имя. А в качестве необязательного атрибута тег <INPUT> может содержать VALUE. В него записывается значение, отображаемое в соответствующих элементах формы при ее загрузке. Например, использование VALUE=«@» приведет к тому, что при загрузке формы в браузер поле ввода адреса электронной почты будет содержать символ @.
Заполним форму, исходный текст которой приводился и, нажав кнопку PostIt, подтвердим ее!
Программа обработки данных из формы и вывода их в браузер
#!/usr/local/bin/perl
&GetFormInput;
$Name=$field{‘name’};
$Email=$field{‘email’};
$City=$field{‘city’};
$Url=$field{‘url’};
$Comments=$field{‘comments’};
print ”Content-type:text/html\n\n”;
&Title;
print ”<B>Name: $Name</B><BR>\n
<B>Email:</B>
<A HREF=\”mailto:$Email\”>$Email</A><BR>\n
<B>City:</B> $City<BR>\n
<B>Url:</B>
<A HREF=\”$Url\”>$Url</A><BR>\n
<B>Comments:</B> $Comments<BR>\n”;
sub GetFormInput {
(*fval) = @_ if @_ ;
local ($buf);
if ($ENV{‘REQUEST_METHOD’} eq ‘POST’) {
read(STDIN,$buf,$ENV{‘CONTENT_LENGTH’});
}
else {
$buf=$ENV{‘QUERY_STRING’};
}
if ($buf eq ””) {
return 0 ;
}
else {
@fval=split(/&/,$buf);
foreach $i (0 .. $#fval){
($name,$val)=split (/=/,$fval[$i],2);
$val=~tr/+/ /;
$val=~ s/%(..)/pack(”c”,hex($1))/ge;
$name=~tr/+/ /;
$name=~ s/%(..)/pack(”c”,hex($1))/ge;
if (!defined($field{$name})) {
$field{$name}=$val;
}
else {
$field{$name} .= ”,$val”;
#if you want multi-selects to goto into an array change to:
#$field{$name} .= ”\0$val”;
}
}
}
return 1;
}
sub Title {
print ”<H2>Simple GuestBook</H2><P>\n”;
return 1;
}
В результате произойдет запуск серверной программы для обработки этой формы и вывода данных в виде отдельной HTML-странички. В форме использовался метод GET, так как в строке ввода адреса вместе с названием самой CGI-программы присутствуют также закодированные данные.
Если использовать метод POST, то в строке адреса отобразится только название самой CGI-программы. Алгоритм работы программы очень прост: вызывается подпрограмма &GetFormInput, декодирующая данные из формы, которые затем записываются в соответствующие переменные. Далее с помощью строки print «Content-type:text/html\ n\n» объявляется MIME-тип вывода информации (в данном случае — в виде HTML-страницы), потом запускается подпрограмма &Title для вывода заголовка «Simple Guestbook» и в конце выводятся декодированные данные в Web-браузер в виде HTML-страницы.
Гостевая книга должна сохранять введенные пользователем данные в каком-либо файле для дальнейшего их отображения и использования при новом посещении страницы.
Процесс декодирования данных формы практически во всех CGI-программах одинаков. Поэтому, чтобы не повторять его от программы к программе, создаются библиотеки подпрограмм. На сегодняшний день самые популярные из них для Perl — CGI-LIB.PL и CGI.PM. Благодаря этим программам можно сократить размер Perl-программы. Возможностями CGI-LIB.PL воспользуемся ниже.
Для объявления библиотеки необходимо в начале программы написать: require ”../cgi-lib.pl”;
В кавычках указан физический путь к библиотеке. Если требуется, можно организовать и свою библиотеку с набором часто используемых собственных подпрограмм:
require ”../mylib.pl”;
Объявив эту библиотеку в начале программы гостевой книги, можно убрать из текста подпрограмму декодирования данных. Теперь для обработки закодированных данных нужно просто вызвать из нее соответствующую подпрограмму. Это действие практически не отличается от вызова обычной внутренней подпрограммы: &Parse_Data;
Из-за того что используется библиотечная подпрограмма (а она, естественно, отличается названиями переменных), в месте присваивания данных переменным нужно $field{‘ ‘} заменить на $CGI{‘ ‘}. А после внесения всех необходимых изменений в текст программы гостевой книги следует реализовать механизм сохранения пользовательской информации в текстовую базу данных
# Создание текстовой БД записей посетителей
#!/usr/local/bin/perl
require 'cgi_lib.pl';
&Parse_Data;
$Name=$CGI{'name'};
$Email=$CGI{'email'};
$City=$CGI{'city'};
$Url=$CGI{'url'};
@Comments=$CGI{'comments'};
# Убираем символы конца строки из переменной окна прокрутки
$c=0;
foreach (@Comments) {
$Comments[$c] =~ s/\n/ /g;
chomp($Comments[$c]);
$q=$Comments[$c]+$Desc[$c];
$q = ~ s/\n/ /g;
$c++;
}
$file="guestbook";
$dbase="../";
open (F, "+>>$dbase/$file") || die "Error of adding a record
$!\n";
print F join ("::","$Name", "$Email", "$City", "$Url",
"@Comments"),"\n";
$i=1;
foreach (@F) {
print F $_;
$i++;
}
close (F);
print "Content-type:text/html\n\n";
&Title;
print "<B>Name: $Name</B><BR>\n
<B>Email:</B> <A HREF=\"mailto:$Email\">$Email</A><BR>\n
<B>City:</B> $City<BR>\n
<B>Url:</B> <A HREF=\"$Url\">$Url</A><BR>\n
<B>Comments:</B> $Comments<BR>\n";
CGI-программа обрабатывает введенные данные и записывает их в файл. Вместо обычного открытия файла для записи используется режим добавления записей (Append), чтобы не была уничтожена записанная ранее информация.
Web -сервер
Что делает web – сервер? Web сервер Apache просто забирает пакеты идущие по адресу 127.0.0.1 или "http://localhost". Затем их обрабатывает и отсылает ответ клиенту. Клиент ожидает ответ на запрос (Request).
Apache будет установлен в любую директорию какую вы укажете. Можете создать файл конфигурации config.conf, а можете, не удаляя старой конфигурации, воспользоваться новой, указав в коммандной строке соответственно комманду -f "path", где path это полный путь к файлу новой конфигурации *.cfg. Вам будет предложено установить Apache Server в какую-либо директорию. В строке "Install to" введите полный путь для установки, к примеру z:\home\web_server. В результате этого будут созданы папка Apache и файл MakeConf.exe. Запустите MakeConf.exe из директории, где он был создан, и укажите ту же папку что и при инсталляции, только с маленькой оговоркой: для правильного создания файла конфигурации путь надо будет прописывать с правым слэшем: "z:/home/web_server".
Для запуска Apache сервера используйте файл start_apache.cmd, для остановки stop.cmd.Все ошибки, которые возникнут в процессе работы с сервером будут занесены в файлы error.log и access.log в директории logs.