Как я могу устранить неполадки моего скрипта Perl CGI? - PullRequest
99 голосов
/ 29 января 2010

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


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

Ответы [ 8 ]

125 голосов
/ 29 января 2010

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


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

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

 % perl -w program.pl

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

 use warnings;

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

 use diagnostics;

Сначала вы вывели действительный заголовок CGI?

Сервер ожидает, что первый вывод скрипта CGI будет заголовком CGI. Обычно это может быть просто print "Content-type: text/plain\n\n"; или с CGI.pm и его производными print header(). Некоторые серверы чувствительны к выводу ошибок (на 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, установив $| в истинное значение Обычно вы можете увидеть $|++; в CGI программы. После установки, каждая печать и запись будет немедленно перейти к выводу, а не буферизироваться. Вы должны установить это для каждого дескриптора файла. Используйте select для измените дескриптор файла по умолчанию, например:

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

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

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

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

Сброс или удаление этих переменных

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

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

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

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

use CGI qw(-debug)

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

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

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

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

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

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

Используете ли вы 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] может дать вам свежая перспектива, с которой вам нужно заново подойти к проблеме.

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

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

10 голосов
/ 29 января 2010

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

8 голосов
/ 26 августа 2013

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

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

Здесь я буду работать в /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 $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'

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

http://127.0.0.1:8080/test.pl

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


Теперь, чтобы отладить этот скрипт с помощью RemotePort, сначала нам нужен слушатель в сети, через которую мы будем взаимодействовать с отладчиком Perl;мы можем использовать инструмент командной строки netcat (nc, видел здесь: Perl 如何 удаленная отладка? ).Итак, сначала запустите прослушиватель 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

Thisэто довольно сложная вещь - см. сценарий оболочки - Как я могу использовать переменные окружения в моем 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 находятся в /tmpnc прослушивает отладочные соединения через порт 7234 - так что мы можем наконец открыть другое окно терминала, изменить каталог на /tmp и запустить там однострочный веб-сервер (который будет прослушивать веб-соединения через порт 8080):

cd /tmp
perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) 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 (и Enter) для «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 как исполняемого файла в том же каталог).

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

7 голосов
/ 30 января 2010

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

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

Один из способов сделать это - позвонить

   use CGI::Carp qw(fatalsToBrowser);

вверху вашего скрипта. Этот вызов установит обработчик $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, как у Mikael S предлагается, также является очень полезным и настраиваемым инструментом для этой цели.

5 голосов
/ 20 ноября 2013

Для меня я использую 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");
1 голос
/ 05 февраля 2014

Честно говоря, вы можете сделать все самое интересное над этим постом. Хотя самое простое и упреждающее решение, которое я нашел, было просто «напечатать».

В примере: (Нормальный код)

`$somecommand`;

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

print "$somecommand";
1 голос
/ 18 октября 2013

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

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

% perl myscript.cgi 

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

0 голосов
/ 05 апреля 2016

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

 $ perl filename.cgi

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...