J'ai un script Perl qui ne fonctionne pas et je ne sais pas comment commencer à réduire le problème. Que puis-je faire?
Remarque: j'ajoute la question parce que je veux vraiment ajouter ma très longue réponse à Stackoverflow. Je continue à faire des liens externes avec cela dans d'autres réponses et cela mérite d'être ici. N'hésitez pas à modifier ma réponse si vous avez quelque chose à ajouter.
Réponses:
Cette réponse est conçue comme un cadre général pour résoudre les problèmes avec les scripts Perl CGI et est apparue à l'origine sur Perlmonks en tant que Dépannage des scripts Perl CGI . Ce n'est pas un guide complet de tous les problèmes que vous pourriez rencontrer, ni un tutoriel sur la correction des bogues. C'est juste le point culminant de mon expérience de débogage de scripts CGI pendant vingt (plus!) Ans. Cette page semble avoir eu de nombreuses maisons différentes, et je semble oublier qu'elle existe, donc je l'ajoute à StackOverflow. Vous pouvez m'envoyer vos commentaires ou suggestions à [email protected]. C'est aussi un wiki communautaire, mais ne devenez pas trop fou. :)
Utilisez-vous les fonctionnalités intégrées de Perl pour vous aider à trouver des problèmes?
Activez les avertissements pour laisser Perl vous avertir des parties douteuses de votre code. Vous pouvez le faire à partir de la ligne de commande avec le
-w
commutateur afin de ne pas avoir à changer de code ou à ajouter un pragma à chaque fichier:Cependant, vous devez vous forcer à toujours effacer le code douteux en ajoutant le
warnings
pragma à tous vos fichiers:Si vous avez besoin de plus d'informations que le court message d'avertissement, utilisez le
diagnostics
pragma pour obtenir plus d'informations, ou consultez la documentation de perldiag :Avez-vous d'abord sorti un en-tête CGI valide?
Le serveur s'attend à ce que la première sortie d'un script CGI soit l'en-tête CGI. En règle générale qui pourrait être aussi simple que
print "Content-type: text/plain\n\n";
ou avec CGI.pm et ses dérivés,print header()
. Certains serveurs sont sensibles à la sortie d'erreur (surSTDERR
) apparaissant avant la sortie standard (activéeSTDOUT
).Essayez d'envoyer des erreurs au navigateur
Ajouter cette ligne
à votre script. Cela envoie également des erreurs de compilation à la fenêtre du navigateur. Veillez à le supprimer avant de passer à un environnement de production, car les informations supplémentaires peuvent constituer un risque pour la sécurité.
Que dit le journal des erreurs?
Les serveurs conservent des journaux d'erreurs (ou ils devraient, au moins). La sortie d'erreur du serveur et de votre script devrait apparaître là-haut. Trouvez le journal des erreurs et voyez ce qu'il dit. Il n'y a pas d'espace standard pour les fichiers journaux. Recherchez leur emplacement dans la configuration du serveur ou demandez à l'administrateur du serveur. Vous pouvez également utiliser des outils tels que CGI :: Carp pour conserver vos propres fichiers journaux.
Quelles sont les autorisations du script?
Si vous voyez des erreurs telles que «Autorisation refusée» ou «Méthode non implémentée», cela signifie probablement que votre script n'est pas lisible et exécutable par l'utilisateur du serveur Web. Sur les versions d'Unix, en changeant le mode 755 est recommandé:
chmod 755 filename
. Ne définissez jamais un mode sur 777!Utilisez-vous
use strict
?N'oubliez pas que Perl crée automatiquement des variables lorsque vous les utilisez pour la première fois. Ceci est une fonctionnalité, mais peut parfois causer des bogues si vous saisissez mal un nom de variable. Le pragma
use strict
vous aidera à trouver ce genre d'erreurs. C'est ennuyeux jusqu'à ce que vous vous y habituiez, mais votre programmation s'améliorera considérablement après un certain temps et vous serez libre de faire différentes erreurs.Le script se compile-t-il?
Vous pouvez vérifier les erreurs de compilation en utilisant le
-c
commutateur. Concentrez-vous sur les premières erreurs signalées. Rincez, répétez. Si vous rencontrez des erreurs vraiment étranges, vérifiez que votre script a les bonnes fins de ligne. Si vous effectuez un FTP en mode binaire, une extraction depuis CVS ou quelque chose d'autre qui ne gère pas la traduction de fin de ligne, le serveur Web peut voir votre script comme une seule grande ligne. Transférez les scripts Perl en mode ASCII.Le script se plaint-il de dépendances non sécurisées?
Si votre script se plaint de dépendances non sécurisées, vous utilisez probablement le
-T
commutateur pour activer le mode taint, ce qui est une bonne chose car il vous permet de continuer à transmettre des données non vérifiées au shell. S'il se plaint, il fait son travail pour nous aider à écrire des scripts plus sécurisés. Toute donnée provenant de l'extérieur du programme (c'est-à-dire de l'environnement) est considérée comme corrompue. Les variables d'environnement telles quePATH
etLD_LIBRARY_PATH
sont particulièrement gênantes. Vous devez les définir sur une valeur sûre ou les désactiver complètement, comme je le recommande. Vous devriez de toute façon utiliser des chemins absolus. Si la vérification de l'altération se plaint d'autre chose, assurez-vous que vous n'avez pas altéré les données. Voir la page de manuel de perlsec pour plus de détails.Que se passe-t-il lorsque vous l'exécutez à partir de la ligne de commande?
Le script produit-il ce que vous attendez lorsqu'il est exécuté à partir de la ligne de commande? L'en-tête est-il sorti en premier, suivi d'une ligne vide? N'oubliez pas que cela
STDERR
peut être fusionné avecSTDOUT
si vous êtes sur un terminal (par exemple, une session interactive), et qu'en raison de la mise en mémoire tampon, cela peut apparaître dans un ordre confus. Activez la fonction autoflush de Perl en définissant$|
une valeur vraie. En règle générale, vous pouvez voir$|++;
dans les programmes CGI. Une fois définies, chaque impression et écriture ira immédiatement à la sortie plutôt que d'être mise en mémoire tampon. Vous devez définir ceci pour chaque descripteur de fichier. Utilisezselect
pour changer le descripteur de fichier par défaut, comme ceci:Dans tous les cas, la première sortie doit être l'en-tête CGI suivi d'une ligne vide.
Que se passe-t-il lorsque vous l'exécutez à partir de la ligne de commande avec un environnement de type CGI?
L'environnement du serveur Web est généralement beaucoup plus limité que votre environnement de ligne de commande et contient des informations supplémentaires sur la demande. Si votre script s'exécute correctement à partir de la ligne de commande, vous pouvez essayer de simuler un environnement de serveur Web. Si le problème apparaît, vous avez un problème d'environnement.
Annuler ou supprimer ces variables
PATH
LD_LIBRARY_PATH
ORACLE_*
variablesDéfinissez ces variables
REQUEST_METHOD
(fixé àGET
,HEAD
ouPOST
selon le cas)SERVER_PORT
(défini sur 80, généralement)REMOTE_USER
(si vous faites des choses à accès protégé)Les versions récentes de
CGI.pm
(> 2.75) nécessitent l'-debug
indicateur pour obtenir l'ancien comportement (utile), vous devrez donc peut-être l'ajouter à vosCGI.pm
importations.Utilisez-vous
die()
ouwarn
?Ces fonctions s'impriment
STDERR
sauf si vous les avez redéfinies. Ils ne produisent pas non plus d'en-tête CGI. Vous pouvez obtenir la même fonctionnalité avec des packages tels que CGI :: CarpQue se passe-t-il après avoir vidé le cache du navigateur?
Si vous pensez que votre script fait la bonne chose et que lorsque vous exécutez la requête manuellement, vous obtenez le bon résultat, le navigateur peut être le coupable. Videz le cache et définissez la taille du cache sur zéro pendant le test. N'oubliez pas que certains navigateurs sont vraiment stupides et ne rechargeront pas réellement le nouveau contenu même si vous leur dites de le faire. Ceci est particulièrement répandu dans les cas où le chemin de l'URL est le même, mais le contenu change (par exemple les images dynamiques).
Le script est-il là où vous pensez qu'il se trouve?
Le chemin du système de fichiers vers un script n'est pas nécessairement directement lié au chemin de l'URL du script. Assurez-vous d'avoir le bon répertoire, même si vous devez écrire un court script de test pour le tester. De plus, êtes-vous sûr de modifier le bon fichier? Si vous ne voyez aucun effet avec vos modifications, vous êtes peut-être en train de modifier un autre fichier ou de télécharger un fichier au mauvais endroit. (C'est d'ailleurs ma cause la plus fréquente de tels problèmes;)
Utilisez-vous
CGI.pm
ou un dérivé de celui-ci?Si votre problème est lié à l' analyse de l'entrée de CGI et vous n'êtes pas en utilisant un module largement testé comme
CGI.pm
,CGI::Request
,CGI::Simple
ouCGI::Lite
, utilisez le module et se concentrer sur la vie.CGI.pm
a uncgi-lib.pl
mode de compatibilité qui peut vous aider à résoudre les problèmes d'entrée dus aux anciennes implémentations de l'analyseur CGI.Avez-vous utilisé des chemins absolus?
Si vous exécutez des commandes externes avec
system
, des graduations inverses ou d'autres fonctions IPC, vous devez utiliser un chemin absolu vers le programme externe. Non seulement vous savez exactement ce que vous exécutez, mais vous évitez également certains problèmes de sécurité. Si vous ouvrez des fichiers en lecture ou en écriture, utilisez un chemin absolu. Le script CGI peut avoir une idée différente de la vôtre sur le répertoire actuel. Alternativement, vous pouvez faire un explicitechdir()
pour vous mettre au bon endroit.Avez-vous vérifié vos valeurs de retour?
La plupart des fonctions Perl vous diront si elles ont fonctionné ou non et seront activées
$!
en cas d'échec. Avez-vous vérifié la valeur de retour et examiné$!
les messages d'erreur? Avez-vous vérifié$@
si vous utilisiezeval
?Quelle version de Perl utilisez-vous?
La dernière version stable de Perl est la 5.28 (ou non, selon la date de la dernière modification). Utilisez-vous une ancienne version? Différentes versions de Perl peuvent avoir différentes idées d'avertissement.
Quel serveur Web utilisez-vous?
Différents serveurs peuvent agir différemment dans la même situation. Le même produit serveur peut agir différemment avec différentes configurations. Incluez autant de ces informations que possible dans toute demande d'aide.
Avez-vous vérifié la documentation du serveur?
Les programmeurs CGI sérieux doivent en savoir autant que possible sur le serveur - y compris non seulement les fonctionnalités et le comportement du serveur, mais également la configuration locale. La documentation de votre serveur peut ne pas être disponible si vous utilisez un produit commercial. Sinon, la documentation doit être sur votre serveur. Si ce n'est pas le cas, recherchez-le sur le Web.
Avez-vous recherché les archives de
comp.infosystems.www.authoring.cgi
?Cette utilisation était utile, mais toutes les bonnes affiches sont soit mortes, soit errantes.
Il est probable que quelqu'un ait déjà eu votre problème et que quelqu'un (peut-être moi) y ait répondu dans ce groupe de discussion. Bien que ce groupe de discussion ait passé son apogée, la sagesse recueillie du passé peut parfois être utile.
Pouvez-vous reproduire le problème avec un court script de test?
Dans les grands systèmes, il peut être difficile de localiser un bogue car il se passe tellement de choses. Essayez de reproduire le problème avec le script le plus court possible. Connaître le problème est l'essentiel du correctif. Cela peut certainement prendre du temps, mais vous n'avez pas encore trouvé le problème et vous manquez d'options. :)
Avez-vous décidé d'aller voir un film?
Sérieusement. Parfois, nous pouvons être tellement absorbés par le problème que nous développons un «rétrécissement perceptif» (vision tunnel). Prendre une pause, prendre une tasse de café ou faire exploser des méchants dans [Duke Nukem, Quake, Doom, Halo, COD] pourrait vous donner la nouvelle perspective dont vous avez besoin pour ré-aborder le problème.
Avez-vous exprimé le problème?
Sérieusement encore. Parfois, expliquer le problème à haute voix nous conduit à nos propres réponses. Parlez au pingouin (peluche) parce que vos collègues n'écoutent pas. Si cela vous intéresse en tant qu'outil de débogage sérieux (et je le recommande si vous n'avez pas encore trouvé le problème), vous pouvez également lire The Psychology of Computer Programming .
la source
$|=1
au lieu de$|++
?$|=1
au lieu de$|++
? Cela ne fait pas vraiment de différence, et même alors,$|
c'est magique.use strict
est généralement bon à utiliser à tout moment, alors que l'utilisationfatalsToBrowser
peut ne pas être conseillée en production, surtout si vous utilisezdie
.Je pense que CGI :: Debug mérite également d'être mentionné.
la source
die
les instructions et autres erreurs fatales lors de l'exécution et de la compilation sont impriméesSTDERR
, ce qui peut être difficile à trouver et peut être confondu avec des messages provenant d'autres pages Web de votre site. Pendant que vous déboguez votre script, il est judicieux d'afficher les messages d'erreur fatale dans votre navigateur.Une façon de faire est d'appeler
en haut de votre script. Cet appel installera un
$SIG{__DIE__}
gestionnaire (voir perlvar ) affichant des erreurs fatales dans votre navigateur, en le précédant d'un en-tête valide si nécessaire. Une autre astuce de débogage CGI que j'ai utilisée avant d'en entendre parlerCGI::Carp
était d'utilisereval
avec les installationsDATA
et__END__
sur le script pour détecter les erreurs de compilation:Cette technique plus verbeuse a un léger avantage
CGI::Carp
en ce qu'elle détectera plus d'erreurs de compilation.Mise à jour: je ne l'ai jamais utilisé, mais il semble
CGI::Debug
, comme l'a suggéré Mikael S, qu'il soit également un outil très utile et configurable à cet effet.la source
<DATA>
est un gestionnaire de fichier magique qui lit le script courant en commençant par__END__
. Join fournit un contexte de liste, donc <fh> renvoie un tableau, une ligne par élément. Ensuite, join le remet ensemble (en le joignant avec ''). Enfin, eval.eval join(q{}, <DATA>);
Je me demande pourquoi personne n'a mentionné l'
PERLDB_OPTS
option appeléeRemotePort
; bien que certes, il n'y ait pas beaucoup d'exemples de travail sur le Web (RemotePort
n'est même pas mentionné dans perldebug ) - et c'était un peu problématique pour moi de trouver celui-ci, mais voilà (c'est un exemple Linux).Pour faire un bon exemple, j'avais d'abord besoin de quelque chose qui puisse faire une simulation très simple d'un serveur Web CGI, de préférence via une seule ligne de commande. Après avoir trouvé le serveur Web de ligne de commande simple pour exécuter cgis. (perlmonks.org) , j'ai trouvé que IO :: All - A Tiny Web Server était applicable pour ce test.
Ici, je vais travailler dans le
/tmp
répertoire; le script CGI sera/tmp/test.pl
(inclus ci-dessous). Notez que leIO::All
serveur ne servira que les fichiers exécutables dans le même répertoire que CGI, c'est doncchmod +x test.pl
obligatoire ici. Donc, pour faire le test CGI habituel, je change de répertoire/tmp
dans le terminal et j'y lance le serveur Web à une ligne:La commande du serveur Web se bloquera dans le terminal, et sinon démarrera le serveur Web localement (sur 127.0.0.1 ou
localhost
) - après, je peux accéder à un navigateur Web et demander cette adresse:... et je devrais observer le
print
s fait entest.pl
étant chargé - et affiché - dans le navigateur Web.Maintenant, pour déboguer ce script avec
RemotePort
, nous avons d'abord besoin d'un écouteur sur le réseau, à travers lequel nous allons interagir avec le débogueur Perl; nous pouvons utiliser l'outil de ligne de commandenetcat
(nc
, vu ça ici: Perl 如何 remote debug? ). Alors, lancez d'abord l'netcat
écouteur dans un terminal - où il bloquera et attendra les connexions sur le port 7234 (qui sera notre port de débogage):Ensuite, nous voudrions
perl
démarrer en mode débogage avecRemotePort
, lorsque letest.pl
a été appelé (même en mode CGI, via le serveur). Cela, sous Linux, peut être fait en utilisant le script suivant "shebang wrapper" - qui ici doit également être dans/tmp
, et doit être rendu exécutable:C'est un peu une chose délicate - voir script shell - Comment puis-je utiliser des variables d'environnement dans mon shebang? - Échange de piles Unix et Linux . Mais, l'astuce ici semble être de ne pas bifurquer l'
perl
interpréteur qui gèretest.pl
- donc une fois que nous l'avons frappé, nous ne le faisons pasexec
, mais à la place nous appelonsperl
"clairement", et fondamentalement "source" notretest.pl
script en utilisantdo
(voir Comment exécuter un Script Perl depuis un script Perl? ).Maintenant que nous avons
perldbgcall.sh
dans/tmp
- nous pouvons changer letest.pl
fichier, afin qu'il fasse référence à ce fichier exécutable sur sa ligne shebang (au lieu de l'interpréteur Perl habituel) - ici est/tmp/test.pl
modifié ainsi:Maintenant, les deux
test.pl
et son nouveau gestionnaire de shebang,,perldbgcall.sh
sont en/tmp
; et nousnc
écoutons les connexions de débogage sur le port 7234 - afin que nous puissions enfin ouvrir une autre fenêtre de terminal, changer de répertoire/tmp
et exécuter le serveur Web à une ligne (qui écoutera les connexions Web sur le port 8080) là:Une fois que cela est fait, nous pouvons accéder à notre navigateur Web et demander la même adresse,
http://127.0.0.1:8080/test.pl
. Cependant, maintenant, lorsque le serveur Web essaiera d'exécuter le script, il le fera viaperldbgcall.sh
shebang - qui démarreraperl
en mode débogueur distant. Ainsi, l'exécution du script s'arrêtera - et ainsi le navigateur Web se verrouillera, en attendant les données. Nous pouvons maintenant passer aunetcat
terminal, et nous devrions voir le texte familier du débogueur Perl - cependant, sortir vianc
:Comme le montre l'extrait de code, nous utilisons maintenant essentiellement
nc
comme un "terminal" - afin que nous puissions taperr
(et Enter) pour "run" - et le script exécutera l'instruction breakpoint (voir aussi En perl, quelle est la différence entre $ DB :: single = 1 et 2? ), Avant de s'arrêter à nouveau (notez qu'à ce stade, le navigateur se verrouille toujours).Donc, maintenant nous pouvons, disons, parcourir le reste de
test.pl
, via lenc
terminal:... cependant, également à ce stade, le navigateur se verrouille et attend les données. Seulement après avoir quitté le débogueur avec
q
:... le navigateur arrête-t-il le verrouillage - et affiche finalement la sortie (complète) de
test.pl
:Bien sûr, ce type de débogage peut être effectué même sans exécuter le serveur Web - cependant, la chose intéressante ici, c'est que nous ne touchons pas du tout au serveur Web; nous déclenchons l'exécution "nativement" (pour CGI) à partir d'un navigateur Web - et le seul changement nécessaire dans le script CGI lui-même est le changement de shebang (et bien sûr, la présence du script wrapper shebang, en tant que fichier exécutable dans le même annuaire).
Eh bien, j'espère que cela aide quelqu'un - j'aurais certainement aimé tomber dessus, au lieu de l'écrire moi-même
:)
.
la source
Pour moi, j'utilise log4perl . C'est assez utile et facile.
la source
Honnêtement, vous pouvez faire toutes les choses amusantes ci-dessus. BIEN QUE, la solution la plus simple et la plus proactive que j'ai trouvée était de simplement «l'imprimer».
Par exemple: (code normal)
Pour voir s'il fait ce que je veux vraiment qu'il fasse: (Dépannage)
la source
Il vaudra probablement également la peine de mentionner que Perl vous indiquera toujours sur quelle ligne l'erreur se produit lorsque vous exécutez le script Perl à partir de la ligne de commande. (Une session SSH par exemple)
Je le ferai généralement si tout le reste échoue. Je vais SSH sur le serveur et exécuter manuellement le script Perl. Par exemple:
S'il y a un problème, Perl vous en informera. Cette méthode de débogage supprime tout problème lié à l'autorisation de fichier ou problème de navigateur Web ou de serveur Web.
la source
Vous pouvez exécuter le script perl cgi dans le terminal en utilisant la commande ci-dessous
Il interprète le code et fournit le résultat avec du code HTML. Il signale l'erreur le cas échéant.
la source
perl -c filename
ne vérifiera en effet que la syntaxe. Maisperl filename
imprime la sortie HTML. Ce n'est pas une garantie qu'il n'y aura pas d'erreur de 500 CGI, mais c'est un bon premier test.