CGI

      Тема  CGI 

      Содержание 

 

Введение

 

      Главным достижением технологии World Wide Web по праву считают унификацию интерфейса пользователя при работе с информационными  ресурсами Internet. Универсальный мультипротокольный браузер, будь то Netscape Navigator или Internet Explorer, позволяет путем выбора гипертекстовой ссылки получить доступ к FTP-архиву, архиву Gopher, новостям из конференции Usenet или отправить письмо по электронной почте. До эпохи Web для каждого из этих ресурсов пришлось бы запускать отдельную программу.

      Однако, кроме текстов, которые можно  читать, или картинок, которые можно  просматривать, существует множество  ресурсов, требующих ввода информации в процессе работы с ними. К таким  ресурсам, в частности, относятся информационно-поисковые системы, где пользователь должен вводить список ключевых слов или реляционные (да и любые другие) базы данных, формулируя запрос к отношениям. Более того, для любой страницы, которая требует аутентификации пользователя, необходимо вводить идентификатор и пароль.

      На  сегодня уже сложился определенный стиль графического интерфейса приложения. Существует достаточно большое число  прикладных пакетов, которые позволяют "прилаживать" такой интерфейс  к программе. Однако на такое "прилаживание" или прямое программирование уходит до 80% трудозатрат программистов. При этом в большинстве случаев все сводится к разбору введенных параметров с последующей выдачей результатов в виде отформатированного текста.

      Форматирование  страниц в Web-технологии достигается за счет HTML-разметки. Остается только создать инструмент ввода данных через рабочее окно браузера или через HTML-документ. В 1991 году эта проблема была решена специалистами NCSA. Они разработали и реализовали две взаимосвязанные спецификации: HTML-формы и Common Gateway Interface.

      Формы произвели настоящую революцию  в HTML-разметке: авторы документов получили возможность создавать сложные  шаблоны ввода информации в рамках HTML-страницы, пользователи — эти  шаблоны заполнять. При этом авторы форм опирались на свойства HTTP-протокола и универсальный локатор ресурсов URL с учетом того, что при HTTP-обмене можно использовать различные методы доступа к ресурсам. Это позволило сделать механизм интерпретации форм расширяемым и легко приспосабливаемым к дальнейшему развитию Web-технологии. Таким образом, кроме HTTP, можно было использовать и другие протоколы, которые поддерживали универсальные браузеры, например mailto.

      Common Gateway Interface (CGI) — это спецификация обмена данными между прикладной программой, выполняемой по запросу пользователя, и HTTP-сервером, который данную программу запускает. До появления CGI новые функции нужно было внедрять непосредственно в сервер. CGI позволила разрабатывать программы независимо от сервера, а механизм передачи им управления и данных был унаследован от программирования в среде командной строки. Последнее резко сократило трудозатраты на разработку приложений, так как не надо было программировать интерфейс пользователя: его функции выполняли формы.  

      По  мере выполнения данной работы будет рассмотрено как создавать документы с формами, программировать на стороне сервера с использованием CGI и обрабатывать данные, передаваемые браузером серверу. Также будут кратко рассмотрены различные способы такой обработки, а также основные приемы построения интерактивных страниц Web-узла.

 

1. Обмен данными  в Web-технологии

 

      Обмен данными в Web-технологии подразделяется в соответствии с типами методов  доступа протокола HTTP и видами запросов в спецификации CGI.

      Основных  методов доступа два: GET и POST. Помимо них часто используются HEAD и PUT.

      Виды  запросов CGI разделяют на два основных MIME-типа: application/x-www-form-urlencoded и multipart/form-data. Второй тип запроса специально создан для передачи больших внешних  файлов. При реализации нестандартных методов доступа, например, DELETE, могут быть несколько иные комбинации содержания откликов и ответов. Мы рассмотрим все эти типы обменов.

      Все данные в рамках Web-технологии передаются по протоколу HTTР. Исключение составляет обмен с использованием программирования на Java или обмен из Plugin-приложений. Учитывая реальный объем трафика, который передается в рамках Web-обмена по HTTP, мы будем рассматривать только этот протокол.

      HTTP — это протокол прикладного  уровня. Он ориентирован на модель обмена "клиент-сервер". Клиент и сервер обмениваются фрагментами данных, которые называются HTTP-сообщениями. Сообщения, отправляемые клиентом серверу, называют запросами, а сообщения, отправляемые сервером клиенту — откликами. Сообщение может состоять из двух частей: заголовка и тела. Тело от заголовка отделяется пустой строкой.

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

      Тело  сообщения не является обязательным, в отличие от заголовка сообщения. Оно может содержать текст, графику, аудио- или видеоинформацию.

      Ниже  приведен HTTP-запрос:  

      GET / HTTP/1.0

      Accept: image/jpeg

      пустая строка  

      И отклик:  

      HTTP/1.0 200 OK

      Date: Fri, 24 Jul 1998 21:30:51 GMT

      Server: Apache/1.2.5

      Content-type: text/html

      Content-length: 21345

      пустая строка

      <HTML>

      ...

      </HTML>  

      Текст "пустая строка" — это просто обозначение наличия пустой строки, которая отделяет заголовок HTTP-сообщения от его тела.  

      Сервер, принимая запрос от клиента, часть информации заголовка HTTP-запроса преобразует  в переменные окружения, которые  доступны для анализа CGI-скриптом. Если запрос имеет тело, то оно становится доступным скрипту через поток стандартного ввода.

      Самой главной директивой HTTP-запроса является метод доступа. Он указывается первым словом в первой строке запроса. В  нашем примере это GET. Различают  четыре основных метода доступа: GET; HEAD; POST; PUT. Кроме этих методов существует еще около пяти дополнительных методов доступа, но они используются редко. Кратко рассмотрим их.

      Метод GET. Метод GET применяется клиентом при запросе к серверу по умолчанию. В этом случае клиент сообщает адрес ресурса (URL), который он хочет получить, версию протокола HTTP, поддерживаемые им MIME-типы документов, версию и название клиентского программного обеспечения. Все эти параметры указываются в заголовке HTTP-запроса. Тело в запросе не передается. В ответ сервер сообщает версию HTTP-протокола, код возврата, тип содержания тела сообщения, размер тела сообщения и ряд других необязательных директив HTTP-заголовка. Сам ресурс, обычно HTML-страница, передается в теле отклика.

      Метод HEAD. Метод HEAD используется для уменьшения обменов при работе по протоколу HTTP. Он аналогичен методу GET за исключением того, что в отклике тело сообщения не передается. Данный метод используется для проверки времени последней модификации ресурса и срока годности кэшированных ресурсов, а также при использовании программ сканирования ресурсов World Wide Web. Одним словом, метод HEAD предназначен для уменьшения объема передаваемой по сети информации в рамках HTTP-обмена.

      Метод POST. Метод POST — это альтернатива методу GET. При обмене данными по методу POST в запросе клиента присутствует тело HTTP-сообщения. Это тело может формироваться из данных, которые вводятся в HTML-форме, или из присоединенного внешнего файла. В отклике, как правило, присутствует и заголовок, и тело HTTP-сообщения. Чтобы инициировать обмен по методу POST, в атрибуте METHOD контейнера FORM следует указать значение "post".

      Метод PUT. Метод PUT используется для публикации HTML-страниц в каталоге HTTP-сервера. При передаче данных от клиента к серверу в сообщении присутствует и заголовок сообщения, в котором указан URL данного ресурса, и тело — содержание размещаемого ресурса. В отклике тело ресурса обычно не передается, а в заголовке сообщения указывается код возврата, который определяет успешное или неуспешное размещение ресурса.

2. Спецификация CGI

 

      Данная  спецификация определяет стандартный  способ обмена данными между прикладной программой и HTTP-сервером. Спецификация была предложена для сервера NCSA и является основным средством расширения возможностей обработки запросов клиентов HTTP-сервером.

      Основное  назначение CGI — обработка данных из HTML-форм. В настоящее время область применения CGI гораздо шире.

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

      Наиболее  популярными языками для разработки скриптов являются Perl и С.

      Различают два типа запросов к CGI-скриптам: по методу GET и по методу POST. В свою очередь, запросы по методу GET подразделяются на запросы по типам кодирования: isindex и form-urlencoded, а запросы по методу POST — multipart/form-data и form-urlencoded.

      В запросах по методу GET данные от клиента передаются скрипту в переменной окружения QUERY_STRING. В запросах по методу POST данные от скрипта передаются в потоке стандартного ввода скрипта. При передаче через поток стандартного ввода в переменной окружения CONTENT_LENGTH указывается число передаваемых символов.

      Запрос  типа ISINDEX — это запрос вида:  

      http://domain.ru/somthing-cgi/cgi-script?слово1+слово2+слово3  

      Главным здесь является список слов после  символа "?". Слова перечисляются  через символ "+" и для кириллицы  в шестнадцатеричные последовательности не кодируются. Последовательность слов после символа "?" будет размещена в переменной окружения QUERY_STRING.

      Запрос  типа form-urlencoded — это запрос вида:  

      http://domain.ru/somthing-cgi/cgi-script?field=word1&field2=word2  

      Данные  формы записываются в виде пар "имя_поля-значение", которые разделены символом "&".

      Приведенный пример — это обращение к скрипту по методу GET. Все символы после "?" попадут в переменную окружения QUERY_STRING. При этом если в значениях полей появляется кириллица или специальные символы, то они заменяются шестнадцатиричным кодом символа, который следует за символом "%".

      При обращении к скрипту по методу POST данные после символа "?" не будут размещаться в QUERY_STRING, а будут направлены в поток стандартного ввода скрипта. В этом случае количество символов в потоке стандартного ввода скрипта будет указано в переменной окружения CONTENT_LENGTH.

      При запросе типа multipart/form-data применяется составное тело HTTP-сообщения, которое представляет собой данные, введенные в форме, и данные присоединенного внешнего файла. Это тело помещается в поток стандартного ввода скрипта. При этом к данным формы применяется кодирование как в form-urlencoded, а данные внешнего файла передаются как есть.

      Скрипт  может принять данные от сервера  тремя способами: через переменные окружения; через аргументы командной строки; через поток стандартного ввода. При описании этих механизмов будем считать, что речь идет об обмене данными с сервером Apache для платформы Unix.

      При вызове скрипта сервер выполняет  системные вызовы fork и exec. При этом он создает среду выполнения скрипта, определяя ее переменные. В спецификации CGI определены 22 переменные окружения. При обращении к скрипту разными методами и из различных контекстов реальные значения принимают разные совокупности этих переменных. Например, при обращении по методу POST переменная QUERY_STRING не имеет значения, а по методу GET — имеет. Другой пример — переменная окружения HTTP_REFERER. При переходе по гипертекстовой ссылке она определена, а если перейти по значению поля location или через JavaScript-программу, то HTTP_REFERER определена не будет.

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

      #Perl

      $a = $ENV{CONTENT_LENGTH};

      ...

      // C

      a = getenv("CONTENT_LENGTH");  

      В случае доступа к скрипту по методу GET данные, которые передаются скрипту, размещаются в переменной окружения QUERY_STRING.

      Как ни странно звучит, но у CGI-скрипта может быть такой элемент операционного окружения как командная строка. Это не означает, что скрипт реально можно вызвать из командной строки через сервер. Тем не менее, получить доступ к содержанию командной строки скрипта можно с помощью тех же функций, что и при вызове его из-под интерактивной оболочки:  

      #Perl

      foreach $a (@ARGV)

      {

      print $a,"\n";

      } 

      // C

      void main(argc,argv)

      int argc;

      char *argv[];

      {

      int i;

      for(i=0;i<argc;i++)

      {

      printf("%s\n",argv[i]);

      }

      }  

      В обоих примерах показана распечатка аргументов командной строки для программ на Perl и C соответственно. Аргументы командной строки появляются только в запросах типа ISINDEX.

      Ввод  данных в скрипт через поток стандартного ввода осуществляется только при  использовании метода доступа к  ресурсу (скрипту) POST. При этом в переменную окружения CONTENT_LENGTH помещается число символов, которое необходимо считать из потока стандартного ввода скрипта, а в переменную окружения CONTENT_TYPE помещается тип кодирования данных, которые считываются из потока стандартного ввода.

      При посимвольном считывании в C можно применить, например, такой фрагмент кода:  

      int n;

      char *buf;

      n= atoi(getenv("CONTENT_LENGTH"));

      buf = (char *) malloc(n+1);

      memset(buf,'\000',n+1);

      for(i=0;i<n;i++)

      {

      buf[i]=getchar();

      }

      free(buf);  

      В данном фрагменте применено динамическое размещение памяти в скрипте, поэтому при выходе из него память следует освободить. Вообще говоря, память будет автоматически освобождена операционной системой после завершения скрипта. Однако, если переносить скрипт на спецификацию FCGI (Fast CGI), что требует минимума переделок, из-за неаккуратной работы с памятью могут возникнуть проблемы.

      Существует  только один способ вернуть данные серверу и, соответственно, браузеру пользователя — писать в поток  стандартного вывода (STDOUT). При этом скрипт должен формировать HTTP-сообщение.

      Сначала выводятся директивы HTTP-заголовка. В минимальном варианте это либо  

      Content-type: text/html,  

      либо  

      Location: http://domain.ru/  

      В первом случае определяется тип тела HTTP-сообщения, а во втором осуществляется перенаправление запроса. После заголовка генерируется отклик в виде тела HTTP-сообщения, которое должно быть отделено от заголовка пустой строкой:  

      #!/bin/sh

      echo Content-type: text/plain

      echo

      echo Hello  

      В данном случае используется командный интерпретатор sh. Если скрипт начинает формирование заголовка с директивы версии HTTP-протокола, то сервер не анализирует отклик и передает его как есть. Если в заголовке, сгенерированном скриптом, эта директива отсутствует, то сервер считает, что заголовок неполный, и вставляет в него дополнительные директивы.

3. Web-формы и CGI

 

      Контейнер (элемент разметки) FORM позволяет  определить в рамках HTML-документа  форму ввода. В рамках этого контейнера размещаются все поля ввода, куда пользователь может поместить свою информацию. Если контейнер формы открыт, т.е. в документе указан тег начала контейнера <FORM ...>, то обязательно нужно указать и тег конца контейнера </FORM>.

      В общем случае контейнер имеет  следующий вид: 

      <FORM

      NAME=...

      ACTION=url

      METHOD=POST|GET|PUT|...

      enctype=application/x-www-form-urlencoded|

              multipart/form-data

      [target=window_name]

      >

      ...

      </FORM> 

      Атрибут NAME используется для именования формы. Это делается главным образом  в JavaScript-программах. Атрибут ACTION задает URL, по которому отправляются данные из формы. Атрибут METHOD определяет метод передачи данных (фактически, речь идет о формировании сообщения, передаваемого по сети). Атрибут ENCTYPE определяет тип кодирования данных в теле сообщения и разбиение сообщения на части. Необязательный атрибут TARGET позволяет адресовать окно, в котором будет отображаться результат обработки данных из формы.

      В рамках обзора применения контейнера FORM мы рассмотрим:

    • передачу данных по электронной почте;
    • передачу данных скрипту через атрибут ACTION;
    • передачу данных через Server Side Include.

      Инициировать  обмен можно при помощи JavaScript-кода, но рассматривать данный способ программирования обмена данными мы здесь не будем. 

      FORM (mailto). Контейнер FORM позволяет определить в рамках HTML-документа форму ввода. В рамках этого контейнера размещаются все поля ввода, в которые пользователь может поместить информацию. Часто автор страниц Web-сайта по тем или иным причинам не имеет возможности программировать на стороне сервера. Однако это не означает, что он не может применять формы. Формы можно применять для отправки почты.

      Для того, чтобы получить тело сообщения, необходимо указать метод POST (cgimail2.htm). В этом случае сообщение должно уйти абоненту без открытия окна почтового клиента:  

      <FORM METHOD=post

            ACTION=mailto:[email protected]>

      <INPUT NAME=n1 VALUE="Поле1">

      <INPUT TYPE=BUTTON VALUE="Отправить">

      </FORM> 

      В данном случае мы использовали протокол, отличный от HTTP — SMTP. В нем нет понятия метода доступа вообще. Тем не менее логика разбиения текстовых сообщений для всех протоколов одна и та же, как, собственно, и предполагалось при создании Web-технологии — унификация доступа к ресурсам.

      FORM (HTTP). Основной целью введения форм в HTML было обеспечение ввода данных в прикладную программу из универсального мультипротокольного браузера. При этом нужно отдавать себе отчет, что прикладная программа естественным образом должна выполняться на компьютере, где функционирует HTTP-сервер. Она не может работать в пустоте. Программу должен кто-то загружать, настраивать в адресном пространстве компьютера (linking), передавать ей управление и удалять из памяти после ее завершения.

      Основная  задача формы — это предоставление шаблона ввода данных, которые  будут переданы скрипту. Сам скрипт при этом указывается через URL, который задается в атрибуте ACTION:  

      <FORM ACTION=script.cgi>

      <INPUT NAME=n1 VALUE="Поле1">

      <INPUT NAME=n2 VALUE="Поле2">

      <INPUT TYPE=BUTTON VALUE="Отправить">

      </FORM> 

      или 

      <FORM METHOD=post ACTION=script.cgi>

      <INPUT NAME=n1 VALUE="Поле1">

      <INPUT NAME=n2 VALUE="Поле2">

      <INPUT TYPE=BUTTON VALUE="Отправить">

      </FORM> 
 

      В данном примере скрипт просто распечатывает  пару "имя поля формы — значение поля формы" в виде HTML-таблицы (formcgi1.htm).

      FORM (SSI). Когда говорят о формах, обычно предполагается, что в контейнере FORM обязательно должен быть указан адрес скрипта. Этот скрипт примет данные и "на лету" сгенерирует страницу, которая и будет возвращена пользователю. Из этого правила существует, по крайней мере, два исключения.

      Во-первых, атрибут ACTION можно не указывать в том случае, если данные, введенные в форму, обрабатываются JavaScript-программой. В этом случае достаточно дать форме имя, чтобы к ее элементам (контейнерам) можно было обращаться. Передачу данных можно реализовать через метод submit, который будет выполняться при нажатии на гипертекстовую ссылку, например, formssi1.htm. Более подробно данный материал описан в главе "Программирование на JavaScript".  

      Во-вторых, принять данные можно через скрипт, который встроен в документ как Server Side Include. Этот способ показан ниже.  

      <FORM>

      <INPUT NAME=n1 VALUE="Поле1">

      <INPUT NAME=n2 VALUE="Поле2">

      <INPUT TYPE=BUTTON VALUE="Отправить">

      <HR>

      <!--#exec cgi=./cgi.cgi -->

      </FORM> 

      Сам скрипт принимает запрос из QUERY_STRING и распечатывает его в виде HTML-таблицы. При этом результат распечатывается вслед за формой после горизонтального отчеркивания. Точно так же можно обработать данные и методом POST, только для этого необходимо указать его в атрибуте METHOD контейнера FORM.  
 

 

Заключение

 
 

      В заключении, как обычно, подведем черту  под рассматриваемой темой и  коротко сформулируем преимущества CGI.

      1. Так как программа выполняется сервером, нет никакого значения, какой у посетителя браузер - древний Lynx или новейший Internet Explorer. Нет никаких возможных недоразумений и сообщений об ошибках.

      2. CGI-скрипты позволяют реализовать гораздо более широкий набор функций чем, например, Java и JavaScript.

      3. Код cgi-скрипта закрыт для конкурентов.

      4. Писать CGI-скрипты можно практически на любом из современных языков программирования. 

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

 

Список  использованной литературы

 

      1. Материалы с сайта www.intuit.ru

      2. Материалы с сайта http://www.cetis-media.ru/library/cgi/cgiv.html

      3. Материалы с сайта http://pwd.boom.ru/cgi/index.htm

      4. Материалы с сайта http://php.su

      5. Лекционный материал по курсу  «IT»

CGI