Отладка CGI-скриптов на Perl
 

Отладка CGI-скриптов на Perl CGI-скрипты можно отнести к наиболее "трудноотлаживаемым" приложениям. Как правило, их отладку производят на сервере, где они будут работать. При этом процесс поиска ошибок, таких как синтаксические, становится очень трудной задачей, т.к. ввиду специфики интерфейса CGI сообщения об ошибках на стадии компиляции не "доходят" до оператора, который отлаживает скрипт, находясь за клиентской машиной. А при повременной оплате за Интернет отладка CGI-скриптов становится также довольно дорогим занятием :).
Целью данной статьи является представить некоторые способы и приемы, призванные, по мнению автора, заметно упростить процесс отладки CGI-скриптов на Perl, а также указать на некоторые самые распространенные ошибки при их написании.
Далее предполагается, что отладка CGI-скриптов ведется под Windows-9x.

Подготовка рабочей среды.

Для работы по написанию и отладке CGI-скриптов на Perl удобно использовать локальный Web-сервер, т.е. Web-сервер, установленный на Вашем компьютере. При этом с точки зрения браузера работа с таким сервером ничем не будет отличаться от работы с сервером в Интернет. В качестве локального веб-сервера можно использовать практически любой веб-сервер под Windows; надо только, чтобы он поддерживал запуск CGI-скриптов. Из самых простых вариантов можно предложить PWS (Personal Web Server) из комплекта Windows9x или IIS (Internet Information Server) из NT. Однако, если Ваш сайт использует такие вещи, как SSI, то лучше все-таки установить Apache для Windows. У большинства сегодняшних хостинг-провайдеров стоит Apache Web Server под UNIX-ом, так что такая совместимость не помешает. Кроме того, Apache позволяет использовать дополнительные нестандартные переменные среды CGI, так что CGI-скрипты, которые "в реальности" будут работать на Apache, лучше отлаживать именно на нем (хотя это мое мнение). Локальный сервер имеет "доменное имя" localhost и IP-адрес 127.0.0.1. Соответственно, обращение к нему ведется через URL вида: http://localhost/... Однако для исполнения CGI-скриптов на Perl установка Web-сервера недостаточна, надо установить еще и сам Perl. Я бы порекомендовал Perl for Win32 от ActiveState.
После установки Perl его нужно "прописать" в установках Web-сервера так, чтобы он являлся Script Handler-ом для Perl-скриптов. В разных Web-серверах это делается по-разному, прочитайте документацию к своему серверу. Для PWS и IIS установка Perl - задача особенная . В большинстве веб-серверов для Windows принадлежность CGI-скрипта к определенному "типу" (Perl-скрипт, еще какой-то скрипт...), а соответственно и handler-у определяется по расширению имени файла. Если на Вашем сервере это так, надо установить для CGI-скриптов на Perl такое расширение, какое оно у Вашего хостинг-провайдера (стандартом де-факто является *.cgi, всречается и *.pl). В Apache принадлежность скрипта определяется не по расширению, а по строчке "#!..." в начале скрипта, как почти во всех UNIX-серверах. При установке всего вышеизложенного для нас очень важна возможность запускать Perl-скрипты "без веб-сервера", т.е. как обычные программы. Это очень удобно при проверке их на синтаксические ошибки. Проверить правильную установку всего можно, написав простой скрипт:

#!/usr/bin/perl
print "Content-Type: text/plain ; charset=windows-1251 ";
print "Скрипт отработал успешно! Поздравляю!";

Сохраните этот скрипт в файле, например, test.cgi и положите этот файл в вашу cgi-bin папку. Теперь проверьте работу скрипта, запустив браузер и выполнив URL: http://localhost/cgi-bin/test.cgi Если все нормально, вы должны увидеть в окне браузера следующий вывод:

Скрипт отработал успешно! Поздравляю!

Если же Вы вместо этого вывода скрипта увидели на экране сам скрипт или нечто вроде "Access Denied", "Permission Denied", "Forbidden" или ничего не увидели вообще (как при загрузке "пустого" документа), то проверьте настройки Вашего веб-сервера - скорее всего, у Вас неверно установлены права доступа на Вашу cgi-папку.
Теперь попробуем запустить наш CGI-скрипт как обычную программу на Perl. Зайдем в какую-нибудь команднострочную оболочку (например, FAR manager) и наберем: perl (адрес Вашего скрипта)
В результате Вы должны увидеть вывод:

Content-Type: text/plain ;charset=windows-1251 Скрипт отработал успешно! Поздравляю!

Вместо слов в последней строчке возможна "абракадабра" - это ничего страшного; просто несоответствие кодировок в скрипте и в оболочке, в которой мы его исполняем. Главное, чтобы он заработал. Если оба вышеуказанных теста прошли успешно - поздравляю! Теперь Вы можете отлаживать большинство CGI-скриптов на своем компьютере, не платя провайдеру за это ни копейки! Теперь у Вас есть свой маленький "интернет в миниатюре" :)))

Приемы отладки скриптов.

Довольно распространенной синтаксической ошибкой является пропуск ";" в конце оператора. (особенно это характерно для тех кто привык к Бейсику, где разделитель строки является разделителем между операторами. В Perl, как и в C/C++, все переводы строки, возвраты каретки и табуляции приравнены по значимости к пробелу и называются "пробельными символами". Разделителями операторов они не являются. Единственным исключением является их использование в строковых константах, где они являются "сами собой", но это только подтверждает правило, что они не разделяют операторы.)
Итак, если Ваш скрипт содержит синтаксическую ошибку, то сообщение об этой ошибке все равно до браузера не "дойдет". Чаще всего при синтаксической ошибке в скрипте сервер выдает ошибку "500 Internal Server Error". Что ж, это действительно считается "внутренней ошибкой сервера"... Вот только в какой она строке?! Но ведь мы теперь можем запустить CGI-скрипт "как программу", и увидеть сообщение Perl об ошибке! Если в вышеуказанном скрипте сделать намеренную ошибку, убрав ";" в конце предпоследней строки, то запустив его "через сервер", мы скорее всего увидим большими буквами написанное "500 Internal Server Error" (Внутренняя ошибка сервера). А если мы запустим его "как программу", то увидим сообщение наподобие следующего:

syntax error at test.cgi line 3, near "print"
Execution of test.pl aborted due to compilation errors.


В первой строке указано, что синтаксическая ошибка произошла в файле test.cgi, в строке 3, рядом со словом print. По-моему, довольно исчерпывающая информация! :) (во второй строке сказано, что выполнение скрипта прервано из-за ошибок компиляции). Теперь мы ищем строку 3, оператор print и исправляем ошибку. Также довольно неприятной ошибкой, приводящей к, на первый взгляд, совершенно непонятному поведению скрипта, является пропуск закрывающей фигурной скобки (}). Чаще всего Perl определит это как ошибку компиляции, но у меня были случаи, когда ошибки не выдавалось.
Вообще, все ошибки в CGI-скриптах можно, на мой взгляд, условно разделить на следующие категории:

  • Синтаксические (ошибки компиляции);
  • Ошибки взаимодействия с CGI;
  • Ошибки взаимодействия с другими программами и/или файлами;
  • Логические.

Первые ошибки удобнее всего находить описанным выше способом. Ко вторым относится некорретный вывод скрипта: скрипт должен выводить свой ответ в формате HTTP, т.е. поля заголовка ответа, затем - пустая строка, а затем - собственно тело ответа. В описанном выше примере выводилась строка заголовка: Content-Type: text/plain ;charset=windows-1251 затем-пустая строка - и тело ответа:
Скрипт отработал успешно! Поздравляю!
При этом сервер, получив ответ от скрипта, разбирает выданный им заголовок, добавляет в него дополнительные поля и основную строку ответа. Поэтому CGI-скрипту вовсе необязательно формировать полный заголовок. Обычно обязательным является указание поля Content-Type, но в любом случае пустая строка после заголовка обязательно должна быть

Несколько слов о так называемых nph- CGI-скриптах.

Это скрипты, полностью формирующие HTTP-заголовок. Поэтому сервер не должен "разбирать" заголовки, выданные такими скриптами, а передавать браузеру все "как есть". Отсюда и название - nph (non-parsed headers - неразбираемые заголовки). Для некоторых серверов такие скрипты должны иметь определенное строение имени файла (имя должно начинаться с nph-), для других это не обязательно. Также к ошибкам связи с CGI относится неправильное указание переменных среды CGI, а также - для скриптов, обрабатывающих формы - метода передачи данных от формы (GET или POST). При этом, если скрипт ожидает данных, посланных методом POST (на стандартный ввод), а в форме ошибочно указан метод GET, то скрипт "застрянет" - он будет ждать поступления данных на стандартный ввод!
Если же скрипт принимает данные по методу GET, а в форме указан POST, скрипт отработает, но не получит из формы никаких данных (как если бы в форме не было ни одного поля). Для скриптов, выводящих "картинки" (GIF, JPG), характерной ошибкой является ASCII-режим передачи. Сразу после открытия файла оператором open этому файлу соответствует ASCII-режим чтения/записи, предназначенный для "простых текстов" (text/plain), как, например, текст в "блокноте". Все файлы, которые задействованы в выводе картинки, (в том числе STDOUT !) должны быть переведены в "бинарный" режим Perl-оператором: binary FILE;
Иначе произойдет искажение данных, поскольку он будет передаваться как текст:
во-первых, произойдет замена "концов строк",
во-вторых, символ с кодом 0 будет воспринят как конец файла.
К ошибкам связи с внешними программами и файлами можно отнести неверный вызов, например, UNIX-команд sendmail, date и т.п. Сюда же можно отнести и неправильный путь к Perl, записанный в первой строке после #!.
Как же отлаживать на локальной машине скрипты, использующие, скажем, sendmail, если у Вас (под Windows) нет sendmail?
Наиболее простой способ - закомментировать то место скрипта, которое высылает письмо. Оно скорее всего в общем случае имеет вид:

open EMAIL,"|путь_к_sendmail список_получателей";
print EMAIL "....";
....
close EMAIL;


где в операторе open открывается sendmail,
EMAIL - дескриптор файла; может быть любой.

Таким образом, можно проверить работу скрипта без высылки сообщения по E-Mail, если оно является вспомогательным (скажем, в гостевых книгах, высылающих вебмастеру уведомление о новой записи).
Можно поступить и другим путем: вместо открытия sendmail в команде open записать открытие файла на запись. Ничего другого при этом менять не нужно. В этом случае при "отсылке сообщения" создастся файл с этим письмом, и Вы сможете вручную проконтролировать его формат.
Кстати, поскольку E-Mail адрес имеет вид user@hostname, а символ @ в Perl- обозначение массива, то "прямая" запись такого адреса вызовет ошибку! Поэтому перед @ нужно ставить обратный слэш . То есть адрес в строчке Perl должен иметь вид user@hostname. То же самое относится и к другим зарезервированным символам, например, $.

Относительно команды date можно сказать, что в большинстве случаев ее может заменить функция perl scalar localtime которая возвращает строку с текущей датой/временем, например:

Sun Oct 22 16:11:42 2000

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

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

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

Окончательная отладка CGI-скриптов на сервере.

Итак, Ваш скрипт работает на локальном компьютере прекрасно, теперь настало время перенести его на сервер.
Итак, на что следует обратить внимание:

  • Путь к Perl в первой строчке. Измените его на путь к Perl Вашего хостинга. Отлаживая скрипт, Вы либо вообще не нуждались в этой строчке, либо, если Вы вели отладку на Apache, то этот путь на Вашем компьютере скорее всего другой.
  • Пути к другим программам, используемым CGI-скриптом.
  • Имена файлов, к которым обращается скрипт.
    В Windows нет различий между заглавными и строчными буквами в именах файлов, т.е. A.TXT и a.txt - идентичные имена. В UNIX, на базе которого работает большинство интернет- серверов, заглавные и строчные буквы в именах файлов - различные символы. Таким образом, скрипт, открывающий файл a.txt командой: open FILE,"a.TXT"; будет нормально работать под Windows, но не захочет работать под UNIX (файл не будет найден).
  • Режим закачки файлов на сервер. Наиболее частой ошибкой является закачивание всего сайта в "бинарном" режиме. И если с закачанными в таком режиме html и txt - файлами особых проблем не будет (хотя могут возникнуть), закачанные таким образом скрипты работать _не будут_.
    Все файлы CGI-скриптов, а также используемых ими текстовых файлов, должны быть закачаны в ASCII-режиме.
  • Права доступа к файлам. Даже если все сделано правильно, скрипт после закачки на UNIX-сервер вряд ли сразу начнет работать. Для того, чтобы он начал работать, надо установить права доступа для файлов CGI-скрипта и используемых ими файлов. Как правило, сразу после закачки файлов на сайт им всем устанавливаются некоторый "стандартный" набор прав (по умолчанию), например: -rw-r--r--
    В общем, все файлы с точки зрения необходимого к ним доступа можно разделить на 3 группы:
    1. Файлы CGI-скрипта;
    2. Файлы, используемые CGI-скриптом для чтения;
    3. Файлы, которые CGI-скрипт использует для чтения и записи;
    Как правило, хостинг провайдер, разрешающий использование CGI, указывает, какие права доступа должны быть установлены для файлов каждого типа. Если нет, то в качестве компромисса можно использовать следующие установки:
    CGI-скрипт - -rwx-r-x-r-x (755);
    Файлы для чтения - -rw-r--r-- (644);
    Файлы для записи - -rw-rw-rw- (666);

ВНИМАНИЕ! На некоторых хостингах рекомендуются другие, более строгие конфигурации прав доступа, обеспечивающие более надежную защиту от взлома для Вашего сайта и системы в целом! Поэтому следуйте рекомендациям своего хостинг-провайдера, если они есть!

 
Автор: Анатолий
 
Оригинал статьи: http://woweb.ru/publ/58-1-0-1