Next Previous Contents

5. CGI-скрипты

5.1 Что такое CGI и как с ним работать

CGI -- Common Gateway Interface. Стандарт интерфейса внешних программ с http-сервером.

Как работать

HTTP -- клиент-серверный протокол, следовательно со стороны CGI-программы, как серверного процесса, все взаимодействие выглядит следующим образом

  1. Получение данных от клиента
  2. Обработка данных
  3. Выдача ответа клиенту.

Пункты 1 и 3 я вкратце опишу здесь, а 2, надеюсь, сделаете сами :-). Начнем с п.3, как наиболее простого.

3. Выдача данных клиенту

Обычно клиенту выдают текст в формате HTML (ничто не мешает Вам отправить ему и картинку/видео/etc). Для того, чтобы сервер и клиент вас поняли, необходимо сказать, что вы выдаете, c помощью заголовка Content-Type: mime-type/mime-subtype. Обратите внимание на регистр и последовательность -- если вы скажите нечто типа Content_type, то сервер вас скорее всего не поймет. (Сообщение типа "500 Internal Server Error" будет симптомом).

Пример:

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

# Мы выдаем текст в формате HTML. Также можно: text/plain -- простой текст, в
# браузере отобразится аналогично тексту, заключённому между тегами
# <pre></pre>.  image/gif -- Картинка, формат gif video/mpeg --
# mpeg-видео И целая куча других форматов, см.  файл mime.types из apache

print "\n"; 
# <-- еще одна пустая строка, обозначает конец вывода наших 
# заголовков. ВАЖНО!

# Теперь мы можем написать свой текст клиенту
print qq{
<html>
<head>
<title>Моя первая CGI программа</title>
</head>
<body>
<h1>Моя первая CGI программа</h1>
</body>
</head>
};

Прием данных от клиента

Взаимодействие с клиентом обеспечивается так: Он заполняет форму своими значениями, нажимает на кнопку "submit", броузер кодирует данные соответствующим образом и отправляет их серверу.

Определение форм

Производится тегами <form> и </form>. Тег определения форм имеет следующие атрибуты

action

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

method

тип взаимодействия с сервером. Может иметь значения GET и POST. Плюс, еще некоторые специальные, которые вы можете посмотреть в rfc

(Аттрибуты перечислены не все, как обычно)

Формы не могут быть вложенными.

Элементы ввода

Определяются тегами <input>, <textarea> и <select> тег <input>:

<input type=checkbox>

Элемент ввода "Опция"

<input type=hidden>

Элемент ввода, который не виден пользователю

<input type=file>

позволяет загрузить файл на сервер

<input type=image>

Изображение. Если по нему щелкнуть, это вызовет submit формы и серверу будут выданы две переменные вида name.x и name.y, где name -- то, что вы пропишете в name=... тега <input>

<input type=password>

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

<input type=radio>

Радиокнопки

<input type=reset>

Кнопка сброса значений формы на начальные

<input type=submit>

Кнопка отправки формы на сервер

<input type=text>

строка ввода

Все теги <input> имеют атрибут name -- Наименование элемента. Служит для идентификации при передаче на сервер, а также другие типа value, width, etc, название и назначение которых можно опять-таки посмотреть в учебнике.

Тег <textarea> -- Поле многострочного ввода.

Тег <select> -- списочный выбор

Пример:

  <form action=/cgi-bin/myscript.pl method=GET>
  Имя: <input type=string name=name><p>
  Пол: <input type=radio name=gender value=male>Мужской
       <input type=radio name=gender value=female>Женский
  <input type=submit><input type=reset>
  </form>

Как это будет видно в моей программе?

Это определяется методом формы, GET или POST

В случае GET сервер установит переменную окружения QUERY_STRING в виде name1=vaue1&name2=value2&..&nameN=valueN.

В случае POST аналогичная строка будет записана на стандартный ввод. Ее длину можно получить через переменную окружения CONTENT_LENGTH.

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

Декодирование на perl

  tr/+/ /;
  s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
(списано из CGI.pm)

На самом деле, можно не возится со всем этим, а использовать модуль CGI.pm (Имеется в поставке Perl 5.004 и более поздних. Если у вас perl версии 4 или 1, нужно срочно взять на CPAN новую версию perl)

Самый большой и последний пример

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

search.html
<html>
<head>
<title>Поиск</title>
</head>
<<body>
<h1>Чего искать?</h1>
<form action=/cgi-bin/search.pl method=get>
Строка для поиска: <input type=text name=string width=70><p>
Искать в <input type=checkbox name=searchin value=internet>Интернет
  <input type=checkbox name=searchin value=intranet>Интранет
  <input type=checkbox name=searchin value=extranet>Экстранет<p>
<input type=submit value=Давай!><input type=reset value="Нет, не надо">
</form>
</body>
</html>

Программа:

#!/usr/bin/perl -- поменяйте, как надо
use CGI qw(:standard); 

print "Content-Type: text/html\n\n"; # Не забудьте про два "\n"

$string = param("string");
@searchin = param("searchin"); # searchin это checkbox и его значения
             # возвращаются списком

# Искать мы сегодня ничего не будем
print "<html>
<body>
<h1>Мы сегодня ничего не ищем</h1>
Но, если бы искали, то: <br>
Искали бы строку <b>$string</b><br>\n";
print "В <b>" . join(" ", @searchin) . "</b>\n";
print "
</body>
</html>
";

Да, кстати, если вы собираетесь писать в файлы с помощью CGI-программ, не забывайте про file locking (См. главу 8 за подробностями).

5.2 Как заставить браузеры не кешировать выдаваемый результат?

Выдавайте заголовки в таком виде:

print "Content-Type: type/sub-type\n"; # Подставьте Ваш тип/подтип
print "Pragma: no-cache\n"; # Для HTTP/1.0 клиентов
print "Cache-Control: no-cache\n"; # Для HTTP/1.1
print "Expires: Thu Jan  1 00:00:00 1970\n\n"; # Это уже любой броузер должен
                                               # понять

5.3 Как перенаправить клиента на другой URL?

В заголовке напишите:

        
print "Status: 302\n";
# Или 301. Разница состоит в том, что по стандарту 301 значит "перемещён
# навсегда", а 302 -- "перемещён временно"
print "Location: ВАШ Новый URL\n";
# URL должен быть указан абсолютный
print "URI: ВАШ новый URL\n\n"; # Для http/1.0
Подробности: см. rfc1945(http/1.0), rfc2068(http/1.1)

5.4 Как загрузить файл на сервер?

В поставку CGI.pm входит пример file_upload.cgi. За подробностями смотрите CGI(3).

Учтите, что если у вас система, которая разделяет бинарные и текстовые файлы -- вам понадобится использовать binmode.

Также, помните, что "Русский Apache" не будет производить перекодировку multipart форм.

5.5 Как получить файл по URL?

Возьмите на CPAN библиотеку libwww-perl и смотрите lwpcook(3), там написаны основы использования библиотеки и есть примеры.

5.6 Как использовать плюшки (cookies)?

Плюшки работают следующим образом: программа CGI добавляет в свой ответ директиву Set-Cookie, а клиент (если он поддерживает плюшки), при следующих запросах возвращает их в заголовке Cookie. Сами плюшки представляют из себя пары имя=значение.

Синтаксис Set-Cookie

Set-Cookie: имя=значение; expires=дата; path=путь; domain=домен; secure

Сервер может установить не более 20 плюшек, размер всей плюшки не может превышать 4Kb.

Имя=значение

единственный обязательный параметр. И имя, и значение могут быть строками текста, не содержащими символов перевода строки, пробелов, ; и табуляции. Если необходимо их использовать, можно эти символы закодировать при помощи стандартного uri-кодирования.

expires=дата

устанавливается дата истечения срока действия плюшки. После этой дата плюшка клиентом не возвращается. Если дата не установлена, то плюшка действует до завершения работы браузера.

path=путь

обозначает путь на сервере, для которого возвращается эта плюшка, если не указано, то только для того, который ее создал.

domain=домен

домен, для которого возвращается эта плюшка. Может быть доменом уровня 2 и выше, т.е. .example.ru, а не .ru. Если не установлен, то плюшка возвращается только серверу, который выдал плюшку.

secure

указывает, что плюшка должна возвращаться только по защищенному соединению (SSL).

Синтаксис ответа клиента

Cookie: имя1=значение1; имя2=значение2;....;имяn=значениеn
Программы CGI могут получить пары имя-значение через переменную окружения HTTP_COOKIE. В модуле CGI.pm значение можно получить при помощи метода cookie().

В деталях, механизм плюшек описан в rfc2109 (HTTP State Management Mechanism. D. Kristol, L. Montulli. February 1997.)

Пример: 1. Установка плюшки

setcookie.pl
#!/usr/bin/perl 

print "Content-Type: text/html\n";
print "Set-Cookie: mycookie=some+string\n\n";
print "<html><head><title>Установка плюшки</title></head>\n";
print "<body><h1>Установка плюшки</h1>\n";
print "<a href=getcookie.pl>Щелкни здесь,</a> чтобы посмотреть, что
получилось.
print "</body></html>";

2. Получение плюшки

getcookie.pl;
#!/usr/bin/perl 
use CGI qw(:standard);

print "Content-Type: text/html\n\n";
print "<html><head><title>Получение плюшки</title></head>\n";
print "<body><h1>Плюшка</h1>\n";
print "mycookie = ", cookie('mycookie');
print "</body></html>";


Next Previous Contents