Cgi pm библиотека cgi для perl 5


Содержание

Язык Perl и CGI-программирование

2. Анализ и обработка полученной информации. Данные, извлеченные из HTML-формы, передаются для обработки CGI-программе. Они не всегда могут быть обработаны CGI-программой самостоятельно. Например, они могут содержать запрос к некоторой базе данных, которую CGI-программа читать «не умеет». В этом случае CGI-программа на основании полученной информации формирует запрос к компетентной программе, выполняющейся на том же компьютере. CGI-программа может быть написана на любом языке программирования, имеющем средства обмена данными между программами. В среде UNIX для этой цели наиболее часто используется язык Perl. Так как UNIX является наиболее популяр-

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

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

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

(Различные аспекты передачи данных Web-серверу будут рассмотрены в разделе 15.3.)

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

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

Cgi pm библиотека cgi для perl 5

Архивы самого языка Перл и его библиотек распространяются свободно и доступны через сайты CPAN. Библиотеки Перла называются модулями (стандартное расширение .pm), а сами программы — скриптами. И модули, и скрипты являются текстовыми файлами.

Для установки языка Перл необходимо иметь в системе компилятор С (желательно, gcc). Распаковать архив с языком (на текущий момент 27.11.99 это perl5.005_03.tar.gz). В каталоге, куда распаковался архив, выполнить следующие команды:

По умолчанию perl установится в /usr/local (исполнимые файлы — в /usr/local/bin/, библиотеки — в /usr/local/lib/perl5/, документы справочника man — в /usr/local/man (по самому языку) и в /usr/local/lib/perl5/5.00503/man (по библиотекам). Следует добавить соответстующие пути в переменные окружения PATH и MANPATH (в файле .profile).

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

Перл поставляется с несколькими стандартными модулями. Для работы с CGI требуется взять из CPAN и установить следующие библиотеки (в указанном порядке):

  1. Digest-MD5
  2. MIME-Base64
  3. URI
  4. HTML-Parser
  5. libnet
  6. libwww-perl
  7. CGI

Установка каждой библиотеки производится командой поданной в каталоге, куда распаковаля архив библиотеки. Для выполнения последней части команды (make install) требуются привилегии суперпользователя.

Библиотеки устанавливаюися в дерево /usr/local/lib/perl5/. Документы man по установленным библиотекам находятся в /usr/local/lib/perl5/5.00503/man.

Минимальное введение в Перл

В этом разделе дана минимальная необходимая информация по тем элементам Перла, которые чаще всего используются при написании скриптов. Перл здесь рассматривается как С-подобный язык, поэтому акцентируются отличия от С. Этот раздел ни в коей мере не претендует на описание языка Перл (многие моменты сознательно опущены); для этой цели обратитесь к Camel Book, Llama Book или книге Маслова.

Комментарий «отсюда и до конца строки» — символ «#».

Типы переменных

Переменные бывают трех типов: скаляры, списки и хэши. Описывать переменные не нужно, если только вы не используете директиву «use strict»; иначе каждая переменная должна быть описана с помощью «my имя_переменной«.

Скаляр содержит одно значение; это может быть строка или число, Перл сам определяет тип значения по контексту проводимых со скаляром операций. Например, при попытке конкатенировать два скаляра операцией «.» они будут рассмотрены как строки, а при попытке сложить их значения операцией «+» — как числа. При проведении числовых операций над строками, значение которых не может быть интерпретировано как число, числовое значение такого скаляра считается нулевым (см. также ниже п. Операторы, выражения и операции).

Повтор специально для программистов на С : строковые значения не оканчиваются на символ «\0». Строковых значений как таковых вообще не существует, строка — это один из двух способов интерепретации значения скаляра, который сам по себе ни на что особенное не заканчивается.

Имена всех скалярных переменных обязаны начинаться на $ ($x, $my_variable_1).

Имеется специальное скалярное значение undef — «неопределенность». Такое значение имеют, например, переменные, которым не было присвоено никакого значения. В логических и арифметических операциях undef считается нулем, в строковых операциях — пустой строкой. Функция defined(выражение) возвращает истину, если выражение не равно undef (хотя может быть равно нулю).

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

Переменная, значением которой является список, называется массивом (array). Имена всех массивов обязаны начинаться с @ (@array). При обращении к элементу массива знак @ заменяется на $: (смысл: элемент массива — это скаляр, следовательно он начинается с $). Примеры формирования массивов: Количество элементов в массиве: scalar @array (см. также п. «Контексты» ниже); индекс последнего элемента: $last_index = $#array.

Извлечение части массива: Соответственно, наоборот: производит присвоение значений части массива @array (если элементы @array[0-2] ранее отсутствовали, они создаются со значениями undef).

Двух- и более мерные массивы в явном виде не поддерживаются.

Функции для работы с массивами:

— возвращает список, состоящий из значений массива @array, взятых в обратном порядке (сам массив @array не изменяется). Аргументом функции reverse может быть не только массив, но любое выражение, имеющее списочное значение.

— помещает значение или список значений в конец массива. Список может быть как явным перечислением значений через запятую, так и любым выражением, имеющим списочное значение. Функция push возвращает новую длину массива @array.

— извлекает из массива последний элемент (элемент из массива удаляется). Если массив не указан — подразумевается список аргументов функции (т.е. массив @_), если вызов произведен внутри какой-либо функции, или аргументы командной строки скрипта (т.е. массив @ARGV), если вызов произведен из основной части скрипта.

— извлекает из массива первый элемент (элемент из массива удаляется). Если массив не указан — подразумевается список аргументов функции (т.е. массив @_), если вызов произведен внутри какой-либо функции, или аргументы командной строки скрипта (т.е. массив @ARGV), если вызов произведен из основной части скрипта.

— аналогично push, но новые элементы помещаются в начало массива @array.

— удаляет из массива @array $length элементов, начиная с индекса $from. Если присутствует список, то вместо удаленных элементов помещаются значения из списка; если их больше, чем удаленных, то массив увеличивается, если меньше — то соответственно уменьшается. Если $length отсутствует, то удаляются все элементы, начиная с индекса $from. Индекс $from может быть отрицательным — тогда счет производится с конца, т.е. splice(@array,-2) удаляет два последних элемента из массива @array, а splice(@array,-2,1) удаляет предпоследний элемент. Функция splice возвращает список удаленных из массива элементов. Функции push, pop, unshift и shift являются частными случаями функции splice.

Переменная-хэш представляет собой массив, элементы которого индексируются строками (ассоциативный массив). Порядок хранения элементов в хэше не определен. Имена всех переменных-хэшей обязаны начинаться на % (%my_hash). При обращении к элементу списка знак % заменяется на $ и используются фигурные скобки: Хэши могут быть сформированы с помощью объединения четного числа скаляров в скобки: Вообще, любой список (массив) может быть рассмотрен в качестве хэша, т.е. %hash=@array. При этом нечетные элементы списка станут ключами хэша, а четные — соответствующими значениями. Если число элементов в списке нечетное, то последний элемент сконструированного таким образом хэша будет существовать со значением undef («неопределенность»). Если в списке есть одинаковые элементы на нечетных позициях, то в хэш будет внесено значение, ключом которого является последний из одинаковых нечетных элементов списка.

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

Функции для работы с хэшами:

— возвращает список ключей хэша (порядок неопределен).

— возвращает список значений хэша (порядок неопределен, но для одного и того же хэша всегда совпадает с порядком выдачи ключей функцией keys).

— возвращает список из двух скаляров: ключ и значение очередного элемента хэша; используется в циклах для прохода по всем элементам хэша.

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

— удаляет указанный элемент хэша.

— меняет местами ключи и значения элементов хэша; работает корректно в случае, если в хэше %hash не было элементов с одинаковыми значениями.

Операторы, выражения и операции

Операторы, выражения и операции Перла во многом аналогичны языку С. Ниже рассмотрены отличия.

Каждое выражение в Перл вычисляется в списочном, либо скалярном контексте. То есть в списочном контексте предполагается, что значение выражения должно быть списком, а в скалярном — скаляром. Контекст определяется, например, типом переменной, стоящей в левой части оператора присвоения. Многие функции определяют контекст, в котором они были вызваны и возвращают разные результаты в зависимости от контекста. Например, функция localtime (текущее местное время) в скалярном контексте возвращает строку вида «Fri Nov 26 20:36:33 1999», а в списочном контексте — список из чисел: секунды, минуты, часы, день месяца, месяц и т.д. Для того чтобы форсировать скалярный контекст, можно использовать оператор scalar.

Значением списка в скалярном контексте является длина списка: Значением скаляра в списочном контексте является список, состоящий из одного этого скаляра.

Значения выражений и операции

Большинство арифметических и логических операций аналогично операциям языка С (в том числе операции типа $x++; ++$x; $x += 5; $x=$y=5). Различия рассмотрены ниже.

Результат многих операций может быть рассмотрен как истинное (ненулевое) или ложное (нулевое или неопределенное) значение. Можно использовать операции «И» («&&» или «and») и «ИЛИ» («||» или «or») для выстраивания цепочки действий, которые выполняются в зависимости от успеха (истинного значения) или неуспеха предыдущего действия. Это позволяет сократить запись (иначе пришлось бы использовать оператор if).

Имеется ряд операций для работы со скалярами как со строками. Операция «.» (точка) вызывает конкатенацию строк: Сравнения скаляров как строк выполняются следующими операциями:

$a eq $b Истинно, если $a и $b одинаковы
$a ne $b Истинно, если $a и $b неодинаковы
$a lt $b Истинно, если $a раньше по алфавиту, чем $b
$a gt $b Истинно, если $a позже по алфавиту, чем $b
$a le $b Истинно, если $a раньше по алфавиту или совпадает с $b
$a ge $b Истинно, если $a позже по алфавиту или совпадает с $b
$a cmp $b -1, если $a раньше по алфавиту, чем $b; 0, если $a и $b одинаковы; 1, если $a позже по алфавиту, чем $b

Внимание, распространенная ошибка! Операции «== != > = «2», но «2»gt»11″. Более того, $a=»xyz»; $b=»qwerty»; $a==$b — истинно, поскольку как числа обе этих переменных равны нулю.

Дополнительная операция для сравнения скаляров как чисел: $x $y равно -1, если $x $y.

Если в выражении не указано, откуда берутся или куда возвращаются данные, то подразумевается, что речь идет о переменной $_ (в скалярном контексте) или о @_ (в списочном контексте).

Имеются аналогичные языку С операторы Отличия и дополнения рассмотрены ниже.

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

Скобки вокруг аргументов стандартных функций не требуются (если только не возникает неоднозначностей):

Оператор foreach производит цикл по всем элементам списка:

Оператор unless — это оператор if с отрицанием: Будьте внимательны при программировании сложных условий с помощью unless — помните теорему де Моргана: отрицание произведения есть сумма отрицаний; отрицание суммы есть произведение отрицаний.

Оператор until — это оператор while с отрицанием: соответственно и do <. >until(. ).

Оператор switch отсутствует. Пользуйтесь конструкцией if () . elsif () . elsif () . else . или изобретайте что-то свое.

Управление циклами:

  • досрочный переход на следующую итерацию ближайшего объемлющего цикла — next (аналог оператора continue в С):
  • досрочный выход из ближайшего объемлющего цикла — last (аналог оператора break в С):
  • каждый цикл может быть снабжен меткой, на которую могут ссылаться операторы next и last; это позволяет производить выход сразу из нескольких объемлющих циклов:

Кавычки и интерполяция

Строковые выражения заключаются в одинарные (‘) или двойные («) кавычки. Везде внутри двойных кавычек производится подстановка переменных — скаляров, элементов списков и элементов хэшей; целые списки подставляются как подстрока в которой все элементы списка следуют друг за другом без разделителя; хэши целиком не подставляются. Для экранирования спецсимволов внутри двойных кавычек используется обратный слэш: \$, \@, \», \\; также распознаются все спецсимволы языка С: \n, \t и т.п.

Строки, употребляемые как ключи хэшей, если это буквальные строки без подстановок («abc»), в кавычки можно не заключать: $hash.

Внутри одинарных кавычек никакие подстановки не производятся, спецсиволы типа «\n» не интепретируются и все символы воспринимаются буквально; исключение: комбинация \’ (обратный слэш — одинарная кавычка), которая интепретируется как одинарная кавычка, являющаяся частью строки. Одинарная кавычка внутри двойных кавычек воспринимается буквально.

Работа с регулярными выражениями

Регулярные выражения (РВ) Перла — надмножество РВ grep/awk, используемых в Unix. В РВ следующие символы имеют специальное значение:

— любой единичный символ, кроме \n (если только не используется модификатор s — см. ниже).

— ноль или более появлений РВ, непосредственно предшествующего этому символу.

— одно или более появлений РВ, непосредственно предшествующего этому символу.

— ноль или одно появлений РВ, непосредственно предшествующего этому символу.

— один символ из (не)перечисленных внутри скобок. Все метасимволы внутри квадратных скобок теряют свое специальное значение, кроме символа «^», если он находится непосредственно после открывающей скобки (в этом случае он обозначает отрицание набора символов); если символ «^» находится не сразу после открывающей скобки, он воспринимается буквально. Если символ «]» находится непосредственно за открывающей скобкой или непосредственно за комбинацией «[^», он воспринимается буквально, а не как закрывающая скобка; в этом случае должна быть еще одна закрывающая скобка.

— группировка регулярного выражения РВ. Используется в том числе и для последующей ссылки на часть строки, которая соответствует РВ.

— операция «ИЛИ» — требуется срабатывание хотя бы одного из РВ, находящихся слева и справа от символа «|».

— любой пробельный символ (то же, что [ \t\n\r\f]).

— любой алфавитно-цифровой символ (то же, что [a-ZA-Z_0-9]).

— любая цифра (то же, что [0-9]).

— отрицание регулярных выражений, соответственно, \s, \w, \d, \w.

— подстановка значения переменной.

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

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

  • i — игнорировать различие прописных и строчных букв (в общем случае — только для латиницы),
  • s — воспринимать скалярное выражение, подлежащее обработке, как состоящее из нескольких строк, разделенных символами \n (т.е. метасимволы ^ и $ будут срабатывать на символах \n, которые возможно встретятся внутри обрабатываемого скалярного выражения),
  • m — воспринимать скалярное выражение, подлежащее обработке, как одну строку, независимо от того, встречаются ли внутри этого выражения символы \n или нет (т.е. метасимволы ^ и $ не будут срабатывать на символах \n, но метасимвол . будет срабатывать на \n).

Обратите внимание, что метасимволы $, ^, \b не поглощают символы обрабатываемой строки, т.е. например, ^ — это не первый символ строки, а начало строки как таковое; аналогично, \b — это не первый или последний символ слова, а граница между символами типа \W и \w. Иначе говоря, слово cat соответствует РВ /^c/, а слово act ему не соответствует; или в строке «a yellow cat» регулярному выражению /\byellow\b/ соответствует подстрока «yellow», а не » yellow » или «ello».

Поиск РВ в строке: Операция возвращает в скалярном контексте «Истинно», если строка $s (не) соответствует РВ, иначе возвращается «Ложно». Если $s не указано, используется $_.

Замена части строки: Операция производит поиск подстроки строки $s, соответствующей РВ, после чего заменяет эту подстроку на замену. Если указан модификатор g, то заменяются все подстроки, соответствующие РВ, иначе заменяется только первая найденная подстрока. Операция возвращает количество произведенных замен. Если $s не указано, используется $_. Подстановку переменных можно использовать и в РВ, и в замене. В части замена можно использовать также спецсимволы $1,$2. которые произведут подстановку соответствующей части РВ, взятой в скобки. Примеры:

Работа с файлами и запуск других программ

Чтение и запись файлов осуществляется через переменную-дескриптор файла. Имя такой переменной не имеет специального префикса и, как правило, записывается прописными буквами. Дексриптор создается при вызове функции open. Дескрипторы файлов не требуется предварительно объявлять даже при использовании «use strict».

Открытие файла Функция open возвращает «ложно» в случае невозможности открыть файл, в этом случае выполняется функция die, которая выводит свой аргумент на печать и завершает работу скрипта. Переменная S! — стандартная переменная Перла, содержит описание последней возникшей системной ошибки.

FILE — дескриптор файла, он будет использован ниже в операциях чтения, записи и закрытия файла.

В приведенном примере файл filename открывается для чтения. Для открытия файла на запись с нуля его имя нужно предварить символом «>» (если файл до этого существовал, его содержимое пропадет); для открытия на добавление в конец — предварить символами «>>»: Для любого скрипта при его запуске по умолчанию открываются дескрипторы STDIN, STDOUT и STDERR.

Оператор производит чтение из файла с дескриптором FILE. В скалярном контексте (например, в условии цикла while) оператор при кадом вызове возвращает очередную строку текста до следующего символа перевода строки включительно. В списочном контексте возвращается список всех текстовых строк от текущей позиции до конца файла.

Внимание, распространенная ошибка! Строка, считанная из файла, скорее всего оканчивается на символ перевода строки (если только это не последняя строка в файле и при этом файл не заканчивается переводом строки). Про этот символ часто забывают и пытаются сравнивать считанное значение с неким другим значением, не содержащим, разумеется, перевода строки. Используйте функцию chomp для того, чтобы избавиться от этого символа на конце строки.

Еще одна распространенная ошибка! Оператор <> (внутри скобок пусто) считывает не из стандартного ввода, а из файлов, имена которых указанны как аргументы командной строки. При завершении одного файла ввод продолжается с начала следующего файла в том порядке, в каком имена файлов указаны в командной строке. Открывать файлы при использовании оператора <> не требуется.

Хотя при выходе из скрипта Перл и закрывает все незакрытые файлы, настоятельно рекомендуется делать это явным вызовом функции close во избежание различных побочных эффектов.

Для передачи данных в стандартный ввод другой программы нужно создать с помощью open соответствующий дескриптор файла (при этом программа будет запущена) и вывести в него данные. Для создания такого дескриптора вторым аргументом в функцию open передается путь к программе, предваренный символом «|»:

Для приема данных из стандартного вывода другой программы нужно создать с помощью open соответствующий дескриптор файла (при этом программа будет запущена) и ввести из него данные. Для создания такого дескриптора вторым аргументом в функцию open передается путь к программе, после которого следует символ «|»:

Переименование, удаление файла и изменение его атрибутов

Запуск другой программы

Для выполнения другой программы из скрипта используется функция system, аргументом которой является список argc[] (т.е. командная строка вывываемой программы, начинающаяся с имени самой программы). Функция возвращает 0 при успешном завершении вызванной программы и X*256, если статус выхода программы был X.

Работа со строками

В этом пункте описаны некоторые полезные функции Перла для работы со строками (функции для работы с регулярными выражениями рассмотрены выше).

Функция split разбивает скалярное значение, интерпретируемое как строка, на части, используя указанный разделитель, и возвращает результат в виде списка.

Лимит указывает, что строка будет разбита не более, чем на лимит частей (иными словами, будут восприняты только первые лимит-1 разделителей; весь остаток будет возвращен в последнем элементе списка). Если лимит отсутствует, то все встретившиеся в строке разделители будут участвовать в разбиении.

Если строка отсутствует, обрабатывается $_.

Разделитель может быть регулярным выражением (заключается в слэши: /РВ/) или буквальной строкой (заключается в кавычки: ‘строка‘). Если разделитель отсутствует, то подразумевается /\s+/ («один или более пробельных символов подряд»); т.е. split без аргументов экивалентен «split /\s+/, $_».

Формирование строки из списка элементов

Функция join формирует скаляр-строку, состоящую из элементов списка, отделяя значения элементов друг от друга разделителем.

sprintf
Функция sprintf работает так же, как в языке С.

Поиск подстроки в строке

index Функция index возвращает позицию в строке, с которой начинается подстрока (имеется в виду первое вхождение подстроки, если их несколько). Если указана начальная позиция, то поиск начинается с этой позиции, иначе — с начала строки. Позиции в строке нумеруются, начиная с нуля. Если подстрока не найдена, функция возвращает -1.

Функция rindex аналогична index, но возвращает позицию последнего вхождения подстроки в строку. В этом случае третий аргумент, если он указан, определяет позицию, на которой поиск следует прекратить.

Извлечение подстроки из строки в известной позиции Функция substr извлекает из строки подстроку длиной длина, начинающуюся с позиции смещение. Если длина не указана, то подстрока извлекается от смещения до конца строки. Позиции в строке нумеруются, начиная с нуля.

Если смещение отрицательно, то оно отсчитывается не от начала, а от конца строки. Если длина отрицательна: длина=-N, то это значит, что извлекается подстрока такой длины, что она заканчивается за N символов до конца строки.

Вставка/замена части строки в известной позиции

Для вставки подстроки в строку или замены одной подстроки другой подстрокой используется функция substr в левой части оператора присвоения. В этом случае первый аргумент функции substr обязан быть скалярным выражением, которому можно присвоить значение — скалярной переменной, элементом массива или элементом хэша. Примеры (перед каждым примером предполагается, что $a=»abcdef»):

Вышеприведенные операции можно понимать так: из переменной $a извлекается указанная подстрока, а потом вместо нее в этой же позиции вставляется слово «HELLO».

Если аргументы вышеприведенных не указаны, подразумевается $_.

Написание функций

Функции описываются в любом месте скрипта с помощью конструкции и вызываются обычным образом: Скобки при вызове написанных пользователем функций обязательны.

Количество и тип аргументов не декларируются и могут быть любыми и различными при последовательных вызовах одной и той же функции; все аргументы при передаче в функцию объединяются в единый список; внутри функции все аргументы доступны через массив @_ в том порядке, в каком они были указаны при вызове функции. Если аргументов не было, то массив @_ пуст. Хэш, переданный в качестве аргумента, преобразуется в список (о взаимоотношениях списков и хэшей см. выше п. «Типы переменных. Хэши»).

Каждая функция возвращает значение. Это может быть сделано явно с помощью оператора return, аргументом которого является скаляр или список. Если оператор return не встретился до конца функции, то возвращается значение последнего вычисленного выражения. Возвращаемое любой функцией значение может быть как использовано, так и проигнорировано вызывающей программой.

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

Для определения того, в каком контексте была вызвана функция, внутри нее используется оператор wantarray, возвращающий истину, если данная функция была вызвана в списочном контексте. Рассмотрим пример функции, которая возвращает список в списочном контексте и первый элемент списка — в скалярном.

Оглавление:

Пару слов от автора

Что меня заставило взятся за этот нелегкий труд написания данного учебного пособия. Ну во первых то что практически НЕТ ничего по CGI-програмированию на русском языке, а большинству тех,кто хотел бы изучить CGI, документация на английском в отличии от тех немногих типа меня практически недоступна для понимания.Чтоб помочь им преодолеть этот в первую очередь языковый барьер я и сел писать эту книгу.
Еще причина ,отчасти перекликающаяся с первой, это то что когда говорят об интернет-программировании обычно излагают HTML со всеми тэгами, которые всем уже по ночам в кошмарах снятся ,ну а после чего начинают долго охать и ахать над прелестями нового аппаратно и платформо-независимого, переносимого, безопасного. и.т.д. языка Java.Иногда в еще и могут тонким краешком затронуть JavaScript.Видя эту не побоюсь этого слова безнадежную ситуацию, я как доблестный CGI-программист решил хоть что-то поправить к лучшему. Если у меня это хоть немного удалось, то напишите мне.
Если также у вас есть какие-то вопросы -тоже пишите, я с радостью постараюсь ответить на них всех.

Краткое лирическое отступление насчет CGI

Итак что такое CGI— скрипты и вообще подобные вещи. Начнем с того что ваш браузер (когда вы набрали URL) соединяется по протоколу HTTP с указаным сервером и просит у него нужный файл,примерно так:

Вот это самое главное в запросе

Ну тут дальше идет посылаемая браузером информация о себе и о том что более подробно ему надо.(Например Accept: */*)

Ну и если запрошен простой файл например .html то если если такой файл есть, То сервер отошлет браузеру ответ:

В ответе , состоящем из зоголовка и тела, в заголовке содержится код возврата и информация о типе содержимого. Далее после пустой строки (она нужна чтоб отделить заголовок от тела) идет информация из самого документа , по заданому URL .
Вот в принципе и весь WWW . ходишь от ссылки к ссылке.
А что если Нужно внести в этот унылый процесс что-нибудь по настоящему интерактивное , динамическое,прекрасное и великолепное. Чтож есть ответ и на этот вопрос. Просто что если в запрашиваемом URL указать специальную программу (CGI,программа Common Gateway IntefaceОбщего Шлюзового Интерфейса) и то что эта прога выдаст то и отправитьс браузеру. Сервер запускает .cgi программу и она например обработав данные формы заносит вас куда-нибудь в свою базу данных,а вам сообщит что вы большой молодец :)
Ну надеюсь я вас заинтриговал.

Итак . приступим.

Краткие сведения о том что надо знать чтоб писать CGI скрипты:
Ну вопервых надо знать что такое интернет и как он работает (а вы знаете? ;))) ) Ну и чуть-чуть умения програмировать(это самое главное)

На кого ориентировано данное учебное пособие -спросите вы ? Ну в принципе на достаточно широкую аудиторию тех, кто занимается Интернет-программированием и кто хотел бы освоить премудрости интерфейса CGI. Данная книга будет весьма полезна для web-дизайнеров, системных администраторов интернет-серверов, программистов и для простых пользователей интернет, которые хотели бы сделать свой сайт по-настоящему достойным называться хорошим сайтом.
Так как интернет в основном строится на операционной системе UNIX , то изложеный сдесь материал может быть без особых модификаций реализован на практически любой UNIX-системе.
Кроме того, я также делаю предположение , что ваш web-сервер поддерживает интерфейс CGI и для вас эта поддержка включена. (на «халявных» серверах администраторы отключают CGI и SSI для пользовательских директорий — просто это такая политика — предоставлять только ОЧЕНЬ МИНИМАЛЬНЫЙ сервис.) Так что если вы хотите изучать CGI то вам нужет нормальный ,полнофункциональный сервер. Если же вы сами являетесь системным администратором на своем сервере , то для вас, естественно нет проблем, ведь включить CGI для какой-нибудь директории — это просто подправить одну строчку в файле конфигурации сервера.

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

Давайте вместе писанем какой нибудь простенький скриптик а потом я вам расскажу где сдесь собака порылась.
Ну сначала в своем домашнем каталоге создайте директорию cgi-bin:

cd public_html
mkdir cgi-bin
chmod 0777 cgi-bin

Последняя строчка будет очень важна.
Возьмите редактор и наберите:
Сохраните его в директории cgi-bin под именем first.cgi .Ну как сохранили?
А теперь сделайте его исполняемым(ведь это программа):

chmod +x first.cgi


Ну вот,подходим к торжественному моменту. наберите в строке браузера http://www.ваш.сервер.ru/

ваш_логин/cgi-bin/first.cgi
и посмотрите чо будет. Будет одно из двух ,либо скрипт заработает и вы увидите сгенерированую им страничку (поздравляю,в нашем полку прибыло!) либо Internal Server Error -тогда не расстраивайтесь,вы что-то сделали не так.
Вам тогда пригодится пособие по ловле блох.
Ну вопервых проверку синтаксиса можно осуществить следующим образом:

perl -с first.cgi

Perl вам сразу выдаст либо сообщения об ошибках(ну бывает,точку с запятой пропустили, скобочки или кавычки забыли закрыть. ) это сразу по ходу дела поправимо.
Более грубая с логической точки зрения это пропустить вывод пустой строки, которая отделяет заголовок от тела:

Разберем скрипт:
Первая строка #!/usr/bin/perl Просто указывает где в системе расположен компилятор Perl. Обычно он находится /usr/bin/perl или /usr/local/bin/perl ,выяснить это можно одной из комманд или ну или (что очень долго) запустить полный поиск .
Вторая строка это просто коментарий -вы можете тыкать чо угодно после знака #, однако я пишу обычно во второй строке название скрипта, что очень удобно.
Затем идет print «Content-Type: text/html\n\n»; Это заголовок указывающий тип содержимого.
Все что скрипт печатает в свой стандартный вывод STDOUT идет на обработку к серверу. Пустая строка отделяет заголовок от тела,которое в нашем случае представляет собой
Сервер обработает ответ скрипта и на базе него сформирует и пошлет браузеру ответ.(Сервер обычно не изменяет тела сообщения,он только дополняет заголовок нужными для работы протокола HTTP полями)

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

Переменные среды CGI

Предыдущий скрипт не содержал ничего особенно замечательного,так просто вываливал HTMLый текст который благополучно и отбражался на экране браузера.Но По настоящему мощь придает CGI возможность обработки параметров,которые переданы скрипту.например вы можете набрать
http://www.somehost.ru/somedir/cgi-bin/my_cgi.cgi?param=value
то есть вы хотите чтоб скрипт my_cgi.cgi обработал для вас параметер param со значением value (ну это например) или когда вы заполнили запрос в форме (в например yahoo или altavista).Ну это с точки зрения пользователя. А на сервере при запуске CGI-скрипта сервер формирует среду окружения в которой скрипт может найти всю доступную информацию о HTTP-соединении и о запросе.
Вот эти переменные:

Это одно из самых главных поле используемое для определения метода запроса HTTP Протокол HTTP использует методы GET и POST для запроса к серверу.Они отличаются тем что при методе GET запрос является как-бы частью URL т.е. http://www. /myscript.cgi?request а при методе POST данные передаются в теле HTTP-запроса (при GET тело запроса пусто) и следовательно для CGI тоже есть различие при GET запрос идет в переменную QUERY_STRING а при POST подается на STDIN скрипта.
Пример:REQUEST_METHOD=GET

Это строка запроса при методе GET. Вам всем известно что запрос из формы кодируется браузером поскольку не все символы разрешены в URL некоторые имеют специальное назначение. Теперь о методе urlencode: неплохо бы чисто формально напомнить,что все пробелы заменяются в URL на знак ‘+’, а все специальные и непечатные символы на последовательность %hh ,где hh-шестнадцатиричный код символа,разделитель полей формы знак ‘&’,так что при обработке форм надо произвести декодирование.
Пример:QUERY_STRING= name=quake+doomer&age=20&hobby=games

Длина в байтах тела запроса.При методе запроса POST необходимо считать со стандартного входа STDIN CONTENT_LENGTH байт,а потом производить их обработку.Обычно методом POST пользуютс для передачи форм,содержащих потенциально большие области ввода текста TEXTAREA.При этом методе нет никаких ограничений,а при методе GET существуют ограничения на длину URL .
Пример:CONTENT_LENGTH=31

Тип тела запроса(для форм кодированых выше указаным образом он application/x-www-form-urlencoded)

IP-Адрес удаленого хоста,делающего данный запрос.
Пример:REMOTE_ADDR=139.142.24.157

Если запрашивающий хост имеет доменное имя,то эта переменная содержит его, в противном случае -тот же самый IP-адресс что и REMOTE_ADDR
Пример:REMOTE_HOST=idsoftware.com

Имя скрипта,исполизованое в запросе.Для получения реального пути на сервере используйте SCRIPT_FILENAME
Пример:SCRIPT_NAME=/

Имя файла скрипта на сервере.
Пример:SCRIPT_FILENAME=/home/p/paaa/public_html/cgi-bin/guestbook.cgi

Имя серера ,чаще всего доменное как www.microsoft.com ,но в редких случаях за неимением такового может быть IP-адресом как 157.151.74.254
Пример:SERVER_NAME=www.uic.nnov.ru

TCP-Порт сервера используюшийся для соединения .По умолчаниию HTTP-порт 80, хотя может быть в некоторых случаях другим.
Пример:SERVER_PORT=80

Версия протокола сервера.
Пример:SERVER_PROTOCOL=HTTP/1.1

Програмное обеспечение сервера.
Пример:Apache/1.0

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

Давая запрос на сервер браузер обычно расчитывает получить информацию определеного формата,и для этого он в заголовке запроса указывает поле Accept:,Отсюда скрипту поступает cписок тех MIME,которые браузер готов принять в качестве ответа от сервера.
Пример:HTTP_ACCEPT=text/html,text/plain,image/gif

Браузер обычно посылает на сервер и информацию о себе,чтоб базируясь на знании особеностей и недостатков конкретных браузеров CGI-скрипт мог выдать информацию с учетом этого. Например,разные браузеры могут поддерживать или не поддерживать какие-то HTMLые тэги.
Пример:HTTP_USER_AGENT=Mozila/2.01 Gold(Win95;I)

Имя хоста к которому обращается браузер. Так как физически на одном сервере может находиться сразу много серверов (Виртуальные Хосты), то должен быть способ сообщить серверу к какому именно идет обращение. Скрипт же может тоже в зависимости от этой переменной производить различные действия, таким если он используется на сайтах сразу нескольких виртуальных хостов.
Пример:HTTP_HOST=www.nnov.city.ru

Ну,начнем применять на практике усвоеные уроки. Так как все ваши .cgi -файлы должны быть исполняемыми то чтоб облегчить себе жизнь заведите себе в директории cgi-bin командный файл mkcgi ,содержащий и сделайте его в свою очередь исполняемым chmod +x mkcgi -он сильно упростит вам жизнь.
Ну а теперь запускайте скрипт.
Изучив информацию,выдаваемую данным скриптом вы сможете лучше ориентироваться в переменных окружения CGI.

Прекрасный язык Perl

Вы наверное обратили свое внимание что CGI скрипты пишутся обычно на языке Perl (Practical Extraction and Report Language)— очень удобном языке,впитавшем из других все лучшие черты.Может у вас возникнуть сомнение :Ну вот!Изучать новый язык программирования!? Спешу вас успокоить,изучение Perl не будет в тягость (я сужу по своему опыту!). Вы даже сами не заметите как выучите его.Если вы хоть когда-нибудь программировали скажем на C и использовали утилиту grep для поиска регулярных выражений в тексте,то вам будет еще легче. Для Perl родной платформой является Unix поэтому пользователям PC он мало известен. Мое целенаправленое доведение Perl до широкой публики началось с того что я скачал Perl под Windows (фирмы ActiveWare) К нему прилагается отличная гипертекстовая HTML— документация, даже быстрого просмотра которой хватит , чтобы начать хорошо и широко использовать его. Хоть он значительно уступает и по скорости и по эффективности своему Unix’ному аналогу, все равно самый лучший способ изучить язык это программировать на нем. Если вы как я дома используете большую часть времени не Windows а Unix то с изучением Perl у вас вообще не должно быть особых сложностей. Я же от себя могу сказать, что даже после небольшого опыта изучения его, он стал моим любимым языком программирования.

Все в нем сделано для удобства программиста (в отличии например от Java ;( )
Начнем с переменных,они в Perl бывают 3х типов скаларные,списковые(массивы) и хэши(ассоциативные массивы). Для указания компилятору(да и для немалого удобства программиста) перед именем скалярной переменной стоит знак ‘$’ перед массивом ‘@’,перед хешем ‘%’. т.е. например $scalar_var,@array_var,%hash_var Скалярные переменные могут быть как числовые так и строковые,но это не надо указывать Perl сам по контексту в зависимости от операций может привести одно к другому.
Например: «123»+»4″ будет 127 (или «127») так как операция ‘+’ действует над числами а вот если применить операцию конкатенации строк ‘.’ то строковое «test» . 1 будет «test1»
Ну а вот операции над скалярными переменными:

Операцыи Описание Пример
+ — * / % Арифметические print 2*7+4/(8%3);
print int(127/15); #целая часть
** Возведение в степень print 2**16;
++ — Инкремент-декремент $i++;
& | ^

>

Побитовые $x=3;$y=4;
print $x|$y;
print $x&$y;
== != = Числовые операции сравнения if($x==9)
eq ne lt gt le ge cmp стрковые операции сравнения if($game eq ‘doom’)
|| && ! Логические if(($x==9)||($game eq ‘doom’))
?: Условный оператор $x=($game eq ‘quake’?9:8);
, Последовательное вычисление $x=10,$y=20;
. Конкатенация $x=’http://’.’www.uic.nnov.ru’;
x Повторение $x=’1234’x5; #$x=’12341234123412341234′
=

Сопоставление с образцом if($url= То же но с отрицанием if($url!

= >= .= x=

Присваивание $x+=$y;

Пусь это будет вам справочником ,да кстати насчет строк,вы заметили,что они могут быть в двойных и одинарных кавычках, разница между ними состоит в том ,что в одинарных не осуществляется подстановка переменных, а в двойных осущестляется, Например: Списки: Спискочные переменные начинаются с символа ‘@’ конструируются следующим образом Также можно список использовать как lvalue: Можно обращаться к нескольким,выбраным элементам массива(срезу массива): Обратится к скаларному значению -элементу массива можно $имя_массива[индекс], сдесь обратите внимание на знак ‘$’— мы ведь обращаемся к скаляру-элементу.
Теперь немного о хешах:
хеш это такой массив который состоит из пар ключ-значение, весь хеш обозначается %хеш ,к отдельным элементам доступ $хеш конструируется хеш так: Хеш может быть также сконструирован из массива с четным числом элементов где пары превращаются в ключ-значение удаление из хеша -операция delete: есть функции выдающие ключи и значения соответственно. Операторы:
Набор операторов в Perl Очень широк,многие из них прямые аналоги имеющихся в других языках,например if,for,while;но есть и значительные улучшения имеюшихся и конечно новые.
Тот же самый оператор if имеет две формы (как когда удобнее): В пару к оператору if имеется оператор unless : означающий if с отрицанием: Также в пару while существует until
синтаксис оператора for полностью аналогичен C: новшеством(и приятным) является foreach позволяющий пройтись по всем элементам массива,присваивая по очереди его элементы какой-то переменной, его синтаксис такой:
Последний пример особенно важен для упрощения вашего тяжкого труда програмиста и демонтстрирует интересную особенность Perl-переменную по умолчанию $_: в оргомном количестве операторов и функций при опускании аргумента она подразумевается по умолчанию. Она также по умолчанию сопоставляется с регулярным выражением: как видите затраты труда значительно сокращаются,благодаря этому маленькому трюку.

Регулярные выражения.
регулярное выражение записывается между двух слэшей /рег_выр/ это самый простой пример применения регулярного выражения а теперь посложнее вот тут в табличке (из того что я помню наизусть):

Символ Значение Пример применения
. Соответствует любому символу print if /ab.c/;
[мн-во симв] Соответствует любому символу из данного мн-ва /[abc]d/;#соответствует ad,bd,cd
[^мн-во] Отрицание мн-ва символов /[^xyz]/;#
(. ) Группировка элементов(и также запоминание в переменных $1 $2 $3 . ) /(xyz)*/
/([abc].[^xy]qwerty)/
(..|..|..) Одна из альтернатив
* повторение образца 0 или более раз /.*/;#соответствует всему
? Повторение 0 или 1 раз /(http:\/\/)?.*\.cgi/
+ Повторение 1 или более раз
повторение от n до m раз
повторение точно n раз
повторение n и более раз
Спец символы:
\t \r \n . Управляющие символы:табуляции,возврат каретки,перевод строки.
\d Соответствует цифре,Аналог [0-9]
\D Соответствует нецифровому симсволу,аналог[^0-9]
\w Соответствует букве
\W Соответствует небуквеному символу
\s Соответствует пробельным символам(пробелы,табуляции,новые строки..)
\S Соответствует непробельному символу
\b Соответствует границе слова $test1=»this is test»;
$test2=»wise»;
if($test1=

/\bis\b/)#нет

\B Соответствует не границе слова /\Bis\B/ соответсвует ‘wise’ но не ‘is’

Для того чтоб поместить в регулярное выражение любой специальный символ,поставьте реред ним обратный слэш Заставить Perl игнорировать регистр можно поставив i после регулярного выражени
Полезные функции.
В Perl очень много различных функций ,как говорится на все случаи жизни,все о них конечно не опишу,но обо многих. Начну с тех,которые больше относятся к операторам. Операция замены s/рег.выражение/строка/ игнорировать регистр — опция i глобальная(по всей строке) замена -опция g; Пример: Очень полезная опция у s/// e -она означает что вторая строка не строка а выражение, результат которого и будет подставлен. Например,у вас есть файл в котором все записи о возрасте через год надо менять или более показательным примером послужит функция urldecode,которая будет встречатс в каждой вашей программе,обрабатывающей формы: Также важным удобством в Perl являются операции для работы с файлами для выполнения схожих функций в других языках приходиться проделывать огромную массу работы. Аргументами могут быть как Файловые переменные,так и строки,представляющие имя файла.

Операция Описание Пример использоввания
-r Доступен для чтения unless(-r «myfile»)
-w Доступен для записи
-x Для исполнения
-o Принадлежит пользователю if(-o «index.htm»)
-R Доступен для чтения реальным
пользователем,а не только «эффективным».
Имеет значения для set-uid -скриптов
if(-r FILE)>
-W Доступен для записи реальным пользователем
-X Доступен для исполнения реальным пользователем
-O Принадлежит реальному пользователю
-e Файл или каталог Существует unless(-e $htmlfile)<
open(HTML,»>$htmlfile»);
print HTMLFILE » «;
close(HTMLFILE);
>
-z Существует,но имеет нулевую длину if(-z ‘tmpfile’)
-s Размер файла в байтах system(«rar m -m5 archive.rar $myfile») if -s $myfile > 1000;
-f Файл существует и является простым файлом
-d Файл существует и является каталогом if(-d ‘public_html’)
-l Символической ссылкой
-p Каналом FIFO
-u Имеет бит установки пользователя
-g Имеет бит установки группы
-k Установлен sticky-бит
-t Является терминальным устройством
-M Время с последнего изменения (в днях) while(defiled($file=glob(‘*’))) <
if(-M $file >= 7.0) <
unlink($file);#удаляем слишком старые файлы
>
>
-A Время последнего доступа(в днях) if(-A «$ENV<'HOME'>/public_html/index.html»
избавиться от символа новой строки на конце поможет функция chomp, ведь этот символ может помешаться например в имени файла или при выводе на экран Если также подставить списочную переменную,то получим список строк файла от текущей строки и до конца бинарный файл можно читать и писать функциями sysread и syswrite:
sysread(ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт)
syswrite(ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт)
функции split и join: @Список=split(/рег.выр/,$скаляр);
$скаляр=join(строка,@Список);
Встроеные функции Perl можно вызывать со скобками или без (как вам удобно), скобки программисты указывают или для красоты,или чаще,что устранить возможную неоднозначность в выраженнии: Надеюсь что я вас позабавил примерами функций ;).

Примеры применения Perl для различных нужд.
Следующая программа переводит текстовый файл в формат HTML (вспомните сколько хлопот вам доставит отлов во всем файле ‘ ‘ и ‘&’ чтоб заменить их на &tl; , > и & а как неплохо чтоб автоматически все http://www. превратились в http://www. ) Более подробную информацию о Perl вы можете получить по адресам:
http://www.perl.com
http://www.metronet.com/0/perlinfo/perl5/manual/perl.html
http://www.ActiveWare.com/

Заголовки запросов и ответов

Даже если вы и знаете кое-что о HTTP все равно не лишне будет вспомнить о том как это все работает тем более на эту информацию придется ориентироваться при написании CGI скриптов.
Этапы соедирения.
Первый этап это когда HTTP -клиент(браузер) соединяется с сервером.для этого он использует протокол TCP/IP соединение происходит к известному клиенту TCP-порту (80 -номер порта HTTP) (другие сервисы сидят на других портах ,например FTP и SMTP на 21 и 25)
Вторым этапом идет запрос клиента:клиент передает заголовок запроса и возможно(в зависимости от метода) тело сообщения запроса.В заголовке обязательно указывается метод ,URI,и версия HTTP,и может быть еще несколько необязательных полей
Третий этап -ответ сервера,который опять таки состоит из заголовка,в котором сервер указывает версию HTTP и код статуса, который может говорить о успешном или неуспешном результате и его причинах.Далее идет тело ответа.
Четвертым этапом происходит разрыв TCP/IP соединения.
HTTP -запрос.
Запрос состоит из Строки запроса(она обязательна) и остальных полей. Синтаксис строки :МЕТОД URI HTTP/версия
где -пробел , -переход на новую строку
Методы HTTP.
GET
Самый часто применяемый метод,в протоколе HTTP/0.9 был единственным методом,и применяется для извлечения информации по заданому URI Может быть условным если в заголовке указано поле If-Modified-Since:

HEAD
Почти идентичен GET но отличается тем что сервер не возвращает тело обьекта а только его заголовок (метаинформацию) программы могут применять его для проверки гиперссылок на правильность,доступность и изменения.

POST
передает данные для обработки их программой ,указаной в URI сдесь обязательно указывается поле Content-Length:

Сушествуют и другие ,реже применяемые методы,например PUT -для сохранения передавемых данных в указаном URI и DELETE для удаления ресурса.

Поля заголовка запроса.
После строки запроса идут поля заголовка запроса. Поля общего(general-header) заголовка (он общий как для запросов так и для ответов):
Date:
Указывает дату запроса,например:
Date: Sun, 20 Nov 1994 08:12:31 GMT

MIME-version:
Указывает версию MIME (по умолчанию 1.0)
MIME-version: 1.0

Pragma:
Содержит указания для таких промежуточных агентов как прокси и шлюзы,
Pragma: no-cache

Поля относящиеся к запросу(Request-Header):
Authorization:
Содержит информацию аутентификации
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

From:
Браузер может посылать адрес пользователя серверу
From: quake@doom.ru

If-Modified-Since:
используется при методе GET ресурс возвращается ,если он был изменен с указаного момента, может использоваться при кешировании.
If-Modified-Since:Mon 15 Jul 1997 00:15:24 GMT

Referer:
Содержит URL предшествующего ресурса.
Referer: http://www.uic.nnov.ru/

User-Agent:
Програмное обеспечение клиента.
User-Agent: Mozilla/3.0

Заголовок информации сообщения (Entity-Header) применяется как в запросах так и в ответах (при этом некоторые поля только в ответах):
Allow: (в ответе сервера)
Список методов,поддерживаемых ресурсом.
Allow: GET, HEAD

Content-Encoding:
идентифицирует метод кодировки,которым был закодирован ресурс
Content-Encoding: x-gzip

Content-Length:
Длина тела сообщения
Content-Length: 102

Content-Type:
Содержит тип ресурса(MIME),для текстовых еще и кодировку символов(необязательно)
Content-Type: text/html; charset=windows-1251

Expires: (в ответе сервера)
Дата окончания действия ресурса,применяется в кешировании для запрета кеширования устаревших ресурсов (в ответе)
Expires: Tue, 24 Sep 1998 23:00:15 GMT

Last-Modified: (в ответе сервера)
Время последнего обновления ресурса
Last-Modified: Tue, 23 sep 1998 13:48:40 GMT

Другие поля:
Поля Accept: указывают серверу выдавать только указаные форматы данных,которые клиент может распознать.
Accept: text/html
Accept: text/plain
Accept: image/gif

Поле Host: служит для того , чтобы указать, к какому хосту идет обращение. Данное поле не входит в число обязательных. Однако оно является необходимым в тех случаях, когда одному физическому серверу соответствует несколько виртуальных хостов. В этом поле тогда указывается какой из виртуальных хостов имеется в виду.
Host: www.nnov.city.ru

Примеры запросов: Ответ HTTP-сервера.
Ответ идет от сервера.Состоит он из строки состояния и затем поля ответа Общий заголовок(General-Header) и заголовок тела сообщения (Entity-Header),которые уже описаны при обсуждении запроса. и еще идет заголовок ответа(Response-Header).
Строка состояния имеет следующий формат:
HTTP/version Status-Code Status-Phrase
где HTTP/version версия,Status-Code -3х значный код,и Status-Phrase текстовая фраза, поясняющая код ,пример: HTTP/1.0 200 Ok
,200 -код означающий успешную обработку запроса,что и поясняет «Ok» Заголовок ответа состоит из полей:
Location:
Содержит URI ресурса,может быть использован для переключения клиента в другое место, если например ресурс был перемещен в другое место или на другой сервер.
Location: http://www.uic.nnov.ru/newlocation/index.html

Server:
Информация о програмном обеспечении сервера
Server: Apache/1.1

WWW-Autenticate:
Параметры аутентификации.
WWW-Autenticate: Basic realm=»doomsday»

Коды ответов HTTP.

Код статуса Значение
200 OK
201 Успешная команда POST
202 Запрос принят
203 Запрос GET или HEAD выполнен
204 Запрос выполнен но нет содержимого
300 Ресурс обнаружен в нескольких местах
301 Ресурс удален навсегда
302 Ресурс отсутствует временно
304 Ресурс был изменен
400 Плохой запрос от клиента
401 Неавторизованый запрос
402 Необходима оплата за ресурс
403 Доступ Запрещен
404 Ресурс не найден
405 Метод не применим для данного ресурса
406 Недопустимый тип ресурса
410 Ресурс Недоступен
500 Внутренняя ошибка сервера
(это по вашу душу,юные CGI-программисты ;( )
501 Метод не выполнен
502 Неисправный шлюз либо перегруз сервера
503 Сервер недоступен/тайм-аут шлюза
504 Вторичный шлюз/тай-аут сервера

Более подробное описание всех кодов можно найти в RFC-1945
Несколько примеров:
CGI-заголовок.
В том случае когда запрашиваемый URI есть CGI-скрипт сервер базируясь на данных запроса создает среду переменных CGI и передает управление скрипту скрипт должен выдать CGI-заголовок,после которого и идет тело ответа,сгенерированое скриптом.
Заголовок (CGI-Header) состоит из полей:
Content-Type:
Должно обязательно присутствовать,если есть тело.
Content-Type: text/html

Location:
Содержит URL ресурса на который скрипт перенаправляет запрос.Как правило,если присутствует это поле больше ничего не указывается.
Location: http://www.idsoftware.com/index.html

Status:
Позволяет CGI скрипту вернуть статус обработки,если это поле не задано,то сервер подразумевает
Status: 404 Not found

На базе этой информации сервер и формирует окончательный заголовок,который и передается клиенту.
Примеры: nph-скрипты.
Иногда возникает необходимость чтобы CGI -скрипт сам отвечал напрямую клиенту, минуя разбор заголовка.Это во-первых уменьшает нагрузку на сервер,и во вторых, что самое главное такой прямой ответ клиенту позволяет скрипту полностью контролировать транзакцию.Для этого существуют nph-скрипты(Not Parse Header) ,имя скрипта должно начинатьс с префикса «nph-« ,Например «nph-animate.cgi» .Такие скрипты сами формируют HTTP-ответ клиенту,что полезно при анимации:
Этот пример вам выдаст анимацию ,составленую из нескольких .gif -файлов.Если же вы получили вместо анимации сообщение об ошибках,то вам следует,может быть перейти к следующей главе, которая поведает вам о правах доступа- того,без чего Unix не был бы Unixом.

Права Доступа

Я бы ни за что не написал этот раздел,если бы он не был так важен.Сидя в пределах своей домашней директории и занимаясь только тем,что качаете с Инета всякую херню,вы возможно и не задавались некоторыми вопросами. а зря. Ведь немного надо,чтоб попортить нервы начинающему CGI -програмисту.
Одна из таких вещей это права доступа.
Начнем с того ,что в системе Unix каждый пользователь имеет свой идентификатор- число,уникально идентифицирующее его в этой системе.(Мой логин paaa а ему соответсвует число 1818).Это число внутреннее для операционной системы,для пользования оно представлено как логин,который и соответствует пользователю.
Только не надо думать о пользователе,как о конкретном человеке сидящим за клавиатурой, пользователем может быть и какой-нибудь процесс.Важно отметить что пользователь-это определенна область прав доступа,которая ему соответствует.(Вы например не можете обычно писать и удалять файлы из каталога другого пользователя). Это и дает возможность стабильной работы всей системы.
Итак есть идентификатор пользователя.Также имеется идентификатор группы.
Группа служит для выделения пользователей по группам. Например у пользователей группы users (Обычные пользователи) не такие права как у группы wheels (административная группа).
Каждый процесс который вами запущен(Будь то Netscape,терминал,или текстовый редактор)получают ваши идентификаторы пользователя и группы. таким образом исполняются от вашего имени.
Теперь рассмотрим повнимательней файловую систему.В Unix с файлом связано много характеристик. Во-первых в системе нет «ничьих» файлов ,все файлы имеют владельца-пользователя и владельца-группу. Любой файл который вы создаете автоматически получает ваш идентификатор.По этому система очень легко отслеживает, чьи это файлы и каталоги.
Следующее новшество по сравнению с DOS это права доступа к файлу.Их может сменить только тот пользователь которому принадлежит файл,или супервизор.(Это в отличии от DOS где каждая дрянь типа вируса может снять атрибут readonly читать и писать все файлы ;()
Права доступа задаются обычно числом в восьмеричной записи и разбиты на 3 части по 3 бита: Каждая часть задает права доступа для конкретной группы:

1я -права доступа для пользователя,которому принадлежит файл
2я -для группы которой принадлежит файл
3я -для всех остальных

В каждой такой категории выделяются 3 права: Право на чтение,Право на запись,и право на исполнение. (все права и аттрибуты очень наглядно показаваютя командой ls с ключом -l) Так как исполнять каталоги бессмыслено,то право на исполнение для них означает право обращатся к файлам из этого каталога.

Бит Описание
8 Право на чтение для пользователя
7 Право на запись для пользователя
6 Право на исполнение для пользователя
5 Право на чтение для группы
4 Право на запись для группы
3 Право на исполнение для группы
2 Право на чтение для всех остальных
1 Право на запись для всех остальных
Право на исполнение для всех остальных

Изменяются права командой chmod,ее синтаксис такой:
chmod [u|g|o]<+|-> file
chmod number file
,где uuser,ggroup,oother,rread,wwrite,x-execute;-удалить,+-установить
Примеры:
chmod +r file.txt #разрешает всем право на чтения файла
chmod u+w file.txt #устанавливает для владельца файла право на запись в него
chmod +x gbook.cgi #право на исполнение для всех,как для ползователя,группы,и для других
chmod 0777 cgi-bin #Разрешает самые широкие права доступа для cgi-bin

Приоткрытии файла программой,операционная система сравнивает идентификатор пользователя с идентификатором пользователя владельца файла, если они равны,то действуют права пользователя,если не равны то сравниваются идентификаторы группы,если и они не равны,то действуют права доступа для остальных остальных.В том случае если у процесса нет достаточных прав,система возвращает ошибку. Следует заметить ,что для супервизора root права доступа не проверяются.
Можно выполнить скрипт,только если есть права на его исполнение. Вот почему следует давать chmod +x *.cgi иначе ваши скрипты станут просто недоступными. Но и это еще не все.
Ваш скрипт может обращатся к вашим файлам (например ведет базу данных гостевой книги). Все выглядит нормально,но только ничего не работает,файл в который вы намеревались писать,
не открывается,знакомая проблема ;(( ?.Так вот чтобы вы не мучались в догадках Ваш скрипт не может получить доступ к вашим файлам,потому что он выполняется не вами (не с вашим идентификатором), а от имени nobody (непривелигированый пользователь).Это мера предосторожности направлена на то, чтоб скрипты ,взбесившись из-за неправильно переданых параметров(или вообще от глюков) не могли ничего повредить ценного и важного на сервере.
Поэтому к тем файлам,к которым скрипт по смыслу должен обращатся нужно присвоить самые широкие права доступа 0777
Например в случае гостевой книги chmod 0777 guestbook.dat
Если также важно чтоб скрипты могли заводить новые файлы в cgi-bin то надо дать также права на это chmod 0777 cgi-bin
Если вы видите что ваш скрипт не может обратится к какому-то файлу,то это в 99% случаев из-за вашей забывчивости.
На самый крайний случай воспользуйтесь setuid-скриптами (к этому делу ,если вы на это решились,отнеситесь ОЧЕНЬ серьезно,так как целые тома по безопасности в Unix посвящены именно setuid-программам). Хочу сразу предупредить ,сам я таких не так уж много писал,да и вам не особенно советую. Но для общего как говорится развития,имейте в виду следующую информацыю.
Кроме указания прав доступа,существуют специальные биты у файла.Это биты установки пользователя и группы. Когда процесс выполняется(простой процесс) то его реальный и эффективный идентификаторы пользователей совпадают,идентификаторы групп тоже. На самом деле значение имеют как раз эффективные значения пользователя и группы,они учавствуют в сравнении прав доступа. Нельзя ли их как-то изменить,когда уж совсем нужда заставит? Можно! .На этот вопрос дают ответ программы с установленым битом пользователя.Когда система запускает такую программу,она присваивает новому процессу не идентификатор того пользователя,что запустил ее, а идентификатор пользователя-владельца исполняемого файла.
Самый классический пример setuid-программ это программа passwd ,предназначеная для смены пароля пользователя. Такие данные как пароль и прочие характеристики пользователей хранятся в специальном файле,который имеет огромное значение при входе в систему. Так как это системный файл,то открыть к нему доступ на запись всем-значит подвергнуть ВСЮ систему риску,ведь любое неправильное изменение его повлечет катастрофические последствия(в конце концов бывает просто хулиганство). Поэтому доступ к этому файлу закрыт для всех пользователей.А что если надо сменить пароль? Запускаем программу passwd! Если глянуть на ее аттрибуты ,то видно что она принадлежит root -супервизору, и еще имеет установленый бит setuid. Так корректно обходится эта проблема.
Если вы все-же решили попытаться ,то знайте ,что сделать программу setuid можно
коммандой : chmod +s myprogramm

И как всгда Примерчик напоследок:
Эта программа выдает содержимое вашей директории public_html в том случае,если она доступна для чтения,и для каждого файла указывает ,можно ли его читать,писать и исполнять. Попробуйте ее сделать setuid и посмотрите как изменится результат.

Генерация ответа

Большую часть того что нужно знать о генерации ответа,я сказал в разделе Заголовки запросов и ответов.Нет,не угадали! Я не буду сдесь говорить о всяком дизайне того что вы выдаете.Этому вы успели напрактиковатся на HTML -страничках.
Я поговорю о MIME (Multipurpose Internet Mail Extension).И о разных браузерах.
Стандарт MIME появился в электронной почте (e-mail) потому что остро стала проблемма пересылки по e-mail различных данных в различных форматах.Так как HTTP тоже работает с различными типами данных то поэтому тоже использует MIME для своих нужд. Типы MIME состоят из Типа и подтипа (например text/plain,где text-указывает на наличие текстового содержимого,а plain-уточняет его как простой текст) приведеный ниже список (он далеко не полн,типов MIME огромное количество) описывает некоторые часто встречающиеся типы.: text/html text/plain text/richtext image/gif image/jpeg image/tiff audio/basic audio/32kadpcm audio/ video/mpeg video/quicktime multipart/mixed multipart/alternate multipart/ application/octet-stream application/msword application/postscript message/digest
Информация о MIME больше возможно пригодится вам в том случае если вы собираетесь работать из ваших скриптов с электронной почтой,но и для WWW она не повредит. Особенно знание Content-Type:
Content-Type:
Состоит из типа и подтипа типы могут быть как стандартные так и экспериментальные начинающиеся с префикса ‘x-‘:

text
Текстовые данные.Первым подтипом который включен сюда это plain,что значит простой текст. сюда же включен самый ходовой формат html .У типа text как и у многих типов могут быть параметры,главным из них является charset он как раз и указывает на раскладку символов, которая применена в тексте, так что если вы хотите указать браузеру какую раскладку применять, то просто укажите charset:
Content-Type: text/plain; charset=us-ascii
Content-Type: text/html; charset=iso-8859-1
Content-Type: text/html; charset=koi8-r

multipart
Данные которые могут состоять из нескольких частей,различных типов данных.Поэтому параметром multipart служит boundary, позволяюший указать разделитель.Каждый фрагмент в многочастевом сообщении имеет свой Content-Type: (Он может быть также multipart,т.е. допускаются вложеные multipart,главное чтоб boundary были разными).В электронной почте применяется больше multipart/mixed (основной подтип) и multipart/alternative (Он отличается тем что показывается одна из альтернатив,например сообщение шлется в простом и HTMLом форматах,и почтовая программа показывает либо часть,которую она способна отобразить). В WWW -програмировании распостранен x-mixed-replace ,который означает что следующая часть должна заменить предыдущую после подгрузки, что применяется для анимации(см.Пример с анимацией).
Теперь о разделителе,его надо выбирать так,чтоб он не встретился где-то в данных (т.е. что-то вроде «diUr344rnmvforgefvrg923rghyj2»).Когда вы задали разделитель,например boundary=»boundary» то когда закончилась одна часть,вы должны выдать строку —boundary,последн часть —boundary—,причем эти разделители должны быть на отдельной строке,а не сливаться с текстом:
Пример:

message
Представляет инкапсулированое почтовое сообщение.Используется в e-mail ,а не в WWW.

image
Некоторое Графическое изображение.(чаще всего image/gif и image/jpeg)

application
бинарные данные какого-нибудь приложения.В том случае если данное приложение может быть запущено,Браузер запускает его.Например при поступлении данных application/msword Браузер спросит,нужно ли запустить Word для просмотра досумента.При отсутствии нужного приложения браузер спросит в каком файле сохранить данные.Подтип octet-stream как раз и означает поток байт информации,который и используется по умолчанию.(К сожалению не все так гладко,известен глюк в Netscape Navigator‘е который вместо того чтоб сохранить application/octet-stream пытается его показать как text/plain что если это сгенерировано из CGI,ни к чему хорошему не приводит ;(()
Что касается application ,то Вы можете тут смело извращатся,используя x- типы данных,
Например application/x-fuck-to-netscape-navigator. ;)))))
Часто используемый параметр name позволяет указать имя файла.Например:
Content-Type: application/msword; name=»readme.doc»
Что полезно при полученнии файлов через HTTP,причем этот параметр может применятся и для других типов таких image или audio ,Например:
Content-Type: image/gif; name=»myfoto.gif»

Content-Transfer-Encoding:
Применяется больше в системе электронной почты и обозначает метод кодирования, которым были закодированы данные при передаче сообщения.Например:
7bit 8bit quoted-printable base64 binary x-типы
MIME-Version:
Указывает версию MIME .

Теперь поговорим о разных браузерах вы знаете что браузеры бывают разные,разных версий на разных платформах, поддерживают и не разные тэги и глюки у них тоже разные. ;((( .
Это могло попортить много нервов WEB-дизайнерам и конечно же нам ,CGI-програмистам. Профессионально написаный сайт от просто хорошего отличается тем что хорошо выглядит Не только на экране того браузера,которым пользуется сам его автор,а на других тоже.
Если вы используете JavaScript для своих страничек,то вы уже наверно использовали (или хотя бы вам в голову приходила мысль использовать)свойства navigator.AppName navigator.AppCodeName navigator.appVersion navigator.userAgent:
Ну не волнуйтесь вы так ,мы CGI-программисты не в самых худших условиях на этот счет. Вспомните о том что браузер сам при запросе посылает вам данные о себе и о своей версии. И делает он это для того,чтобы эту информацию можно было учесть.
В запросе он указывает User-Agent: которое и попадает на сервере в переменную среды HTTP_USER_AGENT ,которую и можно использовать.
Например если в ней содержится Mozilla/3.01Gold (Win95;I) то значит вы имеете дело с Netscape (Mozilla-кодовое название Netscape Navigator‘а),версии 3.01Gold и далее после имени и версии может следовать необязательная информация ,например как в приведеном примере о платформе Win95 и о том является ли версия U -для США (USA) или I -международной(International). Напомню,что такая информация необязательна.(То есть если браузер послал информацию User-Agent: то гарантировано расчитывать вы можете только на Название/Версия).
Ну вот я слишком много развел демагогии,пора переходить к практическим примерам.
Допустим ваш скрипт генерирует какие-то тэги,которые слишком старые браузеры не поддерживают,причем без них не обойдешся,они составляют всю ‘изюминку’ сайта.
Ну уже почувствовали,насколько это здорово.А вот еще примерчик.Это из разряда того, что тэги бывают разные.Например в Explorer есть тэг BGSOUND предназначеный для проигрывани музыки на страничке.(В Netscape этого тега нет,и поэтому для втыкания музыки приходится использовать подключаемые модули plugin).Мутится с этими Плугинами Вам в облом,а хочется побаловать человека хорошей музыкой,если браузер позволяет. Ну вот вы уже можете управлять этим процессом.Только не забывайте,что если вы не получили информацию о клиенте(так может быть,если например ваш скрипт вызвал какая-нибудь поисковая машина) то не в этом случае не надо делать никаких предположений,а просто пусть ваш скрипт продолжает делать то что должен был делать.

Как всегда Примерчик на последок.Этот примерчик позволит выбирать из списка файлов. и загружать что пользователь хочет.

Обработка Форм

Ну вот ,вы уже знаете достаточно,кое в чем уже успели приобрести опыт, пришло время перейти к очень важной теме — обработке форм. При всей простоте (кажушейся) это едва ли не самое главное предназначение всего стандарта CGI . Куда бы вы не зашли на любой уважающий себя сайт,везде вы встретите формы, которые вам предложат заполнить.В этом деле можно положится только на CGI, так как Java и JavaScript ,выполняющиеся на страничке у клиента не имеют доступа к серверу,на котором находится сайт.
Коротко вспомним о том что происходит при рассматриваемом процессе поближе,так сказать на трезвую голову ;). Итак браузер требует у сервера определенный URL (это может быть как простой документ,так и сгенерированый CGI) в этом документе может содержаться форма.Отображая такой документ браузер также выводит элементы формы (кнопки, поля ввода, поля ввода пароля, переключатели, радио-кнопки, списки, текстовые области,скрытые поля). И со всем этим добром пользователь может взаимодействовать.К форме естественно имеет доступ и встроеный язык программирования JavaScript -он может как использовать форму для своих нужд,не передавая CGI,так и помогать пользователю в заполнении формы.
После того,как пользователь заполнил форму он нажимат кнопку Submit которая говорит, что форму надо отправить на сервер. Браузер собирает все имена и значения элементов формы ,кодирует их методом urlencode и в зависимости от указаного в тэге FORM метода вызывает GET или POST с указаным URL,передавая ему данные. На сервере CGI-скрипту это попадает (в зависимости от метода) либо в переменную QUERY_STRING либо на STDIN.Скрипт может проверить данные ,занести их в какую нибудь базу данных,может как yahoo выполнить какой-нибудь поиск, может что-нибудь вычислить. да мало ли что он может,все зависит только от нашей фантазии. В конце концов скрипт выдает браузеру ответ,который он и отображает.В этом ответе может содержаться все что вашей душе угодно от сообщения об удачном или неправильном запросе до таких ответов,по сравнению с которыми yahoo и altavista подвиснут от зависти, главное чтоб вам и тем кто посещает ваш сайт это нравилось.;)

Ну а теперь немного о синтаксисе элементов форм ,их описании и самое главное особенностях при обработке CGI-скриптом.
Итак немного экскурс в HTML:
FORM
Атрибуты:
action
как раз и задает тот URL,который будет и обрабатывать форму, если он опущен,то текущий URL документа(а он-то может быть сгенерирован нашим скриптом).
method
задает метод GET или POST
enctype
обычно не задается,для форм он application/x-www-form-urlencoded -по умолчанию, и поддерживается всеми CGI скриптами.Но если вы уж очень хотите чтобы браузер послал вам данные в другом формате (например text/plain) то можете указать этот тип кодировки,только потом не жалуйтесь,что ваш скрипт не может разделить поля,или вообще начинает глючить когда пользователь ввел какой-то спецсимвол.
name
Задается для JavaScript,чтоб обращатся к форме по имени,а не по номеру. Для CGI не играет ни какой роли,так как внутреннее для браузера.
target
Может Определять в какой фрейм отправить полученую информацию.Имеет значение во фреймосодержащих документах.Прозрачен для CGI обработки данных.
onSubmit
Определяет JavaScript -обработчик активизации формы.Применяется для проверки JavaScript‘ом правильности заполнения.Опять таки прозрачен для CGI.
Пример типичной формы: Форма может содержать элементы.Элементы имеют имена,которые используются дл кодирования пар имя=значение.Некоторые Элементы не передаются CGI,а используются JavaScript для управления,например кнопки.Некоторые поля передаются только в тех случаях, когда в них что-то выбрано,например списки и переключатели.Остальные поля передаются всегда, даже когда они пустые.
Например: Допустим вы ввели имя lesha и адрес paaa@uic.nnov.ru,при этом выбрали переключатель После нажатия кнопки будет отправлен вот такой запрос:
http://www.doom/cgi-bin/test.cgi?Name=lesha&Email=paaa@uic.nnov.ru&doomer=Yes
Если же вы не выбрали переключатель,то запрос будет таким:
http://www.doom/cgi-bin/test.cgi?Name=lesha&Email=paaa@uic.nnov.ru
,как видите элемент doomer не вошел в строку запроса
Теперь попробуйте оставить поля редактирования пустыми:
http://www.doom/cgi-bin/test.cgi?Name=&Email=
Эти элементы (Name и Email) присутствуют и сообщают что они пустые.

Кнопка(button)

В форме изображается кнопка,при нажатии которой вызывается JavaScript-обработчик заданый атрибутом onClick ,атрибут name служит для JavaScript-именования кнопки а не дл передачи CGI.Так как значение кнопки не передается CGI, value задает Текст,изображаемый на кнопке.

Submit

Кнопка,предназначеная для передачи формы.Опять же,сама не передается,а служит только для управления. текст на ней задается атрибутом value.
Reset

Кнопка очистки формы.При ее нажатиивсем измененым элементам возвращается значение по умолчанию.
Поле ввода(text)

Применяется очень часто,поэтому тип «text» служит для INPUT по умолчанию,его не надо каждый раз указывать.Имя поля,задаваемое name является обязательным для CGI (в отличии от JavaScript,где элементы формы можно индексировать по номерам,а имена для удобства и читабельности кода служат).Можно задать значение по умолчанию атрибутом value,которое будет после загрузки докумета.атрибут size позволяет задать размер поля.Также может содержать обработчики onBlur,onChange,onFocus,onSelect.
Текстовая Область(textarea)
Область многострочного редактирования.Размеры в строках и столбцах задаютс атрибутами rows и cols.Значения атрибута wrap «hard» и «soft» -означают соответственно мягкую или жесткую разбивку на строки (в большинстве случаев ето не существенно). На что следует действительно обратить внимание так это на символ,используемый для указания перехода на новую строку. В Windows это ‘\r\n’ а в Unix ‘\n’,так что если это для вас существенно,то приводите преобразование,например так:
$my_text =

s/\r\n/\n/g;
Поле ввода пароля(password)

Очень похоже на поле ввода,отличается тем что вместо символов в нем отображаютс символы ‘*’.Служит для ввода пользователем пароля.
Скрытое поле(hidden)

Поле не отображаемое на экране.Но оно имеет имя и значение и следовательно передается в форму. Служит для того (и очень часто програмисты его применяют) чтоб передавать скрипту какую нибудь информацию.Например,если ваш скрипт обрабатывает несколько форм разных типов,то в скрытом поле каждой формы можно указать с какой формой конкретно вы имеете дело. Так как это ваша внутренняя кухня то нечего пользователю мозолить глаза этой информацией.
Переключатель(checkbox)
Text
В отличии от кнопки,атрибут value сдесь не задает на надпись на переключателе,а его значение(внутреннее).Поэтому если надо что-то подписать,пишите рядом в ним. Может быть сразу выбраным если указан атрибут checked .Если value не указано то значение по умолчанию «on» .Передается только в том случае,когда выбран.
Радио-кнопка(radio)
Text
В отличие от checkbox может быть несколько радиокнопок с одинаковым параметром name ,но с разными value,из них передается только та,что выбрана.Одна из них может быть изначально выбрана по умолчанию checked.Например:
Список(select)
Задает список,позволяющий выбрать одну (или несколько) опций из списка. Если атрибут multiple не указан,то создается простой выпадающий список,в котором можно выбрать только одну из опций.Его значение всегда передается,т.к. всегда хоть одно выбрано. Если указан атрибут multiple,то во первых можно указать размер видимой части списка атрибутом size (Если опций больше появится скролинг).Во вторых передаются только выбраные опции ,т.е.Он может передатся несколько раз ?SelectName=opt1&SelectName=opt2&SelectName=opt9 если выбраны скажем несколько опций.А может и не разу,если ничего не выбрано из списка. Можно задавать обработчики onBlur,onChange,onFocus.
Небольшая Помощь JavaScript
Для CGI-програмиста конечно JavaScript -это иной мир,вы можете спокойно пропустить этот абзац,если вы не знаете JavaScript,так как написаное в нем к CGI не относится, а скорей к самим формам и дизайну сайта.Я скажу пару слов о том как JavaScript может оказать посильную помощь в проверке правильности заполнения форм.Все проверки конечно можно и нужно делать на сервере,но когда имеешь дело с рассеяным пользователем, то для него заполнение простой формы превратится в мучение.Поясню на примере,в форме есть какие-то обязательные поля,например имя.Если пользователь забыл его указать то скрипт скажет ему об этом в сообщении он исправит это, допустим что-нибудь еще не так ввел . Только на передачу данных по сети может уходить масса времени.А на обработку на локальной машине-доли секуды.
Вот Например как это можно применить JavaScript для предварительного контроля правильности. Допустим простейшая форма содержит имя и возраст.Имя не должно быть пустым, а возраст должен состоять из цифр. Ну вот ,на этом можно закончить это краткое введение в HTMLые формы.
Итак,У нас на входе скрипта данные формы,закодированые методом urlencode Положеные в Переменную QUERY_STRING или подаваемые на STDIN.Мы должны вопервых их получить. Вот,мы уже считали наш запрос в переменную $query.Теперь пришло самое время ее обработать. Мы знаем что поля разделены символом ‘&’ значит используем его в качестве разделителя функции split: Вот разделили,а теперь организуем цикл foreach по полученым полям @formfields Сдесь выражение в регулярном выражении в круглых скобках (.*) после знака ‘=’,запоминаетс в скалярную переменную $1 ,которая затем и декодируется нашей старой и знакомой функцией urldecode (я предупреждал,что она будет почти в каждой вашей CGI-программе) Так мы проходим по всем полям,которые нам переданы.Это стандартный подход,он годится в качестве шаблона.У вас может возникнуть вопрос,а что делать если вам переданы данные от списка у которого задана возможность выбора нескольких элементов и данные поступают в таком виде: Sel=opt1&Sel=opt2&Sel=opt9. Тут тоже нет никаких проблем,просто запихиваем эти поступающие значения в массив. И потом спокойно оперируем с Полученым Массивом @Sel.
На этом можно так сказать заканчивается шаблонная часть скрипта и начинается содержательная, которая зависит только от вашей фантазии.
Вы можете сколько угодно анализировать полученые значения,обращатся при этом к различным файлам .Если вы к этому приложите фантазию,то кто знает что получится.
А Пока Ради примера я вам напишу скрипт,который ведет социологическое исследование насчет курения и отношения к нему.Может он слишком массивен для данного пособия, но зато он наглядно показывает как достаточно простыми средствами можно проводить социологические исследования. А вот скрипт для его обработки:

Изображения ismap

Анимация

Когда говорят о каком-то популярном сайте,то частенько к преимуществам относят и анимацию. Действительно,когда изображение изменяется (и особенно к месту ;)),то это смотритс и пользователю нравится.
Говоря об анимации нужно сразу отметить что нет лучшего способа. Анимацию можно сделать ДЕСЯТКАМИ Способов,каждый хорош в своей области применения. Я перечислю только некоторые из них,которые чаще всего применяются:
Самый простой,но наименее функциональный способ это GIF с анимацией.
Потом можно воткнуть анимационный файл MPEG или AVI они более отражают суть анимации, но имеют недостаток,что для проигрывания их на некоторых браузерах нужны специальные подключаемые модули.К тому же они не интерактивны.
Можно реализовать анимацию в рамках Java-апплета,когда апплет находясь на страничке сам перерисовывается со временем.
Таким же интерактивным средством служит обращение к массиву document.images[] из JavaScript.Достоинство-помимо интерактивности,полная интегрированость с HTML -станичкой.Но может как и предыдущий использоваться только с относительно новыми браузерами,которые поддерживают Java и JavaScript.

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

Несколько советов по отладке

CGI-программы -не самые простые в отладке,по сложности отладки они способны сравнится лишь с отладкой драйверов. Вся сложность заключается в том,что скрипт выполняется не как обычная программа. Он выполняется в специальной среде сервера,которая создается при клиентском запросе, к тому же он исполняется не из под вашего аккаунта,а на непривилегированом уровне.
Если скрипт не исполняется потому,что вы допустили синтаксические ошибки,то самих этих ошибок вы не увидите,на экране будет только из-за чего она произошла вы можете только гадать. Также если вы забыли задать к какому-то файлу нужные права доступа ,то тоже будет трудно выяснить что же произошло и в чем причина ошибки (если конечно к этому вы не готовы).
Ну вот ,хватит вас пугать,тем более что нас не запугаешь ;) !
Приступим к отладке.Я вам опишу достаточно примитивные меры,которыми я сам пользуюсь.
Начнем с того что у нас есть скрипт test.cgi мы уже сделали его исполняемым chmod +x test.cgi Простейший способ проверить его на ошибки это команда Ключ -c говорит Perl что надо только проверить синтаксис.Все сообщения об ошибках вы можете видеть и подправить.Более тяжелый случай состоит в том когда Perl встроен в Web -Сервер, причем версии разные.Как у до недавнего времени было на uic‘е ;(( ! Тот Perl с которым работаем в командной строке 4й версии ,а на сервере стоит 5й версии.Если ваша CGI-программа использует при этом какие-нибудь преимущества 5-й версии (например обьектно-ориентированые модули),то вы думаете отладить ее низ -ошибаетесь!.Только приготовтесь к тому, что я сейчас скажу,вы сядте,а то упадете ;)) :
Закоментируйте всю вашу программу ,т.е. перед каждой строчкой поставьте символ ‘#’. После чего,добавьте вот такие строчки: ,Должно получится так: А теперь запускайте скрипт.Естественно он выдаст Одно только слово ‘Test’. Разкоментируйте несколько строчек.Еще раз запустите скрипт.Он опять выдаст ‘Test’. Значит синтаксически эти только что разкоментированые строчки были правильные. И так далее.
Если очередной раз после раскоментирования вы запустили скрипт и получили ‘Internal Server Error’ — значит в этих строках содержалась какая-та синтаксическая ошибка. Это способ отловки синтаксических ошибок трудоемок,но к нему придется прибегнуть если ваш скрипт писан под ту версию Perl,что на сервере,а не под ту что у вас.
Узнать версию Perl можно
Ну вот мы отловили в нашем скрипте все синтаксические ошибки,он заработал, но это не значит,что он работает правильно.
Что еще можно посоветовать при отладке CGI-скриптов от ошибок возникающих во время выполнения программы. Допустим какой-то файл не открылся.Конечно показывать перепуганому пользователю эти технические подробности никчему,поэтому заведите себе специальный файл debug.txt и пусть ваши скрипты пишут в этот файл причины своих ошибок и сбоев, да и вообще о всех непредвиденых событиях.
Это можно реализовать так: Примеры использования (Напомню,что встроеная переменная Perl $! содержит сообщение о причине последней ошибки,поэтому включайте ее всегда в свои сообщения): Потом можно периодически заглядывать в этот файл debug.txt и смотреть,какие ошибки встречались при работе ваших скриптов.Таким образом ваши скрипты сами помогать будут в своей отладке ;).

Также очень может оказать помощь (может и не оказать) просмотр http‘шных логов. Все обращения к URL на сервере и все возникающие при этом ошибки идут в логи сервера httpd. Сразу хочу предупредить — размеры этих логов даже на средних размеров сервере достигает десятков мегабайт. Поэтому даже не пытайтесь их вот так просто посмотреть.- Лучше если вы уж за данное дело взялись — воспользуйтесь такими утилитами как grep,head,tail,more,less. .

Кстати я хочу сказать о причине еще одной (совсем не очевидной) ошибки.Если вы набрали скрипт у себя дома на компутере,то полученый скрипт состоит из текста в DOS‘ом формате, а не в Unix‘ом так что имейте это ввиду. Запускать вам его придется в системе Unix , так что следует перевести програмный текст в нужный формат.
Дело в том что в системах DOS и Windows (это уж очередной раз скажите все что вы думаете о Билле Гейтсе и Ко) для разделения строк используетс не один («\n»),а пара символов («\r») и («\n»). Для простых HTML-файлов это не критично — браузеры игнорируют такие символы при выводе. Но скрипт является ПРОГРАММОЙ. А в программе никаких символов возврата каретки быть не должно!! Особенно в первой строке. Потому что когда операционная система запускает скрипт, она определяет какое приложение запустить для обработки данного скрипта именно по первой строке. В первой строке как вы знаете содержится #!/usr/bin/perl или #!/usr/local/bin/perl .Поэтому при запуске скрипта mysrcipt (это кстати вы можете сами увидеть коммандами top и ps) Система запускает комманду .А теперь представьте что будет если не убрать символ возврата каретки из Windows-файла. Получиться и естественно что такого приложения нет, и следовательно попытка выполнить коммаду ни к чему не приведет.
Как с таким злом бороться я раскажу в моей следующей главе.

Trics and traps

Примеры приложений:

Кто посещает мою страничку?

Гостевая книга

Счетчик посещений

Наверное тоже одним из часто встречающихся приложений CGI являются счетчики посещений. Они стоят практически на каждой страничке, возможно даже и у вас. Но иногда вас не устраивает тот факт, что счетчик лежит где-то в другом месте.Из-за этого скажем невозможно начать счет с произвольного числа.Или еще некоторые счетчики по разному фильтруют ‘Reload’. Да и мало ли? Ну а иногда вам хочется просто сделать другой дизайн цифр. То если вы CGI-програмист то возможно имеет смысл написать свой счетчик. И делать с ним что захочется. Вот я так-же написал.
Скрипт данного счетчика обслужевает несколько счетчиков ,им вы присваиваете идентификаторы. Поэтому вы спокойно можете втыкать независимые счетчики в разные страницы сайта и даже давать это делать друзьям. В общем он прост в использовании: , Где name -любое уникальное имя идентифицирующее счетчик.Вытакже можете задать необязательный параметр dig который задает количество цифр в счетчике ,Например:

Получится примерно вот так:
.gif‘ы в счетчике с прозрачными областями.Что дает дополнительную гибкость к примеру для улучшения внешнего вида с помощью другого фона его иногда имеет смысл запихнуть в «таблицу»:

Свои данные он пишет примерно в такой файл counter.dat: Вы спросите,зачем столько информации? Чтобы отфильтровывать нажатия Reload. Если с одного IP-адреса между заходами промежуток меньше чем 30 секунд,то счетчик не инкрементируется (Так например поступает счетчик в Rambler‘е).
Теперь об исходнике. Скрипт получился великоват,потому,что сдесь большую часть занимает генерация .gif — файлов.. Выглядит громоздко , зато пашет как трактор ;))!! Если вам циферки не понравились вы их легко сможете заменить.

Вместо заключения

Оглавление:

Пару слов от автора

Что меня заставило взятся за этот нелегкий труд написания данного учебного пособия. Ну во первых то что практически НЕТ ничего по CGI-програмированию на русском языке, а большинству тех,кто хотел бы изучить CGI, документация на английском в отличии от тех немногих типа меня практически недоступна для понимания.Чтоб помочь им преодолеть этот в первую очередь языковый барьер я и сел писать эту книгу.
Еще причина ,отчасти перекликающаяся с первой, это то что когда говорят об интернет-программировании обычно излагают HTML со всеми тэгами, которые всем уже по ночам в кошмарах снятся ,ну а после чего начинают долго охать и ахать над прелестями нового аппаратно и платформо-независимого, переносимого, безопасного. и.т.д. языка Java.Иногда в еще и могут тонким краешком затронуть JavaScript.Видя эту не побоюсь этого слова безнадежную ситуацию, я как доблестный CGI-программист решил хоть что-то поправить к лучшему. Если у меня это хоть немного удалось, то напишите мне.
Если также у вас есть какие-то вопросы -тоже пишите, я с радостью постараюсь ответить на них всех.

Краткое лирическое отступление насчет CGI

Итак что такое CGI— скрипты и вообще подобные вещи. Начнем с того что ваш браузер (когда вы набрали URL) соединяется по протоколу HTTP с указаным сервером и просит у него нужный файл,примерно так:

Вот это самое главное в запросе

Ну тут дальше идет посылаемая браузером информация о себе и о том что более подробно ему надо.(Например Accept: */*)

Ну и если запрошен простой файл например .html то если если такой файл есть, То сервер отошлет браузеру ответ:

В ответе , состоящем из зоголовка и тела, в заголовке содержится код возврата и информация о типе содержимого. Далее после пустой строки (она нужна чтоб отделить заголовок от тела) идет информация из самого документа , по заданому URL .
Вот в принципе и весь WWW . ходишь от ссылки к ссылке.
А что если Нужно внести в этот унылый процесс что-нибудь по настоящему интерактивное , динамическое,прекрасное и великолепное. Чтож есть ответ и на этот вопрос. Просто что если в запрашиваемом URL указать специальную программу (CGI,программа Common Gateway IntefaceОбщего Шлюзового Интерфейса) и то что эта прога выдаст то и отправитьс браузеру. Сервер запускает .cgi программу и она например обработав данные формы заносит вас куда-нибудь в свою базу данных,а вам сообщит что вы большой молодец :)
Ну надеюсь я вас заинтриговал.

Итак . приступим.

Краткие сведения о том что надо знать чтоб писать CGI скрипты:
Ну вопервых надо знать что такое интернет и как он работает (а вы знаете? ;))) ) Ну и чуть-чуть умения програмировать(это самое главное)

На кого ориентировано данное учебное пособие -спросите вы ? Ну в принципе на достаточно широкую аудиторию тех, кто занимается Интернет-программированием и кто хотел бы освоить премудрости интерфейса CGI. Данная книга будет весьма полезна для web-дизайнеров, системных администраторов интернет-серверов, программистов и для простых пользователей интернет, которые хотели бы сделать свой сайт по-настоящему достойным называться хорошим сайтом.
Так как интернет в основном строится на операционной системе UNIX , то изложеный сдесь материал может быть без особых модификаций реализован на практически любой UNIX-системе.
Кроме того, я также делаю предположение , что ваш web-сервер поддерживает интерфейс CGI и для вас эта поддержка включена. (на «халявных» серверах администраторы отключают CGI и SSI для пользовательских директорий — просто это такая политика — предоставлять только ОЧЕНЬ МИНИМАЛЬНЫЙ сервис.) Так что если вы хотите изучать CGI то вам нужет нормальный ,полнофункциональный сервер. Если же вы сами являетесь системным администратором на своем сервере , то для вас, естественно нет проблем, ведь включить CGI для какой-нибудь директории — это просто подправить одну строчку в файле конфигурации сервера.

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

Давайте вместе писанем какой нибудь простенький скриптик а потом я вам расскажу где сдесь собака порылась.
Ну сначала в своем домашнем каталоге создайте директорию cgi-bin:

cd public_html
mkdir cgi-bin
chmod 0777 cgi-bin

Последняя строчка будет очень важна.
Возьмите редактор и наберите:
Сохраните его в директории cgi-bin под именем first.cgi .Ну как сохранили?
А теперь сделайте его исполняемым(ведь это программа):

chmod +x first.cgi

Ну вот,подходим к торжественному моменту. наберите в строке браузера http://www.ваш.сервер.ru/

ваш_логин/cgi-bin/first.cgi
и посмотрите чо будет. Будет одно из двух ,либо скрипт заработает и вы увидите сгенерированую им страничку (поздравляю,в нашем полку прибыло!) либо Internal Server Error -тогда не расстраивайтесь,вы что-то сделали не так.
Вам тогда пригодится пособие по ловле блох.
Ну вопервых проверку синтаксиса можно осуществить следующим образом:

perl -с first.cgi

Perl вам сразу выдаст либо сообщения об ошибках(ну бывает,точку с запятой пропустили, скобочки или кавычки забыли закрыть. ) это сразу по ходу дела поправимо.
Более грубая с логической точки зрения это пропустить вывод пустой строки, которая отделяет заголовок от тела:

Разберем скрипт:
Первая строка #!/usr/bin/perl Просто указывает где в системе расположен компилятор Perl. Обычно он находится /usr/bin/perl или /usr/local/bin/perl ,выяснить это можно одной из комманд или ну или (что очень долго) запустить полный поиск .
Вторая строка это просто коментарий -вы можете тыкать чо угодно после знака #, однако я пишу обычно во второй строке название скрипта, что очень удобно.
Затем идет print «Content-Type: text/html\n\n»; Это заголовок указывающий тип содержимого.
Все что скрипт печатает в свой стандартный вывод STDOUT идет на обработку к серверу. Пустая строка отделяет заголовок от тела,которое в нашем случае представляет собой
Сервер обработает ответ скрипта и на базе него сформирует и пошлет браузеру ответ.(Сервер обычно не изменяет тела сообщения,он только дополняет заголовок нужными для работы протокола HTTP полями)

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

Переменные среды CGI

Предыдущий скрипт не содержал ничего особенно замечательного,так просто вываливал HTMLый текст который благополучно и отбражался на экране браузера.Но По настоящему мощь придает CGI возможность обработки параметров,которые переданы скрипту.например вы можете набрать
http://www.somehost.ru/somedir/cgi-bin/my_cgi.cgi?param=value
то есть вы хотите чтоб скрипт my_cgi.cgi обработал для вас параметер param со значением value (ну это например) или когда вы заполнили запрос в форме (в например yahoo или altavista).Ну это с точки зрения пользователя. А на сервере при запуске CGI-скрипта сервер формирует среду окружения в которой скрипт может найти всю доступную информацию о HTTP-соединении и о запросе.
Вот эти переменные:

Это одно из самых главных поле используемое для определения метода запроса HTTP Протокол HTTP использует методы GET и POST для запроса к серверу.Они отличаются тем что при методе GET запрос является как-бы частью URL т.е. http://www. /myscript.cgi?request а при методе POST данные передаются в теле HTTP-запроса (при GET тело запроса пусто) и следовательно для CGI тоже есть различие при GET запрос идет в переменную QUERY_STRING а при POST подается на STDIN скрипта.
Пример:REQUEST_METHOD=GET

Это строка запроса при методе GET. Вам всем известно что запрос из формы кодируется браузером поскольку не все символы разрешены в URL некоторые имеют специальное назначение. Теперь о методе urlencode: неплохо бы чисто формально напомнить,что все пробелы заменяются в URL на знак ‘+’, а все специальные и непечатные символы на последовательность %hh ,где hh-шестнадцатиричный код символа,разделитель полей формы знак ‘&’,так что при обработке форм надо произвести декодирование.
Пример:QUERY_STRING= name=quake+doomer&age=20&hobby=games

Длина в байтах тела запроса.При методе запроса POST необходимо считать со стандартного входа STDIN CONTENT_LENGTH байт,а потом производить их обработку.Обычно методом POST пользуютс для передачи форм,содержащих потенциально большие области ввода текста TEXTAREA.При этом методе нет никаких ограничений,а при методе GET существуют ограничения на длину URL .
Пример:CONTENT_LENGTH=31

Тип тела запроса(для форм кодированых выше указаным образом он application/x-www-form-urlencoded)

IP-Адрес удаленого хоста,делающего данный запрос.
Пример:REMOTE_ADDR=139.142.24.157

Если запрашивающий хост имеет доменное имя,то эта переменная содержит его, в противном случае -тот же самый IP-адресс что и REMOTE_ADDR
Пример:REMOTE_HOST=idsoftware.com

Имя скрипта,исполизованое в запросе.Для получения реального пути на сервере используйте SCRIPT_FILENAME
Пример:SCRIPT_NAME=/

Имя файла скрипта на сервере.
Пример:SCRIPT_FILENAME=/home/p/paaa/public_html/cgi-bin/guestbook.cgi

Имя серера ,чаще всего доменное как www.microsoft.com ,но в редких случаях за неимением такового может быть IP-адресом как 157.151.74.254
Пример:SERVER_NAME=www.uic.nnov.ru

TCP-Порт сервера используюшийся для соединения .По умолчаниию HTTP-порт 80, хотя может быть в некоторых случаях другим.
Пример:SERVER_PORT=80

Версия протокола сервера.
Пример:SERVER_PROTOCOL=HTTP/1.1

Програмное обеспечение сервера.
Пример:Apache/1.0

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

Давая запрос на сервер браузер обычно расчитывает получить информацию определеного формата,и для этого он в заголовке запроса указывает поле Accept:,Отсюда скрипту поступает cписок тех MIME,которые браузер готов принять в качестве ответа от сервера.
Пример:HTTP_ACCEPT=text/html,text/plain,image/gif

Браузер обычно посылает на сервер и информацию о себе,чтоб базируясь на знании особеностей и недостатков конкретных браузеров CGI-скрипт мог выдать информацию с учетом этого. Например,разные браузеры могут поддерживать или не поддерживать какие-то HTMLые тэги.
Пример:HTTP_USER_AGENT=Mozila/2.01 Gold(Win95;I)

Имя хоста к которому обращается браузер. Так как физически на одном сервере может находиться сразу много серверов (Виртуальные Хосты), то должен быть способ сообщить серверу к какому именно идет обращение. Скрипт же может тоже в зависимости от этой переменной производить различные действия, таким если он используется на сайтах сразу нескольких виртуальных хостов.
Пример:HTTP_HOST=www.nnov.city.ru

Ну,начнем применять на практике усвоеные уроки. Так как все ваши .cgi -файлы должны быть исполняемыми то чтоб облегчить себе жизнь заведите себе в директории cgi-bin командный файл mkcgi ,содержащий и сделайте его в свою очередь исполняемым chmod +x mkcgi -он сильно упростит вам жизнь.
Ну а теперь запускайте скрипт.
Изучив информацию,выдаваемую данным скриптом вы сможете лучше ориентироваться в переменных окружения CGI.

Прекрасный язык Perl

Вы наверное обратили свое внимание что CGI скрипты пишутся обычно на языке Perl (Practical Extraction and Report Language)— очень удобном языке,впитавшем из других все лучшие черты.Может у вас возникнуть сомнение :Ну вот!Изучать новый язык программирования!? Спешу вас успокоить,изучение Perl не будет в тягость (я сужу по своему опыту!). Вы даже сами не заметите как выучите его.Если вы хоть когда-нибудь программировали скажем на C и использовали утилиту grep для поиска регулярных выражений в тексте,то вам будет еще легче. Для Perl родной платформой является Unix поэтому пользователям PC он мало известен. Мое целенаправленое доведение Perl до широкой публики началось с того что я скачал Perl под Windows (фирмы ActiveWare) К нему прилагается отличная гипертекстовая HTML— документация, даже быстрого просмотра которой хватит , чтобы начать хорошо и широко использовать его. Хоть он значительно уступает и по скорости и по эффективности своему Unix’ному аналогу, все равно самый лучший способ изучить язык это программировать на нем. Если вы как я дома используете большую часть времени не Windows а Unix то с изучением Perl у вас вообще не должно быть особых сложностей. Я же от себя могу сказать, что даже после небольшого опыта изучения его, он стал моим любимым языком программирования.

Все в нем сделано для удобства программиста (в отличии например от Java ;( )
Начнем с переменных,они в Perl бывают 3х типов скаларные,списковые(массивы) и хэши(ассоциативные массивы). Для указания компилятору(да и для немалого удобства программиста) перед именем скалярной переменной стоит знак ‘$’ перед массивом ‘@’,перед хешем ‘%’. т.е. например $scalar_var,@array_var,%hash_var Скалярные переменные могут быть как числовые так и строковые,но это не надо указывать Perl сам по контексту в зависимости от операций может привести одно к другому.
Например: «123»+»4″ будет 127 (или «127») так как операция ‘+’ действует над числами а вот если применить операцию конкатенации строк ‘.’ то строковое «test» . 1 будет «test1»
Ну а вот операции над скалярными переменными:

Операцыи Описание Пример
+ — * / % Арифметические print 2*7+4/(8%3);
print int(127/15); #целая часть
** Возведение в степень print 2**16;
++ — Инкремент-декремент $i++;
& | ^

>

Побитовые $x=3;$y=4;
print $x|$y;
print $x&$y;
== != = Числовые операции сравнения if($x==9)
eq ne lt gt le ge cmp стрковые операции сравнения if($game eq ‘doom’)
|| && ! Логические if(($x==9)||($game eq ‘doom’))
?: Условный оператор $x=($game eq ‘quake’?9:8);
, Последовательное вычисление $x=10,$y=20;
. Конкатенация $x=’http://’.’www.uic.nnov.ru’;
x Повторение $x=’1234’x5; #$x=’12341234123412341234′
=

Сопоставление с образцом if($url= То же но с отрицанием if($url!

= >= .= x=

Присваивание $x+=$y;

Пусь это будет вам справочником ,да кстати насчет строк,вы заметили,что они могут быть в двойных и одинарных кавычках, разница между ними состоит в том ,что в одинарных не осуществляется подстановка переменных, а в двойных осущестляется, Например: Списки: Спискочные переменные начинаются с символа ‘@’ конструируются следующим образом Также можно список использовать как lvalue: Можно обращаться к нескольким,выбраным элементам массива(срезу массива): Обратится к скаларному значению -элементу массива можно $имя_массива[индекс], сдесь обратите внимание на знак ‘$’— мы ведь обращаемся к скаляру-элементу.
Теперь немного о хешах:
хеш это такой массив который состоит из пар ключ-значение, весь хеш обозначается %хеш ,к отдельным элементам доступ $хеш конструируется хеш так: Хеш может быть также сконструирован из массива с четным числом элементов где пары превращаются в ключ-значение удаление из хеша -операция delete: есть функции выдающие ключи и значения соответственно. Операторы:
Набор операторов в Perl Очень широк,многие из них прямые аналоги имеющихся в других языках,например if,for,while;но есть и значительные улучшения имеюшихся и конечно новые.
Тот же самый оператор if имеет две формы (как когда удобнее): В пару к оператору if имеется оператор unless : означающий if с отрицанием: Также в пару while существует until
синтаксис оператора for полностью аналогичен C: новшеством(и приятным) является foreach позволяющий пройтись по всем элементам массива,присваивая по очереди его элементы какой-то переменной, его синтаксис такой:
Последний пример особенно важен для упрощения вашего тяжкого труда програмиста и демонтстрирует интересную особенность Perl-переменную по умолчанию $_: в оргомном количестве операторов и функций при опускании аргумента она подразумевается по умолчанию. Она также по умолчанию сопоставляется с регулярным выражением: как видите затраты труда значительно сокращаются,благодаря этому маленькому трюку.

Регулярные выражения.
регулярное выражение записывается между двух слэшей /рег_выр/ это самый простой пример применения регулярного выражения а теперь посложнее вот тут в табличке (из того что я помню наизусть):

Символ Значение Пример применения
. Соответствует любому символу print if /ab.c/;
[мн-во симв] Соответствует любому символу из данного мн-ва /[abc]d/;#соответствует ad,bd,cd
[^мн-во] Отрицание мн-ва символов /[^xyz]/;#
(. ) Группировка элементов(и также запоминание в переменных $1 $2 $3 . ) /(xyz)*/
/([abc].[^xy]qwerty)/
(..|..|..) Одна из альтернатив
* повторение образца 0 или более раз /.*/;#соответствует всему
? Повторение 0 или 1 раз /(http:\/\/)?.*\.cgi/
+ Повторение 1 или более раз
повторение от n до m раз
повторение точно n раз
повторение n и более раз
Спец символы:
\t \r \n . Управляющие символы:табуляции,возврат каретки,перевод строки.
\d Соответствует цифре,Аналог [0-9]
\D Соответствует нецифровому симсволу,аналог[^0-9]
\w Соответствует букве
\W Соответствует небуквеному символу
\s Соответствует пробельным символам(пробелы,табуляции,новые строки..)
\S Соответствует непробельному символу
\b Соответствует границе слова $test1=»this is test»;
$test2=»wise»;
if($test1=

/\bis\b/)#нет

\B Соответствует не границе слова /\Bis\B/ соответсвует ‘wise’ но не ‘is’

Для того чтоб поместить в регулярное выражение любой специальный символ,поставьте реред ним обратный слэш Заставить Perl игнорировать регистр можно поставив i после регулярного выражени
Полезные функции.
В Perl очень много различных функций ,как говорится на все случаи жизни,все о них конечно не опишу,но обо многих. Начну с тех,которые больше относятся к операторам. Операция замены s/рег.выражение/строка/ игнорировать регистр — опция i глобальная(по всей строке) замена -опция g; Пример: Очень полезная опция у s/// e -она означает что вторая строка не строка а выражение, результат которого и будет подставлен. Например,у вас есть файл в котором все записи о возрасте через год надо менять или более показательным примером послужит функция urldecode,которая будет встречатс в каждой вашей программе,обрабатывающей формы: Также важным удобством в Perl являются операции для работы с файлами для выполнения схожих функций в других языках приходиться проделывать огромную массу работы. Аргументами могут быть как Файловые переменные,так и строки,представляющие имя файла.

Операция Описание Пример использоввания
-r Доступен для чтения unless(-r «myfile»)
-w Доступен для записи
-x Для исполнения
-o Принадлежит пользователю if(-o «index.htm»)
-R Доступен для чтения реальным
пользователем,а не только «эффективным».
Имеет значения для set-uid -скриптов
if(-r FILE)>
-W Доступен для записи реальным пользователем
-X Доступен для исполнения реальным пользователем
-O Принадлежит реальному пользователю
-e Файл или каталог Существует unless(-e $htmlfile)<
open(HTML,»>$htmlfile»);
print HTMLFILE » «;
close(HTMLFILE);
>
-z Существует,но имеет нулевую длину if(-z ‘tmpfile’)
-s Размер файла в байтах system(«rar m -m5 archive.rar $myfile») if -s $myfile > 1000;
-f Файл существует и является простым файлом
-d Файл существует и является каталогом if(-d ‘public_html’)
-l Символической ссылкой
-p Каналом FIFO
-u Имеет бит установки пользователя
-g Имеет бит установки группы
-k Установлен sticky-бит
-t Является терминальным устройством
-M Время с последнего изменения (в днях) while(defiled($file=glob(‘*’))) <
if(-M $file >= 7.0) <
unlink($file);#удаляем слишком старые файлы
>
>
-A Время последнего доступа(в днях) if(-A «$ENV<'HOME'>/public_html/index.html»
избавиться от символа новой строки на конце поможет функция chomp, ведь этот символ может помешаться например в имени файла или при выводе на экран Если также подставить списочную переменную,то получим список строк файла от текущей строки и до конца бинарный файл можно читать и писать функциями sysread и syswrite:
sysread(ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт)
syswrite(ФАЙЛОВАЯ_ПЕРЕМЕННАЯ,$скалярная_перемменая,сколько_байт)
функции split и join: @Список=split(/рег.выр/,$скаляр);
$скаляр=join(строка,@Список);
Встроеные функции Perl можно вызывать со скобками или без (как вам удобно), скобки программисты указывают или для красоты,или чаще,что устранить возможную неоднозначность в выраженнии: Надеюсь что я вас позабавил примерами функций ;).

Примеры применения Perl для различных нужд.
Следующая программа переводит текстовый файл в формат HTML (вспомните сколько хлопот вам доставит отлов во всем файле ‘ ‘ и ‘&’ чтоб заменить их на &tl; , > и & а как неплохо чтоб автоматически все http://www. превратились в http://www. ) Более подробную информацию о Perl вы можете получить по адресам:
http://www.perl.com
http://www.metronet.com/0/perlinfo/perl5/manual/perl.html
http://www.ActiveWare.com/

Заголовки запросов и ответов

Даже если вы и знаете кое-что о HTTP все равно не лишне будет вспомнить о том как это все работает тем более на эту информацию придется ориентироваться при написании CGI скриптов.
Этапы соедирения.
Первый этап это когда HTTP -клиент(браузер) соединяется с сервером.для этого он использует протокол TCP/IP соединение происходит к известному клиенту TCP-порту (80 -номер порта HTTP) (другие сервисы сидят на других портах ,например FTP и SMTP на 21 и 25)
Вторым этапом идет запрос клиента:клиент передает заголовок запроса и возможно(в зависимости от метода) тело сообщения запроса.В заголовке обязательно указывается метод ,URI,и версия HTTP,и может быть еще несколько необязательных полей
Третий этап -ответ сервера,который опять таки состоит из заголовка,в котором сервер указывает версию HTTP и код статуса, который может говорить о успешном или неуспешном результате и его причинах.Далее идет тело ответа.
Четвертым этапом происходит разрыв TCP/IP соединения.
HTTP -запрос.
Запрос состоит из Строки запроса(она обязательна) и остальных полей. Синтаксис строки :МЕТОД URI HTTP/версия
где -пробел , -переход на новую строку
Методы HTTP.
GET
Самый часто применяемый метод,в протоколе HTTP/0.9 был единственным методом,и применяется для извлечения информации по заданому URI Может быть условным если в заголовке указано поле If-Modified-Since:

HEAD
Почти идентичен GET но отличается тем что сервер не возвращает тело обьекта а только его заголовок (метаинформацию) программы могут применять его для проверки гиперссылок на правильность,доступность и изменения.

POST
передает данные для обработки их программой ,указаной в URI сдесь обязательно указывается поле Content-Length:

Сушествуют и другие ,реже применяемые методы,например PUT -для сохранения передавемых данных в указаном URI и DELETE для удаления ресурса.

Поля заголовка запроса.
После строки запроса идут поля заголовка запроса. Поля общего(general-header) заголовка (он общий как для запросов так и для ответов):
Date:
Указывает дату запроса,например:
Date: Sun, 20 Nov 1994 08:12:31 GMT

MIME-version:
Указывает версию MIME (по умолчанию 1.0)
MIME-version: 1.0

Pragma:
Содержит указания для таких промежуточных агентов как прокси и шлюзы,
Pragma: no-cache

Поля относящиеся к запросу(Request-Header):
Authorization:
Содержит информацию аутентификации
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

From:
Браузер может посылать адрес пользователя серверу
From: quake@doom.ru

If-Modified-Since:
используется при методе GET ресурс возвращается ,если он был изменен с указаного момента, может использоваться при кешировании.
If-Modified-Since:Mon 15 Jul 1997 00:15:24 GMT

Referer:
Содержит URL предшествующего ресурса.
Referer: http://www.uic.nnov.ru/

User-Agent:
Програмное обеспечение клиента.
User-Agent: Mozilla/3.0


Заголовок информации сообщения (Entity-Header) применяется как в запросах так и в ответах (при этом некоторые поля только в ответах):
Allow: (в ответе сервера)
Список методов,поддерживаемых ресурсом.
Allow: GET, HEAD

Content-Encoding:
идентифицирует метод кодировки,которым был закодирован ресурс
Content-Encoding: x-gzip

Content-Length:
Длина тела сообщения
Content-Length: 102

Content-Type:
Содержит тип ресурса(MIME),для текстовых еще и кодировку символов(необязательно)
Content-Type: text/html; charset=windows-1251

Expires: (в ответе сервера)
Дата окончания действия ресурса,применяется в кешировании для запрета кеширования устаревших ресурсов (в ответе)
Expires: Tue, 24 Sep 1998 23:00:15 GMT

Last-Modified: (в ответе сервера)
Время последнего обновления ресурса
Last-Modified: Tue, 23 sep 1998 13:48:40 GMT

Другие поля:
Поля Accept: указывают серверу выдавать только указаные форматы данных,которые клиент может распознать.
Accept: text/html
Accept: text/plain
Accept: image/gif

Поле Host: служит для того , чтобы указать, к какому хосту идет обращение. Данное поле не входит в число обязательных. Однако оно является необходимым в тех случаях, когда одному физическому серверу соответствует несколько виртуальных хостов. В этом поле тогда указывается какой из виртуальных хостов имеется в виду.
Host: www.nnov.city.ru

Примеры запросов: Ответ HTTP-сервера.
Ответ идет от сервера.Состоит он из строки состояния и затем поля ответа Общий заголовок(General-Header) и заголовок тела сообщения (Entity-Header),которые уже описаны при обсуждении запроса. и еще идет заголовок ответа(Response-Header).
Строка состояния имеет следующий формат:
HTTP/version Status-Code Status-Phrase
где HTTP/version версия,Status-Code -3х значный код,и Status-Phrase текстовая фраза, поясняющая код ,пример: HTTP/1.0 200 Ok
,200 -код означающий успешную обработку запроса,что и поясняет «Ok» Заголовок ответа состоит из полей:
Location:
Содержит URI ресурса,может быть использован для переключения клиента в другое место, если например ресурс был перемещен в другое место или на другой сервер.
Location: http://www.uic.nnov.ru/newlocation/index.html

Server:
Информация о програмном обеспечении сервера
Server: Apache/1.1

WWW-Autenticate:
Параметры аутентификации.
WWW-Autenticate: Basic realm=»doomsday»

Коды ответов HTTP.

Код статуса Значение
200 OK
201 Успешная команда POST
202 Запрос принят
203 Запрос GET или HEAD выполнен
204 Запрос выполнен но нет содержимого
300 Ресурс обнаружен в нескольких местах
301 Ресурс удален навсегда
302 Ресурс отсутствует временно
304 Ресурс был изменен
400 Плохой запрос от клиента
401 Неавторизованый запрос
402 Необходима оплата за ресурс
403 Доступ Запрещен
404 Ресурс не найден
405 Метод не применим для данного ресурса
406 Недопустимый тип ресурса
410 Ресурс Недоступен
500 Внутренняя ошибка сервера
(это по вашу душу,юные CGI-программисты ;( )
501 Метод не выполнен
502 Неисправный шлюз либо перегруз сервера
503 Сервер недоступен/тайм-аут шлюза
504 Вторичный шлюз/тай-аут сервера

Более подробное описание всех кодов можно найти в RFC-1945
Несколько примеров:
CGI-заголовок.
В том случае когда запрашиваемый URI есть CGI-скрипт сервер базируясь на данных запроса создает среду переменных CGI и передает управление скрипту скрипт должен выдать CGI-заголовок,после которого и идет тело ответа,сгенерированое скриптом.
Заголовок (CGI-Header) состоит из полей:
Content-Type:
Должно обязательно присутствовать,если есть тело.
Content-Type: text/html

Location:
Содержит URL ресурса на который скрипт перенаправляет запрос.Как правило,если присутствует это поле больше ничего не указывается.
Location: http://www.idsoftware.com/index.html

Status:
Позволяет CGI скрипту вернуть статус обработки,если это поле не задано,то сервер подразумевает
Status: 404 Not found

На базе этой информации сервер и формирует окончательный заголовок,который и передается клиенту.
Примеры: nph-скрипты.
Иногда возникает необходимость чтобы CGI -скрипт сам отвечал напрямую клиенту, минуя разбор заголовка.Это во-первых уменьшает нагрузку на сервер,и во вторых, что самое главное такой прямой ответ клиенту позволяет скрипту полностью контролировать транзакцию.Для этого существуют nph-скрипты(Not Parse Header) ,имя скрипта должно начинатьс с префикса «nph-« ,Например «nph-animate.cgi» .Такие скрипты сами формируют HTTP-ответ клиенту,что полезно при анимации:
Этот пример вам выдаст анимацию ,составленую из нескольких .gif -файлов.Если же вы получили вместо анимации сообщение об ошибках,то вам следует,может быть перейти к следующей главе, которая поведает вам о правах доступа- того,без чего Unix не был бы Unixом.

Права Доступа

Я бы ни за что не написал этот раздел,если бы он не был так важен.Сидя в пределах своей домашней директории и занимаясь только тем,что качаете с Инета всякую херню,вы возможно и не задавались некоторыми вопросами. а зря. Ведь немного надо,чтоб попортить нервы начинающему CGI -програмисту.
Одна из таких вещей это права доступа.
Начнем с того ,что в системе Unix каждый пользователь имеет свой идентификатор- число,уникально идентифицирующее его в этой системе.(Мой логин paaa а ему соответсвует число 1818).Это число внутреннее для операционной системы,для пользования оно представлено как логин,который и соответствует пользователю.
Только не надо думать о пользователе,как о конкретном человеке сидящим за клавиатурой, пользователем может быть и какой-нибудь процесс.Важно отметить что пользователь-это определенна область прав доступа,которая ему соответствует.(Вы например не можете обычно писать и удалять файлы из каталога другого пользователя). Это и дает возможность стабильной работы всей системы.
Итак есть идентификатор пользователя.Также имеется идентификатор группы.
Группа служит для выделения пользователей по группам. Например у пользователей группы users (Обычные пользователи) не такие права как у группы wheels (административная группа).
Каждый процесс который вами запущен(Будь то Netscape,терминал,или текстовый редактор)получают ваши идентификаторы пользователя и группы. таким образом исполняются от вашего имени.
Теперь рассмотрим повнимательней файловую систему.В Unix с файлом связано много характеристик. Во-первых в системе нет «ничьих» файлов ,все файлы имеют владельца-пользователя и владельца-группу. Любой файл который вы создаете автоматически получает ваш идентификатор.По этому система очень легко отслеживает, чьи это файлы и каталоги.
Следующее новшество по сравнению с DOS это права доступа к файлу.Их может сменить только тот пользователь которому принадлежит файл,или супервизор.(Это в отличии от DOS где каждая дрянь типа вируса может снять атрибут readonly читать и писать все файлы ;()
Права доступа задаются обычно числом в восьмеричной записи и разбиты на 3 части по 3 бита: Каждая часть задает права доступа для конкретной группы:

1я -права доступа для пользователя,которому принадлежит файл
2я -для группы которой принадлежит файл
3я -для всех остальных

В каждой такой категории выделяются 3 права: Право на чтение,Право на запись,и право на исполнение. (все права и аттрибуты очень наглядно показаваютя командой ls с ключом -l) Так как исполнять каталоги бессмыслено,то право на исполнение для них означает право обращатся к файлам из этого каталога.

Бит Описание
8 Право на чтение для пользователя
7 Право на запись для пользователя
6 Право на исполнение для пользователя
5 Право на чтение для группы
4 Право на запись для группы
3 Право на исполнение для группы
2 Право на чтение для всех остальных
1 Право на запись для всех остальных
Право на исполнение для всех остальных

Изменяются права командой chmod,ее синтаксис такой:
chmod [u|g|o]<+|-> file
chmod number file
,где uuser,ggroup,oother,rread,wwrite,x-execute;-удалить,+-установить
Примеры:
chmod +r file.txt #разрешает всем право на чтения файла
chmod u+w file.txt #устанавливает для владельца файла право на запись в него
chmod +x gbook.cgi #право на исполнение для всех,как для ползователя,группы,и для других
chmod 0777 cgi-bin #Разрешает самые широкие права доступа для cgi-bin

Приоткрытии файла программой,операционная система сравнивает идентификатор пользователя с идентификатором пользователя владельца файла, если они равны,то действуют права пользователя,если не равны то сравниваются идентификаторы группы,если и они не равны,то действуют права доступа для остальных остальных.В том случае если у процесса нет достаточных прав,система возвращает ошибку. Следует заметить ,что для супервизора root права доступа не проверяются.
Можно выполнить скрипт,только если есть права на его исполнение. Вот почему следует давать chmod +x *.cgi иначе ваши скрипты станут просто недоступными. Но и это еще не все.
Ваш скрипт может обращатся к вашим файлам (например ведет базу данных гостевой книги). Все выглядит нормально,но только ничего не работает,файл в который вы намеревались писать,
не открывается,знакомая проблема ;(( ?.Так вот чтобы вы не мучались в догадках Ваш скрипт не может получить доступ к вашим файлам,потому что он выполняется не вами (не с вашим идентификатором), а от имени nobody (непривелигированый пользователь).Это мера предосторожности направлена на то, чтоб скрипты ,взбесившись из-за неправильно переданых параметров(или вообще от глюков) не могли ничего повредить ценного и важного на сервере.
Поэтому к тем файлам,к которым скрипт по смыслу должен обращатся нужно присвоить самые широкие права доступа 0777
Например в случае гостевой книги chmod 0777 guestbook.dat
Если также важно чтоб скрипты могли заводить новые файлы в cgi-bin то надо дать также права на это chmod 0777 cgi-bin
Если вы видите что ваш скрипт не может обратится к какому-то файлу,то это в 99% случаев из-за вашей забывчивости.
На самый крайний случай воспользуйтесь setuid-скриптами (к этому делу ,если вы на это решились,отнеситесь ОЧЕНЬ серьезно,так как целые тома по безопасности в Unix посвящены именно setuid-программам). Хочу сразу предупредить ,сам я таких не так уж много писал,да и вам не особенно советую. Но для общего как говорится развития,имейте в виду следующую информацыю.
Кроме указания прав доступа,существуют специальные биты у файла.Это биты установки пользователя и группы. Когда процесс выполняется(простой процесс) то его реальный и эффективный идентификаторы пользователей совпадают,идентификаторы групп тоже. На самом деле значение имеют как раз эффективные значения пользователя и группы,они учавствуют в сравнении прав доступа. Нельзя ли их как-то изменить,когда уж совсем нужда заставит? Можно! .На этот вопрос дают ответ программы с установленым битом пользователя.Когда система запускает такую программу,она присваивает новому процессу не идентификатор того пользователя,что запустил ее, а идентификатор пользователя-владельца исполняемого файла.
Самый классический пример setuid-программ это программа passwd ,предназначеная для смены пароля пользователя. Такие данные как пароль и прочие характеристики пользователей хранятся в специальном файле,который имеет огромное значение при входе в систему. Так как это системный файл,то открыть к нему доступ на запись всем-значит подвергнуть ВСЮ систему риску,ведь любое неправильное изменение его повлечет катастрофические последствия(в конце концов бывает просто хулиганство). Поэтому доступ к этому файлу закрыт для всех пользователей.А что если надо сменить пароль? Запускаем программу passwd! Если глянуть на ее аттрибуты ,то видно что она принадлежит root -супервизору, и еще имеет установленый бит setuid. Так корректно обходится эта проблема.
Если вы все-же решили попытаться ,то знайте ,что сделать программу setuid можно
коммандой : chmod +s myprogramm

И как всгда Примерчик напоследок:
Эта программа выдает содержимое вашей директории public_html в том случае,если она доступна для чтения,и для каждого файла указывает ,можно ли его читать,писать и исполнять. Попробуйте ее сделать setuid и посмотрите как изменится результат.

Генерация ответа

Большую часть того что нужно знать о генерации ответа,я сказал в разделе Заголовки запросов и ответов.Нет,не угадали! Я не буду сдесь говорить о всяком дизайне того что вы выдаете.Этому вы успели напрактиковатся на HTML -страничках.
Я поговорю о MIME (Multipurpose Internet Mail Extension).И о разных браузерах.
Стандарт MIME появился в электронной почте (e-mail) потому что остро стала проблемма пересылки по e-mail различных данных в различных форматах.Так как HTTP тоже работает с различными типами данных то поэтому тоже использует MIME для своих нужд. Типы MIME состоят из Типа и подтипа (например text/plain,где text-указывает на наличие текстового содержимого,а plain-уточняет его как простой текст) приведеный ниже список (он далеко не полн,типов MIME огромное количество) описывает некоторые часто встречающиеся типы.: text/html text/plain text/richtext image/gif image/jpeg image/tiff audio/basic audio/32kadpcm audio/ video/mpeg video/quicktime multipart/mixed multipart/alternate multipart/ application/octet-stream application/msword application/postscript message/digest
Информация о MIME больше возможно пригодится вам в том случае если вы собираетесь работать из ваших скриптов с электронной почтой,но и для WWW она не повредит. Особенно знание Content-Type:
Content-Type:
Состоит из типа и подтипа типы могут быть как стандартные так и экспериментальные начинающиеся с префикса ‘x-‘:

text
Текстовые данные.Первым подтипом который включен сюда это plain,что значит простой текст. сюда же включен самый ходовой формат html .У типа text как и у многих типов могут быть параметры,главным из них является charset он как раз и указывает на раскладку символов, которая применена в тексте, так что если вы хотите указать браузеру какую раскладку применять, то просто укажите charset:
Content-Type: text/plain; charset=us-ascii
Content-Type: text/html; charset=iso-8859-1
Content-Type: text/html; charset=koi8-r

multipart
Данные которые могут состоять из нескольких частей,различных типов данных.Поэтому параметром multipart служит boundary, позволяюший указать разделитель.Каждый фрагмент в многочастевом сообщении имеет свой Content-Type: (Он может быть также multipart,т.е. допускаются вложеные multipart,главное чтоб boundary были разными).В электронной почте применяется больше multipart/mixed (основной подтип) и multipart/alternative (Он отличается тем что показывается одна из альтернатив,например сообщение шлется в простом и HTMLом форматах,и почтовая программа показывает либо часть,которую она способна отобразить). В WWW -програмировании распостранен x-mixed-replace ,который означает что следующая часть должна заменить предыдущую после подгрузки, что применяется для анимации(см.Пример с анимацией).
Теперь о разделителе,его надо выбирать так,чтоб он не встретился где-то в данных (т.е. что-то вроде «diUr344rnmvforgefvrg923rghyj2»).Когда вы задали разделитель,например boundary=»boundary» то когда закончилась одна часть,вы должны выдать строку —boundary,последн часть —boundary—,причем эти разделители должны быть на отдельной строке,а не сливаться с текстом:
Пример:

message
Представляет инкапсулированое почтовое сообщение.Используется в e-mail ,а не в WWW.

image
Некоторое Графическое изображение.(чаще всего image/gif и image/jpeg)

application
бинарные данные какого-нибудь приложения.В том случае если данное приложение может быть запущено,Браузер запускает его.Например при поступлении данных application/msword Браузер спросит,нужно ли запустить Word для просмотра досумента.При отсутствии нужного приложения браузер спросит в каком файле сохранить данные.Подтип octet-stream как раз и означает поток байт информации,который и используется по умолчанию.(К сожалению не все так гладко,известен глюк в Netscape Navigator‘е который вместо того чтоб сохранить application/octet-stream пытается его показать как text/plain что если это сгенерировано из CGI,ни к чему хорошему не приводит ;(()
Что касается application ,то Вы можете тут смело извращатся,используя x- типы данных,
Например application/x-fuck-to-netscape-navigator. ;)))))
Часто используемый параметр name позволяет указать имя файла.Например:
Content-Type: application/msword; name=»readme.doc»
Что полезно при полученнии файлов через HTTP,причем этот параметр может применятся и для других типов таких image или audio ,Например:
Content-Type: image/gif; name=»myfoto.gif»

Content-Transfer-Encoding:
Применяется больше в системе электронной почты и обозначает метод кодирования, которым были закодированы данные при передаче сообщения.Например:
7bit 8bit quoted-printable base64 binary x-типы
MIME-Version:
Указывает версию MIME .

Теперь поговорим о разных браузерах вы знаете что браузеры бывают разные,разных версий на разных платформах, поддерживают и не разные тэги и глюки у них тоже разные. ;((( .
Это могло попортить много нервов WEB-дизайнерам и конечно же нам ,CGI-програмистам. Профессионально написаный сайт от просто хорошего отличается тем что хорошо выглядит Не только на экране того браузера,которым пользуется сам его автор,а на других тоже.
Если вы используете JavaScript для своих страничек,то вы уже наверно использовали (или хотя бы вам в голову приходила мысль использовать)свойства navigator.AppName navigator.AppCodeName navigator.appVersion navigator.userAgent:
Ну не волнуйтесь вы так ,мы CGI-программисты не в самых худших условиях на этот счет. Вспомните о том что браузер сам при запросе посылает вам данные о себе и о своей версии. И делает он это для того,чтобы эту информацию можно было учесть.
В запросе он указывает User-Agent: которое и попадает на сервере в переменную среды HTTP_USER_AGENT ,которую и можно использовать.
Например если в ней содержится Mozilla/3.01Gold (Win95;I) то значит вы имеете дело с Netscape (Mozilla-кодовое название Netscape Navigator‘а),версии 3.01Gold и далее после имени и версии может следовать необязательная информация ,например как в приведеном примере о платформе Win95 и о том является ли версия U -для США (USA) или I -международной(International). Напомню,что такая информация необязательна.(То есть если браузер послал информацию User-Agent: то гарантировано расчитывать вы можете только на Название/Версия).
Ну вот я слишком много развел демагогии,пора переходить к практическим примерам.
Допустим ваш скрипт генерирует какие-то тэги,которые слишком старые браузеры не поддерживают,причем без них не обойдешся,они составляют всю ‘изюминку’ сайта.
Ну уже почувствовали,насколько это здорово.А вот еще примерчик.Это из разряда того, что тэги бывают разные.Например в Explorer есть тэг BGSOUND предназначеный для проигрывани музыки на страничке.(В Netscape этого тега нет,и поэтому для втыкания музыки приходится использовать подключаемые модули plugin).Мутится с этими Плугинами Вам в облом,а хочется побаловать человека хорошей музыкой,если браузер позволяет. Ну вот вы уже можете управлять этим процессом.Только не забывайте,что если вы не получили информацию о клиенте(так может быть,если например ваш скрипт вызвал какая-нибудь поисковая машина) то не в этом случае не надо делать никаких предположений,а просто пусть ваш скрипт продолжает делать то что должен был делать.

Как всегда Примерчик на последок.Этот примерчик позволит выбирать из списка файлов. и загружать что пользователь хочет.

Обработка Форм

Ну вот ,вы уже знаете достаточно,кое в чем уже успели приобрести опыт, пришло время перейти к очень важной теме — обработке форм. При всей простоте (кажушейся) это едва ли не самое главное предназначение всего стандарта CGI . Куда бы вы не зашли на любой уважающий себя сайт,везде вы встретите формы, которые вам предложат заполнить.В этом деле можно положится только на CGI, так как Java и JavaScript ,выполняющиеся на страничке у клиента не имеют доступа к серверу,на котором находится сайт.
Коротко вспомним о том что происходит при рассматриваемом процессе поближе,так сказать на трезвую голову ;). Итак браузер требует у сервера определенный URL (это может быть как простой документ,так и сгенерированый CGI) в этом документе может содержаться форма.Отображая такой документ браузер также выводит элементы формы (кнопки, поля ввода, поля ввода пароля, переключатели, радио-кнопки, списки, текстовые области,скрытые поля). И со всем этим добром пользователь может взаимодействовать.К форме естественно имеет доступ и встроеный язык программирования JavaScript -он может как использовать форму для своих нужд,не передавая CGI,так и помогать пользователю в заполнении формы.
После того,как пользователь заполнил форму он нажимат кнопку Submit которая говорит, что форму надо отправить на сервер. Браузер собирает все имена и значения элементов формы ,кодирует их методом urlencode и в зависимости от указаного в тэге FORM метода вызывает GET или POST с указаным URL,передавая ему данные. На сервере CGI-скрипту это попадает (в зависимости от метода) либо в переменную QUERY_STRING либо на STDIN.Скрипт может проверить данные ,занести их в какую нибудь базу данных,может как yahoo выполнить какой-нибудь поиск, может что-нибудь вычислить. да мало ли что он может,все зависит только от нашей фантазии. В конце концов скрипт выдает браузеру ответ,который он и отображает.В этом ответе может содержаться все что вашей душе угодно от сообщения об удачном или неправильном запросе до таких ответов,по сравнению с которыми yahoo и altavista подвиснут от зависти, главное чтоб вам и тем кто посещает ваш сайт это нравилось.;)

Ну а теперь немного о синтаксисе элементов форм ,их описании и самое главное особенностях при обработке CGI-скриптом.
Итак немного экскурс в HTML:
FORM
Атрибуты:
action
как раз и задает тот URL,который будет и обрабатывать форму, если он опущен,то текущий URL документа(а он-то может быть сгенерирован нашим скриптом).
method
задает метод GET или POST
enctype
обычно не задается,для форм он application/x-www-form-urlencoded -по умолчанию, и поддерживается всеми CGI скриптами.Но если вы уж очень хотите чтобы браузер послал вам данные в другом формате (например text/plain) то можете указать этот тип кодировки,только потом не жалуйтесь,что ваш скрипт не может разделить поля,или вообще начинает глючить когда пользователь ввел какой-то спецсимвол.
name
Задается для JavaScript,чтоб обращатся к форме по имени,а не по номеру. Для CGI не играет ни какой роли,так как внутреннее для браузера.
target
Может Определять в какой фрейм отправить полученую информацию.Имеет значение во фреймосодержащих документах.Прозрачен для CGI обработки данных.
onSubmit
Определяет JavaScript -обработчик активизации формы.Применяется для проверки JavaScript‘ом правильности заполнения.Опять таки прозрачен для CGI.
Пример типичной формы: Форма может содержать элементы.Элементы имеют имена,которые используются дл кодирования пар имя=значение.Некоторые Элементы не передаются CGI,а используются JavaScript для управления,например кнопки.Некоторые поля передаются только в тех случаях, когда в них что-то выбрано,например списки и переключатели.Остальные поля передаются всегда, даже когда они пустые.
Например: Допустим вы ввели имя lesha и адрес paaa@uic.nnov.ru,при этом выбрали переключатель После нажатия кнопки будет отправлен вот такой запрос:
http://www.doom/cgi-bin/test.cgi?Name=lesha&Email=paaa@uic.nnov.ru&doomer=Yes
Если же вы не выбрали переключатель,то запрос будет таким:
http://www.doom/cgi-bin/test.cgi?Name=lesha&Email=paaa@uic.nnov.ru
,как видите элемент doomer не вошел в строку запроса
Теперь попробуйте оставить поля редактирования пустыми:
http://www.doom/cgi-bin/test.cgi?Name=&Email=
Эти элементы (Name и Email) присутствуют и сообщают что они пустые.

Кнопка(button)

В форме изображается кнопка,при нажатии которой вызывается JavaScript-обработчик заданый атрибутом onClick ,атрибут name служит для JavaScript-именования кнопки а не дл передачи CGI.Так как значение кнопки не передается CGI, value задает Текст,изображаемый на кнопке.

Submit

Кнопка,предназначеная для передачи формы.Опять же,сама не передается,а служит только для управления. текст на ней задается атрибутом value.
Reset

Кнопка очистки формы.При ее нажатиивсем измененым элементам возвращается значение по умолчанию.
Поле ввода(text)

Применяется очень часто,поэтому тип «text» служит для INPUT по умолчанию,его не надо каждый раз указывать.Имя поля,задаваемое name является обязательным для CGI (в отличии от JavaScript,где элементы формы можно индексировать по номерам,а имена для удобства и читабельности кода служат).Можно задать значение по умолчанию атрибутом value,которое будет после загрузки докумета.атрибут size позволяет задать размер поля.Также может содержать обработчики onBlur,onChange,onFocus,onSelect.
Текстовая Область(textarea)
Область многострочного редактирования.Размеры в строках и столбцах задаютс атрибутами rows и cols.Значения атрибута wrap «hard» и «soft» -означают соответственно мягкую или жесткую разбивку на строки (в большинстве случаев ето не существенно). На что следует действительно обратить внимание так это на символ,используемый для указания перехода на новую строку. В Windows это ‘\r\n’ а в Unix ‘\n’,так что если это для вас существенно,то приводите преобразование,например так:
$my_text =

s/\r\n/\n/g;
Поле ввода пароля(password)

Очень похоже на поле ввода,отличается тем что вместо символов в нем отображаютс символы ‘*’.Служит для ввода пользователем пароля.
Скрытое поле(hidden)

Поле не отображаемое на экране.Но оно имеет имя и значение и следовательно передается в форму. Служит для того (и очень часто програмисты его применяют) чтоб передавать скрипту какую нибудь информацию.Например,если ваш скрипт обрабатывает несколько форм разных типов,то в скрытом поле каждой формы можно указать с какой формой конкретно вы имеете дело. Так как это ваша внутренняя кухня то нечего пользователю мозолить глаза этой информацией.
Переключатель(checkbox)
Text
В отличии от кнопки,атрибут value сдесь не задает на надпись на переключателе,а его значение(внутреннее).Поэтому если надо что-то подписать,пишите рядом в ним. Может быть сразу выбраным если указан атрибут checked .Если value не указано то значение по умолчанию «on» .Передается только в том случае,когда выбран.
Радио-кнопка(radio)
Text
В отличие от checkbox может быть несколько радиокнопок с одинаковым параметром name ,но с разными value,из них передается только та,что выбрана.Одна из них может быть изначально выбрана по умолчанию checked.Например:
Список(select)
Задает список,позволяющий выбрать одну (или несколько) опций из списка. Если атрибут multiple не указан,то создается простой выпадающий список,в котором можно выбрать только одну из опций.Его значение всегда передается,т.к. всегда хоть одно выбрано. Если указан атрибут multiple,то во первых можно указать размер видимой части списка атрибутом size (Если опций больше появится скролинг).Во вторых передаются только выбраные опции ,т.е.Он может передатся несколько раз ?SelectName=opt1&SelectName=opt2&SelectName=opt9 если выбраны скажем несколько опций.А может и не разу,если ничего не выбрано из списка. Можно задавать обработчики onBlur,onChange,onFocus.
Небольшая Помощь JavaScript
Для CGI-програмиста конечно JavaScript -это иной мир,вы можете спокойно пропустить этот абзац,если вы не знаете JavaScript,так как написаное в нем к CGI не относится, а скорей к самим формам и дизайну сайта.Я скажу пару слов о том как JavaScript может оказать посильную помощь в проверке правильности заполнения форм.Все проверки конечно можно и нужно делать на сервере,но когда имеешь дело с рассеяным пользователем, то для него заполнение простой формы превратится в мучение.Поясню на примере,в форме есть какие-то обязательные поля,например имя.Если пользователь забыл его указать то скрипт скажет ему об этом в сообщении он исправит это, допустим что-нибудь еще не так ввел . Только на передачу данных по сети может уходить масса времени.А на обработку на локальной машине-доли секуды.
Вот Например как это можно применить JavaScript для предварительного контроля правильности. Допустим простейшая форма содержит имя и возраст.Имя не должно быть пустым, а возраст должен состоять из цифр. Ну вот ,на этом можно закончить это краткое введение в HTMLые формы.
Итак,У нас на входе скрипта данные формы,закодированые методом urlencode Положеные в Переменную QUERY_STRING или подаваемые на STDIN.Мы должны вопервых их получить. Вот,мы уже считали наш запрос в переменную $query.Теперь пришло самое время ее обработать. Мы знаем что поля разделены символом ‘&’ значит используем его в качестве разделителя функции split: Вот разделили,а теперь организуем цикл foreach по полученым полям @formfields Сдесь выражение в регулярном выражении в круглых скобках (.*) после знака ‘=’,запоминаетс в скалярную переменную $1 ,которая затем и декодируется нашей старой и знакомой функцией urldecode (я предупреждал,что она будет почти в каждой вашей CGI-программе) Так мы проходим по всем полям,которые нам переданы.Это стандартный подход,он годится в качестве шаблона.У вас может возникнуть вопрос,а что делать если вам переданы данные от списка у которого задана возможность выбора нескольких элементов и данные поступают в таком виде: Sel=opt1&Sel=opt2&Sel=opt9. Тут тоже нет никаких проблем,просто запихиваем эти поступающие значения в массив. И потом спокойно оперируем с Полученым Массивом @Sel.
На этом можно так сказать заканчивается шаблонная часть скрипта и начинается содержательная, которая зависит только от вашей фантазии.
Вы можете сколько угодно анализировать полученые значения,обращатся при этом к различным файлам .Если вы к этому приложите фантазию,то кто знает что получится.
А Пока Ради примера я вам напишу скрипт,который ведет социологическое исследование насчет курения и отношения к нему.Может он слишком массивен для данного пособия, но зато он наглядно показывает как достаточно простыми средствами можно проводить социологические исследования. А вот скрипт для его обработки:

Изображения ismap

Анимация

Когда говорят о каком-то популярном сайте,то частенько к преимуществам относят и анимацию. Действительно,когда изображение изменяется (и особенно к месту ;)),то это смотритс и пользователю нравится.
Говоря об анимации нужно сразу отметить что нет лучшего способа. Анимацию можно сделать ДЕСЯТКАМИ Способов,каждый хорош в своей области применения. Я перечислю только некоторые из них,которые чаще всего применяются:
Самый простой,но наименее функциональный способ это GIF с анимацией.
Потом можно воткнуть анимационный файл MPEG или AVI они более отражают суть анимации, но имеют недостаток,что для проигрывания их на некоторых браузерах нужны специальные подключаемые модули.К тому же они не интерактивны.
Можно реализовать анимацию в рамках Java-апплета,когда апплет находясь на страничке сам перерисовывается со временем.
Таким же интерактивным средством служит обращение к массиву document.images[] из JavaScript.Достоинство-помимо интерактивности,полная интегрированость с HTML -станичкой.Но может как и предыдущий использоваться только с относительно новыми браузерами,которые поддерживают Java и JavaScript.

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

Несколько советов по отладке

CGI-программы -не самые простые в отладке,по сложности отладки они способны сравнится лишь с отладкой драйверов. Вся сложность заключается в том,что скрипт выполняется не как обычная программа. Он выполняется в специальной среде сервера,которая создается при клиентском запросе, к тому же он исполняется не из под вашего аккаунта,а на непривилегированом уровне.
Если скрипт не исполняется потому,что вы допустили синтаксические ошибки,то самих этих ошибок вы не увидите,на экране будет только из-за чего она произошла вы можете только гадать. Также если вы забыли задать к какому-то файлу нужные права доступа ,то тоже будет трудно выяснить что же произошло и в чем причина ошибки (если конечно к этому вы не готовы).
Ну вот ,хватит вас пугать,тем более что нас не запугаешь ;) !
Приступим к отладке.Я вам опишу достаточно примитивные меры,которыми я сам пользуюсь.
Начнем с того что у нас есть скрипт test.cgi мы уже сделали его исполняемым chmod +x test.cgi Простейший способ проверить его на ошибки это команда Ключ -c говорит Perl что надо только проверить синтаксис.Все сообщения об ошибках вы можете видеть и подправить.Более тяжелый случай состоит в том когда Perl встроен в Web -Сервер, причем версии разные.Как у до недавнего времени было на uic‘е ;(( ! Тот Perl с которым работаем в командной строке 4й версии ,а на сервере стоит 5й версии.Если ваша CGI-программа использует при этом какие-нибудь преимущества 5-й версии (например обьектно-ориентированые модули),то вы думаете отладить ее низ -ошибаетесь!.Только приготовтесь к тому, что я сейчас скажу,вы сядте,а то упадете ;)) :
Закоментируйте всю вашу программу ,т.е. перед каждой строчкой поставьте символ ‘#’. После чего,добавьте вот такие строчки: ,Должно получится так: А теперь запускайте скрипт.Естественно он выдаст Одно только слово ‘Test’. Разкоментируйте несколько строчек.Еще раз запустите скрипт.Он опять выдаст ‘Test’. Значит синтаксически эти только что разкоментированые строчки были правильные. И так далее.
Если очередной раз после раскоментирования вы запустили скрипт и получили ‘Internal Server Error’ — значит в этих строках содержалась какая-та синтаксическая ошибка. Это способ отловки синтаксических ошибок трудоемок,но к нему придется прибегнуть если ваш скрипт писан под ту версию Perl,что на сервере,а не под ту что у вас.
Узнать версию Perl можно
Ну вот мы отловили в нашем скрипте все синтаксические ошибки,он заработал, но это не значит,что он работает правильно.
Что еще можно посоветовать при отладке CGI-скриптов от ошибок возникающих во время выполнения программы. Допустим какой-то файл не открылся.Конечно показывать перепуганому пользователю эти технические подробности никчему,поэтому заведите себе специальный файл debug.txt и пусть ваши скрипты пишут в этот файл причины своих ошибок и сбоев, да и вообще о всех непредвиденых событиях.
Это можно реализовать так: Примеры использования (Напомню,что встроеная переменная Perl $! содержит сообщение о причине последней ошибки,поэтому включайте ее всегда в свои сообщения): Потом можно периодически заглядывать в этот файл debug.txt и смотреть,какие ошибки встречались при работе ваших скриптов.Таким образом ваши скрипты сами помогать будут в своей отладке ;).

Также очень может оказать помощь (может и не оказать) просмотр http‘шных логов. Все обращения к URL на сервере и все возникающие при этом ошибки идут в логи сервера httpd. Сразу хочу предупредить — размеры этих логов даже на средних размеров сервере достигает десятков мегабайт. Поэтому даже не пытайтесь их вот так просто посмотреть.- Лучше если вы уж за данное дело взялись — воспользуйтесь такими утилитами как grep,head,tail,more,less. .

Кстати я хочу сказать о причине еще одной (совсем не очевидной) ошибки.Если вы набрали скрипт у себя дома на компутере,то полученый скрипт состоит из текста в DOS‘ом формате, а не в Unix‘ом так что имейте это ввиду. Запускать вам его придется в системе Unix , так что следует перевести програмный текст в нужный формат.
Дело в том что в системах DOS и Windows (это уж очередной раз скажите все что вы думаете о Билле Гейтсе и Ко) для разделения строк используетс не один («\n»),а пара символов («\r») и («\n»). Для простых HTML-файлов это не критично — браузеры игнорируют такие символы при выводе. Но скрипт является ПРОГРАММОЙ. А в программе никаких символов возврата каретки быть не должно!! Особенно в первой строке. Потому что когда операционная система запускает скрипт, она определяет какое приложение запустить для обработки данного скрипта именно по первой строке. В первой строке как вы знаете содержится #!/usr/bin/perl или #!/usr/local/bin/perl .Поэтому при запуске скрипта mysrcipt (это кстати вы можете сами увидеть коммандами top и ps) Система запускает комманду .А теперь представьте что будет если не убрать символ возврата каретки из Windows-файла. Получиться и естественно что такого приложения нет, и следовательно попытка выполнить коммаду ни к чему не приведет.
Как с таким злом бороться я раскажу в моей следующей главе.

Trics and traps

Примеры приложений:

Кто посещает мою страничку?

Гостевая книга

Счетчик посещений

Наверное тоже одним из часто встречающихся приложений CGI являются счетчики посещений. Они стоят практически на каждой страничке, возможно даже и у вас. Но иногда вас не устраивает тот факт, что счетчик лежит где-то в другом месте.Из-за этого скажем невозможно начать счет с произвольного числа.Или еще некоторые счетчики по разному фильтруют ‘Reload’. Да и мало ли? Ну а иногда вам хочется просто сделать другой дизайн цифр. То если вы CGI-програмист то возможно имеет смысл написать свой счетчик. И делать с ним что захочется. Вот я так-же написал.
Скрипт данного счетчика обслужевает несколько счетчиков ,им вы присваиваете идентификаторы. Поэтому вы спокойно можете втыкать независимые счетчики в разные страницы сайта и даже давать это делать друзьям. В общем он прост в использовании: , Где name -любое уникальное имя идентифицирующее счетчик.Вытакже можете задать необязательный параметр dig который задает количество цифр в счетчике ,Например:

.gif‘ы в счетчике с прозрачными областями.Что дает дополнительную гибкость к примеру для улучшения внешнего вида с помощью другого фона его иногда имеет смысл запихнуть в «таблицу»:

Свои данные он пишет примерно в такой файл counter.dat: Вы спросите,зачем столько информации? Чтобы отфильтровывать нажатия Reload. Если с одного IP-адреса между заходами промежуток меньше чем 30 секунд,то счетчик не инкрементируется (Так например поступает счетчик в Rambler‘е).
Теперь об исходнике. Скрипт получился великоват,потому,что сдесь большую часть занимает генерация .gif — файлов.. Выглядит громоздко , зато пашет как трактор ;))!! Если вам циферки не понравились вы их легко сможете заменить.

Вместо заключения

Вот и подошла к концу моя книга. Надеюсь что она найдет поддержку в широких слоях интернет-сообщества.В ней я постарался изложить простым и понятным языком немного из того, что я знаю. Очень надеюсь, что я достиг своей цели (если вы дочитали мое учебное пособие до конца).И я также я очень надеюсь, что те цели которые вы перед собой ставили при прочтении данной книги станут осуществимыми. Если вы прочитали эту книгу, и вам понравилось, порекомендуйте ее своим знакомым web-дизайнерам и начинающим интернет-программистам. Для них она будет очень полезна. Также жду ваших отзывов и предложений. Я постараюсь ответить на интересующие вас вопросы. Если вам данная тема понравится, то я обязательно подумаю над тем, чтобы написать продолжение, в котором я расскажу о тех вопросах, с которыми сталкивается профессиональный интернет-программист в своей работе.
И еще раз хочу дать совет и пожелание: если что-нибудь у вас не получается, не огорчайтесь и не опускайте руки, всегда есть способ сделать любое, пусть даже с первого взгляда сложное дело. Тем более в наших руках такая мощная вещь как интернет, и от нас зависит, каким он будет через месяц, через год, через два, через десять лет. И если вы действительно приложите усилия , то ваш сайт станет достойным всеобщего восхищения.

leejo/CGI.pm

The CGI.pm perl module

CGI — Handle Common Gateway Interface requests and responses

CGI.pm is a stable, complete and mature solution for processing and preparing HTTP requests and responses. Major features including processing form submissions, file uploads, reading and writing cookies, query string generation and manipulation, and processing and preparing HTTP headers.

CGI.pm performs very well in a vanilla CGI.pm environment and also comes with built-in support for mod_perl and mod_perl2 as well as FastCGI.

It has the benefit of having developed and refined over 20 years with input from dozens of contributors and being deployed on thousands of websites. CGI.pm was included in the perl distribution from perl v5.4 to v5.20, however is has now been removed from the perl core.

CGI.pm HAS BEEN REMOVED FROM THE PERL CORE

If you upgrade to a new version of perl or if you rely on a system or vendor perl and get an updated version of perl through a system update, then you will have to install CGI.pm yourself with cpan/cpanm/a vendor package/manually. To make this a little easier the CGI::Fast module has been split into its own distribution, meaning you do not need access to a compiler to install CGI.pm

The rationale for this decision is that CGI.pm is no longer considered good practice for developing web applications, including quick prototyping and small web scripts. There are far better, cleaner, quicker, easier, safer, more scalable, more extensible, more modern alternatives available at this point in time. These will be documented with CGI::Alternatives.

For more discussion on the removal of CGI.pm from core please see:

Note that the v4 releases of CGI.pm will retain back compatibility as much as possible, however you may need to make some minor changes to your code if you are using deprecated methods or some of the more obscure features of the module. If you plan to upgrade to v4.00 and beyond you should read the Changes file for more information and test your code against CGI.pm before deploying it.

HTML Generation functions should no longer be used

All HTML generation functions within CGI.pm are no longer being maintained. Any issues, bugs, or patches will be rejected unless they relate to fundamentally broken page rendering.

The rationale for this is that the HTML generation functions of CGI.pm are an obfuscation at best and a maintenance nightmare at worst. You should be using a template engine for better separation of concerns. See CGI::Alternatives for an example of using CGI.pm with the Template::Toolkit module.

These functions, and perldoc for them, are considered deprecated, they are no longer being maintained and no fixes or features for them will be accepted. They will, however, continue to exist in CGI.pm without any deprecation warnings («soft» deprecation) so you can continue to use them if you really want to. All documentation for these functions has been moved to CGI::HTML::Functions.

There are two styles of programming with CGI.pm, an object-oriented (OO) style and a function-oriented style. You are recommended to use the OO style as CGI.pm will create an internal default object when the functions are called procedurally and you will not have to worry about method names clashing with perl builtins.

In the object-oriented style you create one or more CGI objects and then use object methods to create the various elements of the page. Each CGI object starts out with the list of named parameters that were passed to your CGI script by the server. You can modify the objects, save them to a file or database and recreate them. Because each object corresponds to the «state» of the CGI script, and because each object’s parameter list is independent of the others, this allows you to save the state of the script and restore it later.

For example, using the object oriented style:

In the function-oriented style, there is one default CGI object that you rarely deal with directly. Instead you just call functions to retrieve CGI parameters, manage cookies, and so on. The following example is identical to above, in terms of output, but uses the function-oriented interface. The main differences are that we now need to import a set of functions into our name space (usually the «standard» functions), and we don’t need to create the CGI object.

The examples in this document mainly use the object-oriented style. See HOW TO IMPORT FUNCTIONS for important information on function-oriented programming in CGI.pm

Calling CGI.pm routines

Most CGI.pm routines accept several arguments, sometimes as many as 20 optional ones! To simplify this interface, all routines use a named argument calling style that looks like this:

Each argument name is preceded by a dash. Neither case nor order matters in the argument list: -type, -Type, and -TYPE are all acceptable. In fact, only the first argument needs to begin with a dash. If a dash is present in the first argument CGI.pm assumes dashes for the subsequent ones.

Several routines are commonly called with just one argument. In the case of these routines you can provide the single argument without an argument name. header() happens to be one of these routines. In this case, the single argument is the document type.

Other such routines are documented below.

Sometimes named arguments expect a scalar, sometimes a reference to an array, and sometimes a reference to a hash. Often, you can pass any type of argument and the routine will do whatever is most appropriate. For example, the param() routine is used to set a CGI parameter to a single or a multi-valued value. The two cases are shown below:

Many routines will do something useful with a named argument that it doesn’t recognize. For example, you can produce non-standard HTTP header fields by providing them as named arguments:

This will produce the following nonstandard HTTP header:

Notice the way that underscores are translated automatically into hyphens.

Creating a new query object (object-oriented style)

This will parse the input (from POST, GET and DELETE methods) and store it into a perl5 object called $q. Note that because the input parsing happens at object instantiation you have to set any CGI package variables that control parsing before you call CGI->new.

Any filehandles from file uploads will have their position reset to the beginning of the file.

Creating a new query object from an input file

Perl purists will be pleased to know that this syntax accepts references to file handles, or even references to filehandle globs, which is the «official» way to pass a filehandle. You can also initialize the CGI object with a FileHandle or IO::File object.

If you are using the function-oriented interface and want to initialize CGI state from a file handle, the way to do this is with restore_parameters(). This will (re)initialize the default CGI object from the indicated file handle.

You can also initialize the query object from a hash reference:

or from a properly formatted, URL-escaped query string:

or from a previously existing CGI object (currently this clones the parameter list, but none of the other object-specific fields, such as autoescaping):

To create an empty query, initialize it from an empty string or hash:

Fetching a list of keywords from the query

If the script was invoked as the result of an ISINDEX search, the parsed keywords can be obtained as an array using the keywords() method.

Fetching the names of all the parameters passed to your script

If the script was invoked with a parameter list (e.g. «name1=value1&name2=value2&name3=value3»), the param() / multi_param() methods will return the parameter names as a list. If the script was invoked as an ISINDEX script and contains a string without ampersands (e.g. «value1+value2+value3»), there will be a single parameter named «keywords» containing the «+»-delimited keywords.

The array of parameter names returned will be in the same order as they were submitted by the browser. Usually this order is the same as the order in which the parameters are defined in the form (however, this isn’t part of the spec, and so isn’t guaranteed).

Fetching the value or values of a single named parameter

Pass the param() / multi_param() method a single argument to fetch the value of the named parameter. When calling param() If the parameter is multivalued (e.g. from multiple selections in a scrolling list), you can ask to receive an array. Otherwise the method will return the first value.

Warning — calling param() in list context can lead to vulnerabilities if you do not sanitise user input as it is possible to inject other param keys and values into your code. This is why the multi_param() method exists, to make it clear that a list is being returned, note that param() can still be called in list context and will return a list for back compatibility.

The following code is an example of a vulnerability as the call to param will be evaluated in list context and thus possibly inject extra keys and values into the hash:

The fix for the above is to force scalar context on the call to ->param by prefixing it with «scalar»

If you call param() in list context with an argument a warning will be raised by CGI.pm, you can disable this warning by setting $CGI::LIST_CONTEXT_WARN to 0 or by using the multi_param() method instead

If a value is not given in the query string, as in the queries «name1=&name2=», it will be returned as an empty string.

If the parameter does not exist at all, then param() will return undef in scalar context, and the empty list in a list context.

Setting the value(s) of a named parameter

This sets the value for the named parameter ‘foo’ to an array of values. This is one way to change the value of a field AFTER the script has been invoked once before.

param() also recognizes a named parameter style of calling described in more detail later:

Appending additional values to a named parameter

This adds a value or list of values to the named parameter. The values are appended to the end of the parameter if it already exists. Otherwise the parameter is created. Note that this method only recognizes the named argument calling syntax.

Importing all parameters into a namespace

This creates a series of variables in the ‘R’ namespace. For example, $R::foo, @R:foo. For keyword lists, a variable @R::keywords will appear. If no namespace is given, this method will assume ‘Q’. WARNING: don’t import anything into ‘main’; this is a major security risk!

NOTE 1: Variable names are transformed as necessary into legal perl variable names. All non-legal characters are transformed into underscores. If you need to keep the original names, you should use the param() method instead to access CGI variables by name.

In fact, you should probably not use this method at all given the above caveats and security risks.

Deleting a parameter completely

This completely clears a list of parameters. It sometimes useful for resetting parameters that you don’t want passed down between script invocations.

If you are using the function call interface, use «Delete()» instead to avoid conflicts with perl’s built-in delete operator.

Deleting all parameters

This clears the CGI object completely. It might be useful to ensure that all the defaults are taken when you create a fill-out form.

Use Delete_all() instead if you are using the function call interface.

Handling non-urlencoded arguments

If POSTed data is not of type application/x-www-form-urlencoded or multipart/form-data, then the POSTed data will not be processed, but instead be returned as-is in a parameter named POSTDATA. To retrieve it, use code like this:

Likewise if PUTed and PATCHed data can be retrieved with code like this:

(If you don’t know what the preceding means, worry not. It only affects people trying to use CGI for XML processing and other specialized tasks)

PUTDATA/POSTDATA/PATCHDATA are also available via upload_hook, and as file uploads via «-putdata_upload» option.

Direct access to the parameter list

If you need access to the parameter list in a way that isn’t covered by the methods given in the previous sections, you can obtain a direct reference to it by calling the param_fetch() method with the name of the parameter. This will return an array reference to the named parameter, which you then can manipulate in any way you like.

You can also use a named argument style using the -name argument.

Fetching the parameter list as a hash

Many people want to fetch the entire parameter list as a hash in which the keys are the names of the CGI parameters, and the values are the parameters’ values. The Vars() method does this. Called in a scalar context, it returns the parameter list as a tied hash reference. Changing a key changes the value of the parameter in the underlying CGI parameter list. Called in a list context, it returns the parameter list as an ordinary hash. This allows you to read the contents of the parameter list, but not to change it.

When using this, the thing you must watch out for are multivalued CGI parameters. Because a hash cannot distinguish between scalar and list context, multivalued parameters will be returned as a packed string, separated by the «\0» (null) character. You must split this packed string in order to get at the individual values. This is the convention introduced long ago by Steve Brenner in his cgi-lib.pl module for perl version 4, and may be replaced in future versions with array references.

If you wish to use Vars() as a function, import the :cgi-lib set of function calls (also see the section on CGI-LIB compatibility).

Saving the state of the script to a file

This will write the current state of the form to the provided filehandle. You can read it back in by providing a filehandle to the new() method. Note that the filehandle can be a file, a pipe, or whatever.

The format of the saved file is:

Both name and value are URL escaped. Multi-valued CGI parameters are represented as repeated names. A session record is delimited by a single = symbol. You can write out multiple records and read them back in with several calls to new. You can do this across several sessions by opening the file in append mode, allowing you to create primitive guest books, or to keep a history of users’ queries. Here’s a short example of creating multiple session records:

The file format used for save/restore is identical to that used by the Whitehead Genome Center’s data exchange format «Boulderio», and can be manipulated and even databased using Boulderio utilities. See Boulder for further details.

If you wish to use this method from the function-oriented (non-OO) interface, the exported name for this method is save_parameters().

Retrieving cgi errors

Errors can occur while processing user input, particularly when processing uploaded files. When these errors occur, CGI will stop processing and return an empty parameter list. You can test for the existence and nature of errors using the cgi_error() function. The error messages are formatted as HTTP status codes. You can either incorporate the error text into a page, or use it as the value of the HTTP status:

When using the function-oriented interface (see the next section), errors may only occur the first time you call param(). Be ready for this!

Using the function-oriented interface

To use the function-oriented interface, you must specify which CGI.pm routines or sets of routines to import into your script’s namespace. There is a small overhead associated with this importation, but it isn’t much.

The listed methods will be imported into the current package; you can call them directly without creating a CGI object first. This example shows how to import the param() and header() methods, and then use them directly:

More frequently, you’ll import common sets of functions by referring to the groups by name. All function sets are preceded with a «:» character as in «:cgi» (for CGI protocol handling methods).

Here is a list of the function sets you can import:

:cgi

Import all CGI-handling methods, such as param(), path_info() and the like.

:all

Import all the available methods. For the full list, see the CGI.pm code, where the variable %EXPORT_TAGS is defined. (N.B. the :cgi-lib imports will not be included in the :all import, you will have to import :cgi-lib to get those)

Note that in the interests of execution speed CGI.pm does not use the standard Exporter syntax for specifying load symbols. This may change in the future.

In addition to the function sets, there are a number of pragmas that you can import. Pragmas, which are always preceded by a hyphen, change the way that CGI.pm functions in various ways. Pragmas, function sets, and individual functions can all be imported in the same use() line. For example, the following use statement imports the cgi set of functions and enables debugging mode (pragma -debug):

The current list of pragmas is as follows:

This keeps CGI.pm from including undef params in the parameter list.

This makes CGI.pm treat all parameters as text strings rather than binary strings (see perlunitut for the distinction), assuming UTF-8 for the encoding.

CGI.pm does the decoding from the UTF-8 encoded input data, restricting this decoding to input text as distinct from binary upload data which are left untouched. Therefore, a ‘:utf8’ layer must not be used on STDIN.

If you do not use this option you can manually select which fields are expected to return utf-8 strings and convert them using code like this:

-putdata_upload / -postdata_upload / -patchdata_upload

Makes $cgi->param(‘PUTDATA’); , $cgi->param(‘PATCHDATA’); , and $cgi->param(‘POSTDATA’); act like file uploads named PUTDATA, PATCHDATA, and POSTDATA. See «Handling non-urlencoded arguments» and «Processing a file upload field» PUTDATA/POSTDATA/PATCHDATA are also available via upload_hook.

This makes CGI.pm produce a header appropriate for an NPH (no parsed header) script. You may need to do other things as well to tell the server that the script is NPH. See the discussion of NPH scripts below.

Separate the name=value pairs in CGI parameter query strings with semicolons rather than ampersands. For example:

Semicolon-delimited query strings are always accepted, and will be emitted by self_url() and query_string(). newstyle_urls became the default in version 2.64.


Separate the name=value pairs in CGI parameter query strings with ampersands rather than semicolons. This is no longer the default.

This turns off the command-line processing features. If you want to run a CGI.pm script from the command line, and you don’t want it to read CGI parameters from the command line or STDIN, then use this pragma:

This turns on full debugging. In addition to reading CGI arguments from the command-line processing, CGI.pm will pause and try to read arguments from STDIN, producing the message «(offline mode: enter name=value pairs on standard input)» features.

See the section on debugging for more details.

GENERATING DYNAMIC DOCUMENTS

Most of CGI.pm’s functions deal with creating documents on the fly. Generally you will produce the HTTP header first, followed by the document itself. CGI.pm provides functions for generating HTTP headers of various types.

Each of these functions produces a fragment of HTTP which you can print out directly so that it is processed by the browser, appended to a string, or saved to a file for later use.

Creating a standard http header

Normally the first thing you will do in any CGI script is print out an HTTP header. This tells the browser what type of document to expect, and gives other optional information, such as the language, expiration date, and whether to cache the document. The header can also be manipulated for special purposes, such as server push and pay per view pages.

header() returns the Content-type: header. You can provide your own MIME type if you choose, otherwise it defaults to text/html. An optional second parameter specifies the status code and a human-readable message. For example, you can specify 204, «No response» to create a script that tells the browser to do nothing at all. Note that RFC 2616 expects the human-readable phase to be there as well as the numeric status code.

The last example shows the named argument style for passing arguments to the CGI methods using named parameters. Recognized parameters are -type, -status, -expires, and -cookie. Any other named parameters will be stripped of their initial hyphens and turned into header fields, allowing you to specify any HTTP header you desire. Internal underscores will be turned into hyphens:

Most browsers will not cache the output from CGI scripts. Every time the browser reloads the page, the script is invoked anew. You can change this behavior with the -expires parameter. When you specify an absolute or relative expiration interval with this parameter, some browsers and proxy servers will cache the script’s output until the indicated expiration date. The following forms are all valid for the -expires field:

The -cookie parameter generates a header that tells the browser to provide a «magic cookie» during all subsequent transactions with your script. Some cookies have a special format that includes interesting attributes such as expiration time. Use the cookie() method to create and retrieve session cookies.

The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers that expect all their scripts to be NPH.

The -charset parameter can be used to control the character set sent to the browser. If not provided, defaults to ISO-8859-1. As a side effect, this sets the charset() method as well. Note that the default being ISO-8859-1 may not make sense for all content types, e.g.:

In the above case you need to pass -charset => » to prevent the default being used.

The -attachment parameter can be used to turn the page into an attachment. Instead of displaying the page, some browsers will prompt the user to save it to disk. The value of the argument is the suggested name for the saved file. In order for this to work, you may have to set the -type to «application/octet-stream».

The -p3p parameter will add a P3P tag to the outgoing header. The parameter can be an arrayref or a space-delimited string of P3P tags. For example:

In either case, the outgoing header will be formatted as:

CGI.pm will accept valid multi-line headers when each line is separated with a CRLF value («\r\n» on most platforms) followed by at least one space. For example:

Invalid multi-line header input will trigger in an exception. When multi-line headers are received, CGI.pm will always output them back as a single line, according to the folding rules of RFC 2616: the newlines will be removed, while the white space remains.

Generating a redirection header

Sometimes you don’t want to produce a document yourself, but simply redirect the browser elsewhere, perhaps choosing a URL based on the time of day or the identity of the user.

The redirect() method redirects the browser to a different URL. If you use redirection like this, you should not print out a header as well.

You are advised to use full URLs (absolute with respect to current URL or even including the http: or ftp: part) in redirection requests as relative URLs are resolved by the user agent of the client so may not do what you want or expect them to do.

You can also use named arguments:

All names arguments recognized by header() are also recognized by redirect(). However, most HTTP headers, including those generated by -cookie and -target, are ignored by the browser.

The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers, such as Microsoft IIS, which expect all their scripts to be NPH.

The -status parameter will set the status of the redirect. HTTP defines several different possible redirection status codes, and the default if not specified is 302, which means «moved temporarily.» You may change the status to another status code if you wish.

Note that the human-readable phrase is also expected to be present to conform with RFC 2616, section 6.1.

Creating a self-referencing url that preserves state information

self_url() will return a URL, that, when selected, will re-invoke this script with all its state information intact. This is most useful when you want to jump around within the document using internal anchors but you don’t want to disrupt the current contents of the form(s). Something like this will do the trick:

If you want more control over what’s returned, using the url() method instead.

You can also retrieve a query string representation of the current object state with query_string():

The behavior of calling query_string is currently undefined when the HTTP method is something other than GET.

If you want to retrieved the query string as set in the webserver, namely the environment variable, you can call env_query_string()

Obtaining the script’s url

url() returns the script’s URL in a variety of formats. Called without any arguments, it returns the full form of the URL, including host name and port number

You can modify this format with the following named arguments:

-absolute

If true, produce an absolute URL, e.g.

-relative

Produce a relative URL. This is useful if you want to re-invoke your script with different parameters. For example:

-full

Produce the full URL, exactly as if called without any arguments. This overrides the -relative and -absolute arguments.

-path (-path_info)

Append the additional path information to the URL. This can be combined with -full, -absolute or -relative. -path_info is provided as a synonym.

-query (-query_string)

Append the query string to the URL. This can be combined with -full, -absolute or -relative. -query_string is provided as a synonym.

-base

Generate just the protocol and net location, as in http://www.foo.com:8000

-rewrite

If Apache’s mod_rewrite is turned on, then the script name and path info probably won’t match the request that the user sent. Set -rewrite => 1 (default) to return URLs that match what the user sent (the original request URI). Set -rewrite => 0 to return URLs that match the URL after the mod_rewrite rules have run.

Mixing post and url parameters

It is possible for a script to receive CGI parameters in the URL as well as in the fill-out form by creating a form that POSTs to a URL containing a query string (a «?» mark followed by arguments). The param() method will always return the contents of the POSTed fill-out form, ignoring the URL’s query string. To retrieve URL parameters, call the url_param() method. Use it in the same way as param(). The main difference is that it allows you to read the parameters, but not set them.

Under no circumstances will the contents of the URL query string interfere with similarly-named CGI parameters in POSTed forms. If you try to mix a URL query string with a form submitted with the GET method, the results will not be what you expect.

If running from the command line, url_param will not pick up any parameters given on the command line.

Processing a file upload field

When the form is processed, you can retrieve an IO::File compatible handle for a file upload field like this:

In a list context, upload() will return an array of filehandles. This makes it possible to process forms that use the same name for multiple upload fields.

If you want the entered file name for the file, you can just call param():

Different browsers will return slightly different things for the name. Some browsers return the filename only. Others return the full path to the file, using the path conventions of the user’s machine. Regardless, the name returned is always the name of the file on the user’s machine, and is unrelated to the name of the temporary file that CGI.pm creates during upload spooling (see below).

When a file is uploaded the browser usually sends along some information along with it in the format of headers. The information usually includes the MIME content type. To retrieve this information, call uploadInfo(). It returns a reference to a hash containing all the document headers.

Note that you must use ->upload or ->param to get the file-handle to pass into uploadInfo as internally this is represented as a File::Temp object (which is what will be returned by ->upload or ->param). When using ->Vars you will get the literal filename rather than the File::Temp object, which will not return anything when passed to uploadInfo. So don’t use ->Vars.

If you are using a machine that recognizes «text» and «binary» data modes, be sure to understand when and how to use them (see the Camel book). Otherwise you may find that binary files are corrupted during file uploads.

Accessing the temp files directly

When processing an uploaded file, CGI.pm creates a temporary file on your hard disk and passes you a file handle to that file. After you are finished with the file handle, CGI.pm unlinks (deletes) the temporary file. If you need to you can access the temporary file directly. You can access the temp file for a file upload by passing the file name to the tmpFileName() method:

As with ->uploadInfo, using the reference returned by ->upload or ->param is preferred, although unlike ->uploadInfo, plain filenames also work if possible for backwards compatibility.

The temporary file will be deleted automatically when your program exits unless you manually rename it or set $CGI::UNLINK_TMP_FILES to 0. On some operating systems (such as Windows NT), you will need to close the temporary file’s filehandle before your program exits. Otherwise the attempt to delete the temporary file will fail.

Changes in temporary file handling (v4.05+)

CGI.pm had its temporary file handling significantly refactored, this logic is now all deferred to File::Temp (which is wrapped in a compatibility object, CGI::File::Temp — DO NOT USE THIS PACKAGE DIRECTLY). As a consequence the PRIVATE_TEMPFILES variable has been removed along with deprecation of the private_tempfiles routine and complete removal of the CGITempFile package. The $CGITempFile::TMPDIRECTORY is no longer used to set the temp directory, refer to the perldoc for File::Temp if you want to override the default settings in that package (the TMPDIR env variable is still available on some platforms). For Windows platforms the temporary directory order remains as before: TEMP > TMP > WINDIR ( > TMPDIR ) so if you have any of these in use in existing scripts they should still work.

The Fh package still exists but does nothing, the CGI::File::Temp class is a subclass of both File::Temp and the empty Fh package, so if you have any code that checks that the filehandle isa Fh this should still work.

When you get the internal file handle you will receive a File::Temp object, this should be transparent as File::Temp isa IO::Handle and isa IO::Seekable meaning it behaves as previously. If you are doing anything out of the ordinary with regards to temp files you should test your code before deploying this update and refer to the File::Temp documentation for more information.

Handling interrupted file uploads

There are occasionally problems involving parsing the uploaded file. This usually happens when the user presses «Stop» before the upload is finished. In this case, CGI.pm will return undef for the name of the uploaded file and set cgi_error() to the string «400 Bad request (malformed multipart POST)». This error message is designed so that you can incorporate it into a status code to be sent to the browser. Example:

Progress bars for file uploads and avoiding temp files

CGI.pm gives you low-level access to file upload management through a file upload hook. You can use this feature to completely turn off the temp file storage of file uploads, or potentially write your own file upload progress meter.

This is much like the UPLOAD_HOOK facility available in Apache::Request, with the exception that the first argument to the callback is an Apache::Upload object, here it’s the remote filename.

The $data field is optional; it lets you pass configuration information (e.g. a database handle) to your hook callback.

The $use_tempfile field is a flag that lets you turn on and off CGI.pm’s use of a temporary disk-based file during file upload. If you set this to a FALSE value (default true) then $q->param(‘uploaded_file’) will no longer work, and the only way to get at the uploaded data is via the hook you provide.

If using the function-oriented interface, call the CGI::upload_hook() method before calling param() or any other CGI functions:

This method is not exported by default. You will have to import it explicitly if you wish to use it without the CGI:: prefix.

Troubleshooting file uploads on Windows

If you are using CGI.pm on a Windows platform and find that binary files get slightly larger when uploaded but that text files remain the same, then you have forgotten to activate binary mode on the output filehandle. Be sure to call binmode() on any handle that you create to write the uploaded file to disk.

Older ways to process file uploads

This section is here for completeness. if you are building a new application with CGI.pm, you can skip it.

The original way to process file uploads with CGI.pm was to use param(). The value it returns has a dual nature as both a file name and a lightweight filehandle. This dual nature is problematic if you following the recommended practice of having use strict in your code. perl will complain when you try to use a string as a filehandle. More seriously, it is possible for the remote user to type garbage into the upload field, in which case what you get from param() is not a filehandle at all, but a string.

To solve this problem the upload() method was added, which always returns a lightweight filehandle. This generally works well, but will have trouble interoperating with some other modules because the file handle is not derived from IO::File. So that brings us to current recommendation given above, which is to call the handle() method on the file handle returned by upload(). That upgrades the handle to an IO::File. It’s a big win for compatibility for a small penalty of loading IO::File the first time you call it.

CGI.pm has several methods that support cookies.

A cookie is a name=value pair much like the named parameters in a CGI query string. CGI scripts create one or more cookies and send them to the browser in the HTTP header. The browser maintains a list of cookies that belong to a particular Web server, and returns them to the CGI script during subsequent interactions.

In addition to the required name=value pair, each cookie has several optional attributes:

This is a time/date string (in a special GMT format) that indicates when a cookie expires. The cookie will be saved and returned to your script until this expiration date is reached if the user exits the browser and restarts it. If an expiration date isn’t specified, the cookie will remain active until the user quits the browser.

This is a partial or complete domain name for which the cookie is valid. The browser will return the cookie to any host that matches the partial domain name. For example, if you specify a domain name of «.capricorn.com», then the browser will return the cookie to Web servers running on any of the machines «www.capricorn.com», «www2.capricorn.com», «feckless.capricorn.com», etc. Domain names must contain at least two periods to prevent attempts to match on top level domains like «.edu». If no domain is specified, then the browser will only return the cookie to servers on the host the cookie originated from.

If you provide a cookie path attribute, the browser will check it against your script’s URL before returning the cookie. For example, if you specify the path «/cgi-bin», then the cookie will be returned to each of the scripts «/cgi-bin/tally.pl», «/cgi-bin/order.pl», and «/cgi-bin/customer_service/complain.pl», but not to the script «/cgi-private/site_admin.pl». By default, path is set to «/», which causes the cookie to be sent to any CGI script on your site.

If the «secure» attribute is set, the cookie will only be sent to your script if the CGI request is occurring on a secure channel, such as SSL.

The interface to HTTP cookies is the cookie() method:

cookie() creates a new cookie. Its parameters include:

-name

The name of the cookie (required). This can be any string at all. Although browsers limit their cookie names to non-whitespace alphanumeric characters, CGI.pm removes this restriction by escaping and unescaping cookies behind the scenes.

-value

The value of the cookie. This can be any scalar value, array reference, or even hash reference. For example, you can store an entire hash into a cookie this way:

-path

The optional partial path for which this cookie will be valid, as described above.

-domain

The optional partial domain for which this cookie will be valid, as described above.

-expires

The optional expiration date for this cookie. The format is as described in the section on the header() method:

-secure

If set to true, this cookie will only be used within a secure SSL session.

The cookie created by cookie() must be incorporated into the HTTP header within the string returned by the header() method:

To create multiple cookies, give header() an array reference:

To retrieve a cookie, request it by name by calling cookie() method without the -value parameter. This example uses the object-oriented form:

Cookies created with a single scalar value, such as the «riddle_name» cookie, will be returned in that form. Cookies with array and hash values can also be retrieved.

The cookie and CGI namespaces are separate. If you have a parameter named ‘answers’ and a cookie named ‘answers’, the values retrieved by param() and cookie() are independent of each other. However, it’s simple to turn a CGI parameter into a cookie, and vice-versa:

If you call cookie() without any parameters, it will return a list of the names of all cookies passed to your script:

See the cookie.cgi example script for some ideas on how to use cookies effectively.

If you are running the script from the command line or in the perl debugger, you can pass the script a list of keywords or parameter=value pairs on the command line or from standard input (you don’t have to worry about tricking your script into reading from environment variables). You can pass keywords like this:

To turn off this feature, use the -no_debug pragma.

To test the POST method, you may enable full debugging with the -debug pragma. This will allow you to feed newline-delimited name=value pairs to the script on standard input.

When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs:

Finally, you can set the path info for the script by prefixing the first name/value parameter with the path followed by a question mark (?):

FETCHING ENVIRONMENT VARIABLES

Some of the more useful environment variables can be fetched through this interface. The methods are as follows:

Accept()

Return a list of MIME types that the remote browser accepts. If you give this method a single argument corresponding to a MIME type, as in Accept(‘text/html’), it will return a floating point value corresponding to the browser’s preference for this type from 0.0 (don’t want) to 1.0. Glob types (e.g. text/*) in the browser’s accept list are handled correctly.

Note that the capitalization changed between version 2.43 and 2.44 in order to avoid conflict with perl’s accept() function.

raw_cookie()

Returns the HTTP_COOKIE variable. Cookies have a special format, and this method call just returns the raw form (?cookie dough). See cookie() for ways of setting and retrieving cooked cookies.

Called with no parameters, raw_cookie() returns the packed cookie structure. You can separate it into individual cookies by splitting on the character sequence «; «. Called with the name of a cookie, retrieves the unescaped form of the cookie. You can use the regular cookie() method to get the names, or use the raw_fetch() method from the CGI::Cookie module.

env_query_string()

Returns the QUERY_STRING variable, note that this is the original value as set in the environment by the webserver and (possibly) not the same value as returned by query_string(), which represents the object state

user_agent()

Returns the HTTP_USER_AGENT variable. If you give this method a single argument, it will attempt to pattern match on it, allowing you to do something like user_agent(Mozilla);

path_info()

Returns additional path information from the script URL. E.G. fetching /cgi-bin/your_script/additional/stuff will result in path_info() returning «/additional/stuff».

NOTE: The Microsoft Internet Information Server is broken with respect to additional path information. If you use the perl DLL library, the IIS server will attempt to execute the additional path information as a perl script. If you use the ordinary file associations mapping, the path information will be present in the environment, but incorrect. The best thing to do is to avoid using additional path information in CGI scripts destined for use with IIS. A best attempt has been made to make CGI.pm do the right thing.

path_translated()

As per path_info() but returns the additional path information translated into a physical path, e.g. «/usr/local/etc/httpd/htdocs/additional/stuff».

The Microsoft IIS is broken with respect to the translated path as well.

remote_host()

Returns either the remote host name or IP address if the former is unavailable.

remote_ident()

Returns the name of the remote user (as returned by identd) or undef if not set

remote_addr()

Returns the remote host IP address, or 127.0.0.1 if the address is unavailable.

request_uri()

Returns the interpreted pathname of the requested document or CGI (relative to the document root). Or undef if not set.

script_name()

Return the script name as a partial URL, for self-referring scripts.

referer()

Return the URL of the page the browser was viewing prior to fetching your script.

auth_type()

Return the authorization/verification method in use for this script, if any.

server_name()

Returns the name of the server, usually the machine’s host name.

virtual_host()

When using virtual hosts, returns the name of the host that the browser attempted to contact

server_port()

Return the port that the server is listening on.

server_protocol()


Returns the protocol and revision of the incoming request, or defaults to HTTP/1.0 if this is not set

virtual_port()

Like server_port() except that it takes virtual hosts into account. Use this when running with virtual hosts.

server_software()

Returns the server software and version number.

remote_user()

Return the authorization/verification name used for user verification, if this script is protected.

user_name()

Attempt to obtain the remote user’s name, using a variety of different techniques. May not work in all browsers.

request_method()

Returns the method used to access your script, usually one of ‘POST’, ‘GET’ or ‘HEAD’. If running from the command line it will be undef.

content_type()

Returns the content_type of data submitted in a POST, generally multipart/form-data or application/x-www-form-urlencoded

http()

Called with no arguments returns the list of HTTP environment variables, including such things as HTTP_USER_AGENT, HTTP_ACCEPT_LANGUAGE, and HTTP_ACCEPT_CHARSET, corresponding to the like-named HTTP header fields in the request. Called with the name of an HTTP header field, returns its value. Capitalization and the use of hyphens versus underscores are not significant.

For example, all three of these examples are equivalent:

https()

The same as http(), but operates on the HTTPS environment variables present when the SSL protocol is in effect. Can be used to determine whether SSL is turned on.

USING NPH SCRIPTS

NPH, or «no-parsed-header», scripts bypass the server completely by sending the complete HTTP header directly to the browser. This has slight performance benefits, but is of most use for taking advantage of HTTP extensions that are not directly supported by your server, such as server push and PICS headers.

Servers use a variety of conventions for designating CGI scripts as NPH. Many Unix servers look at the beginning of the script’s name for the prefix «nph-«. The Macintosh WebSTAR server and Microsoft’s Internet Information Server, in contrast, try to decide whether a program is an NPH script by examining the first line of script output.

CGI.pm supports NPH scripts with a special NPH mode. When in this mode, CGI.pm will output the necessary extra header information when the header() and redirect() methods are called.

The Microsoft Internet Information Server requires NPH mode. As of version 2.30, CGI.pm will automatically detect when the script is running under IIS and put itself into this mode. You do not need to do this manually, although it won’t hurt anything if you do.

In the use statement

Simply add the «-nph» pragma to the list of symbols to be imported into your script:

By calling the nph() method:

Call nph() with a non-zero parameter at any point after using CGI.pm in your program.

By using -nph parameters

in the header() and redirect() statements:

CGI.pm provides four simple functions for producing multipart documents of the type needed to implement server push. These functions were graciously provided by Ed Jordan ed@fidalgo.net. To import these into your namespace, you must import the «:push» set. You are also advised to put the script into NPH mode and to set $| to 1 to avoid buffering problems.

Here is a simple script that demonstrates server push:

This script initializes server push by calling multipart_init(). It then enters a loop in which it begins a new multipart section by calling multipart_start(), prints the current local time, and ends a multipart section with multipart_end(). It then sleeps a second, and begins again. On the final iteration, it ends the multipart section with multipart_final() rather than with multipart_end().

Initialize the multipart system. The -boundary argument specifies what MIME boundary string to use to separate parts of the document. If not provided, CGI.pm chooses a reasonable boundary for you.

The -charset provides the character set, if not provided this will default to ISO-8859-1

Start a new part of the multipart document using the specified MIME type and charset. If not specified, text/html ISO-8859-1 is assumed.

End a part. You must remember to call multipart_end() once for each multipart_start(), except at the end of the last part of the multipart document when multipart_final() should be called instead of multipart_end().

End all parts. You should call multipart_final() rather than multipart_end() at the end of the last part of the multipart document.

Users interested in server push applications should also have a look at the CGI::Push module.

AVOIDING DENIAL OF SERVICE ATTACKS

A potential problem with CGI.pm is that, by default, it attempts to process form POSTings no matter how large they are. A wily hacker could attack your site by sending a CGI script a huge POST of many gigabytes. CGI.pm will attempt to read the entire POST into a variable, growing hugely in size until it runs out of memory. While the script attempts to allocate the memory the system may slow down dramatically. This is a form of denial of service attack.

Another possible attack is for the remote user to force CGI.pm to accept a huge file upload. CGI.pm will accept the upload and store it in a temporary directory even if your script doesn’t expect to receive an uploaded file. CGI.pm will delete the file automatically when it terminates, but in the meantime the remote user may have filled up the server’s disk space, causing problems for other programs.

The best way to avoid denial of service attacks is to limit the amount of memory, CPU time and disk space that CGI scripts can use. Some Web servers come with built-in facilities to accomplish this. In other cases, you can use the shell limit or ulimit commands to put ceilings on CGI resource usage.

CGI.pm also has some simple built-in protections against denial of service attacks, but you must activate them before you can use them. These take the form of two global variables in the CGI name space:

$CGI::POST_MAX

If set to a non-negative integer, this variable puts a ceiling on the size of POSTings, in bytes. If CGI.pm detects a POST that is greater than the ceiling, it will immediately exit with an error message. This value will affect both ordinary POSTs and multipart POSTs, meaning that it limits the maximum size of file uploads as well. You should set this to a reasonably high value, such as 10 megabytes.

$CGI::DISABLE_UPLOADS

If set to a non-zero value, this will disable file uploads completely. Other fill-out form values will work as usual.

To use these variables, set the variable at the top of the script, right after the «use» statement:

An attempt to send a POST larger than $POST_MAX bytes will cause param() to return an empty CGI parameter list. You can test for this event by checking cgi_error(), either after you create the CGI object or, if you are using the function-oriented interface, call

for the first time. If the POST was intercepted, then cgi_error() will return the message «413 POST too large».

This error message is actually defined by the HTTP protocol, and is designed to be returned to the browser as the CGI script’s status code. For example:

However it isn’t clear that any browser currently knows what to do with this status code. It might be better just to create a page that warns the user of the problem.

COMPATIBILITY WITH CGI-LIB.PL

To make it easier to port existing programs that use cgi-lib.pl the compatibility routine «ReadParse» is provided. Porting is simple:

CGI.pm’s ReadParse() routine creates a tied variable named %in, which can be accessed to obtain the query variables. Like ReadParse, you can also provide your own variable. Infrequently used features of ReadParse, such as the creation of @in and $in variables, are not supported.

Once you use ReadParse, you can retrieve the query object itself this way:

Глава 19

Если в течение последних нескольких лет вы не сидели взаперти в деревянной хижине без злектричества, то вы наверняка слышали о World Wide Web. Web-адреса (больше известные как URL) сейчас можно найти везде: на рекламних плакатах и в титрах кинофильмов, на обложках журна-лов и на страницах других изданий, от газет до правительственных отчетов.

Многие из самых интересных Web-страниц включают разного рода формы, предназначенные для ввода данных пользователем. Вы вводите данные в такую форму и щелкаете на кнопке или рисунке. Зто действие запускает некую программу на Web-сервере, которая изучает введенные вами данные и генерирует новую выходную информацию. Иногда зта программа (широко известная как программа общего шлюзового интерфейса, или CGI-программа) представляет собой просто интерфейс к существующей базе данных; она преобразует введенные вами данные в нечто понятное для зтой базы данных, а выходную информацию базы данных — в нечто понятное для Web-броузера (обычно в HTML-форме).

CGI-программы не просто обрабатывают данные, введенные в форму. Они вызываются и тогда, когда вы щелкаете на графическом изображении, и фактически могут использоваться для отображения всего того, что «видит» ваш броузер. Web-страницы с CGI-поддержкой — зто не безликие и нудньге документы, а удивительно живые страницы с динамически изменяющимся содержимым. Именно динамическая информация делает Web интересньш и интерактивным источником информации, а не просто средством, предна-значенньш для чтения книги с терминала.

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

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

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

Мы предполагаем, что вы уже в основном знакомы с HTML.

Начиная с версии 5.004, в состав стандартного дистрибутива Perl вклю-чается модуль CGI.pm, который все знает и все умеет*.

Зтот модуль, который написал Линкольн Штейн, автор хорошо извест-ной книги How to Setup and Maintain Your Web Site, превращает процедуру создания CGI-программ на Perl в легкую прогулку. Как и сам Perl, CGI.pm является платформо-независимым, позтому его можно использовать прак-тически с любой ОС, от UNIX и Linux до VMS; он работает даже в таких системах, как Windows и MacOS.

* Если у вас инсталлирована одна из более ранних версии Perl (но как минимум 5.001) и вы еще не собрались переходить на новую, просто получите CGI.pm из CPAN.

Если CGI.pm уже инсталлирован у вас в системо, вы можете прочесть его полную документацию, воспользовавшись любым из способов, которые вы используете для чтения man-страниц Perl, например с помощью команд тап(1) или perldoc(l) либо обратившись к HTML-варианту документации. Если ничего не получается, прочтите файл CGI.pm’. документация на модуль встроена в сам модуль, представленими в простом формате pod *.

Разрабатывая CGI-программы, держите зкземпляр man-страницы модуля CGI.pm под рукой. Она не только содержит описание функций зтого модуля, но и загружается вместе со всевозможными примерами и советами.

Ваша CGI-программа в контексте

На рис. 19.1 показаны взаимосвязи между Web-броузером, Web-сервером и CGI-программой. Когда вы, работая со своим броузером, щелкаете на какой-либо ссылке, помните, что с зтой ссьшкой связан универсальный локатор ресурса, URL (Uniform Resource Locator). Зтот URL указывает на Web-сервер и ресурс, доступний через данини сервер. Таким образом, броузер взаимодействует с сервером, запрашивая указаними ресурс. Если, скажем, ресурс представляет собой HTML-форму, предназначенную для заполнения, то Web-сервер загружает зту форму в броузер, который затем выводит ее на зкран, чтобы вы могли ввести требуемне данные.

Каждое предназначенное для ввода текста поле в зтой форме имеет имя (указанное в HTML-коде формы) и соответствующее значение, которым является все, что вы вводите в зтом поле. Сама форма связана (через HTML-директиву

Помните, что CGI-программа может выдавать ту выходную HTML-информацию, которую вы ей укажете. Эта информация будет затем передаваться в тот броузер, который обратится к URL данной программы. CGI-программа может, таким образом, не только реагировать на данные, введенные пользователем в форму, но и генерировать HTML-страницу с формой. Более того, одна программа может выполнять одну за другой обе эти задачи. Все, что вам нужно сделать,— это разделить программу на две части, которые делают разные вещи в зависимости от того, была ли программа вызвана с аргументами или нет. Если аргументов не было, программа посылает в броузер пустую форму; в противном случае аргументы содержат данные, введенные пользователем в ранее переданную форму, и программа возвращает в броузер ответ на основании этих данных.

* Некоторые броузеры позволяют обходиться без кнопки передачи, если форма содержит только одно поле для ввода текста. Если курсор находится в этом поле и пользователь нажимает клавишу [Enter], это считается запросом на передачу. Однако лучше здесь использовать традиционный способ.

При размещении всех компонентов программы в одном CGI-файле упрощается ее сопровождение. Цена — незначительное увеличение времени обработки при загрузке исходной страницы. Вот как все это выглядит:

# программа ответа на форму о любимом сорте мороженого

# *и генерирования этой формы* (версия 3) use CGI qw(:standard);

my $favorite = param(«flavor»);

print start_html(«Hello Ice Cream»), hi («Hello Ice Cream»);

print p(«Your favorite flavor is $favorite. «);

print hr, start_form;

print p («Please select a flavor: «, textfield(«flavor»,»mint»));

print end form, hr;

Если во время работы с броузером вы щелкнете на ссылке, которая указывает на эту программу (и если ссылка в конце URL не содержит ?whatever), то увидите экран, подобный изображенному на рис. 19.2. Текстовое поле изначально содержит значение по умолчанию, но это значение заменяется данными, введенными пользователями (если они есть).

Рис. 19.2. Исходная заполняемая форма

Теперь заполните поле Please select a flavor, нажмите клавишу [Enter], и вы увидите то, что показано на рис. 19.3.

Рис. 19.3. Результат обработки переданного с использованием формы запроса

Другие компоненты формы

Теперь, когда вы знаете, как создавать в форме простые текстовые поля и заполнять их, вам, наверное, интересно будет узнать, как создавать компоненты формы других типов — кнопки, отмечаемые блоки и меню.

Сейчас мы рассмотрим более развитую версию нашей программы. В частности, мы включили в нее новые компоненты формы: всплывающие меню, кнопку передачи (которая называется order) и кнопку очистки полей формы, позволяющую стереть все данные, введенные пользователем. Всплывающие меню делают именно то, о чем говорят их имена, но аргументы, указанные в popup_menu, могут озадачить вас — пока вы не прочитаете следующий раздел, «Ссылки». Функция textfieldO создает поле для ввода текста с указанным именем. Подробнее об этой функции мы расскажем ниже, когда будем описывать программу гостевой книги.

# программа ответа на форму заказа мороженого и генерирования этой формы (версия 4) use strict;

# ввести объявления переменных и выполнить заключение в кавычки use CGI qw(:standard);

print start html(«Ice Cream Stand»), hi («Ice Cream Stand»);

if (paramO) ( # форма уже заполнена

my $who = param(«name»);

my $flavor = param(«flavor»);

my $scoops = param(«scoops»);

my $taxrate = 1.0743;

my $cost = sprintf(«%.2f», $taxrate * (1.00 + $scoops * 0.25));

print p(«0k, $who, have $scoops scoops of $flavor for \$$cost.»);

> else ( # первый проход, представить незаполненную форму

print p(«What’s your name? «,textfield(«name»));

print p(«What flavor: «, popup_menu(«flavor»,

print p(«How many scoops? «, popup_menu(«scoops», [1..3]));

print p(submit(«order»), reset(«clear»));

print end_form(), hr();

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

Ice Cream Stand

What’s your name? |

What flavor: |t»ii4 How many scoops? 11

Рис. 19.4. Более сложная форма

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

Вы, возможно, заметили, что обе функции popup_menu () в предыдущем примере имеют весьма странные аргументы. Что означают [ ‘mint’, ‘cherry’ , ‘mocha’ ] и [ 1. . 3 ] ? Квадратные скобки создают нечто такое, с чем вы раньше не встречались: ссылку на анонимный массив. Это обусловлено тем, что функция popup_menu () в качестве аргумента рассчитывает получить именно ссылку на массив. Другой способ создания ссылки на массив — использовать перед именованным массивом обратную косую черту, например \@choices. Так, следующий фрагмент кода:

@choises = (‘mint ‘, «cherry ‘, ‘mocha’);

print pC’What flavor: «, popup_menu («flavor», \@choises));

работает так же хорошо, как этот:

print pC’What flavor: «, popup_menu («flavor», [‘mint’,’cherry’,’mocha’]));

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

Также, как методом \@массив можно создавать ссылки на именованные массивы и посредством указания [ список ] — на анонимные хеши, можно методом \%хеш создавать ссылки на именованные хеши, а методом

( ключ1, значение!, ключ2, значение2, . >

Да, фигурные скобки теперь используются в Perl с различными целями. Их функцию определяет контекст, в котором используются фигурные скобки.

Подробнее о ссылках вы прочитаете в главе 4 книги Programming Perl и на man-странице perlref(l).

Более сложные вызывающие последовательности

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

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

-VALUES => [ qw(mint chocolate cherry vanilla peach) ],

mint => «Mighty Mint»,

chocolate => «Cherished Chocolate»,

cherry => «Cherry Cherry»,

vanilla => «Very Vanilla»,

peach => «Perfectly Peachy», >,

-MULTIPLE => 1, tl for true , 0 for false

Значения параметров имеют следующий смысл:

Имя компонента формы. Значение этого параметра можно использовать позже для выборки пользовательских данных из формы с помощью функции param().

Ссылка на анонимный хеш. Значения хеша — это метки (элементы списка), которые видит пользователь формы. Когда пользователь выбирает ту или иную метку, в CGI-программу возвращается соответствующий ключ хеша. Например, если пользователь выбирает элемент, заданный как Perfectly Peachy, CGI-программа получает аргумент peach.

Ссылка на анонимный массив. Этот массив состоит из ключей хеша, на которые ссылается -labels.

Число, определяющее, сколько элементов списка пользователь будет видеть одновременно.

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

Если -multiple установлена в значение «истина», вы можете присвоить список, возвращаемый функцией param(), массиву:

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

«mint», «Mighty Mint»,

«chocolate», «Cherished Chocolate»,

«cherry», «Cherry Cherry»,

«vanilla», «Very Vanilla»,

«peach», «Perfectly Peachy»,

print scrolling list(

-VALUES => [ keys %flavors ],

-MULTIPLE => 1, #1 for true , 0 for false ) ;

На этот раз мы передаем в функцию значения, вычисленные по ключам хеша %flavors, ссылка на который выполняется с помощью операции \, Обратите внимание: параметр -values здесь тоже взят в квадратные скобки. Простая передача результата операции keys в виде списка не сработает, потому что в соответствии с правилом вызова функции scrolling_list() должна быть сделана ссылка на массив, которую как раз и создают квадратные скобки. Считайте квадратные скобки удобным способом представления нескольких значений как одного.

Создание CGI-программы гостевой книги

Если вы внимательно изучили примеры, приведенные выше, то уже должны быть способны заставить работать простые CGI-программы. А как насчет более сложных? Одна из распространенных задач — создание CGT- программы для управления гостевой книгой, чтобы посетители вашего Web-узла могли записывать в нее свои собственные сообщения*.

* Как мы отметим ниже, это приложение можно было бы назвать программой Webchat (переговоров через Web).

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

Вероятно, вы хотите, чтобы сообщения в гостевой книге сохранялись и по завершении посещения вашего узла тем или иным пользователем, поэтому вам нужен файл, куда они будут записываться. Гостевая CGI-программа (вероятно) работает не под вашим управлением, поэтому у нее, как правило, не будет права на обновление вашего файла. Следовательно, первое, что необходимо сделать,— это создать для нее файл с широкими правами доступа. Если вы работаете в UNIX-системе, то можете сделать (из своего shell) для инициализации файла программы гостевой книги следующее:

touch /usr/tmp/chatfile chmod 0666 /usr/tmp/chatfile

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

use Fcnti qw(:flock); # импортирует LOCK_EX, LOCKJ3H, LOCK_NB flock(CHANDLE, LOCK_EX) || bail («cannot flock $CHATNAME: $!»);

Аргумент lock_ex функции flock — вот что позволяет нам обеспечить монопольный доступ к файлу*.

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

* В версиях Perl до 5.004 вы должны превратить в комментарий use Fcnti и в качестве аргумента функции flock использовать просто 2.

Объектно-ориентированное программирование на Perl


Наконец пришло время научить вас пользоваться объектами и классами — и это важнее всего. Хотя решение задачи построения вашего собственного объектного модуля выходит за рамки данной книги, это еще не повод для того, чтобы вы не могли использовать существующие объектно-ориентированные библиотечные модули. Подробная информация об использовании и создании объектных модулей приведена в главе 5 книги Programming Perl и на man-странице perltoot(l).

Мы не будем углубляться здесь в теорию объектов, и вы можете просто считать их пакетами (чем они и являются!) удивительных, великолепных вещей, вызываемых косвенно. Объекты содержат подпрограммы, которые делают все, что вам нужно делать с объектами.

Пусть, например, модуль CGI.pm возвращает объект $query, который представляет собой входные данные пользователя. Если вы хотите получить параметр из этого запроса, вызовите подпрограмму par am () :

Данная запись означает: «Выполнить подпрограмму param () с объектом $query, используя «answer» как аргумент». Такой вызов в точности соответствует вызову любой другой подпрограммы, за исключением того что вы используете имя объекта, за которым следует синтаксическая конструкция ->. Кстати, подпрограммы, связанные с объектами, называются методами.

Если вы хотите получить значение, возвращенное подпрограммой param (), воспользуйтесь обычным оператором присваивания и сохраните это значение в обычной переменной $he_said:

Объекты выглядят как скаляры; они хранятся в скалярных переменных (таких как переменная $ query в нашем примере), и из них можно составлять массивы и хеши. Тем не менее их не следует рассматривать как строки и числа. По сути дела, это особый вид ссылок, их нельзя рассматривать как обычные ссылки. Объекты следует трактовать как особый, определяемый пользователем тип данных.

Тип конкретного объекта известен как его класс. Имя класса обычно состоит из имени модуля без расширения рт, и к тому же термины «класс» и «модуль» часто используются как эквиваленты. Таким образом, мы можем говорить о CGI-модуле или о CGI-классе. Объекты конкретного класса создает и контролирует модуль, реализующий этот класс.

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

$query = CGI->new(); # вызвать метод new() в классе «CGI»

Здесь мы имеем дело с вызовом метода класса. Метод класса выглядит точно так же, как метод объекта (о котором мы говорили секунду назад), за исключением того что вместо использования объекта для вызова метода мы используем имя класса, как будто он сам — объект. Метод объекта говорит «вызвать функцию с этим именем, которая относится к данному объекту», тогда как метод класса говорит «вызвать функцию с этим именем, которая относится к данному классу».

Иногда то же самое записывается так:

$query = new CGI; # то же самое

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

С точки зрения разработчика объектных модулей, объект — это ссылка на определяемую пользователем структуру данных, часто на анонимный хеш. Внутри этой структуры хранится всевозможная интересная информация. Воспитанный пользователь, однако, должен добираться до этой информации (с целью ее изучения или изменения), не рассматривая объект как ссылку и не обращаясь непосредственно к данным, на которые он указывает, а используя только имеющиеся методы объектов и классов. Изменение данных объекта другими средствами — это нечестная игра, после которой о вас обязательно станут говорить и думать плохо. Чтобы узнать о том, что представляют собой и как работают вышеупомянутые методы, достаточно прочитать документацию на объектный модуль, которая обычно прилагается в pod-формате.

Объекты в модуле CGI.pm

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

Сначала, однако, нам нужно создать этот объект явно. Для CGI.pm, как и для многих других классов, метод, который позволяет создавать объекты,— это метод класса new () *.

* В отличие от C++ Perl не считает new ключевым словом; вы совершенно свободно можете использовать такие методы-конструкторы, как gimme_another() или fred.0. Тем не менее большинство пользователей в итоге приходят к тому, что называют свои конструкторы во всех случаях new ().

Данный метод конструирует и возвращает новый CGI-объект, соответствующий заполненной форме. Этот объект содержит все данные, введенные пользователем в форму. Будучи вызванным без аргументов, метод new () создает объект путем чтения данных, переданных удаленным броузером. Если в качестве аргумента указан дескриптор файла, он читает этот дескриптор, надеясь найти в нем данные, введенные в форму в предыдущем сеансе работы с броузером.

Через минуту мы покажем вам эту программу и поясним ее работу. Давайте предположим, что она называется guestbook и находится в каталоге cgi-bin. Хоть она и не похожа ни на один из тех сценариев, которые мы рассмотрели выше (в которых одна часть выводит HTML-форму, а вторая читает данные, введенные в форму пользователем, и отвечает на них), вы увидите, что она, тем не менее, выполняет обе эти функции. Поэтому отдельный HTML-документ, содержащий форму гостевой книги, нам не нужен. Пользователь мог бы сначала запустить нашу программу, просто щелкнув мышкой на такой ссылке:

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

Вот наша программа. Перед тем как разбирать ее поэтапно, вы, возможно, захотите просмотреть программу целиком.

use strict; # установить объявления и взятие в кавычки use CGI qw(:standard); # импортировать сокращения согласно :standard use Fcnti qw(:flock); # импортирует LOCK_EX, LOCKJ3H, LOCK_NB

sub bail ( # функция обработки ошибок

print hi(«Unexpected Error»), p($error), end html;

$CHATNAME, # имя файла гостевой книги $MAXSAVE, # какое количество хранить $TITLE, # название и заголовок страницы @cur, # все текущие записи

Sentry, # одна конкретная запись ) ;

$TITLE = «Simple Guestbook»;

$CHATNAME = «/usr/tmp/chatfile»; # где все это в системе находится $MAXSAVE =10;

print header, start_html($TITLE), hi ($TITLE);

$cur ” CGI->new(); # текущий запрос if ($cur->param(«message»)) ( # хорошо, мы получили сообщение

• $cur->param(«date», scalar localtime); # установить текущее время Sentries = ($cur); # записать сообщение в массив >

# открыть файл для чтения и записи (с сохранением предыдущего содержимого) open(CHANDLE, «+ получить эксклюзивную блокировку на гостевую книгу

# (LOCK_EX == exclusive lock)

flock(CHANDLE, LOCK_EX) || bail(«cannot flock $CHATNAME: $!»);

# занести в $MAXSAVE старые записи (первой — самую новую) while (!eof(CHANDLE) && Sentries new(\*CHANDLE); t передать дескриптор файла по ссылке

push Sentries, $entry;

seek(CHANDLE, 0, 0) 11 bail(«cannot rewind $CHATNAME: $!»);

foreach $entry (Sentries) (

$entry->save(\*CHANDLE); # передать дескриптор файла по ссылке > truncate(CHANDLE, tell(CHANDLE)) || bail(«cannot truncate $CHATNAME: $!»);

close(CHANDLE) || bail («cannot close $CHATNAME: $!»);

print hr, start form; # hr() проводит горизонтальную линию: print p(«Name:», $cur->textfield(

print p(«Message:» $cur->textfield(

-OVERRIDE => 1, # стирает предыдущее сообщение

print p(submit(«send»), reset(«clear»));

print end_form, hr;

print h2(«Prior Messages»);

foreach $entry (Sentries) f

На рис. 19.5 вы видите изображение, которое появляется на экране после запуска этой программы.

Рис. 19.5. Форма простой гостевой книги

Обратите внимание на то, что программа начинается с оператора

Если вы хотите запускать ее с помощью более ранние версии Perl 5, то нужно превратить в комментарий строку

use Fcnti qw(:flock)

и заменить lock_ex в первом вызове flock на z.

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

print header, start_html($TITLE), hi($TITLE) ;

Затем создается новый CGI-объект:

$cur = CGI->new(); # текущий запрос

if ($cur->param(«message»)) ( # хорошо, мы получили сообщение

$cur->param(«date», scalar localtime); # установить текущее время

Sentries = ($cur); # записать сообщение в массив

Если нас вызывают посредством заполнения и передачи формы, то объект $cur должен содержать информацию о тексте, введенном в форму. Форма, которую мы предлагаем (см. ниже), содержит два поля ввода: поле имени для ввода имени пользователя и поле сообщения для ввода сообщения. Кроме того, приведенный выше код ставит на введенные в форму данные (после их получения) метку даты. Передача в метод param() двух аргументов — это способ присваивания параметру, заданному первым аргументом, значения, указанного во втором аргументе.

Если нас вызывают не посредством передачи формы, а выполняя щелчок мышью на ссылке Please sign our guestbook, то объект запроса, который мы создаем, будет пуст. Проверка if даст значение «ложь», и в массив Sentries никакой элемент занесен не будет.

В любом случае мы переходим к проверке наличия записей, созданных ранее в нашем сохраняемом файле. Эти записи мы будем считывать в массив @entries. (Вспомните о том, что мы только что сделали текущие данные, если они имеются в форме, первым элементом этого массива.) Но сначала мы должны открыть сохраняемый файл:

Эта функция открывает файл в режиме неразрушающего чтения-записи. Вместо open можно использовать sysopen (). При таком способе посредством единственного вызова открывается старый файл, если он существует (без уничтожения его содержимого), а в противном случае создается новый файл:

# нужно импортировать две «константы» из модуля Fcnti для sysopen use Fcnti qw( 0_RDWR 0_CREAT );

sysopen(CHANDLE, $CHATFILE, 0_RDWRI0_CREAT, 0666) || bail «can’t open $CHATFILE: $!»;

Затем мы блокируем файл, как описывалось выше, и переходим к считыванию текущих записей из $ мах save в Sentries:

flock(CHANDLE, LOCK_EX) 11 bail(«cannot flock $CHATNAME: $!»);

while (!eof(CHANDLE) &S Sentries new(\*CHANDLE); # передать дескриптор файла по ссылке

push Sentries, $entry;

Функция eof — встроенная Perl-функция, которая сообщает о достижении конца файла. Многократно передавая в метод new () ссылку на дескриптор сохраняемого файла*, мы выбираем старые записи, по одной при каждом вызове. Затем мы обновляем файл так, чтобы он включал новую запись, которую мы (возможно) только что получили:

seek(CHANDLE, 0, 0) || bail(«cannot rewind $CHATNAME: $!»);

foreach $entry (Sentries) <

$entry->save(\*CHANDLE); # передать дескриптор файла по ссылке > truncate(CHANDLE, tell (CHANDLE)) || bail(«cannot truncate $CHATNAME: $!»);

close (CHANDLE) || bailC’cannot close $CHATNAME: $!»);

Функции seek, truncate и tell —встроенные Perl-функции, описания которых вы найдете в любом справочнике по языку Perl. Здесь seek переставляет указатель позиции в начало файла, truncate усекает указанный файл до заданной длины, a tell возвращает текущее смещение указателя позиции в файле по отношению к началу файла. Назначение этих строк программы — сохранить в файле только самые последние записи $maxsave, начиная с той, которая была сделана только что.

Метод save () обеспечивает собственно создание записей. Его можно вызвать здесь как $entry->save, поскольку $entry — это CGI-объект, созданный с помощью CGl->new ().

Формат записи сохраняемого файла выглядит следующим образом (запись завершается знаком «=», стоящим в отдельной строке):

ИМЯ1=ЗНАЧЕНИЕ1 ИМЯ2=ЗНАЧЕНИЕ2 ИМЯЗ=ЗНАЧЕНИЕЗ

Теперь пора возвратить обновленную форму броузеру и его пользователю. (Это будет, конечно, первая форма, которую он видит, в том случае, если он щелкнул на ссылке Please sign our guestbook.) Сначала некоторые предварительные действия:

print hr, start_form; # hr() проводит горизонтальную линию:

Как мы уже упоминали, CGI.pm позволяет нам использовать либо прямые вызовы функций, либо вызовы методов через CGI-объект. В нашей программе для создания базового HTML-кода мы обратились к простым вызовам функций, а для задания полей ввода формы продолжаем пользоваться методами объектов:

print pC’Name:», $cur->textfield( -NAME => «name»)) ;

print p(«Message:» $cur->textfield(

-OVERRIDE => 1, # стирает предыдущее сообщение

print p(submit(«send»), reset(«clear»));

print end_form, hr;

* Фактически она представляет собой glob-ссылку, а не ссылку на дескриптор файла, но в данном случае это почти то же самое.

Метод textfieid() возвращает поле ввода текста для нашей формы. Первый из двух приведенных выше вызовов генерирует HTML-код поля ввода текста с HTML-атрибутом, NAME=»name», а второй — создает поле с атрибутом NAME=»message» .

Компоненты формы, создаваемые модулем CGI.pm, по умолчанию устойчивы: они сохраняют свои значения до следующего вызова. (Но лишь в течение одного «сеанса» работы с формой, считая с того момента, когда пользователь щелкнул на ссылке Please sign our guestbook.) Это значит, что поле name = «name», созданное в результате первого вызова textfield(), будет содержать значение имени пользователя, если он уже хотя бы один раз в этом сеансе заполнял и передавал форму. Таким образом, поле ввода, которое мы сейчас создаем, будет иметь следующие HTML-атрибуты:

NAME=»name» VALUE=»Sam Smith»

Совсем другое дело — второй вызов text field (). Мы не хотим, чтобы поле сообщения содержало значение старого сообщения. Поэтому пара аргументов -override => 1 указывает: «Выбросить предыдущее значение этого текстового поля и восстановить значение по умолчанию». Пара аргументов -size => 50 задает размер (в символах) отображаемого поля ввода. Помимо показанных здесь, могут быть и другие необязательные пары аргументов: -DEFAULT => ‘начальное значение ‘ И -MAXLENGTH => п, где n — максимальное число символов, которое может принять данное поле.

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

print h2(«Prior Messages»);

foreach $entry (Sentries) <

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

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

предыдущие значения компонентов формы автоматически сохраняются до следующего вызова. Это особенно удобно при создании многоступенчатых форм — например, тех, которые используются в так называемых приложениях «тележек для покупок», когда вы, перемещаясь по виртуальному магазину, последовательно «делаете покупки» и форма все их запоминает.

Поиск и устранение ошибок в CGI -программах

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

Помогут вам разобраться в этом сборник часто задаваемых вопросов по CGI и хорошая книга по CGI-программированию. Некоторые из источников перечислены в конце главы.

Вот краткий перечень проблем, часто встречающихся в CGI-программи-ровании. При возникновении почти каждой из них выдается раздражающе-бесполезное сообщение 500 Server Error, с которым вы вскоре познакомитесь и которое возненавидите.

• Если, посылая HTML-код в броузер, вы забыли о пустой строке между HTTP-заголовком (т.е. строкой Content-type) и телом, этот HTML-код работать не будет. Помните, что перед тем, как делать все остальное, нужно ввести соответствующую строку Content-Type (и, возможно, другие HTTP-заголовки) и совершенно пустую строку.

• Серверу необходим доступ к сценарию с правом чтения и выполнения, поэтому он, как правило, должен иметь режим 0555, а лучше 0755. (Это характерно для UNIX.)

• Каталог, в котором находится сценарий, сам должен быть выполняемым, поэтому присвойте ему режим доступа 0111, а лучше 0755. (Это характерно для UNIX.)

• Сценарий должен быть инсталлирован в соответствующем конфигурации вашего сервера каталоге. В некоторых системах, например, это может быть /usr/etc/httpd/cgi-Ып.

Советы по отладке в режиме командной строки приведены в документации на CGI.pm.

• Возможно, в имя файла вашего сценария понадобится вводить определенное расширение, например cgiwivipl. Мы возражаем против подобной настройки WWW-сервера, предпочитая устанавливать разрешение на выполнение CGI для каждого каталога отдельно, но в некоторых конфигурациях она может быть необходима. Автоматически позволять, чтобы все заканчивающиеся на .cgi файлы были исполняемыми, рискованно, если FTP-клиентам разрешается производить запись во всех каталогах, а также при «зеркальном» копировании чужой структуры каталогов. В обоих случаях выполняемые программы могут внезапно появиться у вас на сервере без ведома и разрешения Web-мастера. Это означает также, что все файлы, имена которых имеют расширение cgi или р1, нельзя будет вызывать через обычный URL. Данный эффект может иметь самые разные последствия — от нежелательных до катастрофических.

• Помните: расширение р1 означает, что это Perl-библиотека, а не исполняемый Perl-файл. Не путайте эти понятия, иначе вашей судьбе не позавидуешь. Если у вас безусловно должно быть уникальное расширение для разрешения выполнения Perl-программ (потому что ваша операционная система просто не настольно умна, чтобы использовать нечто вроде записи #!/usr/bin/perl), мы предлагаем использовать расширение^. Это, однако, не избавит вас от других только что упомянутых нами проблем.

• Конфигурация вашего сервера требует особого разрешения на выполнение CGI для каталога, в который вы поместили свой CGI-сценарий. Убедитесь в том, что разрешены и GET, и POST. (Ваш Web-мастер знает, что это значит.)

• Web-сервер не выполняет ваш сценарий при запуске с вашим идентификатором пользователя. Убедитесь в том, что файлы и каталоги, к которым обращается сценарий, открыты для всех пользователей, для которых Web-сервер выполняет сценарии, таких как, например, nobody, wwwuser или httpd. Возможно, вам понадобится заранее создать такие файлы и каталоги и присвоить им самые широкие права доступа для записи. При работе в среде UNIX это делается посредством команды chmod a+w. Предоставляя широкий доступ к файлам, всегда будьте настороже.

• Всегда запускайте свой сценарий с Perl-флагом -w, чтобы иметь возможность получать предупреждения. Они направляются в файл регистрации ошибок Web-сервера, который содержит сообщения об ошибках и предупреждения, выдаваемые вашим сценарием. Узнайте у своего Web-мастера путь к этому файлу и проверяйте его на предмет наличия проблем. О том, как лучше обрабатывать ошибки, можно узнать и из описания стандартного модуля CGLCarp.

• Убедитесь, что версии программ и пути к каталогам с Perl и всем используемым вами библиотекам (вроде CGI.pm) на компьютере, где работает Web-сервер, соответствуют ожидаемым.

• В начале своего сценария включите режим autoflush для дескриптора файла stdout, присвоив переменной $ | значение «истина», например 1. Если вы применили модуль FileHandle или любой из модулей ввода-вывода (скажем, IO::File, IO::Socket и т.д.), то можете использовать с этим дескриптором файла метод, имя которого легко запомнить: auto-flush ():

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

Perl и Web: не только CGI -программирование

Perl используется не только в CGI-программировании. Среди других направлений его применения — анализ файлов регистрации, управление встроенными функциями и паролями, «активными» изображениями, манипулирование изображениями*. И все это — лишь верхушка айсберга.

Специализированные издательские системы

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

Perl — идеальный язык для создания специализированных издательских систем, приспособленных под ваши уникальные потребности. С его помощью можно одним махом преобразовать необработанные данные в мириады HTML-страниц. Perl применяется для формирования и сопровождения узлов по всей World Wide Web. The Perl Journal (www.tpj.com) использует Perl для создания всех своих страниц. Perl Language Home Page (www.perl.com) содержит около 10000 Web-страниц, которые автоматически сопровождаются и обновляются различными Perl-программами.

* Perl-интерфейс к графической библиотеке gd Томаса Баутелла содержится в модуле GD.pm, который можно найти в CPAN.

Самый быстрый, самый дешевый (дешевле бесплатного уже ничего быть не может) и самый популярный Web-сервер в Internet, Apache, может работать с встроенным в него Perl, используя модуль mod_perl из CPAN. С этим модулем Perl становится языком программирования для вашего Web-сервера. Вы можете писать маленькие Perl-программы для обработки запросов проверки полномочий, обработки сообщений об ошибках, проведения регистрации и решения любых других задач. Они не требуют запуска нового процесса, потому что Perl теперь встроен в Web-сервер. Еще более привлекателен для многих тот факт, что при работе с Apache вам не нужно запускать новый процесс всякий раз, когда поступает CGI-запрос. Вместо этого создается новый поток, который и выполняет предкомпилированную Perl-программу . Это значительно ускоряет выполнение ваших CGI-программ; обычно работа замедляется из-за вызовов fork/exec, а не из-за большого объема самой программы.

Другой способ ускорить выполнение CGI — использовать стандартный модуль CGI::Fast. В отличие от описанного выше встроенного интерпретатора Perl, такая схема выполнения CGI не требует наличия Web-сервера Apache. Подробности см. на man-странице модуля CGI::Fast.

Если Web-сервер у вас работает под Windows NT, вам определенно следует посетить Web-сервер ActiveWare, www.acftveware.cow. Там можно найти не только готовые двоичные файлы Perl для Windows-платформ*, но и PerlScript и PerlIS. Пакет PerlScript — это механизм разработки сценариев ActiveX, который позволяет встраивать Perl-код в ваши Web-страницы так, как это делается средствами JavaScript и VBScript. Пакет PerlIS — это динамически связываемая библиотека интерфейса ISAPI, которая выполняет Perl-сценарии непосредственно из IIS и других ISAPI-совместимых Web-серверов, давая значительный выигрыш в производительности.

Автоматизация работы в Web с помощью LWP

Ставили ли вы когда-нибудь перед собой задачу проверить Web-документ на предмет наличия «мертвых» ссылок, найти его название или выяснить, какие из его ссылок обновлялись с прошлого четверга? Может быть, вы хотели загрузить изображения, которые содержатся в каком-либо документе, или зеркально скопировать целый каталог? Что будет, если вам придется проходить через proxy-сервер или проводить переадресацию?

* Стандартный дистрибутив Perl версии 5.004 предусматривает инсталляцию под Windows, при этом предполагается, что у вас есть компилятор С (и это предположение, как правило, оправдывается).

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

Модули LWP (Library for WWW access in Perl — библиотека для доступа к WWW на Perl) из CPAN решают за вас все эти задачи — и даже больше. Например, обращение в сценарии к Web-документу с помощью этих модулей осуществляется настолько просто, что его можно выполнить с помощью одностроковой программы. Чтобы, к примеру, получить документ /perl/in-dex.html с узла www.perl.com, введите следующую строку в свой shell или интерпретатор команд:

peri -MLWP::Simple -e «getprint ‘http://www.perl.com/perl/index.html'»

За исключением модуля LWP: :Simple, большинство модулей комплекта LWP в значительной степени объектно-ориентированы. Вот, например, крошечная программа, которая получает URL как аргументы и выдает их названия:

#!/usr/local/bin/peri use LWP;

$browser = LWP::UserAgent->new(); # создать виртуальный броузер $browser->agent(«Mothra/126-Paladium:); # дать ему имя foreeach $url (@ARGV) ( # ожидать URL как аргументы

# сделать GET-запрос по URL через виртуальный броузер

$webdoc = $browser->request(HTTP::Request->new(GET => $url));

if($webdoc->is success) ( # нашли

print STDOUT «$url: :, $result->title, «\n»;

print STDERR «$0: Couldn’t fetch $url\n»;

Как видите, усилия, потраченные на изучение объектов Perl, не пропали даром. Но не забывайте, что, как и модуль CGI.pm, модули LWP скрывают большую часть сложной работы.

Этот сценарий работает так. Сначала создается объект — пользовательский агент (нечто вроде автоматизированного виртуального броузера). Этот объект используется для выдачи запросов на удаленные серверы. Дадим нашему виртуальному броузеру какое-нибудь глупое имя, просто чтобы сделать файлы регистрации пользователей более интересными. Затем получим удаленный документ, направив HTTP-запрос GET на удаленный сервер. Если результат успешный, выведем на экран URL и имя сервера; в противном случае немножко поплачем.

* Помните, что по Ларри Уоллу три главных достоинства программиста есть Леность, Нетерпение и Гордость.

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

#!/usr/local/bin/peri -w use strict;

my($url, $browser, %saw);

$browser ” LPW::UserAgent->new(); # создать виртуальный броузер f о reach $url ( @ARGV ) (

# выбрать документ через виртуальный броузер

my $webdoc = $browser->request (HTTP: :Request->new (GET => $url).);

next unless $webdoc->is_success;

next unless $webdoc->content_type eq ‘text/html’;

# не могу разобрать GIF-файлы

my $base = $webdoc->base;

# теперь извлечь все ссылки типа . > и ..•> foreach (HTML::LinkExtor->new->parse($webdoc->content)->eof->links)( my($tag, %links) = @$_;

next unless $tag eq «a» or $tag eq «img»;

foreach $link (values %links) (

> > ) print join(«\n»,sort keys %saw), «\n»;

На первый взгляд все кажется очень сложным, но вызвано это, скорее всего, недостаточно четким пониманием того, как работают различные объекты и их методы. Мы не собираемся здесь давать пояснения по этим вопросам, потому что книга и так получилась уже достаточно объемной. К счастью, в LWP можно найти обширную документацию и примеры.

Естественно, о модулях, ссылках, объектах и Web-программировании можно рассказать гораздо больше, чем вы узнали из этой маленькой главы. О CGI-программировании можно написать отдельную книгу — и таких книг уже написаны десятки. Приведенный ниже перечень поможет вам продолжить свои исследования в этой области.

• Файлы документации CGI.pm.

• Библиотека LWP из CPAN.


• CGI Programming on the World Wide Web by Shishir Gundavaram (O’Reilly & Associates).

• Web Client Programming with Perl by Clinton Wong (O’Reilly & Associates).

• HTML: The Definitive Guide by Chuck Musciano and Bill Kennedy (O’Reilly & Associates).

• How to Setup and Maintain a Web Site by Lincoln Stein (Addison-Wesley).

• CGI Programming in С and Perl by Thomas Boutell (Addison-Wesley).

• Сборник FAQ no CGI Ника Кью.

• Man-страницы: perltoot, perlref, perlmod, perlobj.

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

2. Напишите CGI-сценарий, который определяет тип броузера, делающего запрос, и сообщает что-нибудь в ответ. (Совет: воспользуйтесь переменной среды HTTP_USER_AGENT.)

FAQ по Perl и программированию для Web

Павел Аммосов, apv@i-connect.ru

Русскоязычный сборник частозадаваемых вопросов по языку программирования perl и server-side web programming.

На CPAN == Comprehensive Perl Archive Network. Homepage CPAN — http://www.cpan.org/ — там берут все, связанное с перлом. Собственно исходники новейшей версии перла берут из файла http://www.perl.com/CPAN/src/latest.tar.gz (на самом деле с www.perl.com стоит редирект на ближайший, по мнению www.perl.com, mirror).

Там же, где и все, относящееся к перлу — на CPAN. Полный список всех модулей и библиотек — http://www.cpan.org/CPAN.html

Есть. Полный список зеркал находится в ftp://ftp.nluug.nl/pub/languages/perl/CPAN/MIRRORED.BY, там можно найти funet или что там поближе, или даже российские зеркала, например ftp://ftp.sai.msu.su/pub/lang/perl/CPAN/ (иногда в дауне).

Обычно модуль приходит в формате tar+gzip, типа module-0.01.tar.gz. Вам необходимо его развернуть: tar zxf module-0.01.tar.gz и перейти в образовавшуюся директорию, например module-0.01: cd module-0.01 Обычно там находятся несколько файлов. Для вас будут важными следующие:

что это за модуль INSTALL

как его поставить Makefile.PL

перловый скрипт для генерации Makefile

Обычно инсталляция происходит следующим образом: perl Makefile.PL

генерация Makefile make all

сборка модуля make test

тестирование модуля make install

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

Но, если вы их не имеете, то можете инсталлировать модуль у себя. Для этого вам необходимо выбрать, где это будет делаться. Для примера, в $HOME/lib/perl5. Необходимо создать эти директории, если их нет: Затем, при генерации Makefile для модуля, вы должны указать, где вы хотите инсталлировать модуль:perl Makefile prefix=$HOME Все остальные шаги без изменений. В результате вы получите альтернативное место, где у вас будут находиться модули. Например, у меня это выглядит так:

Для того, чтобы их использовать, есть несколько путей:

  1. указывать при запуске perl в командной строке:
  2. завести переменную шелла PERL5LIB: для sh (bash,zsh,ksh) export PERL5LIB для csh (tcsh)
  3. указывать в начале скриптов дополнительные библиотеки: Данный случай подходит к CGI-скриптам, которые не наследуют ваших переменных окружения.

Скачивание и установка вручную — достаточно сложное занятие, требующее постоянного вмешательства с вашей стороны. Можно простым способом: сделать su (желательно), запустить perl -MCPAN -e shell . Если это первый запуск модуля CPAN, вам зададут серию вопросов на тему URL вашего любимого зеркала CPAN. После этого все просто: если вы знаете название модуля или библиотеки, то набираете, скажем, install Net::NNTP . Тогда этот модуль (для работы с NNTP) сам ищется на CPAN, сам скачивается, компилируется, устанавливается. Все, поставили, можно выходить и использовать вновь установленный модуль. Если название точно не известно, то набираем там же help и используем различные команды поиска типа i NNTP.

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

/.cpan/CPAN/MyConfig.pm: указать в строке &makepl_arg& =& q[prefix=/home/you], и теперь всегда при автоматической инсталляции модули будут ставится к вам в $HOME/lib/perl5 Более подробно обо всем этом можно прочитать в документации к ExtUtils::MakeMaker.

NB: Современный Модуль СPAN все сам спросит и сделает.

Две классические книги по перлу, первая имеется в русском переводе и продается в магазинах:

Рандал Шварц, Том Кристиансен. Изучаем перл (aka Llama book)

Лэрри Уолл, Том Кристиансен, Рандал Шварц. Programming Perl (aka Camel book, на русском, кажется, еще нет)

Llama book — учебник для начинающих, Camel book — справочное руководство.

**New: Есть еще русский перевод Perl Cookbook под названием Т. Кристиансен, Н. Торкингтон «Perl: Библиотека программиста» — СПб, Издательство «Питер», 2000. ISBN 5-8046-094-X

И еще книжка: М. Райт и др. «CGI/Perl». Ее я не рекомендую, как и все от Райта.

Перл приходит с полным набором документации и набором программ для перевода в разные форматы. Обычно для подробного ознакомления с некоторой особенностью перла пишут «perldoc perlсвойство» или «man perlсвойство». Базовый набор «свойств» таков:

  • Основы perldata, perlvar, perlsyn, perlop, perlsub
  • Запуск perlrun, perldebug
  • Функции perlfunc
  • Objects perlref, perlmod, perlobj, perltie
  • Data Structures perlref, perllol, perldsc
  • Modules perlmod, perlmodlib, perlsub
  • Regexps perlre, perlfunc, perlop, perllocale
  • Moving to perl5 perltrap, perl
  • Linking w/C perlxstut, perlxs, perlcall, perlguts, perlembed
  • Various http://www.perl.com/CPAN/doc/FMTEYEWTK/index.html (not a man-page but still useful)
  • perl О перле вообще
  • perldelta Что нового в последней версии перла
  • perlfaq FAQ
  • perltoc Подробное оглавление ко всей документации
  • perldata Типы данных
  • perlsyn Синтаксис языка
  • perlop Арифметические, логические, строковые операции и их приоритет
  • perlre Регулярные выражения (обработка текста и поиск)
  • perlrun Опции командной строки
  • perlfunc Встроенные функции
  • perlvar Специальные переменные
  • perlsub Как писать свои функции (процедуры)
  • perlmod Устройство и принцип работы модулей
  • perlmodlib Модули: создание собственных библиотек
  • perlmodinstall Поиск и установка модулей и библиотек на CPAN
  • perlform «Форматы», или шаблоны для выводимых данных
  • perllocale Поддержка интернационализации
  • perlref Ссылки и указатели на данные
  • perldsc Введение в структурные типы данных
  • perllol Структуры данных: массивы и списки
  • perltoot Введение в объектно-ориентированное программирование
  • perlobj Объекты в перле
  • perltie Связь объектов с обыкновенными переменными
  • perlbot Perl OO tricks and examples
  • perlipc Связь между процессами: pipes, sockets, сигналы и др.
  • perldebug Отладка программ
  • perldiag Сообщения об ошибках
  • perlsec Вопросы безопасности
  • perltrap Возможные грабли и ловушки
  • perlport Как писать портабельные программы
  • perlstyle Стиль программирования на перле
  • perlpod Формат стандартной документации и документация, встраиваемая в исходные тексты программ
  • perlbook О книгах про перл — (для совсем крутых) —
  • perlembed Способы внедрения перл-программ в программы на C/C++
  • perlapio Собственный API, используемый в исходниках перла
  • perlxs XS — программирование перловских библиотек, используемых вместе с библиотеками на C
  • perlxstut Учебник по XS
  • perlguts Внутренние функции перла для разработчиков
  • perlcall Соглашения о вызове перловских функций из C
  • perlhist История и полный список всех версий перла

Перл для win32 поставляется с программой perldoc (пользоваться: «perldoc perlfunc» и т. д.) а также с документацией в HTML: если хочешь perldoc perlfunc, ищи perlfunc.html.

Формат стандартной документации по перлу (pod) обладает возможностью встраивания прямо в тексты программ, а программа perldoc — возможностью извлечения этой документации. Поэтому, чтобы получить документацию по модулю Math::Trig , просто запустите perldoc Math::Trig — perldoc найдет этот модуль и покажет документацию из него. Если модуль не является частью какой-то библиотеки, а существует сам по себе, например, CGI.pm тогда просто perldoc CGI.pm или даже perldoc CGI. NB: программа perldoc не очень расторопна, поэтому при установке перла под UNIX производится создание manpages для всех модулей, так что man CGI или man Math::Trig покажет быстрее, чем perldoc.

Да, он тоже входит в набор стандартной документации. Отправная точка — perldoc perlfaq, это оглавление, из которого можно узнать, что FAQ состоит из девяти больших частей.

Про это говорят в perldoc perlpod, в man pod2man.

Да. На мой взгляд, серия статей Рандала Шварца для Unix Review Perl Columns — лучшее введение в перл, и намного интереснее и полезнее книг Llama и Camel ( мнения авторов не всегда совпадают с мнением координатора — Аммосов ). Почитать их можно на http://w3.stonehenge.com:80/merlyn/UnixReview/.

Почему я считаю это лучшим введением в перл? Потому что это отдельные небольшие статьи, каждая из которых иллюстрирует конкретные возможности перла на примере написания программы для достаточно простой задачи. Все же статьи охватывают практически весь спектр возможностей перла — от написания скрипта в одну строку, который может поменять Иванов на Сидоров во всех файлах в дереве директорий, до основ объектно-ориентированного программирования и принципов создания собственных модулей и библиотек.

Если нет возможности купить в магазине, то есть кое-что и в Интернете: книга Маслова «Введение в перл», например. http://citforum.ru/koi/internet/perl_tut/ Есть и другие, особо хороших не видел.

man perlfunc или «perldoc -f имя_функции | pod2text»

С помощью так называемых файловых тестов, которые имеют вид (-тест «имя файла»), например: (-s «file.txt»)

существует ли файл -w

доступен ли на запись -M

количество дней со дня модификации -t

является ли терминалом (Как обычно, это неполный список. См. man perlfunc)

Способ для Unix oт Alex Efros

У меня не Unix! Что делать?

Вероятно, Вам поможет модуль Net::SMTP

Возьмите на CPAN модуль MIME::Tools и прочтите от него README. (MIME-tools.xxxxx.tar.gz)

Гарантированно — никак. Вы можете проверить адрес на правильность синтаксиса при помощи Email::Valid. И все. Если нужен гарантированно правильный e-mail для web-сайта, вы можете воспользоваться методом от Алексея Тутубалина: требовать пароль для доступа к информации, а сам пароль высылать по электронной почте. Тогда человек должен будет указать свой e-mail, конечно же, если ему интересна эта информация с вашего сайта.

Сам модуль представляет из себя файл с именем MyModule.pm следующего содержания:

Программа, его использующая:

Подробности смотрите в perlmod(1), Exporter(3pm), Camel Book

Надо использовать функцию substr. Например, получить 15й символ из строки $string:

Установить 15й символ строки $string: Можно даже использовать более чем односимвольные последовательности:

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» будет симптомом).

Cgi pm библиотека cgi для perl 5

Want to be notified of new releases in leejo/CGI.pm ?

Launching GitHub Desktop .

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop .

If nothing happens, download GitHub Desktop and try again.

Launching Xcode .

If nothing happens, download Xcode and try again.

Launching Visual Studio .

Permalink

CGI — Handle Common Gateway Interface requests and responses

CGI.pm is a stable, complete and mature solution for processing and preparing HTTP requests and responses. Major features including processing form submissions, file uploads, reading and writing cookies, query string generation and manipulation, and processing and preparing HTTP headers.

CGI.pm performs very well in a vanilla CGI.pm environment and also comes with built-in support for mod_perl and mod_perl2 as well as FastCGI.

It has the benefit of having developed and refined over 20 years with input from dozens of contributors and being deployed on thousands of websites. CGI.pm was included in the perl distribution from perl v5.4 to v5.20, however is has now been removed from the perl core.

CGI.pm HAS BEEN REMOVED FROM THE PERL CORE

If you upgrade to a new version of perl or if you rely on a system or vendor perl and get an updated version of perl through a system update, then you will have to install CGI.pm yourself with cpan/cpanm/a vendor package/manually. To make this a little easier the CGI::Fast module has been split into its own distribution, meaning you do not need access to a compiler to install CGI.pm

The rationale for this decision is that CGI.pm is no longer considered good practice for developing web applications, including quick prototyping and small web scripts. There are far better, cleaner, quicker, easier, safer, more scalable, more extensible, more modern alternatives available at this point in time. These will be documented with CGI::Alternatives.

For more discussion on the removal of CGI.pm from core please see:

Note that the v4 releases of CGI.pm will retain back compatibility as much as possible, however you may need to make some minor changes to your code if you are using deprecated methods or some of the more obscure features of the module. If you plan to upgrade to v4.00 and beyond you should read the Changes file for more information and test your code against CGI.pm before deploying it.

HTML Generation functions should no longer be used

All HTML generation functions within CGI.pm are no longer being maintained. Any issues, bugs, or patches will be rejected unless they relate to fundamentally broken page rendering.

The rationale for this is that the HTML generation functions of CGI.pm are an obfuscation at best and a maintenance nightmare at worst. You should be using a template engine for better separation of concerns. See CGI::Alternatives for an example of using CGI.pm with the Template::Toolkit module.

These functions, and perldoc for them, are considered deprecated, they are no longer being maintained and no fixes or features for them will be accepted. They will, however, continue to exist in CGI.pm without any deprecation warnings («soft» deprecation) so you can continue to use them if you really want to. All documentation for these functions has been moved to CGI::HTML::Functions.

There are two styles of programming with CGI.pm, an object-oriented (OO) style and a function-oriented style. You are recommended to use the OO style as CGI.pm will create an internal default object when the functions are called procedurally and you will not have to worry about method names clashing with perl builtins.

In the object-oriented style you create one or more CGI objects and then use object methods to create the various elements of the page. Each CGI object starts out with the list of named parameters that were passed to your CGI script by the server. You can modify the objects, save them to a file or database and recreate them. Because each object corresponds to the «state» of the CGI script, and because each object’s parameter list is independent of the others, this allows you to save the state of the script and restore it later.

For example, using the object oriented style:

In the function-oriented style, there is one default CGI object that you rarely deal with directly. Instead you just call functions to retrieve CGI parameters, manage cookies, and so on. The following example is identical to above, in terms of output, but uses the function-oriented interface. The main differences are that we now need to import a set of functions into our name space (usually the «standard» functions), and we don’t need to create the CGI object.

The examples in this document mainly use the object-oriented style. See HOW TO IMPORT FUNCTIONS for important information on function-oriented programming in CGI.pm

Calling CGI.pm routines

Most CGI.pm routines accept several arguments, sometimes as many as 20 optional ones! To simplify this interface, all routines use a named argument calling style that looks like this:

Each argument name is preceded by a dash. Neither case nor order matters in the argument list: -type, -Type, and -TYPE are all acceptable. In fact, only the first argument needs to begin with a dash. If a dash is present in the first argument CGI.pm assumes dashes for the subsequent ones.

Several routines are commonly called with just one argument. In the case of these routines you can provide the single argument without an argument name. header() happens to be one of these routines. In this case, the single argument is the document type.

Other such routines are documented below.

Sometimes named arguments expect a scalar, sometimes a reference to an array, and sometimes a reference to a hash. Often, you can pass any type of argument and the routine will do whatever is most appropriate. For example, the param() routine is used to set a CGI parameter to a single or a multi-valued value. The two cases are shown below:

Many routines will do something useful with a named argument that it doesn’t recognize. For example, you can produce non-standard HTTP header fields by providing them as named arguments:

This will produce the following nonstandard HTTP header:

Notice the way that underscores are translated automatically into hyphens.

Creating a new query object (object-oriented style)

This will parse the input (from POST, GET and DELETE methods) and store it into a perl5 object called $q. Note that because the input parsing happens at object instantiation you have to set any CGI package variables that control parsing before you call CGI->new.

Any filehandles from file uploads will have their position reset to the beginning of the file.

Creating a new query object from an input file

Perl purists will be pleased to know that this syntax accepts references to file handles, or even references to filehandle globs, which is the «official» way to pass a filehandle. You can also initialize the CGI object with a FileHandle or IO::File object.

If you are using the function-oriented interface and want to initialize CGI state from a file handle, the way to do this is with restore_parameters(). This will (re)initialize the default CGI object from the indicated file handle.

You can also initialize the query object from a hash reference:

or from a properly formatted, URL-escaped query string:

or from a previously existing CGI object (currently this clones the parameter list, but none of the other object-specific fields, such as autoescaping):

To create an empty query, initialize it from an empty string or hash:

Fetching a list of keywords from the query

If the script was invoked as the result of an ISINDEX search, the parsed keywords can be obtained as an array using the keywords() method.

Fetching the names of all the parameters passed to your script

If the script was invoked with a parameter list (e.g. «name1=value1&name2=value2&name3=value3»), the param() / multi_param() methods will return the parameter names as a list. If the script was invoked as an ISINDEX script and contains a string without ampersands (e.g. «value1+value2+value3»), there will be a single parameter named «keywords» containing the «+»-delimited keywords.

The array of parameter names returned will be in the same order as they were submitted by the browser. Usually this order is the same as the order in which the parameters are defined in the form (however, this isn’t part of the spec, and so isn’t guaranteed).

Fetching the value or values of a single named parameter

Pass the param() / multi_param() method a single argument to fetch the value of the named parameter. When calling param() If the parameter is multivalued (e.g. from multiple selections in a scrolling list), you can ask to receive an array. Otherwise the method will return the first value.

Warning — calling param() in list context can lead to vulnerabilities if you do not sanitise user input as it is possible to inject other param keys and values into your code. This is why the multi_param() method exists, to make it clear that a list is being returned, note that param() can still be called in list context and will return a list for back compatibility.

The following code is an example of a vulnerability as the call to param will be evaluated in list context and thus possibly inject extra keys and values into the hash:

The fix for the above is to force scalar context on the call to ->param by prefixing it with «scalar»

If you call param() in list context with an argument a warning will be raised by CGI.pm, you can disable this warning by setting $CGI::LIST_CONTEXT_WARN to 0 or by using the multi_param() method instead

If a value is not given in the query string, as in the queries «name1=&name2=», it will be returned as an empty string.

If the parameter does not exist at all, then param() will return undef in scalar context, and the empty list in a list context.

Setting the value(s) of a named parameter

This sets the value for the named parameter ‘foo’ to an array of values. This is one way to change the value of a field AFTER the script has been invoked once before.

param() also recognizes a named parameter style of calling described in more detail later:

Appending additional values to a named parameter

This adds a value or list of values to the named parameter. The values are appended to the end of the parameter if it already exists. Otherwise the parameter is created. Note that this method only recognizes the named argument calling syntax.

Importing all parameters into a namespace

This creates a series of variables in the ‘R’ namespace. For example, $R::foo, @R:foo. For keyword lists, a variable @R::keywords will appear. If no namespace is given, this method will assume ‘Q’. WARNING: don’t import anything into ‘main’; this is a major security risk!

NOTE 1: Variable names are transformed as necessary into legal perl variable names. All non-legal characters are transformed into underscores. If you need to keep the original names, you should use the param() method instead to access CGI variables by name.

In fact, you should probably not use this method at all given the above caveats and security risks.

Deleting a parameter completely

This completely clears a list of parameters. It sometimes useful for resetting parameters that you don’t want passed down between script invocations.

If you are using the function call interface, use «Delete()» instead to avoid conflicts with perl’s built-in delete operator.

Deleting all parameters

This clears the CGI object completely. It might be useful to ensure that all the defaults are taken when you create a fill-out form.

Use Delete_all() instead if you are using the function call interface.

Handling non-urlencoded arguments

If POSTed data is not of type application/x-www-form-urlencoded or multipart/form-data, then the POSTed data will not be processed, but instead be returned as-is in a parameter named POSTDATA. To retrieve it, use code like this:

Likewise if PUTed and PATCHed data can be retrieved with code like this:

(If you don’t know what the preceding means, worry not. It only affects people trying to use CGI for XML processing and other specialized tasks)

PUTDATA/POSTDATA/PATCHDATA are also available via upload_hook, and as file uploads via «-putdata_upload» option.

Direct access to the parameter list

If you need access to the parameter list in a way that isn’t covered by the methods given in the previous sections, you can obtain a direct reference to it by calling the param_fetch() method with the name of the parameter. This will return an array reference to the named parameter, which you then can manipulate in any way you like.

You can also use a named argument style using the -name argument.

Fetching the parameter list as a hash

Many people want to fetch the entire parameter list as a hash in which the keys are the names of the CGI parameters, and the values are the parameters’ values. The Vars() method does this. Called in a scalar context, it returns the parameter list as a tied hash reference. Changing a key changes the value of the parameter in the underlying CGI parameter list. Called in a list context, it returns the parameter list as an ordinary hash. This allows you to read the contents of the parameter list, but not to change it.

When using this, the thing you must watch out for are multivalued CGI parameters. Because a hash cannot distinguish between scalar and list context, multivalued parameters will be returned as a packed string, separated by the «\0» (null) character. You must split this packed string in order to get at the individual values. This is the convention introduced long ago by Steve Brenner in his cgi-lib.pl module for perl version 4, and may be replaced in future versions with array references.


If you wish to use Vars() as a function, import the :cgi-lib set of function calls (also see the section on CGI-LIB compatibility).

Saving the state of the script to a file

This will write the current state of the form to the provided filehandle. You can read it back in by providing a filehandle to the new() method. Note that the filehandle can be a file, a pipe, or whatever.

The format of the saved file is:

Both name and value are URL escaped. Multi-valued CGI parameters are represented as repeated names. A session record is delimited by a single = symbol. You can write out multiple records and read them back in with several calls to new. You can do this across several sessions by opening the file in append mode, allowing you to create primitive guest books, or to keep a history of users’ queries. Here’s a short example of creating multiple session records:

The file format used for save/restore is identical to that used by the Whitehead Genome Center’s data exchange format «Boulderio», and can be manipulated and even databased using Boulderio utilities. See Boulder for further details.

If you wish to use this method from the function-oriented (non-OO) interface, the exported name for this method is save_parameters().

Retrieving cgi errors

Errors can occur while processing user input, particularly when processing uploaded files. When these errors occur, CGI will stop processing and return an empty parameter list. You can test for the existence and nature of errors using the cgi_error() function. The error messages are formatted as HTTP status codes. You can either incorporate the error text into a page, or use it as the value of the HTTP status:

When using the function-oriented interface (see the next section), errors may only occur the first time you call param(). Be ready for this!

Using the function-oriented interface

To use the function-oriented interface, you must specify which CGI.pm routines or sets of routines to import into your script’s namespace. There is a small overhead associated with this importation, but it isn’t much.

The listed methods will be imported into the current package; you can call them directly without creating a CGI object first. This example shows how to import the param() and header() methods, and then use them directly:

More frequently, you’ll import common sets of functions by referring to the groups by name. All function sets are preceded with a «:» character as in «:cgi» (for CGI protocol handling methods).

Here is a list of the function sets you can import:

:cgi

Import all CGI-handling methods, such as param(), path_info() and the like.

:all

Import all the available methods. For the full list, see the CGI.pm code, where the variable %EXPORT_TAGS is defined. (N.B. the :cgi-lib imports will not be included in the :all import, you will have to import :cgi-lib to get those)

Note that in the interests of execution speed CGI.pm does not use the standard Exporter syntax for specifying load symbols. This may change in the future.

In addition to the function sets, there are a number of pragmas that you can import. Pragmas, which are always preceded by a hyphen, change the way that CGI.pm functions in various ways. Pragmas, function sets, and individual functions can all be imported in the same use() line. For example, the following use statement imports the cgi set of functions and enables debugging mode (pragma -debug):

The current list of pragmas is as follows:

This keeps CGI.pm from including undef params in the parameter list.

This makes CGI.pm treat all parameters as text strings rather than binary strings (see perlunitut for the distinction), assuming UTF-8 for the encoding.

CGI.pm does the decoding from the UTF-8 encoded input data, restricting this decoding to input text as distinct from binary upload data which are left untouched. Therefore, a ‘:utf8’ layer must not be used on STDIN.

If you do not use this option you can manually select which fields are expected to return utf-8 strings and convert them using code like this:

-putdata_upload / -postdata_upload / -patchdata_upload

Makes $cgi->param(‘PUTDATA’); , $cgi->param(‘PATCHDATA’); , and $cgi->param(‘POSTDATA’); act like file uploads named PUTDATA, PATCHDATA, and POSTDATA. See «Handling non-urlencoded arguments» and «Processing a file upload field» PUTDATA/POSTDATA/PATCHDATA are also available via upload_hook.

This makes CGI.pm produce a header appropriate for an NPH (no parsed header) script. You may need to do other things as well to tell the server that the script is NPH. See the discussion of NPH scripts below.

Separate the name=value pairs in CGI parameter query strings with semicolons rather than ampersands. For example:

Semicolon-delimited query strings are always accepted, and will be emitted by self_url() and query_string(). newstyle_urls became the default in version 2.64.

Separate the name=value pairs in CGI parameter query strings with ampersands rather than semicolons. This is no longer the default.

This turns off the command-line processing features. If you want to run a CGI.pm script from the command line, and you don’t want it to read CGI parameters from the command line or STDIN, then use this pragma:

This turns on full debugging. In addition to reading CGI arguments from the command-line processing, CGI.pm will pause and try to read arguments from STDIN, producing the message «(offline mode: enter name=value pairs on standard input)» features.

See the section on debugging for more details.

GENERATING DYNAMIC DOCUMENTS

Most of CGI.pm’s functions deal with creating documents on the fly. Generally you will produce the HTTP header first, followed by the document itself. CGI.pm provides functions for generating HTTP headers of various types.

Each of these functions produces a fragment of HTTP which you can print out directly so that it is processed by the browser, appended to a string, or saved to a file for later use.

Creating a standard http header

Normally the first thing you will do in any CGI script is print out an HTTP header. This tells the browser what type of document to expect, and gives other optional information, such as the language, expiration date, and whether to cache the document. The header can also be manipulated for special purposes, such as server push and pay per view pages.

header() returns the Content-type: header. You can provide your own MIME type if you choose, otherwise it defaults to text/html. An optional second parameter specifies the status code and a human-readable message. For example, you can specify 204, «No response» to create a script that tells the browser to do nothing at all. Note that RFC 2616 expects the human-readable phase to be there as well as the numeric status code.

The last example shows the named argument style for passing arguments to the CGI methods using named parameters. Recognized parameters are -type, -status, -expires, and -cookie. Any other named parameters will be stripped of their initial hyphens and turned into header fields, allowing you to specify any HTTP header you desire. Internal underscores will be turned into hyphens:

Most browsers will not cache the output from CGI scripts. Every time the browser reloads the page, the script is invoked anew. You can change this behavior with the -expires parameter. When you specify an absolute or relative expiration interval with this parameter, some browsers and proxy servers will cache the script’s output until the indicated expiration date. The following forms are all valid for the -expires field:

The -cookie parameter generates a header that tells the browser to provide a «magic cookie» during all subsequent transactions with your script. Some cookies have a special format that includes interesting attributes such as expiration time. Use the cookie() method to create and retrieve session cookies.

The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers that expect all their scripts to be NPH.

The -charset parameter can be used to control the character set sent to the browser. If not provided, defaults to ISO-8859-1. As a side effect, this sets the charset() method as well. Note that the default being ISO-8859-1 may not make sense for all content types, e.g.:

In the above case you need to pass -charset => » to prevent the default being used.

The -attachment parameter can be used to turn the page into an attachment. Instead of displaying the page, some browsers will prompt the user to save it to disk. The value of the argument is the suggested name for the saved file. In order for this to work, you may have to set the -type to «application/octet-stream».

The -p3p parameter will add a P3P tag to the outgoing header. The parameter can be an arrayref or a space-delimited string of P3P tags. For example:

In either case, the outgoing header will be formatted as:

CGI.pm will accept valid multi-line headers when each line is separated with a CRLF value («\r\n» on most platforms) followed by at least one space. For example:

Invalid multi-line header input will trigger in an exception. When multi-line headers are received, CGI.pm will always output them back as a single line, according to the folding rules of RFC 2616: the newlines will be removed, while the white space remains.

Generating a redirection header

Sometimes you don’t want to produce a document yourself, but simply redirect the browser elsewhere, perhaps choosing a URL based on the time of day or the identity of the user.

The redirect() method redirects the browser to a different URL. If you use redirection like this, you should not print out a header as well.

You are advised to use full URLs (absolute with respect to current URL or even including the http: or ftp: part) in redirection requests as relative URLs are resolved by the user agent of the client so may not do what you want or expect them to do.

You can also use named arguments:

All names arguments recognized by header() are also recognized by redirect(). However, most HTTP headers, including those generated by -cookie and -target, are ignored by the browser.

The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers, such as Microsoft IIS, which expect all their scripts to be NPH.

The -status parameter will set the status of the redirect. HTTP defines several different possible redirection status codes, and the default if not specified is 302, which means «moved temporarily.» You may change the status to another status code if you wish.

Note that the human-readable phrase is also expected to be present to conform with RFC 2616, section 6.1.

Creating a self-referencing url that preserves state information

self_url() will return a URL, that, when selected, will re-invoke this script with all its state information intact. This is most useful when you want to jump around within the document using internal anchors but you don’t want to disrupt the current contents of the form(s). Something like this will do the trick:

If you want more control over what’s returned, using the url() method instead.

You can also retrieve a query string representation of the current object state with query_string():

The behavior of calling query_string is currently undefined when the HTTP method is something other than GET.

If you want to retrieved the query string as set in the webserver, namely the environment variable, you can call env_query_string()

Obtaining the script’s url

url() returns the script’s URL in a variety of formats. Called without any arguments, it returns the full form of the URL, including host name and port number

You can modify this format with the following named arguments:

-absolute

If true, produce an absolute URL, e.g.

-relative

Produce a relative URL. This is useful if you want to re-invoke your script with different parameters. For example:

-full

Produce the full URL, exactly as if called without any arguments. This overrides the -relative and -absolute arguments.

-path (-path_info)

Append the additional path information to the URL. This can be combined with -full, -absolute or -relative. -path_info is provided as a synonym.

-query (-query_string)

Append the query string to the URL. This can be combined with -full, -absolute or -relative. -query_string is provided as a synonym.

-base

Generate just the protocol and net location, as in http://www.foo.com:8000

-rewrite

If Apache’s mod_rewrite is turned on, then the script name and path info probably won’t match the request that the user sent. Set -rewrite => 1 (default) to return URLs that match what the user sent (the original request URI). Set -rewrite => 0 to return URLs that match the URL after the mod_rewrite rules have run.

Mixing post and url parameters

It is possible for a script to receive CGI parameters in the URL as well as in the fill-out form by creating a form that POSTs to a URL containing a query string (a «?» mark followed by arguments). The param() method will always return the contents of the POSTed fill-out form, ignoring the URL’s query string. To retrieve URL parameters, call the url_param() method. Use it in the same way as param(). The main difference is that it allows you to read the parameters, but not set them.

Under no circumstances will the contents of the URL query string interfere with similarly-named CGI parameters in POSTed forms. If you try to mix a URL query string with a form submitted with the GET method, the results will not be what you expect.

If running from the command line, url_param will not pick up any parameters given on the command line.

Processing a file upload field

When the form is processed, you can retrieve an IO::File compatible handle for a file upload field like this:

In a list context, upload() will return an array of filehandles. This makes it possible to process forms that use the same name for multiple upload fields.

If you want the entered file name for the file, you can just call param():

Different browsers will return slightly different things for the name. Some browsers return the filename only. Others return the full path to the file, using the path conventions of the user’s machine. Regardless, the name returned is always the name of the file on the user’s machine, and is unrelated to the name of the temporary file that CGI.pm creates during upload spooling (see below).

When a file is uploaded the browser usually sends along some information along with it in the format of headers. The information usually includes the MIME content type. To retrieve this information, call uploadInfo(). It returns a reference to a hash containing all the document headers.

Note that you must use ->upload or ->param to get the file-handle to pass into uploadInfo as internally this is represented as a File::Temp object (which is what will be returned by ->upload or ->param). When using ->Vars you will get the literal filename rather than the File::Temp object, which will not return anything when passed to uploadInfo. So don’t use ->Vars.

If you are using a machine that recognizes «text» and «binary» data modes, be sure to understand when and how to use them (see the Camel book). Otherwise you may find that binary files are corrupted during file uploads.

Accessing the temp files directly

When processing an uploaded file, CGI.pm creates a temporary file on your hard disk and passes you a file handle to that file. After you are finished with the file handle, CGI.pm unlinks (deletes) the temporary file. If you need to you can access the temporary file directly. You can access the temp file for a file upload by passing the file name to the tmpFileName() method:

As with ->uploadInfo, using the reference returned by ->upload or ->param is preferred, although unlike ->uploadInfo, plain filenames also work if possible for backwards compatibility.

The temporary file will be deleted automatically when your program exits unless you manually rename it or set $CGI::UNLINK_TMP_FILES to 0. On some operating systems (such as Windows NT), you will need to close the temporary file’s filehandle before your program exits. Otherwise the attempt to delete the temporary file will fail.

Changes in temporary file handling (v4.05+)

CGI.pm had its temporary file handling significantly refactored, this logic is now all deferred to File::Temp (which is wrapped in a compatibility object, CGI::File::Temp — DO NOT USE THIS PACKAGE DIRECTLY). As a consequence the PRIVATE_TEMPFILES variable has been removed along with deprecation of the private_tempfiles routine and complete removal of the CGITempFile package. The $CGITempFile::TMPDIRECTORY is no longer used to set the temp directory, refer to the perldoc for File::Temp if you want to override the default settings in that package (the TMPDIR env variable is still available on some platforms). For Windows platforms the temporary directory order remains as before: TEMP > TMP > WINDIR ( > TMPDIR ) so if you have any of these in use in existing scripts they should still work.

The Fh package still exists but does nothing, the CGI::File::Temp class is a subclass of both File::Temp and the empty Fh package, so if you have any code that checks that the filehandle isa Fh this should still work.

When you get the internal file handle you will receive a File::Temp object, this should be transparent as File::Temp isa IO::Handle and isa IO::Seekable meaning it behaves as previously. If you are doing anything out of the ordinary with regards to temp files you should test your code before deploying this update and refer to the File::Temp documentation for more information.

Handling interrupted file uploads

There are occasionally problems involving parsing the uploaded file. This usually happens when the user presses «Stop» before the upload is finished. In this case, CGI.pm will return undef for the name of the uploaded file and set cgi_error() to the string «400 Bad request (malformed multipart POST)». This error message is designed so that you can incorporate it into a status code to be sent to the browser. Example:

Progress bars for file uploads and avoiding temp files

CGI.pm gives you low-level access to file upload management through a file upload hook. You can use this feature to completely turn off the temp file storage of file uploads, or potentially write your own file upload progress meter.

This is much like the UPLOAD_HOOK facility available in Apache::Request, with the exception that the first argument to the callback is an Apache::Upload object, here it’s the remote filename.

The $data field is optional; it lets you pass configuration information (e.g. a database handle) to your hook callback.

The $use_tempfile field is a flag that lets you turn on and off CGI.pm’s use of a temporary disk-based file during file upload. If you set this to a FALSE value (default true) then $q->param(‘uploaded_file’) will no longer work, and the only way to get at the uploaded data is via the hook you provide.

If using the function-oriented interface, call the CGI::upload_hook() method before calling param() or any other CGI functions:

This method is not exported by default. You will have to import it explicitly if you wish to use it without the CGI:: prefix.

Troubleshooting file uploads on Windows

If you are using CGI.pm on a Windows platform and find that binary files get slightly larger when uploaded but that text files remain the same, then you have forgotten to activate binary mode on the output filehandle. Be sure to call binmode() on any handle that you create to write the uploaded file to disk.

Older ways to process file uploads

This section is here for completeness. if you are building a new application with CGI.pm, you can skip it.

The original way to process file uploads with CGI.pm was to use param(). The value it returns has a dual nature as both a file name and a lightweight filehandle. This dual nature is problematic if you following the recommended practice of having use strict in your code. perl will complain when you try to use a string as a filehandle. More seriously, it is possible for the remote user to type garbage into the upload field, in which case what you get from param() is not a filehandle at all, but a string.

To solve this problem the upload() method was added, which always returns a lightweight filehandle. This generally works well, but will have trouble interoperating with some other modules because the file handle is not derived from IO::File. So that brings us to current recommendation given above, which is to call the handle() method on the file handle returned by upload(). That upgrades the handle to an IO::File. It’s a big win for compatibility for a small penalty of loading IO::File the first time you call it.

CGI.pm has several methods that support cookies.

A cookie is a name=value pair much like the named parameters in a CGI query string. CGI scripts create one or more cookies and send them to the browser in the HTTP header. The browser maintains a list of cookies that belong to a particular Web server, and returns them to the CGI script during subsequent interactions.

In addition to the required name=value pair, each cookie has several optional attributes:

This is a time/date string (in a special GMT format) that indicates when a cookie expires. The cookie will be saved and returned to your script until this expiration date is reached if the user exits the browser and restarts it. If an expiration date isn’t specified, the cookie will remain active until the user quits the browser.

This is a partial or complete domain name for which the cookie is valid. The browser will return the cookie to any host that matches the partial domain name. For example, if you specify a domain name of «.capricorn.com», then the browser will return the cookie to Web servers running on any of the machines «www.capricorn.com», «www2.capricorn.com», «feckless.capricorn.com», etc. Domain names must contain at least two periods to prevent attempts to match on top level domains like «.edu». If no domain is specified, then the browser will only return the cookie to servers on the host the cookie originated from.

If you provide a cookie path attribute, the browser will check it against your script’s URL before returning the cookie. For example, if you specify the path «/cgi-bin», then the cookie will be returned to each of the scripts «/cgi-bin/tally.pl», «/cgi-bin/order.pl», and «/cgi-bin/customer_service/complain.pl», but not to the script «/cgi-private/site_admin.pl». By default, path is set to «/», which causes the cookie to be sent to any CGI script on your site.

If the «secure» attribute is set, the cookie will only be sent to your script if the CGI request is occurring on a secure channel, such as SSL.

The interface to HTTP cookies is the cookie() method:

cookie() creates a new cookie. Its parameters include:

-name

The name of the cookie (required). This can be any string at all. Although browsers limit their cookie names to non-whitespace alphanumeric characters, CGI.pm removes this restriction by escaping and unescaping cookies behind the scenes.

-value

The value of the cookie. This can be any scalar value, array reference, or even hash reference. For example, you can store an entire hash into a cookie this way:

-path

The optional partial path for which this cookie will be valid, as described above.

-domain

The optional partial domain for which this cookie will be valid, as described above.

-expires

The optional expiration date for this cookie. The format is as described in the section on the header() method:

-secure

If set to true, this cookie will only be used within a secure SSL session.

The cookie created by cookie() must be incorporated into the HTTP header within the string returned by the header() method:

To create multiple cookies, give header() an array reference:

To retrieve a cookie, request it by name by calling cookie() method without the -value parameter. This example uses the object-oriented form:

Cookies created with a single scalar value, such as the «riddle_name» cookie, will be returned in that form. Cookies with array and hash values can also be retrieved.

The cookie and CGI namespaces are separate. If you have a parameter named ‘answers’ and a cookie named ‘answers’, the values retrieved by param() and cookie() are independent of each other. However, it’s simple to turn a CGI parameter into a cookie, and vice-versa:

If you call cookie() without any parameters, it will return a list of the names of all cookies passed to your script:

See the cookie.cgi example script for some ideas on how to use cookies effectively.

If you are running the script from the command line or in the perl debugger, you can pass the script a list of keywords or parameter=value pairs on the command line or from standard input (you don’t have to worry about tricking your script into reading from environment variables). You can pass keywords like this:

To turn off this feature, use the -no_debug pragma.

To test the POST method, you may enable full debugging with the -debug pragma. This will allow you to feed newline-delimited name=value pairs to the script on standard input.

When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs:

Finally, you can set the path info for the script by prefixing the first name/value parameter with the path followed by a question mark (?):

FETCHING ENVIRONMENT VARIABLES

Some of the more useful environment variables can be fetched through this interface. The methods are as follows:

Accept()

Return a list of MIME types that the remote browser accepts. If you give this method a single argument corresponding to a MIME type, as in Accept(‘text/html’), it will return a floating point value corresponding to the browser’s preference for this type from 0.0 (don’t want) to 1.0. Glob types (e.g. text/*) in the browser’s accept list are handled correctly.

Note that the capitalization changed between version 2.43 and 2.44 in order to avoid conflict with perl’s accept() function.

raw_cookie()

Returns the HTTP_COOKIE variable. Cookies have a special format, and this method call just returns the raw form (?cookie dough). See cookie() for ways of setting and retrieving cooked cookies.

Called with no parameters, raw_cookie() returns the packed cookie structure. You can separate it into individual cookies by splitting on the character sequence «; «. Called with the name of a cookie, retrieves the unescaped form of the cookie. You can use the regular cookie() method to get the names, or use the raw_fetch() method from the CGI::Cookie module.

env_query_string()


Returns the QUERY_STRING variable, note that this is the original value as set in the environment by the webserver and (possibly) not the same value as returned by query_string(), which represents the object state

user_agent()

Returns the HTTP_USER_AGENT variable. If you give this method a single argument, it will attempt to pattern match on it, allowing you to do something like user_agent(Mozilla);

path_info()

Returns additional path information from the script URL. E.G. fetching /cgi-bin/your_script/additional/stuff will result in path_info() returning «/additional/stuff».

NOTE: The Microsoft Internet Information Server is broken with respect to additional path information. If you use the perl DLL library, the IIS server will attempt to execute the additional path information as a perl script. If you use the ordinary file associations mapping, the path information will be present in the environment, but incorrect. The best thing to do is to avoid using additional path information in CGI scripts destined for use with IIS. A best attempt has been made to make CGI.pm do the right thing.

path_translated()

As per path_info() but returns the additional path information translated into a physical path, e.g. «/usr/local/etc/httpd/htdocs/additional/stuff».

The Microsoft IIS is broken with respect to the translated path as well.

remote_host()

Returns either the remote host name or IP address if the former is unavailable.

remote_ident()

Returns the name of the remote user (as returned by identd) or undef if not set

remote_addr()

Returns the remote host IP address, or 127.0.0.1 if the address is unavailable.

request_uri()

Returns the interpreted pathname of the requested document or CGI (relative to the document root). Or undef if not set.

script_name()

Return the script name as a partial URL, for self-referring scripts.

referer()

Return the URL of the page the browser was viewing prior to fetching your script.

auth_type()

Return the authorization/verification method in use for this script, if any.

server_name()

Returns the name of the server, usually the machine’s host name.

virtual_host()

When using virtual hosts, returns the name of the host that the browser attempted to contact

server_port()

Return the port that the server is listening on.

server_protocol()

Returns the protocol and revision of the incoming request, or defaults to HTTP/1.0 if this is not set

virtual_port()

Like server_port() except that it takes virtual hosts into account. Use this when running with virtual hosts.

server_software()

Returns the server software and version number.

remote_user()

Return the authorization/verification name used for user verification, if this script is protected.

user_name()

Attempt to obtain the remote user’s name, using a variety of different techniques. May not work in all browsers.

request_method()

Returns the method used to access your script, usually one of ‘POST’, ‘GET’ or ‘HEAD’. If running from the command line it will be undef.

content_type()

Returns the content_type of data submitted in a POST, generally multipart/form-data or application/x-www-form-urlencoded

http()

Called with no arguments returns the list of HTTP environment variables, including such things as HTTP_USER_AGENT, HTTP_ACCEPT_LANGUAGE, and HTTP_ACCEPT_CHARSET, corresponding to the like-named HTTP header fields in the request. Called with the name of an HTTP header field, returns its value. Capitalization and the use of hyphens versus underscores are not significant.

For example, all three of these examples are equivalent:

https()

The same as http(), but operates on the HTTPS environment variables present when the SSL protocol is in effect. Can be used to determine whether SSL is turned on.

USING NPH SCRIPTS

NPH, or «no-parsed-header», scripts bypass the server completely by sending the complete HTTP header directly to the browser. This has slight performance benefits, but is of most use for taking advantage of HTTP extensions that are not directly supported by your server, such as server push and PICS headers.

Servers use a variety of conventions for designating CGI scripts as NPH. Many Unix servers look at the beginning of the script’s name for the prefix «nph-«. The Macintosh WebSTAR server and Microsoft’s Internet Information Server, in contrast, try to decide whether a program is an NPH script by examining the first line of script output.

CGI.pm supports NPH scripts with a special NPH mode. When in this mode, CGI.pm will output the necessary extra header information when the header() and redirect() methods are called.

The Microsoft Internet Information Server requires NPH mode. As of version 2.30, CGI.pm will automatically detect when the script is running under IIS and put itself into this mode. You do not need to do this manually, although it won’t hurt anything if you do.

In the use statement

Simply add the «-nph» pragma to the list of symbols to be imported into your script:

By calling the nph() method:

Call nph() with a non-zero parameter at any point after using CGI.pm in your program.

By using -nph parameters

in the header() and redirect() statements:

CGI.pm provides four simple functions for producing multipart documents of the type needed to implement server push. These functions were graciously provided by Ed Jordan ed@fidalgo.net. To import these into your namespace, you must import the «:push» set. You are also advised to put the script into NPH mode and to set $| to 1 to avoid buffering problems.

Here is a simple script that demonstrates server push:

This script initializes server push by calling multipart_init(). It then enters a loop in which it begins a new multipart section by calling multipart_start(), prints the current local time, and ends a multipart section with multipart_end(). It then sleeps a second, and begins again. On the final iteration, it ends the multipart section with multipart_final() rather than with multipart_end().

Initialize the multipart system. The -boundary argument specifies what MIME boundary string to use to separate parts of the document. If not provided, CGI.pm chooses a reasonable boundary for you.

The -charset provides the character set, if not provided this will default to ISO-8859-1

Start a new part of the multipart document using the specified MIME type and charset. If not specified, text/html ISO-8859-1 is assumed.

End a part. You must remember to call multipart_end() once for each multipart_start(), except at the end of the last part of the multipart document when multipart_final() should be called instead of multipart_end().

End all parts. You should call multipart_final() rather than multipart_end() at the end of the last part of the multipart document.

Users interested in server push applications should also have a look at the CGI::Push module.

AVOIDING DENIAL OF SERVICE ATTACKS

A potential problem with CGI.pm is that, by default, it attempts to process form POSTings no matter how large they are. A wily hacker could attack your site by sending a CGI script a huge POST of many gigabytes. CGI.pm will attempt to read the entire POST into a variable, growing hugely in size until it runs out of memory. While the script attempts to allocate the memory the system may slow down dramatically. This is a form of denial of service attack.

Another possible attack is for the remote user to force CGI.pm to accept a huge file upload. CGI.pm will accept the upload and store it in a temporary directory even if your script doesn’t expect to receive an uploaded file. CGI.pm will delete the file automatically when it terminates, but in the meantime the remote user may have filled up the server’s disk space, causing problems for other programs.

The best way to avoid denial of service attacks is to limit the amount of memory, CPU time and disk space that CGI scripts can use. Some Web servers come with built-in facilities to accomplish this. In other cases, you can use the shell limit or ulimit commands to put ceilings on CGI resource usage.

CGI.pm also has some simple built-in protections against denial of service attacks, but you must activate them before you can use them. These take the form of two global variables in the CGI name space:

$CGI::POST_MAX

If set to a non-negative integer, this variable puts a ceiling on the size of POSTings, in bytes. If CGI.pm detects a POST that is greater than the ceiling, it will immediately exit with an error message. This value will affect both ordinary POSTs and multipart POSTs, meaning that it limits the maximum size of file uploads as well. You should set this to a reasonably high value, such as 10 megabytes.

$CGI::DISABLE_UPLOADS

If set to a non-zero value, this will disable file uploads completely. Other fill-out form values will work as usual.

To use these variables, set the variable at the top of the script, right after the «use» statement:

An attempt to send a POST larger than $POST_MAX bytes will cause param() to return an empty CGI parameter list. You can test for this event by checking cgi_error(), either after you create the CGI object or, if you are using the function-oriented interface, call

for the first time. If the POST was intercepted, then cgi_error() will return the message «413 POST too large».

This error message is actually defined by the HTTP protocol, and is designed to be returned to the browser as the CGI script’s status code. For example:

However it isn’t clear that any browser currently knows what to do with this status code. It might be better just to create a page that warns the user of the problem.

COMPATIBILITY WITH CGI-LIB.PL

To make it easier to port existing programs that use cgi-lib.pl the compatibility routine «ReadParse» is provided. Porting is simple:

CGI.pm’s ReadParse() routine creates a tied variable named %in, which can be accessed to obtain the query variables. Like ReadParse, you can also provide your own variable. Infrequently used features of ReadParse, such as the creation of @in and $in variables, are not supported.

Once you use ReadParse, you can retrieve the query object itself this way:

CGI.pm : include image?

I’m writting Perl/CGI script with the module CGI.pm. I can return text/html, but can’t include an image within it, it always display the ‘alt’ tag and I’m sure about the href link.

1 Answer 1

First, you’re not getting the alt text. You’re sending -src http://www.perl.org/simages/lcamel.gif -alt Powered by Perl , so the image doesn’t even have alt text.

The first argument of img should be a hash of attributes. The rest is taken as child elements.

The dashes are optional, so you could also use

Как я могу получить весь объект запроса с CGI.pm?

Я пытаюсь написать Perl CGI script для обработки запросов XML-RPC, в которых XML-документ отправляется как тело HTTP-запроса POST.

Модуль CGI.pm отлично справляется с извлечением именованных параметров из HTTP-запроса, но я не могу понять, как заставить его предоставить мне весь объект HTTP-запроса (т.е. XML-документ в запросе XML-RPC Я работаю).

Если не CGI.pm, есть ли еще один модуль, который мог бы разобрать эту информацию из запроса? Я бы предпочел не извлекать эту информацию «вручную» из переменных окружения. Спасибо за любую помощь.

Вы можете получить необработанные данные POST, используя специальное имя параметра POSTDATA.

Кроме того, вы можете читать STDIN напрямую, а не использовать CGI.pm, но затем вы теряете все другие полезные вещи, которые делает CGI.pm.

Трюк POSTDATA задокументирован в отличном документе CGI.pm здесь.

Правильно, можно использовать POSTDATA, но это работает только в том случае, если в запросе Content-Type не было установлено «multipart/form-data».

Если он настроен на «multipart/form-data», CGI.pm не выполняет свою собственную обработку контента и POSTDATA.

Таким образом, другие параметры включают $cgi->query_string и/или $cgi->Dump .

$cgi->query_string возвращает содержимое POST в формате GET ( param=value&. ), и, похоже, нет способа просто получить содержимое POST STDIN, поскольку они были переданы клиентом.

Таким образом, чтобы получить фактическое содержимое стандартного ввода запроса POST, если вы измените CGI.pm, вы можете изменить строку 620, чтобы сохранить содержимое @lines где-то в переменной, например

И затем войдите в него через $cgi-> .

Глава 19: СGІ-программирование.
19.8 Создание CGI-программы гостевой книги

Если вы внимательно изучили примеры, приведенные выше, то уже должны быть способны заставить работать простые CGI-программы. А как насчет более сложных? Одна из распространенных задач — создание CGT-программы для управления гостевой книгой, чтобы посетители вашего Web-узла могли записывать в нее свои собственные сообщения*.

* Как мы отметим ниже, это приложение можно было бы назвать программой Webchat (переговоров через Web).

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

Вероятно, вы хотите, чтобы сообщения в гостевой книге сохранялись и по завершении посещения вашего узла тем или иным пользователем, поэтому вам нужен файл, куда они будут записываться. Гостевая CGI-программа (вероятно) работает не под вашим управлением, поэтому у нее, как правило, не будет права на обновление вашего файла. Следовательно, первое, что необходимо сделать,— это создать для нее файл с широкими правами доступа. Если вы работаете в UNIX-системе, то можете сделать (из своего shell) для инициализации файла программы гостевой книги следующее:

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

Аргумент lock_ex функции flock — вот что позволяет нам обеспечить монопольный доступ к файлу*.

* В версиях Perl до 5.004 вы должны превратить в комментарий use Fcnti и в качестве аргумента функции flock использовать просто 2.

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

Объектно-ориентированное программирование на Perl

Наконец пришло время научить вас пользоваться объектами и классами — и это важнее всего. Хотя решение задачи построения вашего собственного объектного модуля выходит за рамки данной книги, это еще не повод для того, чтобы вы не могли использовать существующие объектно-ориентированные библиотечные модули. Подробная информация об использовании и создании объектных модулей приведена в главе 5 книги Programming Perl и на man-странице perltoot(l).

Мы не будем углубляться здесь в теорию объектов, и вы можете просто считать их пакетами (чем они и являются!) удивительных, великолепных вещей, вызываемых косвенно. Объекты содержат подпрограммы, которые делают все, что вам нужно делать с объектами.

Пусть, например, модуль CGI.pm возвращает объект $query, который представляет собой входные данные пользователя. Если вы хотите получить параметр из этого запроса, вызовите подпрограмму par am() :

Данная запись означает: «Выполнить подпрограмму param() с объектом $query, используя «answer» как аргумент». Такой вызов в точности соответствует вызову любой другой подпрограммы, за исключением того что вы используете имя объекта, за которым следует синтаксическая конструкция ->. Кстати, подпрограммы, связанные с объектами, называются методами.

Если вы хотите получить значение, возвращенное подпрограммой param(), воспользуйтесь обычным оператором присваивания и сохраните это значение в обычной переменной $he_said:

Объекты выглядят как скаляры; они хранятся в скалярных переменных (таких как переменная $query в нашем примере), и из них можно составлять массивы и хеши. Тем не менее их не следует рассматривать как строки и числа. По сути дела, это особый вид ссылок, их нельзя рассматривать как обычные ссылки. Объекты следует трактовать как особый, определяемый пользователем тип данных.

Тип конкретного объекта известен как его класс. Имя класса обычно состоит из имени модуля без расширения рт, и к тому же термины «класс» и «модуль» часто используются как эквиваленты. Таким образом, мы можем говорить о CGI-модуле или о CGI-классе. Объекты конкретного класса создает и контролирует модуль, реализующий этот класс.

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

Здесь мы имеем дело с вызовом метода класса. Метод класса выглядит точно так же, как метод объекта (о котором мы говорили секунду назад), за исключением того что вместо использования объекта для вызова метода мы используем имя класса, как будто он сам — объект. Метод объекта говорит «вызвать функцию с этим именем, которая относится к данному объекту», тогда как метод класса говорит «вызвать функцию с этим именем, которая относится к данному классу».

Иногда то же самое записывается так:

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

С точки зрения разработчика объектных модулей, объект — это ссылка на определяемую пользователем структуру данных, часто на анонимный хеш. Внутри этой структуры хранится всевозможная интересная информация. Воспитанный пользователь, однако, должен добираться до этой информации (с целью ее изучения или изменения), не рассматривая объект как ссылку и не обращаясь непосредственно к данным, на которые он указывает, а используя только имеющиеся методы объектов и классов. Изменение данных объекта другими средствами — это нечестная игра, после которой о вас обязательно станут говорить и думать плохо. Чтобы узнать о том, что представляют собой и как работают вышеупомянутые методы, достаточно прочитать документацию на объектный модуль, которая обычно прилагается в pod-формате.

Объекты в модуле CGI.pm

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

Сначала, однако, нам нужно создать этот объект явно. Для CGI.pm, как и для многих других классов, метод, который позволяет создавать объекты,— это метод класса new() *.

* В отличие от C++ Perl не считает new ключевым словом; вы совершенно свободно можете использовать такие методы-конструкторы, как gimme_another() или fred.0. Тем не менее большинство пользователей в итоге приходят к тому, что называют свои конструкторы во всех случаях new().

Данный метод конструирует и возвращает новый CGI-объект, соответствующий заполненной форме. Этот объект содержит все данные, введенные пользователем в форму. Будучи вызванным без аргументов, метод new() создает объект путем чтения данных, переданных удаленным броузером. Если в качестве аргумента указан дескриптор файла, он читает этот дескриптор, надеясь найти в нем данные, введенные в форму в предыдущем сеансе работы с броузером.

Через минуту мы покажем вам эту программу и поясним ее работу. Давайте предположим, что она называется guestbook и находится в каталоге cgi-bin. Хоть она и не похожа ни на один из тех сценариев, которые мы рассмотрели выше (в которых одна часть выводит HTML-форму, а вторая читает данные, введенные в форму пользователем, и отвечает на них), вы увидите, что она, тем не менее, выполняет обе эти функции. Поэтому отдельный HTML-документ, содержащий форму гостевой книги, нам не нужен. Пользователь мог бы сначала запустить нашу программу, просто щелкнув мышкой на такой ссылке:

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

Вот наша программа. Перед тем как разбирать ее поэтапно, вы, возможно, захотите просмотреть программу целиком.

На рис. 19.5 вы видите изображение, которое появляется на экране после запуска этой программы.

Рис. 19.5. Форма простой гостевой книги

Обратите внимание на то, что программа начинается с оператора

Если вы хотите запускать ее с помощью более ранние версии Perl 5, то нужно превратить в комментарий строку

и заменить lock_ex в первом вызове flock на z.

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

Затем создается новый CGI-объект:

Если нас вызывают посредством заполнения и передачи формы, то объект $cur должен содержать информацию о тексте, введенном в форму. Форма, которую мы предлагаем (см. ниже), содержит два поля ввода: поле имени для ввода имени пользователя и поле сообщения для ввода сообщения. Кроме того, приведенный выше код ставит на введенные в форму данные (после их получения) метку даты. Передача в метод param() двух аргументов — это способ присваивания параметру, заданному первым аргументом, значения, указанного во втором аргументе.

Если нас вызывают не посредством передачи формы, а выполняя щелчок мышью на ссылке Please sign our guestbook, то объект запроса, который мы создаем, будет пуст. Проверка if даст значение «ложь», и в массив $entries никакой элемент занесен не будет.

В любом случае мы переходим к проверке наличия записей, созданных ранее в нашем сохраняемом файле. Эти записи мы будем считывать в массив @entries. (Вспомните о том, что мы только что сделали текущие данные, если они имеются в форме, первым элементом этого массива.) Но сначала мы должны открыть сохраняемый файл:

Эта функция открывает файл в режиме неразрушающего чтения-записи. Вместо open можно использовать sysopen(). При таком способе посредством единственного вызова открывается старый файл, если он существует (без уничтожения его содержимого), а в противном случае создается новый файл:

Затем мы блокируем файл, как описывалось выше, и переходим к считыванию текущих записей из $махsave в $entries:

Функция eof — встроенная Perl-функция, которая сообщает о достижении конца файла. Многократно передавая в метод new() ссылку на дескриптор сохраняемого файла*, мы выбираем старые записи, по одной при каждом вызове. Затем мы обновляем файл так, чтобы он включал новую запись, которую мы (возможно) только что получили:

* Фактически она представляет собой glob-ссылку, а не ссылку на дескриптор файла, но в данном случае это почти то же самое.

Функции seek, truncate и tell —встроенные Perl-функции, описания которых вы найдете в любом справочнике по языку Perl. Здесь seek переставляет указатель позиции в начало файла, truncate усекает указанный файл до заданной длины, a tell возвращает текущее смещение указателя позиции в файле по отношению к началу файла. Назначение этих строк программы — сохранить в файле только самые последние записи $maxsave, начиная с той, которая была сделана только что.

Метод save() обеспечивает собственно создание записей. Его можно вызвать здесь как $entry->save, поскольку $entry — это CGI-объект, созданный с помощью CGl->new().

Формат записи сохраняемого файла выглядит следующим образом (запись завершается знаком «=», стоящим в отдельной строке):

Теперь пора возвратить обновленную форму броузеру и его пользователю. (Это будет, конечно, первая форма, которую он видит, в том случае, если он щелкнул на ссылке Please sign our guestbook.) Сначала некоторые предварительные действия:

Как мы уже упоминали, CGI.pm позволяет нам использовать либо прямые вызовы функций, либо вызовы методов через CGI-объект. В нашей программе для создания базового HTML-кода мы обратились к простым вызовам функций, а для задания полей ввода формы продолжаем пользоваться методами объектов:

Компоненты формы, создаваемые модулем CGI.pm, по умолчанию устойчивы: они сохраняют свои значения до следующего вызова. (Но лишь в течение одного «сеанса» работы с формой, считая с того момента, когда пользователь щелкнул на ссылке Please sign our guestbook.) Это значит, что поле name = «name», созданное в результате первого вызова textfield(), будет содержать значение имени пользователя, если он уже хотя бы один раз в этом сеансе заполнял и передавал форму. Таким образом, поле ввода, которое мы сейчас создаем, будет иметь следующие HTML-атрибуты:

Совсем другое дело — второй вызов text_field(). Мы не хотим, чтобы поле сообщения содержало значение старого сообщения. Поэтому пара аргументов -override => 1 указывает: «Выбросить предыдущее значение этого текстового поля и восстановить значение по умолчанию». Пара аргументов -size => 50 задает размер (в символах) отображаемого поля ввода. Помимо показанных здесь, могут быть и другие необязательные пары аргументов: -DEFAULT => ‘начальное значение’ И -MAXLENGTH => n, где n — максимальное число символов, которое может принять данное поле.

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

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

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

предыдущие значения компонентов формы автоматически сохраняются до следующего вызова. Это особенно удобно при создании многоступенчатых форм — например, тех, которые используются в так называемых приложениях «тележек для покупок», когда вы, перемещаясь по виртуальному магазину, последовательно «делаете покупки» и форма все их запоминает.

Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:

Илон Маск рекомендует:  Как проверить, содержит ли страница ссылку
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL
Type Name Latest commit message Commit time
Failed to load latest commit information.
examples fix t/examples.t for file_upload.cgi Oct 13, 2020
lib bump VERSION and Changes for CPAN release Jun 3, 2020
.gitignore ref #137 — split out POD into separate file Jan 22, 2015
LICENSE ref #232 — add a copy of Artistic License 2.0 Mar 26, 2020