Основные особенности CGI-сценариев Такие сценарии --- это активные фильтры, которые обрабатывают поток ввода HTTP-сервера (Hyper Text Transfer Protocol --- протокол работы WWW Internet) как свой поток ввода и производят на основе него свой поток вывода, который возвращается обратно клиенту HTTP-сервера. Сценарии выполняются в среде оболочки ОС. Широко используемый в Internet HTTP-сервер --- это программа Apache. CGI-сценарии для Apache обычно хранятся в подкаталоге cgi-bin каталога данных Apache. Создадим в этом каталоге CGI-сценарий в файл cgi1.sh: #!/bin/bash echo 'Content-type: text/html; charset=UTF8' echo echo '<p>Hello from CGI-script' В первой строчке указывается интерпретатор языка программирования для выполнения сценария стандартным для оболочки ОС образом. В следующих, до пустой строки формируется заголовок ответа. Необходимо указывать тип содержимого - это обычно text/html. Информация о кодировке опциональна, но она имеет высший приоритет для браузера. Если кодировка не указана, то она устанавливается браузером по тегу META в заголовке формируемого html-документа. Иногда, особеннно при отладке в заголовок ответа полезно включать строку Pragma: nocache для отключения кэширования. После заголовка идёт текст программы на выбранном языке. Для запуска сценария необходимо установить его файлу соответствующие права. В строке браузера теперь можно набрать localhost/cgi-bin/cgi1.sh Сделаем сценарий cgi2.sh, добавив следующие строки echo '<pre>' set echo '</pre>' Запустив его, получим распечатку окружения. Особенно важны переменные REMOTE_ADDR - сетевой адрес браузера (ip) и SERVER_ADDR - адрес сервера. Поток вывода сценария - это поток html-текста, отправляемый браузеру. Поток ввода сценария формируется браузером в виде текста в специальном формате. Для взаимодействия с CGI-сценариями в HTML используют тег (tag) FORM для создания интерактивных компонент документа, которые оформляются как его элементы INPUT (кнопки и однострочный текст), SELECT (всплывающее меню и списки) и TEXTAREA (многострочный текст). Тег FORM может содержать и неинтерактивные элементы, например, сопроводительный текст. Атрибут ACTION тега FORM должен содержать имя соответствующего форме CGI-сценария. Пример HTML-документа (post.html), использующего CGI-сценарий. <head> <meta http-equiv=Content-Type content=text/html;charset=koi8-r> </head> <body> <p align=center><h1>Здравствуйте!</h1> <br> <p>Это страница с интерактивными элементами для взаимодействия с сервером. <br> <br> <form action=/cgi-bin/cgi3.sh method=post> <p>Введите два сообщения.<br> <input type=text name=field1 value="" size=32 maxlength=64> <br> <input type=text name=field2 value="" size=32 maxlength=64> <br> <input type=submit value=OK> <input type=reset value=Clear> </form> <hr> </body> Введенный пользователем текст и другая информация посылается CGI-сценарию в виде <имя поля>=<значение>, все пробелы в тексте заменяются знаками плюс, а все символы с кодами, большими 127, и специальные символы такие как ``+'', ``&'', ``!'' и ``='' --- на их шестнадцатеричные из двух цифр коды, предваренные знаком процента. Поля разделяются знаком ``&''. Создадим сценарий cgi3.sh, который будет просто возвращать весь ввод обратно браузеру. #!/bin/bash echo Content-type: text/html echo echo '<p>Input stream for CGI-script:' cat CGI-сценарий должен сначала разделить поля, затем имена полей и соответствующих им текстовых значений, затем, как правило, преобразовать значения-тексты в их исходный вид и,наконец, провести собственно обработку запроса к HTTP-серверу, т.е. сформировать на основе запроса HTML-документ (динамическую HTML-страницу). Кроме метода передачи данных на сервер post можно использовать метод get. Разница между ними в том, что при использовании get все данные передаются явно, в URI серверу, а при использовании post без использования URI. Если не указать метод явно, то будет использован get. Метод get позволяет использовать закладки, а post не ограничивает размер посылаемых данных. Кроме того, метод get заносит данные в переменную среды QUERY_STRING, а не в поток вывода. Сделаем cgi4.sh, изменив последнюю строку в последнем сценарии на echo $QUERY_STRING Сделаем также документ get.html из post.html, заменив post на get и cgi3 на cgi4. Посмотрим в браузере на get.html и заметим отличие в адресной строке. Проведем теперь обработку посланных от браузера данных и сформируем динамический html-документ. В post.html заменим cgi3 на cgi5 и сохраним файл с именем dynamic.html. Сценарий cgi5.sh заносит все сообщения в общий список и затем создает из него новую, динамическую страницу. #!/bin/bash echo Content-type: text/html\; charset=UTF8 echo echo '<br>Ваши сообщения:<br><br>' awk '{ n = split($0, b, "&") for (i = 1; i <= n; i++) { split(b[i], a, "=") s = a[2] gsub("+", " ", s) p = index(s, "%") while (p) { d = sprintf("%c", strtonum("0x"substr(s, p + 1, 2))) s = substr(s, 1, p - 1) d substr(s, p + 3) p = index(s, "%") } print s "<br>" } }' >>xmlist awk '{print NR, $0}' xmlist У файла xmlist (он разщещен в каталоге cgi-bin) должны быть установлены права, позволяющие писать в него и читать из него. Этот сценарий написан на языке оболочки, но почти все операции по обработке данных осуществляются вызовами программы аук (awk). CGI-программа может быть написана на любом языке сценариев или быть бинарным файлом. Некоторые языки, например перл, поддерживают специальные операции для проведения замен, более мощные, чем gsub в аук, которые позволяют провести приведенные в сценарии операции замены без цикла двумя строками. При написании CGI-сценариев часто бывает полезна http-команда переадресации, которая вставляется в тег META: <meta http-equiv=refresh content=1;url=http://СЕРВЕР/ФАЙЛ> Например, создадим сценарий cgi6.sh, который осуществит переход на заданную страницу. #!/bin/bash echo Content-type: text/html echo echo '<meta http-equiv=refresh content=1;url=http://'$SERVER_NAME'/get.html>' Величина content задает частоту в секундах для перезагрузки страницы. Можно поставить content=0, тогда переход должен проходить мгновенно, но с некоторыми редкими браузерами возможны проблемы. Для переадресации можно использовать строку http-заголовка, например, сценарий cgi7.sh #!/bin/bash echo Content-type: text/html echo Pragma: nocache echo Location: http://$SERVER_NAME/get.html echo Делает тоже самое, что и cgi6.sh, но без задержки и проблем с кэшированием. Для взаимодействия с CGI-сценариями удобно пользоваться возможностью предварительной обработки html-документов, встроенной во многие http-серверы. Эта возможность даёт вставлять коды сценария прямо в html-файл, используя элементы между <? и >. Чаще всего так работают с языком PHP. Помимо этого, можно использовать специальные команды для сервера, например, для вставки содержимого файла, текущего времени и т.п. Такие команды, позволяют также использовать переменные, условные конструкции, настраивать конфигурацию и др. В сервере Apache их заключают между <!--# -->, т.е. оформляют как комментарий. Эти команды называют SSI - Server Side Includes - вставки стороны сервера. Например, команда <!--#include virtual="/cgi-bin/htmlgen.sh"--> вставит в html содержимое потока вывода указанного сценария, а команда <!--#include virtual="/data.html"--> - содержимое указанного файла, т.е. порядок обработки определяется местоположением файла. Команда exec, например, <!--#exec cmd="ls"-->, очень похожа на первую, разница только в том, что тут можно использовать полный путь к программе относительно ФС ОС и не надо формировать http-заголовок из 2 строк. В первых двух случаях использовалась адресация относительно виртуальной ФС сервера. Вместо virtual можно использовать слово file и использовать адресацию относительно текущего файла, но без .. - перехода на уровень выше. Обычно файл, предназначенный для предварительной обработки, т.е. содержащий коды PHP, SSI и т.п., имеет специальное расширение: php, shtml, ... В конфигурации сервера прописывается, как обрабатывать файлы с такими расширениями. Справку по командам SSI и другим возможностям сервера можно получить из браузера, выбирая ресурс /manual на сервере. Ресурс /server-status показывает текущее состояние сервера Apache, а ресурс /server-info подробную информацию о конфигурации.