Как я могу устранить неполадки моего скрипта Perl CGI?


У меня есть скрипт Perl, который не работает, и я не знаю, как начать сужать проблему. Что я могу сделать?


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

8 96

8 ответов:

этот ответ предназначен в качестве общей основы для работы через проблемы с Perl CGI скриптами и изначально появились на Perlmonks как Устранение неполадок Perl CGI скриптов. Это не полное руководство для каждого проблема, с которой вы можете столкнуться, ни учебник по раздавливанию ошибок. Оно это просто кульминация моего опыта отладки сценариев CGI для двадцати (плюс!) годы. На этой странице, похоже, было много разных домов, и я, кажется чтобы забыть, что он существует, поэтому я добавляю его StackOverflow. Вы можете отправить мне любые комментарии или предложения по адресу bdfoy@cpan.org это также Вики сообщества, но не слишком сходите с ума. :)


вы используете встроенные функции Perl, чтобы помочь вам найти проблемы?

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

 % perl -w program.pl
, вы должны заставить себя всегда очищать сомнительный код, добавляя warnings pragma для всех ваших файлов:
 use warnings;

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

 use diagnostics;

вы сначала вывели допустимый заголовок CGI?

сервер ожидает, что первый вывод из сценария CGI будет заголовком CGI. Как правило, что может быть, так просто, как print "Content-type: text/plain\n\n"; или сCGI.pm и его производные,print header(). Некоторые серверы чувствительны к выводу ошибок (on STDERR) появляется перед стандартным выходом (на STDOUT).

попробуйте отправить ошибки в браузере

добавить строку

 use CGI::Carp 'fatalsToBrowser';

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

что говорится в журнале ошибок?

сервера ведут логи ошибок (или они должны, по крайней мере). Вывод ошибок с сервера и из вашего скрипта должен покажись там. Найдите журнал ошибок и посмотрите, что он говорит. Нет стандартного места для файлов журнала. Посмотрите в конфигурация сервера для их расположения, или спросите сервер администратор. Вы также можете использовать такие инструменты, как CGI:: Carp чтобы сохранить свои собственные файлы журнала.

что такое разрешения скрипта?

если вы видите ошибки, такие как" отказано в разрешении " или " метод нет реализован", это, вероятно, означает, что ваш скрипт не читаемый и исполняемый пользователем веб-сервера. О вкусах в Unix рекомендуется изменить режим на 755: chmod 755 filename. Никогда не устанавливайте режим на 777!

вы используете use strict?

помните, что Perl автоматически создает переменные, когда сначала вы их используете. Это особенность, но иногда может вызвать ошибки, если вы введите имя переменной с ошибкой. Прагма use strict поможет вам найти такие виды ошибки. Это раздражает, пока вы не привыкнете к нему, но ваш Программирование значительно улучшится через некоторое время и вы будете свободны делать различные ошибки.

компилируется ли скрипт?

вы можете проверить на наличие ошибок компиляции с помощью -c переключатель. Сосредоточьтесь на первых сообщенных ошибках. Полоскать, повторять. Если вы получаете действительно странные ошибки, проверьте к убедитесь, что ваш скрипт имеет правильные окончания строк. Если вы FTP в двоичном режиме, проверка из CVS или что-то еще, что не обрабатывает перевод конца строки, веб-сервер может видеть ваш сценарий как одна большая строка. Передача Perl скриптов в ASCII режим.

скрипт жалуется на небезопасные зависимости?

если ваш скрипт жалуется на небезопасные зависимости, вы вероятно, с помощью -T переключатель для включения режима душок, который хорошая вещь, так как это сохраняет у вас передачу непроверенных данных в оболочку. Если он жалуется, что делает свою работу, чтобы помочь нам написать более безопасные сценарии. Любой данные, поступающие извне программы (т. е. из окружающей среды) считается испорченным. Переменные среды, такие как PATH и LD_LIBRARY_PATH особенно хлопотно. Вы должны установить их в безопасное значение или снимите их полностью, как я рекомендую. Вы должны использовать Абсолют во всяком случае, пути. Если проверка на заражение жалуется на что-то другое, убедиться что вы не запятнали данные. Смотрите perlsec man-страницы для деталей.

что происходит, когда вы запустите его из командной строки?

выводит ли скрипт то, что вы ожидаете при запуске командная строка? Является ли вывод заголовка первым, а затем пустая строка? Помните, что STDERR может быть объединен с STDOUT если вы находитесь на терминале (например, интерактивный сеанс), и из-за буферизации может отображаться в беспорядочном порядке. Включить Автосброс в Perl функция, установив $| в истинная ценность. Как правило, вы можете увидеть $|++; in программа cgi. После установки, каждая печать и запись будет немедленно перейдите к выходу, а не буферизуется. Вы должны установить это для каждого файла handle. Используйте select to измените файловый хэндл по умолчанию, например:

$|++;                            #sets $| for STDOUT
$old_handle = select( STDERR );  #change to STDERR
$|++;                            #sets $| for STDERR
select( $old_handle );           #change back to STDOUT

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

что происходит, когда вы запускаете его из командной строки с помощью CGI-like окружающая среда?

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

снимите или удалите эти переменные

  • PATH
  • LD_LIBRARY_PATH
  • все ORACLE_* переменные

установить эти переменные

  • REQUEST_METHOD (для GET,HEAD или POST при необходимости)
  • SERVER_PORT (установлен в 80, как правило)
  • REMOTE_USER (если вы делаете вещи защищенный доступ)

последние версии CGI.pm ( > 2.75 ) требуется -debug флаг to получите старое (полезное) поведение, поэтому вам, возможно, придется добавить его ваш CGI.pm импортозамещающий.

use CGI qw(-debug)

вы используете die() или warn?

функции печати STDERR если вы переопределили их. Они также не выводят заголовок CGI. Вы можете получить та же функциональность с пакетами, такими как CGI:: Carp

что происходит после очистки кэша браузера?

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

сценарий, где вы думаете, что это?

путь файловой системы к скрипту не обязательно непосредственно связанный с URL-адресом путь к скрипт. Убедиться у вас есть правильный каталог, даже если вам нужно написать короткий тестовый скрипт для проверки этого. Кроме того, вы уверены что вы изменяете правильный файл? Если вы не видите любой эффект с вашими изменениями, вы можете изменить a другой файл или загрузка файла в неправильное место. (Это, кстати, моя самая частая причина такой проблемы ;)

вы используете CGI.pm, или производное от него?

если ваша проблема связанный с разбором ввода CGI и вас не используйте широко протестированный модуль, как CGI.pm,CGI::Request, CGI::Simple или CGI::Lite, используйте модуль и продолжайте жить. CGI.pm есть cgi-lib.pl режим совместимости, который может помочь вам решить ввод проблемы из-за более старых реализаций парсера CGI.

вы использовали абсолютные пути?

если вы выполняете внешние команды с помощью system, задние тики или другие IPC средства, вы должны использовать абсолютный путь к внешней программе. Мало того, что вы точно знаете, что вы бежите, но вы избегайте также некоторых проблем безопасности. Если вы открываете файлы для чтения или записи, используйте абсолютный путь. Сценарий CGI может иметь другое представление о текущем каталог, чем вы. Кроме того, вы можете сделать явное chdir(), чтобы поставить вас в нужное место.

вы проверили свои возвращаемые значения?

Большинство Perl функции скажут вам, если они работали или нет и установит $! на провал. Вы проверили верните значение и проверьте $! для сообщений об ошибках? Ты проверял? $@ если вы используете eval?

какую версию Perl вы используете?

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

что веб-сервер вы используете?

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

вы проверили документацию сервера?

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

вы искали архивы comp.infosystems.www.authoring.cgi?

это использование, чтобы быть полезным, но все хорошие плакаты либо умерли, либо разбрелись.

вполне вероятно, что у кого-то была ваша проблема раньше, и что кто-то (возможно я) ответил ему в этом группа новостей. Хотя эта группа новостей прошла свой расцвет, собранная мудрость из прошлого иногда может быть полезна.

можете ли вы воспроизвести проблему с помощью короткого тестового сценария?

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

вы решили пойти в кино?

серьезно. Иногда мы можем настолько погрузиться в проблему, что мы развивайте "сужение восприятия" (туннельное зрение). Делаем перерыв, выпив чашечку кофе или взорвав несколько плохих парней в [Duke Nukem, Quake, Doom, Halo, COD] может дать вам свежий взгляд, что вам нужно заново подойти к проблеме.

вы озвучили проблема?

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

Я думаю CGI:: Debug стоит упомянуть также.

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

чтобы сделать правильный пример, сначала мне нужно было что-то, что может сделать очень простое моделирование веб-сервера CGI, предпочтительно через одну командную строку. После находка простой веб-сервер командной строки для запуска cgis. (perlmonks.org), я нашел IO:: All-крошечный веб-сервер быть применимым для этого испытания.

вот, я буду работать в /tmp каталог; сценарий CGI будет /tmp/test.pl (включенного ниже). Обратите внимание, что IO::All сервер будет обслуживать только исполняемые файлы в том же каталоге, что и CGI, поэтому chmod +x test.pl здесь требуется. Итак, чтобы выполнить обычный тестовый запуск CGI, я меняю каталог на /tmp в терминал, и запустить однострочный веб-сервер там:

$ cd /tmp
$ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x  ? "./ |" : ) if /^GET \/(.*) / })'

команда webserver заблокируется в терминале и в противном случае запустит веб-сервер локально (на 127.0.0.1 или localhost) - после этого я могу перейти в веб-браузер и запросить этот адрес:

http://127.0.0.1:8080/test.pl

... и я должен наблюдать за prints производства test.pl загружается и отображается в веб-браузере.


теперь, чтобы отладить этот скрипт RemotePort, сначала нам нужен слушатель в сети, через которую мы будем взаимодействовать с отладчиком Perl; мы можем использовать инструмент командной строки netcat (nc, увидел, что здесь: Perl如remremote debug?). Итак, сначала запустите netcat слушатель в одном терминале-где он будет блокировать и ждать соединения на порту 7234 (который будет нашим портом отладки):

$ nc -l 7234

тогда, мы бы хотели perl запустить в режиме отладки с RemotePort, когда test.pl был вызван (даже в CGI режиме, через сервер). Это, в Linux, можно сделать с помощью следующего скрипта" shebang wrapper " - который здесь также должен быть в /tmp и должны быть исполняемым:

cd /tmp

cat > perldbgcall.sh <<'EOF'
#!/bin/bash
PERLDB_OPTS="RemotePort=localhost:7234" perl -d -e "do '$@'"
EOF

chmod +x perldbgcall.sh

это своего рода хитрая вещь - см. shell script-как я могу использовать переменные среды в моем shebang? - Unix & Linux Stack Exchange. Но, трюк здесь, кажется,не скопировать perl интерпретатор, который обрабатывает test.pl - поэтому, как только мы хит его, мы не exec, но вместо этого мы называем perl "ясно", и в основном "источник" наш test.pl скрипт с помощью do (см. как запустить скрипт Perl из скрипта Perl?).

теперь у нас есть perldbgcall.sh на /tmp - мы можем изменить test.pl файл, так что он ссылается на этот исполняемый файл в своей строке shebang (вместо обычного интерпретатора Perl) - вот /tmp/test.pl изменен таким образом:

#!./perldbgcall.sh

# this is test.pl

use 5.10.1;
use warnings;
use strict;

my $b = '1';
my $a = sub { "hello $b there" };
$b = '2';
print "YEAH " . $a->() . " CMON\n";
$b = '3';
print "CMON " . &$a . " YEAH\n";

$DB::single=1;  # BREAKPOINT

$b = '4';
print "STEP " . &$a . " NOW\n";
$b = '5';
print "STEP " . &$a . " AGAIN\n";

теперь test.pl и его новый обработчик притон, perldbgcall.sh, в /tmp и nc прослушивание отладочных соединений на порту 7234-так что мы можем, наконец, открыть другое окно терминала, изменить каталог на /tmp, и запустите однострочный веб-сервер (который будет прослушивать веб-соединения на порту 8080) там:

cd /tmp
perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x  ? "./ |" : ) if /^GET \/(.*) / })'

после этого мы можем перейти в наш веб-браузер и запросить тот же адрес, http://127.0.0.1:8080/test.pl. Однако, сейчас, когда сервер пытается выполнить скрипт, он будет делать это через perldbgcall.sh shebang - который начнется perl в режиме удаленного отладчика. Таким образом, выполнение скрипта приостановится - и поэтому веб-браузер заблокируется, ожидая данных. Теперь мы можем переключиться на netcat терминал, и мы должны увидеть знакомый текст отладчика Perl-однако, вывод через nc:

$ nc -l 7234

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1):   do './test.pl'
  DB<1> r
main::(./test.pl:29):   $b = '4';
  DB<1>

как показывает фрагмент, теперь мы в основном используем nc как "терминал" - так что мы можем ввести r (и введите) для "run" - и скрипт запустится сделать точку останова заявление (см. Также в perl, в чем разница между $DB::single = 1 и 2?), перед повторной остановкой (обратите внимание, что в этот момент браузер все равно заблокируется).

Итак, теперь мы можем, скажем, пройти через остальную часть test.pl, через nc терминала:

....
main::(./test.pl:29):   $b = '4';
  DB<1> n
main::(./test.pl:30):   print "STEP " . &$a . " NOW\n";
  DB<1> n
main::(./test.pl:31):   $b = '5';
  DB<1> n
main::(./test.pl:32):   print "STEP " . &$a . " AGAIN\n";
  DB<1> n
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.
  DB<1>

... однако и на этом этапе браузер блокируется и ждет данных. Только после выхода из отладчика с q:

  DB<1> q
$

... останавливается ли блокировка браузера - и, наконец, отображает (полный) вывод test.pl:

YEAH hello 2 there CMON
CMON hello 3 there YEAH
STEP hello 4 there NOW
STEP hello 5 there AGAIN

конечно, этот вид отладки можно сделать даже без запуска веб-сервера-однако, аккуратная вещь здесь заключается в том, что мы вообще не касаемся веб-сервера; мы запускаем выполнение "изначально" (для CGI) из веб-браузера - и единственное изменение, необходимое в самом скрипте CGI, - это изменение shebang (и, конечно же, наличие сценария оболочки shebang, как исполняемый файл в том же справочник.)

ну, надеюсь, это поможет кому - то-я уверен, что хотел бы наткнуться на это, а не писать его сам :)
Ура!

вы используете обработчик ошибок во время отладки?

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

один из способов сделать это является вызов

   use CGI::Carp qw(fatalsToBrowser);

at в верхней части вашего скрипта. что вызов установить $SIG{__DIE__} обработчик (см. perlvar)отображение фатальных ошибок в вашем браузере, добавив его с допустимым заголовком, Если это необходимо. Еще один трюк отладки CGI, который я использовал, прежде чем я когда-либо слышал о CGI::Carp было используйте eval С DATA и __END__ средства на скрипте, чтобы поймать ошибки времени компиляции:

   #!/usr/bin/perl
   eval join'', <DATA>;
   if ($@) { print "Content-type: text/plain:\n\nError in the script:\n$@\n; }
   __DATA__
   # ... actual CGI script starts here

этот более подробный метод имеет небольшое преимущество перед CGI::Carp в том, что он будет ловить больше ошибок времени компиляции.

обновление: я никогда не использовал его, но это выглядит как CGI::Debug, как Микаэль S предложил, тоже очень полезный и настраиваемый инструмент для этой цели.

для меня, я использую log4perl . Это довольно полезно и легко.

use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init( { level   => $DEBUG, file    => ">>d:\tokyo.log" } );

my $logger = Log::Log4perl::get_logger();

$logger->debug("your log message");

честно говоря, вы можете сделать все самое интересное выше этого поста. Хотя, самое простое и самое активное решение, которое я нашел, было просто "распечатать его".

в Примере: (Обычный код)

`$somecommand`;

чтобы увидеть, если он делает то, что я действительно хочу это сделать: (Неисправностей)

print "$somecommand";

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

Я обычно делаю это, если все остальное терпит неудачу. Я буду SSH на сервер и вручную выполнить скрипт Perl. Например:

% perl myscript.cgi 

Если есть проблема, то Perl расскажет вам об этом. Этот метод отладки устраняет любые проблемы, связанные с правами доступа к файлам или веб проблемы с браузером или веб-сервером.

вы можете запустить perl cgi-скрипт в терминале, используя следующую команду

 $ perl filename.cgi

он интерпретирует код и предоставляет результат с HTML-кодом.он сообщит об ошибке, если таковые имеются.