Eu tenho um script Perl que não está funcionando e não sei como começar a restringir o problema. O que eu posso fazer?
Observação: estou adicionando a pergunta porque realmente quero adicionar minha resposta muito longa ao Stackoverflow. Continuo ligando externamente para ele em outras respostas e ele merece estar aqui. Não tenha vergonha de editar minha resposta se você tiver algo a acrescentar.
Respostas:
Esta resposta pretende ser uma estrutura geral para resolver problemas com scripts Perl CGI e apareceu originalmente no Perlmonks como Troubleshooting Perl CGI Scripts . Não é um guia completo para todos os problemas que você pode encontrar, nem um tutorial sobre como eliminar bugs. É apenas o culminar da minha experiência depurando scripts CGI por vinte (mais!) Anos. Esta página parece ter muitas casas diferentes e parece que esqueci que ela existe, então estou adicionando-a ao StackOverflow. Você pode enviar qualquer comentário ou sugestão para mim em [email protected]. Também é wiki da comunidade, mas não enlouqueça. :)
Você está usando os recursos integrados do Perl para ajudá-lo a encontrar problemas?
Ative os avisos para permitir que o Perl o avise sobre partes questionáveis do seu código. Você pode fazer isso a partir da linha de comando com a
-w
opção para que não precise alterar nenhum código ou adicionar um pragma a cada arquivo:No entanto, você deve se forçar a sempre esclarecer o código questionável, adicionando o
warnings
pragma a todos os seus arquivos:Se precisar de mais informações do que a curta mensagem de aviso, use o
diagnostics
pragma para obter mais informações ou consulte a documentação do perldiag :Você gerou um cabeçalho CGI válido primeiro?
O servidor espera que a primeira saída de um script CGI seja o cabeçalho CGI. Normalmente, isso pode ser tão simples quanto
print "Content-type: text/plain\n\n";
ou com CGI.pm e seus derivadosprint header()
,. Alguns servidores são sensíveis à saída de erro (ativadaSTDERR
) exibida antes da saída padrão (ativadaSTDOUT
).Tente enviar erros para o navegador
Adicione esta linha
ao seu script. Isso também envia erros de compilação para a janela do navegador. Certifique-se de removê-lo antes de mudar para um ambiente de produção, pois as informações extras podem representar um risco à segurança.
O que o log de erros diz?
Os servidores mantêm logs de erros (ou deveriam, pelo menos). A saída de erro do servidor e do seu script deve aparecer lá. Encontre o log de erros e veja o que ele diz. Não existe um local padrão para arquivos de log. Procure sua localização na configuração do servidor ou pergunte ao administrador do servidor. Você também pode usar ferramentas como CGI :: Carp para manter seus próprios arquivos de log.
Quais são as permissões do script?
Se você vir erros como "Permissão negada" ou "Método não implementado", provavelmente significa que seu script não pode ser lido e executado pelo usuário do servidor da web. Em sabores de Unix, é recomendado alterar o modo para 755:
chmod 755 filename
. Nunca defina um modo para 777!Você está usando
use strict
?Lembre-se de que Perl cria variáveis automaticamente quando você as usa pela primeira vez. Este é um recurso, mas às vezes pode causar erros se você digitar incorretamente o nome de uma variável. O pragma
use strict
o ajudará a encontrar esses tipos de erros. É irritante até você se acostumar, mas sua programação irá melhorar significativamente depois de um tempo e você estará livre para cometer diversos erros.O script compila?
Você pode verificar se há erros de compilação usando a
-c
opção. Concentre-se nos primeiros erros relatados. Enxágüe, repita. Se você estiver recebendo erros realmente estranhos, verifique se o seu script tem os finais de linha corretos. Se você FTP em modo binário, check-out do CVS ou qualquer outra coisa que não lide com tradução de fim de linha, o servidor da web pode ver seu script como uma grande linha. Transfira scripts Perl no modo ASCII.O script está reclamando de dependências inseguras?
Se o seu script reclamar de dependências inseguras, provavelmente você está usando a
-T
opção para ativar o modo contaminado, o que é uma coisa boa, pois mantém você passando dados não verificados para o shell. Se estiver reclamando, está fazendo seu trabalho para nos ajudar a escrever scripts mais seguros. Quaisquer dados provenientes de fora do programa (ou seja, o meio ambiente) são considerados contaminados. Variáveis de ambiente comoPATH
eLD_LIBRARY_PATH
são particularmente problemáticas. Você deve defini-los com um valor seguro ou removê-los completamente, como eu recomendo. Você deve usar caminhos absolutos de qualquer maneira. Se a verificação de contaminação reclamar de outra coisa, certifique-se de que os dados não foram corrompidos. Veja a página de manual do perlsec para detalhes.O que acontece quando você o executa a partir da linha de comando?
O script produz o que você espera ao ser executado na linha de comando? A saída do cabeçalho é primeiro, seguida por uma linha em branco? Lembre-se de que
STDERR
pode ser mesclado comSTDOUT
se você estiver em um terminal (por exemplo, uma sessão interativa) e, devido ao buffering, pode aparecer em uma ordem confusa. Ative o recurso autoflush do Perl definindo$|
um valor verdadeiro. Normalmente você pode ver$|++;
em programas CGI. Depois de definidas, todas as impressões e gravações irão imediatamente para a saída em vez de serem armazenadas em buffer. Você tem que definir isso para cada filehandle. Useselect
para alterar o manipulador de arquivos padrão, como:De qualquer forma, a primeira saída deve ser o cabeçalho CGI seguido por uma linha em branco.
O que acontece quando você o executa a partir da linha de comando com um ambiente semelhante a CGI?
O ambiente do servidor da web é geralmente muito mais limitado do que o ambiente da linha de comando e possui informações extras sobre a solicitação. Se o seu script funcionar bem na linha de comando, você pode tentar simular um ambiente de servidor da web. Se o problema aparecer, você tem um problema de ambiente.
Cancele ou remova essas variáveis
PATH
LD_LIBRARY_PATH
ORACLE_*
variáveisDefina essas variáveis
REQUEST_METHOD
(definida comoGET
,HEAD
ouPOST
como apropriado)SERVER_PORT
(definido para 80, normalmente)REMOTE_USER
(se você estiver fazendo coisas de acesso protegido)Versões recentes de
CGI.pm
(> 2.75) requerem o-debug
sinalizador para obter o comportamento antigo (útil), portanto, pode ser necessário adicioná-lo às suasCGI.pm
importações.Você está usando
die()
ouwarn
?Essas funções são impressas, a
STDERR
menos que você as tenha redefinido. Eles também não geram um cabeçalho CGI. Você pode obter a mesma funcionalidade com pacotes como CGI :: CarpO que acontece depois que você limpa o cache do navegador?
Se você acha que seu script está fazendo a coisa certa e, ao executar a solicitação manualmente, obtém a saída correta, o navegador pode ser o culpado. Limpe o cache e defina o tamanho do cache para zero durante o teste. Lembre-se de que alguns navegadores são realmente estúpidos e não recarregam conteúdo novo, mesmo que você diga para fazer isso. Isso é especialmente prevalente nos casos em que o caminho da URL é o mesmo, mas o conteúdo muda (por exemplo, imagens dinâmicas).
O script está onde você pensa que está?
O caminho do sistema de arquivos para um script não está necessariamente relacionado ao caminho da URL para o script. Certifique-se de ter o diretório correto, mesmo se você tiver que escrever um pequeno script de teste para testar isso. Além disso, tem certeza de que está modificando o arquivo correto? Se você não notar nenhum efeito nas alterações, pode estar modificando um arquivo diferente ou enviando um arquivo para o local errado. (Esta é, a propósito, minha causa mais frequente de tais problemas;)
Você está usando
CGI.pm
, ou um derivado dele?Se o seu problema está relacionado a analisar a entrada CGI e você não estiver usando um módulo amplamente testado como
CGI.pm
,CGI::Request
,CGI::Simple
ouCGI::Lite
, utilize o módulo e seguir com a vida.CGI.pm
tem umcgi-lib.pl
modo de compatibilidade que pode ajudá-lo a resolver problemas de entrada devido a implementações de analisador CGI mais antigas.Você usou caminhos absolutos?
Se você estiver executando comandos externos com
system
, back ticks ou outros recursos IPC, você deve usar um caminho absoluto para o programa externo. Você não apenas sabe exatamente o que está executando, mas também evita alguns problemas de segurança. Se você estiver abrindo arquivos para leitura ou gravação, use um caminho absoluto. O script CGI pode ter uma ideia diferente sobre o diretório atual da sua. Alternativamente, você pode fazer um explícitochdir()
para colocá-lo no lugar certo.Você verificou seus valores de retorno?
A maioria das funções Perl dirá se elas funcionaram ou não e serão configuradas
$!
em caso de falha. Você verificou o valor de retorno e examinou as$!
mensagens de erro? Você verificou$@
se estava usandoeval
?Qual versão do Perl você está usando?
A última versão estável do Perl é 5.28 (ou não, dependendo de quando foi editado pela última vez). Você está usando uma versão mais antiga? Versões diferentes do Perl podem ter idéias diferentes de avisos.
Qual servidor web você está usando?
Servidores diferentes podem agir de maneira diferente na mesma situação. O mesmo produto de servidor pode agir de maneira diferente com configurações diferentes. Inclua o máximo dessas informações que puder em qualquer pedido de ajuda.
Você verificou a documentação do servidor?
Os programadores CGI sérios devem saber o máximo possível sobre o servidor - incluindo não apenas os recursos e o comportamento do servidor, mas também a configuração local. A documentação do seu servidor pode não estar disponível se você estiver usando um produto comercial. Caso contrário, a documentação deve estar em seu servidor. Se não for, procure na web.
Você pesquisou os arquivos de
comp.infosystems.www.authoring.cgi
?Este uso é útil, mas todos os bons cartazes morreram ou se perderam.
É provável que alguém já tenha tido o seu problema antes e que alguém (possivelmente eu) o tenha respondido neste newsgroup. Embora este newsgroup tenha passado do seu apogeu, a sabedoria coletada no passado às vezes pode ser útil.
Você pode reproduzir o problema com um pequeno script de teste?
Em sistemas grandes, pode ser difícil rastrear um bug, pois muitas coisas estão acontecendo. Tente reproduzir o comportamento do problema com o script mais curto possível. Saber o problema é a maior parte da correção. Certamente, isso pode ser demorado, mas você ainda não encontrou o problema e está ficando sem opções. :)
Você decidiu ir ver um filme?
Seriamente. Às vezes, podemos ficar tão envolvidos com o problema que desenvolvemos um "estreitamento perceptivo" (visão de túnel). Fazer uma pausa, tomar uma xícara de café ou atacar alguns bandidos em [Duke Nukem, Quake, Doom, Halo, COD] pode lhe dar uma nova perspectiva de que você precisa para abordar novamente o problema.
Você vocalizou o problema?
Sério de novo. Às vezes, explicar o problema em voz alta nos leva às nossas próprias respostas. Fale com o pinguim (brinquedo de pelúcia) porque seus colegas de trabalho não estão ouvindo. Se você estiver interessado nisso como uma ferramenta de depuração séria (e eu a recomendo, se você ainda não encontrou o problema), você também pode ler The Psychology of Computer Programming .
fonte
$|=1
vez de$|++
?$|=1
vez de$|++
? Realmente não faz diferença e, mesmo assim,$|
é mágico.use strict
geralmente é bom usar sempre, enquanto o usofatalsToBrowser
pode não ser aconselhado na produção, especialmente se você estiver usandodie
.Acho que CGI :: Debug também vale a pena mencionar.
fonte
die
declarações e outros erros fatais de tempo de execução e de compilação são impressosSTDERR
, o que pode ser difícil de encontrar e pode ser confundido com mensagens de outras páginas da web em seu site. Enquanto você estiver depurando seu script, é uma boa ideia fazer com que as mensagens de erro fatais sejam exibidas em seu navegador de alguma forma.Uma maneira de fazer isso é ligar
no topo do seu script. Essa chamada instalará um
$SIG{__DIE__}
manipulador (consulte perlvar ) para exibir erros fatais em seu navegador, acrescentando um cabeçalho válido se necessário. Outro truque de depuração CGI que usei antes de ouvir falarCGI::Carp
era usareval
com os recursosDATA
e__END__
no script para detectar erros em tempo de compilação:Essa técnica mais detalhada tem uma pequena vantagem,
CGI::Carp
pois captura mais erros de tempo de compilação.Update: Nunca usei, mas parece que
CGI::Debug
, como sugeriu Mikael S, também é uma ferramenta muito útil e configurável para esse fim.fonte
<DATA>
é um identificador de arquivo mágico que lê o script atual começando com__END__
. Join está fornecendo um contexto de lista, então <fh> retorna uma matriz, uma linha por item. Em seguida, o join o reúne (unindo-o com ''). Finalmente, eval.eval join(q{}, <DATA>);
Eu me pergunto como ninguém mencionou a
PERLDB_OPTS
opção chamadaRemotePort
; embora reconheço que não há muitos exemplos de trabalho na web (RemotePort
nem mesmo é mencionado em perldebug ) - e foi meio problemático para mim inventar este, mas aqui vai (sendo um exemplo do Linux).Para fazer um exemplo adequado, primeiro eu precisava de algo que pudesse fazer uma simulação muito simples de um servidor web CGI, de preferência por meio de uma única linha de comando. Depois de encontrar o servidor da web de linha de comando simples para executar cgis. (perlmonks.org) , descobri que o IO :: All - A Tiny Web Server é aplicável para este teste.
Aqui, vou trabalhar no
/tmp
diretório; o script CGI será/tmp/test.pl
(incluído abaixo). Observe que oIO::All
servidor servirá apenas arquivos executáveis no mesmo diretório do CGI, portanto,chmod +x test.pl
é necessário aqui. Portanto, para fazer o teste CGI normal, mudo o diretório para/tmp
no terminal e executo o servidor da Web de uma linha lá:O comando do servidor da web será bloqueado no terminal e, caso contrário, iniciará o servidor da web localmente (em 127.0.0.1 ou
localhost
) - depois, posso ir para um navegador da web e solicitar este endereço:... e devo observar o
print
s feito aotest.pl
ser carregado - e mostrado - no navegador da web.Agora, para depurar esse script
RemotePort
, primeiro precisamos de um listener na rede, por meio do qual interagiremos com o depurador Perl; podemos usar a ferramenta de linha de comandonetcat
(nc
, viu isso aqui: Perl 如何 remote debug? ). Portanto, primeiro execute onetcat
listener em um terminal - onde bloqueará e aguardará as conexões na porta 7234 (que será nossa porta de depuração):Então, queremos
perl
começar no modo de depuração comRemotePort
, quando otest.pl
for chamado (mesmo no modo CGI, através do servidor). Isso, no Linux, pode ser feito usando o seguinte script "shebang wrapper" - que aqui também precisa estar em/tmp
e deve ser tornado executável:Isso é uma coisa meio complicada - veja o script de shell - Como posso usar variáveis de ambiente no meu shebang? - Unix e Linux Stack Exchange . Mas, o truque aqui parece ser não bifurcar o
perl
interpretador que manipulatest.pl
- então, uma vez que o acertamos, não o fazemosexec
, mas em vez disso, chamamosperl
"claramente" e basicamente "fornecemos" nossotest.pl
script usandodo
(consulte Como faço para executar um Script Perl de dentro de um script Perl? ).Agora que temos
perldbgcall.sh
em/tmp
- nós podemos mudar otest.pl
arquivo, para que se refere a este arquivo executável em sua linha de shebang (em vez do intérprete habitual Perl) - aqui é/tmp/test.pl
modificado assim:Agora, ambos
test.pl
e seu novo manipulador shebang,,perldbgcall.sh
estão na/tmp
; e temos anc
escuta de conexões de depuração na porta 7234 - para que possamos finalmente abrir outra janela de terminal, alterar o diretório/tmp
e executar o servidor da web one-liner (que escutará as conexões da web na porta 8080) lá:Feito isso, podemos ir ao nosso navegador e solicitar o mesmo endereço
http://127.0.0.1:8080/test.pl
,. No entanto, agora, quando o servidor da web tentar executar o script, ele o fará por meio doperldbgcall.sh
shebang - que iniciaráperl
no modo de depuração remota. Assim, a execução do script será pausada - e o navegador da web travará, aguardando os dados. Agora podemos mudar para onetcat
terminal e devemos ver o conhecido texto do depurador Perl - no entanto, a saída através denc
:Como mostra o snippet, agora usamos basicamente
nc
como um "terminal" - para que possamos digitarr
(e Enter) para "executar" - e o script executará a instrução do ponto de interrupção (consulte também Em perl, qual é a diferença entre $ DB :: single = 1 e 2? ), Antes de parar novamente (observe que nesse ponto o navegador ainda travará).Então, agora nós podemos, dizer, passo pelo resto do
test.pl
, através donc
terminal:... entretanto, também neste ponto, o navegador bloqueia e espera pelos dados. Somente depois de sairmos do depurador com
q
:... o navegador para de bloquear - e finalmente exibe a saída (completa) de
test.pl
:Claro, esse tipo de depuração pode ser feito mesmo sem executar o servidor web - no entanto, o legal aqui, é que não tocamos no servidor web; disparamos a execução "nativamente" (para CGI) a partir de um navegador da web - e a única mudança necessária no próprio script CGI é a mudança de shebang (e, claro, a presença do script shebang wrapper, como arquivo executável no mesmo diretório).
Bem, espero que isso ajude alguém - eu certamente adoraria ter tropeçado nisso, em vez de escrever eu mesmo
:)
. Cheers!
fonte
Para mim, eu uso log4perl . É muito útil e fácil.
fonte
Honestamente, você pode fazer todas as coisas divertidas acima deste post. EMBORA, a solução mais simples e proativa que encontrei foi apenas "imprimir".
Por exemplo: (código normal)
Para ver se ele está fazendo o que eu realmente quero: (Resolução de problemas)
fonte
Provavelmente também valerá a pena mencionar que o Perl sempre dirá em qual linha o erro ocorre quando você executa o script Perl na linha de comando. (Uma sessão SSH, por exemplo)
Normalmente farei isso se tudo mais falhar. Vou usar o SSH no servidor e executar manualmente o script Perl. Por exemplo:
Se houver um problema, Perl irá informá-lo sobre ele. Este método de depuração elimina qualquer problema relacionado à permissão de arquivo ou navegador da web ou servidor da web.
fonte
Você pode executar o perl cgi-script no terminal usando o comando abaixo
Ele interpreta o código e fornece o resultado com o código HTML. Ele relatará o erro se houver.
fonte
perl -c filename
irá de fato verificar apenas a sintaxe. Masperl filename
imprime a saída HTML. Não há garantia de que não haverá um erro de 500 CGI, mas é um bom primeiro teste.