Hello World!’
print ‘You are %s (%s)’ % (name, email)
Стало стандартной практикой завершать заголовки HTTP последователь-
HTTP последователь- последователь- ностью символов ‘\r\n’ завершения строки в стиле Windows. Именно по этой причине в примере выполняется вывод символа ‘\r’. Если программе потребуется сообщить об ошибке, можно добавить вывод специального за- головка ‘Status:’. Например:
print ‘Status: 401 Forbidden\r’ # Код ошибки HTTP
print ‘Content-type: text/plain\r’
print ‘\r’ # Пустая строка (обязательно)
print ‘You’re not worthy of accessing this page!’
Если необходимо переадресовать клиента на другую страницу, можно соз- дать такой вывод:
print ‘Status: 302 Moved\r’
print ‘Location: http://www.foo.com/orderconfirm.html\r’
print ‘\r’
Основная работа выполняется модулем cgi при создании экземпляра клас- са FieldStorage.
[, headers [, outerboundary [, environ [, keep_blank_values
[, strict_parsing]]]]]])
Читает содержимое формы, анализируя строку запроса, переданную через переменную окружения или через поток стандартного ввода. Аргумент in-
put
определяет объект, похожий на файл, из которого будет выполняться чтение данных формы, полученных в составе запроса POST. По умолчанию используется объект sys.stdin. Аргументы headers и outerboundary использу-
Модуль cgi
665ются для внутренних нужд и не должны указываться в вызове конструкто- ра. В аргументе
environ передается словарь, содержащий переменные окру- жения для CGI-сценария. В аргументе
keep_blank_values передается логи- ческий флаг, разрешающий сохранение пустых значений. По умолчанию принимает значение False. В аргументе
strict_parsing передается логиче- ский флаг, разрешающий возбуждение исключения в случае обнаружения ошибок при анализе. По умолчанию принимает значение False.
Экземпляр
form класса FieldStorage действует как словарь. Например, ин- струкция
f =
form[
key] извлечет информацию о параметре
key. Экземпляр
f,
полученный таким способом, будет либо еще одним экземпляром класса
FieldStorage
, либо экземпляром класса MiniFieldStorage. Ниже перечислены атрибуты, которыми обладает экземпляр
f:
АтрибутОписаниеf.name
Имя поля, если указано
f.filename
Имя выгружаемого файла на стороне клиента
f.value
Значение в виде строки
f.file
Объект, похожий на файл, с помощью которого можно читать данные
f.type
Тип содержимого
f.type_options
Словарь с параметрами, указанными в заголовке content- type
HTTP-запроса
f.disposition
Значение заголовка ‘content-disposition’; None – если не указан
f.disposition_options
Словарь с параметрами, указанными в заголовке ‘content- disposition
f.headers
Объект,
похожий на словарь, содержащий все заголовки
HTTP
Значения полей формы могут извлекаться с помощью следующих методов:
form.getvalue(fieldname [, default])Возвращает значение поля с именем
fieldname. Если поле определено дваж- ды, этот метод вернет список всех значений. Аргумент
default определяет значение, возвращаемое в случае отсутствия указанного поля. Будьте вни- мательны: если одно и то же имя поля включено в запрос дважды, этот метод вернет список, содержащий оба значения. Чтобы упростить работу с такими значениями, можно использовать метод
form.getfirst(), который возвращает первое найденное значение.
form.getfirst(fieldname [, default])Возвращает первое значение поля с именем
fieldname. Аргумент
default определяет значение, возвращаемое в случае отсутствия указанного поля.
666Глава 23. Веб-программирование
form.getlist(fieldname)Возвращает список всех значений поля с именем
fieldname. Этот метод все гда возвращает список, даже если поле имеет единственное значение.
В случае отсутствия значений возвращает пустой список.
Дополнительно модуль cgi объявляет класс MiniFieldStorage, содержащий только атрибуты name и value. Этот класс используется для представления отдельных полей формы, переданных в строке запроса, тогда как класс
FieldStorage используется для представления набора полей и для представ- ления полей с несколькими значениями.
Экземпляры класса FieldStorage действуют, как словари Python, в кото-
Python, в кото-
, в кото- рых ключами являются имена полей формы. При обращении к ним таким способом они возвращают объекты, которые сами являются экземпляра- ми класса FieldStorage – в случае полей с несколькими значениями (тип содержимого ‘multipart/form-data’) или полей с выгружаемыми файлами.
В случае простых полей (тип содержимого ‘application/x-www-form-urlencod- application/x-www-form-urlencod-
/x-www-form-urlencod- x-www-form-urlencod-
-www-form-urlencod- www-form-urlencod-
-form-urlencod- form-urlencod-
-urlencod- urlencod- ed’
) возвращаются экземпляры класса MiniFieldStorage или
списки экзем- пляров этого класса, если форма содержит несколько полей с одинаковыми именами. Например:
form = cgi.FieldStorage()
if “name” not in form:
error(“Name is missing”)
return name = form[‘name’].value # Вернет поле ‘name’ формы email = form[‘email’].value # Вернет поле ‘email’ формы
Если поле представляет выгружаемый файл, операция обращения к атри- буту value прочитает все содержимое файла и сохранит его в памяти в виде строки байтов. Так как это может приводить к потреблению существенных объемов памяти на стороне сервера, предпочтительнее читать содержимое файла небольшими фрагментами, с помощью атрибута file. Например, в следующем примере демонстрируется построчное чтение выгружаемого файла:
fileitem = form[‘userfile’]
if fileitem.file:
# Это выгружаемый файл; подсчитать строки linecount = 0
while True:
line = fileitem.file.readline()
if not line: break linecount = linecount + 1
Ниже перечислены вспомогательные функции, которые часто используют- ся в CGI-сценариях:
escape(s [, quote])Преобразует символы ‘&’, ‘< и ‘>’, присутствующие в строке
s, в соответству- ющие сущности языка разметки HTML, такие как ‘&’, ‘<’ и ‘>’.
Модуль cgi
667Е
сли в необязательном булевском аргументе
quote передается истинное зна- чение, символ двойной кавычки (“) также замещается сущностью ‘"’.
parse_header(string)Анализирует данные, следующие за именем HTTP-заголовка, такого как
‘content-type’
. Возвращает кортеж, содержащий основное значение и сло- варь с параметрами. Например, вызов parse_header(‘text/html; a=hello; b=”world”’) вернет:
(‘text/html’, {‘a’:’hello’, ‘b’:’world’}).
parse_multipart(fp, pdict)Анализирует входные данные типа ‘multipart/form-data’, которые обыч- но представляют выгружаемый файл. В аргументе
fp передается входной файл, а в аргументе
pdict – словарь с параметрами из заголовка ‘content- type’
. Возвращает словарь, отображающий имена полей в списки значений.
Эта функция не обрабатывает вложенные части ‘multipart/*’. Для работы с такими полями следует использовать класс FieldStorage.
print_directory()Преобразует имя текущего рабочего каталога в формат HTML и выводит его. Вывод отправляется обратно броузеру клиента. Может использоваться для отладки.
print_environ()Создает список всех переменных окружения в формате HTML. Может ис-
HTML. Может ис-
. Может ис- пользоваться для отладки.
print_environ_usage()Выводит список наиболее полезных переменных окружения в формате
HTML. Может использоваться для отладки.
print_form(form)Форматирует данные, полученные в составе формы. В аргументе
form дол- жен передаваться экземпляр класса FieldStorage. Может использоваться для отладки.
test()Выводит минимальный HTTP-заголовок и всю переданную программе ин-
HTTP-заголовок и всю переданную программе ин-
-заголовок и всю переданную программе ин- формацию в формате HTML. В основном используется для отладки, позво-
HTML. В основном используется для отладки, позво-
. В основном используется для отладки, позво- ляя убедиться, что окружение CGI настроено корректно.
Советы по созданию CGI-сценариевПри нынешнем уровне развития веб-фреймворков разработка CGI-сцена- риев выходит из моды. Однако если у вас появится потребность в их соз- дании, следующие несколько советов помогут вам упростить эту работу.
Во-первых, не используйте большое количество инструкций print для вы- вода жестко определенной разметки HTML. В противном случае програм-
HTML. В противном случае програм-
. В противном случае програм-
668Глава 23. Веб-программирование ма превратится в жуткую смесь инструкций языка Python и разметки
HTML,
которую не только невозможно читать, но и невозможно поддержи-
, которую не только невозможно читать, но и невозможно поддержи- вать. Лучше всего использовать шаблоны. Для этого можно использовать объекты string.Template. Ниже приводится пример, демонстрирующий ис- пользование этого подхода:
import cgi from string import Template
ёёё
def error(message):
temp = Template(open(“errormsg.html”).read())
print ‘Content-type: text/html\r’
print ‘\r’
print temp.substitute({‘message’ : message})
ёёё
form = cgi.FieldStorage()
name = form.getfirst(‘name’)
email = form.getfirst(‘email’)
if not name:
error(“name not specified”)
raise SystemExit elif not email:
error(“email not specified”)
raise SystemExit
ёёё
# Выполнить обработку данных confirmation = subscribe(name, email)
ёёё
# Вывести содержимое страницы values = {
‘name’ : name,
‘email’ : email,
‘confirmation: ‘: confirmation,
# Здесь можно добавить другие значения
...}
temp = Template(open(“success.html”).read()
print temp.substitute(values)
В этом примере используются файлы ‘error.html’ и ‘success.html’, кото- рые содержат всю необходимую разметку HTML, но включают символы подстановки вида $
variable, соответствующие значениям, генерируемым в CGI-сценарии. Например, содержимое файла ‘success.html’ могло бы вы- глядеть примерно так: