Как я могу устранить неполадки моего скрипта Perl CGI?
У меня есть скрипт Perl, который не работает, и я не знаю, как начать сужать проблему. Что я могу сделать?
Примечание: я добавляю вопрос, потому что я действительно хочу добавить мой очень длинный ответ на Stackoverflow. Я продолжаю внешне связываться с ним в других ответах, и он заслуживает того, чтобы быть здесь. Не стесняйтесь редактировать мой ответ, если у вас есть что добавить.
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()
. Некоторые серверы чувствительны к выводу ошибок (onSTDERR
) появляется перед стандартным выходом (на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
... и я должен наблюдать за
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 расскажет вам об этом. Этот метод отладки устраняет любые проблемы, связанные с правами доступа к файлам или веб проблемы с браузером или веб-сервером.