Tengo un script en Perl que no funciona y no sé cómo empezar a reducir el problema. ¿Que puedo hacer?
Nota: Estoy agregando la pregunta porque realmente quiero agregar mi respuesta muy larga a Stackoverflow. Sigo vinculándome externamente en otras respuestas y merece estar aquí. No dude en editar mi respuesta si tiene algo que agregar.
Respuestas:
Esta respuesta está pensada como un marco general para resolver problemas con los scripts CGI de Perl y apareció originalmente en Perlmonks como Troubleshooting Perl CGI Scripts . No es una guía completa de todos los problemas que pueda encontrar, ni un tutorial sobre la eliminación de errores. Es solo la culminación de mi experiencia depurando scripts CGI durante veinte (¡más!) Años. Esta página parece haber tenido muchos hogares diferentes, y parece que me olvido de que existe, así que la estoy agregando a StackOverflow. Puede enviarme cualquier comentario o sugerencia a [email protected]. También es un wiki de la comunidad, pero no te vuelvas loco. :)
¿Está utilizando las funciones integradas de Perl para ayudarlo a encontrar problemas?
Active las advertencias para que Perl le advierta sobre partes cuestionables de su código. Puede hacer esto desde la línea de comando con el
-w
interruptor para que no tenga que cambiar ningún código o agregar un pragma a cada archivo:Sin embargo, debe obligarse a aclarar siempre el código cuestionable agregando el
warnings
pragma a todos sus archivos:Si necesita más información que el breve mensaje de advertencia, use
diagnostics
pragma para obtener más información o busque en la documentación de perldiag :¿Produjo primero un encabezado CGI válido?
El servidor espera que la primera salida de un script CGI sea el encabezado CGI. Típicamente que podría ser tan simple como
print "Content-type: text/plain\n\n";
o con CGI.pm y sus derivados,print header()
. Algunos servidores son sensibles a la salida de error (activadaSTDERR
) que aparece antes que la salida estándar (activadaSTDOUT
).Intente enviar errores al navegador
Agregar esta línea
a tu guión. Esto también envía errores de compilación a la ventana del navegador. Asegúrese de eliminar esto antes de pasar a un entorno de producción, ya que la información adicional puede representar un riesgo para la seguridad.
¿Qué decía el registro de errores?
Los servidores mantienen registros de errores (o deberían, al menos). La salida de error del servidor y de su script debería aparecer allí. Busque el registro de errores y vea lo que dice. No existe un lugar estándar para los archivos de registro. Busque en la configuración del servidor su ubicación o pregunte al administrador del servidor. También puede utilizar herramientas como CGI :: Carp para mantener sus propios archivos de registro.
¿Cuáles son los permisos del script?
Si ve errores como "Permiso denegado" o "Método no implementado", probablemente significa que el usuario del servidor web no puede leer ni ejecutar su script. En las variantes de Unix, se recomienda cambiar el modo a 755:
chmod 755 filename
. ¡Nunca establezca un modo en 777!¿Usted está utilizando
use strict
?Recuerde que Perl crea automáticamente variables cuando las usa por primera vez. Esta es una característica, pero a veces puede causar errores si escribe mal el nombre de una variable. El pragma
use strict
le ayudará a encontrar ese tipo de errores. Es molesto hasta que te acostumbras, pero tu programación mejorará significativamente después de un tiempo y podrás cometer diferentes errores.¿Se compila el script?
Puede comprobar si hay errores de compilación utilizando el
-c
conmutador. Concéntrese en los primeros errores notificados. Enjuague, repita. Si está recibiendo errores realmente extraños, verifique que su script tenga los finales de línea correctos. Si utiliza FTP en modo binario, realiza el pago desde CVS o cualquier otra cosa que no maneja la traducción del final de línea, el servidor web puede ver su script como una línea grande. Transfiera scripts de Perl en modo ASCII.¿El script se queja de dependencias inseguras?
Si su secuencia de comandos se queja de dependencias inseguras, probablemente esté usando el
-T
interruptor para activar el modo de corrupción, lo cual es bueno ya que le mantiene pasando datos no verificados al shell. Si se queja, está haciendo su trabajo para ayudarnos a escribir scripts más seguros. Cualquier dato que se origine fuera del programa (es decir, el medio ambiente) se considera contaminado. Las variables de entorno comoPATH
yLD_LIBRARY_PATH
son particularmente problemáticas. Debe configurarlos en un valor seguro o desarmarlos por completo, como recomiendo. De todos modos, deberías usar rutas absolutas. Si la comprobación de manchas se queja de otra cosa, asegúrese de haber limpiado los datos. Consulte la página del manual de perlsec para obtener más detalles.¿Qué sucede cuando lo ejecuta desde la línea de comandos?
¿El script genera lo que espera cuando se ejecuta desde la línea de comando? ¿La salida del encabezado es primero, seguida de una línea en blanco? Recuerde que
STDERR
puede fusionarse conSTDOUT
si está en una terminal (por ejemplo, una sesión interactiva) y, debido al almacenamiento en búfer, puede aparecer en un orden desordenado. Active la función de descarga automática de Perl estableciendo$|
un valor real. Por lo general, es posible que vea$|++;
en programas CGI. Una vez configuradas, cada impresión y escritura irá inmediatamente a la salida en lugar de almacenarse en búfer. Debe configurar esto para cada identificador de archivo. Úseloselect
para cambiar el identificador de archivo predeterminado, así:De cualquier manera, la primera salida debería ser el encabezado CGI seguido de una línea en blanco.
¿Qué sucede cuando lo ejecuta desde la línea de comandos con un entorno similar a CGI?
El entorno del servidor web suele ser mucho más limitado que el entorno de la línea de comandos y tiene información adicional sobre la solicitud. Si su secuencia de comandos se ejecuta bien desde la línea de comandos, puede intentar simular un entorno de servidor web. Si aparece el problema, tiene un problema medioambiental.
Desarmar o eliminar estas variables
PATH
LD_LIBRARY_PATH
ORACLE_*
variablesEstablecer estas variables
REQUEST_METHOD
(establecido enGET
,HEAD
oPOST
según el caso)SERVER_PORT
(establecido en 80, generalmente)REMOTE_USER
(si está haciendo cosas de acceso protegido)Las versiones recientes de
CGI.pm
(> 2.75) requieren que el-debug
indicador obtenga el comportamiento anterior (útil), por lo que es posible que deba agregarlo a susCGI.pm
importaciones.¿Estás usando
die()
owarn
?Esas funciones se imprimen en a
STDERR
menos que las haya redefinido. Tampoco generan un encabezado CGI. Puede obtener la misma funcionalidad con paquetes como CGI :: Carp¿Qué sucede después de borrar la memoria caché del navegador?
Si cree que su script está haciendo lo correcto y cuando realiza la solicitud manualmente obtiene el resultado correcto, el navegador podría ser el culpable. Borre el caché y establezca el tamaño del caché en cero durante la prueba. Recuerde que algunos navegadores son realmente estúpidos y no volverán a cargar contenido nuevo aunque usted le diga que lo haga. Esto es especialmente frecuente en los casos en que la ruta URL es la misma, pero el contenido cambia (por ejemplo, imágenes dinámicas).
¿Está el guión donde crees que está?
La ruta del sistema de archivos a un script no está necesariamente relacionada directamente con la ruta URL del script. Asegúrese de tener el directorio correcto, incluso si tiene que escribir un breve script de prueba para probarlo. Además, ¿está seguro de que está modificando el archivo correcto? Si no ve ningún efecto con sus cambios, es posible que esté modificando un archivo diferente o cargando un archivo en el lugar equivocado. (Esta es, por cierto, mi causa más frecuente de tal problema;)
¿Está usando
CGI.pm
, o un derivado de él?Si su problema está relacionado con el análisis de la entrada de CGI y no está usando un módulo ampliamente probado como
CGI.pm
,CGI::Request
,CGI::Simple
oCGI::Lite
, utilice el módulo y continuar con su vida.CGI.pm
tiene uncgi-lib.pl
modo de compatibilidad que puede ayudarlo a resolver problemas de entrada debido a implementaciones de analizador CGI más antiguas.¿Usaste caminos absolutos?
Si está ejecutando comandos externos con
system
retrocesos u otras funciones de IPC, debe usar una ruta absoluta al programa externo. No solo sabe exactamente lo que está ejecutando, sino que también evita algunos problemas de seguridad. Si abre archivos para leer o escribir, utilice una ruta absoluta. El script CGI puede tener una idea diferente a la tuya sobre el directorio actual. Alternativamente, puede hacer un explícitochdir()
para ponerlo en el lugar correcto.¿Verificó sus valores devueltos?
La mayoría de las funciones de Perl le dirán si funcionaron o no y se establecerán
$!
en falla. ¿Verificó el valor de retorno y examinó$!
los mensajes de error? ¿Verificó$@
si estaba usandoeval
?¿Qué versión de Perl estás usando?
La última versión estable de Perl es 5.28 (o no, dependiendo de cuándo se editó por última vez). ¿Estás usando una versión anterior? Las diferentes versiones de Perl pueden tener diferentes ideas de advertencias.
¿Qué servidor web estás usando?
Diferentes servidores pueden actuar de manera diferente en la misma situación. El mismo producto de servidor puede actuar de manera diferente con diferentes configuraciones. Incluya tanta información como pueda en cualquier solicitud de ayuda.
¿Verificó la documentación del servidor?
Los programadores serios de CGI deben saber todo lo posible sobre el servidor, incluidas no solo las características y el comportamiento del servidor, sino también la configuración local. Es posible que la documentación de su servidor no esté disponible si está utilizando un producto comercial. De lo contrario, la documentación debería estar en su servidor. Si no es así, búsquelo en la web.
¿Buscaste en los archivos de
comp.infosystems.www.authoring.cgi
?Esto solía ser útil, pero todos los buenos carteles han muerto o se han perdido.
Es probable que alguien haya tenido su problema antes y que alguien (posiblemente yo) lo haya respondido en este grupo de noticias. Aunque este grupo de noticias ha pasado su apogeo, la sabiduría recopilada del pasado a veces puede ser útil.
¿Puede reproducir el problema con un breve script de prueba?
En sistemas grandes, puede ser difícil rastrear un error debido a que están sucediendo muchas cosas. Intente reproducir el comportamiento problemático con el script más corto posible. Conocer el problema es la mayor parte de la solución. Sin duda, esto puede llevar mucho tiempo, pero aún no ha encontrado el problema y se están quedando sin opciones. :)
¿Decidiste ir a ver una película?
Seriamente. A veces podemos estar tan envueltos en el problema que desarrollamos un "estrechamiento perceptivo" (visión de túnel). Tomarte un descanso, tomar una taza de café o criticar a los malos en [Duke Nukem, Quake, Doom, Halo, COD] puede darte la nueva perspectiva de que necesitas para volver a abordar el problema.
¿Ha vocalizado el problema?
En serio otra vez. A veces, explicar el problema en voz alta nos lleva a nuestras propias respuestas. Habla con el pingüino (peluche) porque tus compañeros de trabajo no te escuchan. Si está interesado en esto como una herramienta de depuración seria (y la recomiendo si aún no ha encontrado el problema), también puede leer La psicología de la programación informática .
fuente
$|=1
lugar de$|++
?$|=1
lugar de$|++
? Realmente no hace una diferencia, e incluso entonces,$|
es mágico.use strict
generalmente es bueno usarlo en todo momento, mientras que esfatalsToBrowser
posible que no se recomiende el uso en producción, especialmente si está usandodie
.Creo que CGI :: Debug también vale la pena mencionar.
fuente
die
Se imprimen declaraciones y otros errores fatales en tiempo de ejecución y tiempo de compilaciónSTDERR
, que pueden ser difíciles de encontrar y pueden confundirse con mensajes de otras páginas web de su sitio. Mientras está depurando su script, es una buena idea que los mensajes de error fatales se muestren en su navegador de alguna manera.Una forma de hacer esto es llamar
en la parte superior de su guión. Esa llamada instalará un
$SIG{__DIE__}
controlador (ver perlvar ) que mostrará errores fatales en su navegador, anteponiéndolo con un encabezado válido si es necesario. Otro truco de depuración de CGI que utilicé antes de oír hablarCGI::Carp
fue usareval
las instalacionesDATA
y__END__
en el script para detectar errores en tiempo de compilación:Esta técnica más detallada tiene una ligera ventaja
CGI::Carp
en cuanto a que detectará más errores en tiempo de compilación.Actualización: nunca lo he usado, pero parece que
CGI::Debug
, como sugirió Mikael S, también es una herramienta muy útil y configurable para este propósito.fuente
<DATA>
es un identificador de archivo mágico que lee el script actual comenzando con__END__
. Join le proporciona un contexto de lista, por lo que <fh> devuelve una matriz, una línea por elemento. Luego, unir lo vuelve a unir (uniéndolo con ''). Finalmente, eval.eval join(q{}, <DATA>);
Me pregunto cómo es que nadie mencionó la
PERLDB_OPTS
opción llamadaRemotePort
; aunque es cierto que no hay muchos ejemplos de trabajo en la web (RemotePort
ni siquiera se menciona en perldebug ), y fue un poco problemático para mí encontrar este, pero aquí va (es un ejemplo de Linux).Para hacer un ejemplo adecuado, primero necesitaba algo que pudiera hacer una simulación muy simple de un servidor web CGI, preferiblemente a través de una sola línea de comando. Después de encontrar el servidor web de línea de comandos simple para ejecutar cgis. (perlmonks.org) , encontré que IO :: All - A Tiny Web Server es aplicable para esta prueba.
Aquí, trabajaré en el
/tmp
directorio; será el script CGI/tmp/test.pl
(incluido a continuación). Tenga en cuenta que elIO::All
servidor solo servirá archivos ejecutables en el mismo directorio que CGI, por lo quechmod +x test.pl
se requiere aquí. Entonces, para hacer la ejecución de prueba CGI habitual, cambio el directorio a/tmp
en la terminal y ejecuto el servidor web de una sola línea allí:El comando del servidor web se bloqueará en la terminal y, de lo contrario, iniciará el servidor web localmente (en 127.0.0.1 o
localhost
); luego, puedo ir a un navegador web y solicitar esta dirección:... y yo debería observar las
print
s realizados portest.pl
ser cargado - y se muestra - en el navegador web.Ahora, para depurar este script
RemotePort
, primero necesitamos un oyente en la red, a través del cual interactuaremos con el depurador de Perl; podemos usar la herramienta de línea de comandosnetcat
(nc
, lo vi aquí: Perl 如何 ¿depuración remota? ). Entonces, primero ejecute elnetcat
oyente en una terminal, donde se bloqueará y esperará conexiones en el puerto 7234 (que será nuestro puerto de depuración):Luego, querríamos
perl
comenzar en modo de depuración conRemotePort
, cuandotest.pl
se haya llamado (incluso en modo CGI, a través del servidor). Esto, en Linux, se puede hacer usando el siguiente script "shebang wrapper", que aquí también debe estar incluido/tmp
y debe hacerse ejecutable:Esto es algo complicado - vea el script de shell - ¿Cómo puedo usar variables de entorno en mi shebang? - Stack Exchange de Unix y Linux . Pero, el truco aquí parece ser no bifurcar el
perl
intérprete que manejatest.pl
, así que una vez que lo golpeamos, no lo hacemosexec
, sino que llamamosperl
"llanamente", y básicamente "fuente" nuestrotest.pl
script usandodo
(ver ¿Cómo ejecuto un ¿Secuencia de comandos Perl desde dentro de una secuencia de comandos Perl? ).Ahora que tenemos
perldbgcall.sh
en/tmp
- podemos cambiar eltest.pl
archivo, para que se refiera a este archivo ejecutable en su línea shebang (en lugar del intérprete de Perl habitual) - aquí se/tmp/test.pl
modifica así:Ahora, ambos
test.pl
y su nuevo manejador de shebangperldbgcall.sh
, están en/tmp
; y hemosnc
escuchado conexiones de depuración en el puerto 7234, por lo que finalmente podemos abrir otra ventana de terminal, cambiar el directorio/tmp
y ejecutar el servidor web de una sola línea (que escuchará las conexiones web en el puerto 8080) allí:Una vez hecho esto, podemos ir a nuestro navegador web, y solicitar la misma dirección,
http://127.0.0.1:8080/test.pl
. Sin embargo, ahora, cuando el servidor web intente ejecutar el script, lo hará a través deperldbgcall.sh
shebang, que se iniciaráperl
en modo depurador remoto. Por lo tanto, la ejecución del script se detendrá y el navegador web se bloqueará, esperando los datos. Ahora podemos cambiar a lanetcat
terminal, y deberíamos ver el texto familiar del depurador de Perl; sin embargo, la salida es a través denc
:Como muestra el fragmento, ahora básicamente lo usamos
nc
como un "terminal", por lo que podemos escribirr
(y Enter) para "ejecutar", y el script se ejecutará para hacer la declaración de punto de interrupción (consulte también En perl, ¿cuál es la diferencia entre $ DB :: single = 1 y 2? ), Antes de detenerse nuevamente (tenga en cuenta que en ese punto, el navegador aún se bloqueará).Entonces, ahora podemos, digamos, recorrer el resto de
test.pl
, a través de lanc
terminal:... sin embargo, también en este punto, el navegador se bloquea y espera los datos. Solo después de que salgamos del depurador con
q
:... el navegador deja de bloquearse y finalmente muestra el resultado (completo) de
test.pl
:Por supuesto, este tipo de depuración se puede realizar incluso sin ejecutar el servidor web; sin embargo, lo bueno aquí es que no tocamos el servidor web en absoluto; activamos la ejecución "de forma nativa" (para CGI) desde un navegador web, y el único cambio necesario en el propio script CGI es el cambio de shebang (y, por supuesto, la presencia del script de envoltura shebang, como archivo ejecutable en el mismo directorio).
Bueno, espero que esto ayude a alguien. Seguro que me hubiera encantado encontrarme con esto, en lugar de escribirlo yo mismo
:)
. ¡Salud!
fuente
Para mí, uso log4perl . Es bastante útil y fácil.
fuente
Honestamente, puedes hacer todas las cosas divertidas que aparecen en esta publicación. AUNQUE, la solución más simple y proactiva que encontré fue simplemente "imprimirlo".
En ejemplo: (código normal)
Para ver si está haciendo lo que realmente quiero que haga: (Solución de problemas)
fuente
Probablemente también valdrá la pena mencionar que Perl siempre le dirá en qué línea ocurre el error cuando ejecuta el script Perl desde la línea de comandos. (Una sesión SSH, por ejemplo)
Normalmente haré esto si todo lo demás falla. Conectaré SSH al servidor y ejecutaré manualmente el script Perl. Por ejemplo:
Si hay un problema, Perl se lo informará. Este método de depuración elimina cualquier problema relacionado con permisos de archivo o problemas con el navegador web o el servidor web.
fuente
Puede ejecutar el script perl cgi en la terminal usando el siguiente comando
Interpreta el código y proporciona el resultado con código HTML. Informará el error si lo hubiera.
fuente
perl -c filename
hecho, la invocación solo comprobará la sintaxis. Peroperl filename
imprime la salida HTML. Sin embargo, no es garantía de que no haya un error de 500 CGI, pero es una buena primera prueba.