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

91

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


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

  • 5
    @Evan - моя точка просто , что даже не-CW это все еще редактируемые - если у вас есть достаточное количество кармы; 100 для CW, 2k в противном случае. Так что теперь у вас есть 2060, вы должны иметь возможность редактировать посты не-CW.
  • 1
    @Evan, магические точки перечислены во всплывающих подсказках в правом столбце здесь: stackoverflow.com/privileges
Показать ещё 1 комментарий
Теги:
cgi

8 ответов

124
Лучший ответ

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


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

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

 % perl -w program.pl

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

 use warnings;

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

 use diagnostics;

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

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

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

Добавьте строку

 use CGI::Carp 'fatalsToBrowser';

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

Что сказал журнал ошибок?

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

Какие существуют разрешения script?

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

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

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

Скомпилирован ли script?

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

Является ли script жалобой на небезопасные зависимости?

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

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

Выводит ли script то, что вы ожидаете при запуске с командная строка? Сначала вывод заголовка, за которым следует пустая строка? Помните, что 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-подобной среды?

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

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

  • 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

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

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

Является ли script, где вы думаете?

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

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

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

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

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

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

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

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

Последняя стабильная версия Perl - 5.16.2. Используете ли вы более старую версия? Различные версии Perl могут иметь разные представления о предупреждениях.

Какой веб-сервер вы используете?

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

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

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

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

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

Можете ли вы воспроизвести проблему с коротким тестом script?

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

Вы решили пойти посмотреть фильм?

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

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

Серьезно снова. Иногда объясняя проблему вслух приводит нас к собственным ответам. Поговорите с пингвином (плюшевая игрушка), потому что ваши сотрудники не слушают. Если вас это интересует как серьезный инструмент отладки (и я рекомендую его, если у вас нет нашел проблему до сих пор), вам также может понравиться читать Психология компьютерного программирования.
  • 4
    Не стесняйтесь редактировать мой ответ, если вам есть, что добавить.
  • 0
    Похоже, вы хотите удалить ссылку на CGI meta FAQ. 5.12.1 считается "стабильным"?
Показать ещё 5 комментариев
10

Думаю, CGI::Debug.

  • 0
    Это сообщество вики, так что вики нету :)
  • 0
    К сожалению, я могу редактировать только вопрос, а не ответы.
7

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

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

Здесь я буду работать в каталоге /tmp; CGI script будет /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 \/(.*) / })'

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

http://127.0.0.1:8080/test.pl

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


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

$ nc -l 7234

Затем мы хотим, чтобы perl запускался в режиме отладки с помощью RemotePort, когда был вызван test.pl (даже в режиме CGI, через сервер). Это можно сделать в Linux, используя следующую "shebang wrapper" script, которая здесь также должна быть в /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 "явно" и в основном "source <наш > test.pl script с помощью do (см. Как запустить Perl script из Perl script?).

Теперь, когда мы имеем 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 и его новый обработчик shebang perldbgcall.sh находятся в /tmp; и у нас есть nc прослушивание отладочных подключений на порту 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. Однако теперь, когда веб-сервер пытается выполнить script, он сделает это через perldbgcall.sh shebang - который запустит perl в режиме удаленного отладчика. Таким образом, выполнение script приостанавливается - и поэтому веб-браузер блокируется, ожидая данных. Теперь мы можем переключиться на терминал 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" - и script запустится оператор breakpoint ( см. также В 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 script, является изменение shebang (и, конечно же, наличие оболочки shebang script в качестве исполняемого файла файл в том же каталоге).

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

7

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

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

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

   use CGI::Carp qw(fatalsToBrowser);

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

   #!/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 предлагается, также очень полезный и настраиваемый инструмент для этой цели.

  • 1
    Я смотрю на этот фрагмент кода, пытаясь выяснить, как он работает ...
  • 3
    @Ether: <DATA> - это магический файловый дескриптор, который читает текущий скрипт, начиная с __END__ . Join предоставляет ему контекст списка, поэтому <fh> возвращает массив, по одной строке на элемент. Затем join соединяет его вместе (соединяя с помощью ''). Наконец, Eval.
Показать ещё 4 комментария
4

Для меня я использую 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

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

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

`$somecommand`;

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

print "$somecommand";
1

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

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

% perl myscript.cgi 

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

  • 0
    Perl не всегда сообщает вам номер строки, где происходит ошибка. Он говорит вам номер строки, где он понимает, что что-то не так. Вероятно, ошибка уже произошла.
0

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

 $ perl filename.cgi

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

  • 1
    Извините, команда $ perl -c filename.cgi проверяет синтаксис кода и сообщает об ошибке, если таковая имеется. Он не будет предоставлять HTML-код CGI.
  • 0
    Вызов perl -c filename действительно проверяет только синтаксис. Но perl filename выводит вывод HTML. Хотя нет гарантии, что не будет ошибки 500 CGI, но это хороший первый тест.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню