Глава 3. ДОСТУП К БАЗАМ ДАННЫМ ПОСРЕДСТВОМ CGI-СКРИПТОВ

В данной главе излагаются основные понятия программирования CGI-скриптов и написания на их основе программ доступа к базам данных. Поскольку данная тема напрямую затрагивает работу WWW-сервера, желательно предварительно познакомиться со средствами создания HTML-документов [12-15]. Поскольку средства HTML являются достаточно обширными, в дальнейшем мы ограничимся лишь теми из них, которые непосредственно связаны с темой данного пособия. Краткий обзор средств HTML приведен в Приложении4.

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

Как видно из данной схемы, обращение к базе данных происходит из CGI-скрипта.

3.1. ПОНЯТИЕ CGI-СКРИПТА

Связь клиент-сервер, имеющая место между программой-броузером и Web-сервером, очень хорошо проявляет себя при обслуживании HTML и графических файлов из каталогов Web-сервера. Но помимо доступа к статическим документам сервера существует потребность получения документов как результата выполнения прикладной программы. Получение документов как результата выполнения прикладной программы (CGI-скрипта) реализуется на сервере WWW благодаря использованию общего стандартного интерфейса CGI (Common Gateway Interface).

Спецификация CGI описывает формат и правила обмена данными между программным обеспечением WWW-сервера и запускаемой программой и представляет собой общую среду и набор протоколов для внешних приложений, которые используются при взаимодействии с Web-сервером. Это существенно расширяет диапазон функций Web-сервера. CGI-программа может обрабатывать сигналы с датчиков установок, взаимодействовать с мощным сервером баз данных и т.п. При осуществлении таких соединений сервер отвечает за получение информации от программы-броузера и за пересылку данных обратно на броузер. Для инициирования CGI необходимо, чтобы в запрашиваемом URL был указан путь до запускаемой программы. Программное обеспечение WWW-сервера исполняет эту программу, передает ей входные параметры и возвращает результаты ее работы, как результат обработки запроса, клиенту. CGI-программой может являться любая программа локальной операционной системы сервера - в двоичном виде или в виде программы для интерпретатора (Basic, Perl и т.д.).

С целью облегчения администрирования CGI-программ, а также для удовлетворения требованиям безопасности CGI-программы группируются в одном или нескольких явно указанных серверу каталогах. По умолчанию это каталог cgi-bin в иерархии серверных каталогов, однако, его имя и положение могут отличаться. Например, клиент, обращающийся к CGI- программе script, будет использовать URL http://<имя_сервера>/cgi-bin/script.cgi. В последующем изложении будет рассматриваться CGI- программирование на языке C, поскольку в данном случае важно рассмотреть сам принцип CGI-программирования, а реализация на различных языках отличается некоторыми нюансами и не имеет большого значения.

Общая схема выглядит следующим образом: пишется программа на C, затем она компилируется, и исполняемый файл (как, правило, с расширением cgi) помещается в каталог для CGI-скриптов (по умолчанию каталог cgi-bin в иерархии серверных каталогов). Данная процедура может различаться для различных платформ сервера. Однако поскольку подготовленный файл (к примеру first.cgi), помещенный в каталог, будет исполнен после того, как будет набран адрес в броузере http://<имя_сервера>/cgi-bin/first.cgi, необходимо, чтобы

Ниже приведен пример простейшей CGI-программы:

Строка printf("Content-Type: text/html\n\n"); является заголовком, указывающим тип содержимого. В данном случае тип генерируемого документа HTML, хотя может быть абсолютно любым. Кроме Content-Type возможно поле Location, содержащее URL ресурса, на который скрипт перенаправляет запрос. К примеру вместо Content-Type: text/html могло бы стоять:

Возможное поле Status позволяет вернуть статус обработки (код ошибки). Информация о коде находится в строке состояния при ответе сервера. Коды возврата протокола HTTP находятся в Приложении 3.

Два символа \n\n образуют пустую строку. Их задача отделить заголовок от тела, который генерирует простейший HTML-код. Все, что скрипт печатает в стандартный поток вывода STDOUT, идет на обработку серверу. Затем сервер формирует и посылает программе-броузеру ответ. В нашем случае HTML формирует страницу с кодом

В приведенном примере отсутствует обмен данными. Прежде, чем приступить к описанию механизма, посредством которого пользователь вводит определенные данные и в результате работы скрипта получает ответ на эти данные, необходимо познакомиться с программированием HTML-формы.

3.2. ПОНЯТИЕ HTML-ФОРМЫ

В общем случае, интерактивный интерфейс пользователя представляет собой систему, обеспечивающую взаимодействие пользователя и программы. Для WWW интерактивный интерфейс можно определить как последовательность HTML-документов, реализующих интерфейс пользователя. Можно также условно классифицировать принципы построения интерфейса по типу формирования HTML-документа на статический и динамический. В первом случае источником интерфейса является HTML-документ, созданный в каком-либо текстовом или HTML-ориентированном редакторе. Во втором случае источником интерфейса является HTML-документ, сгенерированный cgi-модулем, что обеспечивает гибкость в видоизменении интерфейса во время использования. Задача построения вышеназванных интерфейсов делится на клиентскую и серверную части. Для создания клиентской части необходимо иметь HTML-документ, в котором реализован интерфейс с пользователем. Для успешного решения подобной задачи HTML-документы должны содержать некоторые элементы управления. Под элементами управления понимаются такие объекты, как флажки-переключатели, радио- и обычные кнопки, поля ввода текста (одно- и многострочные), списки с единственным и множественным выбором и т.д. Все подобные элементы можно создавать с помощью различных тегов HTML. При этом, каждый такой элемент управления должен принадлежать объекту HTML, носящему название формы. Иными словами, форма представляет собой контейнер, в котором хранятся объекты управления.

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

  1. Адрес CGI-скрипта (программы-обработчика, расположенной на некотором сервере), которому будут пересылаться данные из формы. Следует обратить внимание, что при этом выполняется пересылка не всей страницы целиком, а только значений, соответствующих элементам управления формы, которая инициировала запуск программы-обработчика.
  2. Метод передачи данных (наиболее применяемые POST и GET).
  3. Некоторый объект формы, при нажатии на который произойдет пересылка данных. Очень часто в качестве такого объекта выступает кнопка со специальным значением "Submit", которое определяет тип данной кнопки, как объекта, ответственного за отправку данных из формы серверу.

Форма задается в HTML-документе с помощью тега FORM. Все элементы управления находятся внутри контейнера FORM.../FORM.

ег FORM имеет ряд атрибутов. Среди них для CGI-программирования наиболее важны первые два (ими можно ограничиться на начальной стадии написания CGI-программ).

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

Пример_3.2.1. Использование текстового поля и радиокнопки в форме.

Более сложные элементы HTML-формы позволяют задавать:

Ниже приведен вид, в котором приведенная выше HTML-форма отображается на экране.

3.3. ПЕРЕМЕННЫЕ CGI-ОКРУЖЕНИЯ

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

Ниже приведен скрипт, который выводит переменные окружения.

3.4. ОБРАБОТКА ФОРМЫ С ПОМОЩЬЮ CGI-СКРИПТОВ

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

Основная работа такой программы заключается в:

В общем случае CGI-интерфейс будет схематично выглядеть следующим образом:

На входе скрипта имеются данные формы, закодированные методом urlencode. На входе скрипта имеются данные формы, закодированные методом urlencode. Кроме того, скрипт получает от сервера некоторые параметры через переменные среды окружения, которые формируются перед запуском скрипта. В зависимости от метода (GET или POST) данные формы будут помещены в переменную окружения QUERY_STRING или поданы на стандартный ввод STDIN. Узнать какой метод применил пользователь, мы можем, проанализировав переменную REQUEST_METHOD. Данные, веденные в форме, передаются CGI-модулю в формате: Кроме того, скрипт получает от сервера некоторые параметры через переменные среды окружения, которые формируются перед запуском скрипта. В зависимости от метода (GET или POST) данные формы будут помещены в переменную окружения QUERY_STRING или поданы на стандартный ввод STDIN. Узнать какой метод применил пользователь, мы можем, проанализировав переменную REQUEST_METHOD. Данные, веденные в форме, передаются CGI-модулю в формате:

где имяi - значение параметра name из элемента HTML-формы, значениеi - введенное или выбранное значение независимо от его типа.

Алгоритм обработки передаваемой в CGI-скрипт строки данных состоит в разделении ее на пары имя=значение и декодирования каждой пары, учитывая, что все пробелы в введенных значениях в форме сервером были заменены символом "+" и символы с десятичным кодом больше 128 преобразованы в символ "%" и следующим за ним шестнадцатеричным кодом символа.

Так приведенная ранее форма из примера 3.2.1 раздела 3.2 в ответ на ввод данных

передаст в CGI-скрипт последовательность:

При отправке значений элементов формы по умолчанию

в CGI-скрипт будет передана последовательность:

Для реализации взаимодействия "клиент-сервер" важно, какой метод HTTP-запроса использует клиентская часть при обращении к WWW- серверу. В общем случае, запрос - это сообщение, посылаемое клиентом серверу. Первая строка HTTP-запроса включает в себя метод, который должен быть применен к запрашиваемому ресурсу, идентификатор ресурса (URI-Uniform Resource Identifier), и используемую версию HTTP-протокола. Метод, указанный в строке запроса может быть одним из следующих:

Существуют и другие реже используемые методы.

Проблема перекодировки строки не является слишком сложной. Она подразумевает решение довольно простой задачи перевода числа из одной системы счисления в другую (из шестнадцатеричной системы в десятичную). Необходимо учитывать также, что все пробелы при декодировании сервером были заменены символом "+" и все символы с десятичным кодом больше 128 преобразованы в символ "%" и следующим за ним шестнадцатеричным кодом символа.

Процедура значительно облегчается в случае, если вводимые через форму интересуемые значения заведомо являются символами с кодом меньше 128. Фрагмент приведенного ниже CGI-скрипта test.cgi, указанного в атрибуте action формы из примера 3.2.1, обрабатывает данные, введенные пользователем для случая, когда текстовое поле c именем содержит лишь фамилию, записанную английскими буквами.

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

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

3.5 ДОСТУП К ДАННЫМ ИЗ CGI-СКРИПТА, НАПИСАННОГО НА ЯЗЫКЕ ESQL/C

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

Правила работы с базой данных CGI-скрипта, написанного на языке ESQL/C, мало отличается от тех положений, которые описаны в первой части нашего учебного пособия. Работа с базой данных ведется средствами встроенного языка SQL и главных переменных, через которые передаются и возвращаются данные к серверу баз данных.

В основе взаимодействия CGI-программ и базы данных лежат простые принципы:

В данном разделе мы остановимся на тех особенностях, которые необходимо учесть ввиду того, что CGI-скрипт запускается из среды WWW и является, по сути, публичным ресурсом.

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

Предоставление всем пользователям привилегий на доступ к данным

В том случае, когда любой пользователь без ограничений может иметь доступ к данным, проблему целесообразно решить следующим образом:

Предварительно средствами программы phpPgAdmin, либо средствами иного программного приложений владелец базы данных SQL-оператором

grant usage on schema schema-name to nobody

предоставляет пользователю PostgreSQL nobody минимальные права, в том числе в отношении баз данных. Пользователем nobody является, в частности, любой пользователь, работающий в WWW-среде. Это позволяет при написании CGI-скрипта использовать простейший вариант подключения к серверу баз данных без проверки индивидуальных полномочий пользователя.

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

revoke usage on schema schema-name from nobody

Предоставление пользователям индивидуальных привилегий на доступ к данным

В том случае, когда необходимо контролировать доступ того или иного пользователя к базе данных или когда разные пользователи обладают разными полномочиями в отношении доступа к данным, следует проверять эти полномочия при подключении к серверу баз данных. Сделать это можно, как минимум, двумя путями:

grant usage on schema schema-name to nobody

Существует большое количество подходов к решению этой чрезвычайно важной проблемы безопасности, с некоторыми из которых можно познакомиться в [3,17,18].

3. Все действия по работе с базой данных, как уже отмечалось, выполняются средствами встроенного ESQL/C, описанными в первой части данного учебного пособия.

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

Приведем пример CGI-скрипта, который выводит количество и перечень поставок поставщика, имя которого введено в HTML-форме.

5. Дополнительную гибкость приложениям придает динамическое формирование HTML-форм в CGI-скриптах, когда CGI-программа анализирует введенные пользователем данные и порождает новую HTML-форму для ввода дополнительной информации. Делается это посредством той же функции printf(), выводящей в выходной поток атрибуты тега FORM в соответствии с ее синтаксисом и с учетом особенностей форматирования HTML-документа. Особой сложности это не вызывает, однако требует определенной тщательности, учитывая, что в элементах формы могут встречаться символы <',",">, которым должен предшествовать символ обратной наклонной черты.

Подведем некоторые итоги. В настоящее время технология CGI занимает доминирующую позицию в Интернете. К недостаткам CGI можно отнести трудности в решении проблемы безопасности. Слишком много изъянов в защите может появиться при неосторожном использовании. Низка и производительность CGI. Если программа открывает соединение с базой данных, то для нового экземпляра CGI-соединение должно быть открыто заново, что резко ограничивает число CGI-запросов. Однако: