Ich habe ein Perl-Skript, das nicht funktioniert, und ich weiß nicht, wie ich das Problem eingrenzen soll. Was kann ich tun?
Hinweis: Ich füge die Frage hinzu, weil ich Stackoverflow wirklich meine sehr lange Antwort hinzufügen möchte. Ich verlinke in anderen Antworten immer wieder extern darauf und es verdient, hier zu sein. Scheuen Sie sich nicht, meine Antwort zu bearbeiten, wenn Sie etwas hinzufügen möchten.
Antworten:
Diese Antwort ist als allgemeiner Rahmen für die Behebung von Problemen mit Perl-CGI-Skripten gedacht und wurde ursprünglich in Perlmonks als Fehlerbehebung bei Perl-CGI-Skripten angezeigt . Es ist weder eine vollständige Anleitung zu jedem Problem, auf das Sie stoßen könnten, noch ein Tutorial zum Squashing von Fehlern. Es ist nur der Höhepunkt meiner Erfahrung mit dem Debuggen von CGI-Skripten über zwanzig (plus!) Jahre. Diese Seite scheint viele verschiedene Häuser gehabt zu haben, und ich scheine zu vergessen, dass es sie gibt, also füge ich sie dem StackOverflow hinzu. Sie können mir Kommentare oder Vorschläge an [email protected] senden. Es ist auch Community-Wiki, aber nicht zu verrückt. :) :)
Verwenden Sie die integrierten Funktionen von Perl, um Probleme zu finden?
Aktivieren Sie Warnungen, damit Perl Sie vor fragwürdigen Teilen Ihres Codes warnt. Sie können dies über die Befehlszeile mit dem
-w
Schalter tun, sodass Sie keinen Code ändern oder jeder Datei ein Pragma hinzufügen müssen:Sie sollten sich jedoch zwingen, immer fragwürdigen Code zu löschen, indem Sie
warnings
allen Ihren Dateien das Pragma hinzufügen :Wenn Sie mehr Informationen als die kurze Warnmeldung benötigen, verwenden Sie das
diagnostics
Pragma, um weitere Informationen zu erhalten, oder lesen Sie die perldiag- Dokumentation:Haben Sie zuerst einen gültigen CGI-Header ausgegeben?
Der Server erwartet, dass die erste Ausgabe eines CGI-Skripts der CGI-Header ist. In der Regel ist dies so einfach wie
print "Content-type: text/plain\n\n";
oder mit CGI.pm und seinen Derivatenprint header()
. Einige Server reagieren empfindlich auf Fehlerausgaben (einSTDERR
), die vor der Standardausgabe (ein ) angezeigt werdenSTDOUT
.Versuchen Sie, Fehler an den Browser zu senden
Fügen Sie diese Zeile hinzu
zu Ihrem Skript. Dadurch werden auch Kompilierungsfehler an das Browserfenster gesendet. Entfernen Sie dies unbedingt, bevor Sie in eine Produktionsumgebung wechseln, da die zusätzlichen Informationen ein Sicherheitsrisiko darstellen können.
Was hat das Fehlerprotokoll gesagt?
Server führen Fehlerprotokolle (oder sollten es zumindest). Dort sollte eine Fehlerausgabe vom Server und von Ihrem Skript angezeigt werden. Suchen Sie das Fehlerprotokoll und sehen Sie, was darin steht. Es gibt keinen Standardplatz für Protokolldateien. Suchen Sie in der Serverkonfiguration nach ihrem Speicherort oder fragen Sie den Serveradministrator. Sie können auch Tools wie CGI :: Carp verwenden , um Ihre eigenen Protokolldateien zu speichern.
Was sind die Berechtigungen des Skripts?
Wenn Fehler wie "Berechtigung verweigert" oder "Methode nicht implementiert" angezeigt werden, bedeutet dies wahrscheinlich, dass Ihr Skript vom Webserverbenutzer nicht lesbar und ausführbar ist. Bei Unix-Versionen wird empfohlen, den Modus auf 755 zu ändern :
chmod 755 filename
. Stellen Sie niemals einen Modus auf 777 ein!Benutzt du
use strict
?Denken Sie daran, dass Perl bei der ersten Verwendung automatisch Variablen erstellt. Dies ist eine Funktion, kann jedoch manchmal Fehler verursachen, wenn Sie einen Variablennamen falsch eingeben. Das Pragma
use strict
hilft Ihnen dabei, diese Art von Fehlern zu finden. Es ist ärgerlich, bis Sie sich daran gewöhnt haben, aber Ihre Programmierung wird sich nach einer Weile erheblich verbessern und Sie können verschiedene Fehler machen.Kompiliert das Skript?
Sie können mit dem
-c
Schalter nach Kompilierungsfehlern suchen . Konzentrieren Sie sich auf die ersten gemeldeten Fehler. Spülen, wiederholen. Wenn Sie wirklich seltsame Fehler erhalten, überprüfen Sie, ob Ihr Skript die richtigen Zeilenenden hat. Wenn Sie im Binärmodus FTP ausführen, aus CVS auschecken oder etwas anderes, das die Übersetzung am Zeilenende nicht verarbeitet, sieht der Webserver Ihr Skript möglicherweise als eine große Zeile. Übertragen Sie Perl-Skripte im ASCII-Modus.Beschwert sich das Skript über unsichere Abhängigkeiten?
Wenn sich Ihr Skript über unsichere Abhängigkeiten beschwert, verwenden Sie wahrscheinlich den
-T
Schalter, um den Taint-Modus zu aktivieren. Dies ist eine gute Sache, da Sie weiterhin ungeprüfte Daten an die Shell übergeben. Wenn es sich beschwert, macht es seine Arbeit, um uns zu helfen, sicherere Skripte zu schreiben. Alle Daten, die von außerhalb des Programms (dh der Umgebung) stammen, gelten als fehlerhaft. Umgebungsvariablen wiePATH
undLD_LIBRARY_PATH
sind besonders problematisch. Sie müssen diese auf einen sicheren Wert setzen oder sie vollständig deaktivieren, wie ich empfehle. Sie sollten sowieso absolute Pfade verwenden. Wenn sich die Verschmutzungsprüfung über etwas anderes beschwert, stellen Sie sicher, dass Sie die Daten nicht beschmutzt haben. Weitere Informationen finden Sie in der Perlsec- Manpage.Was passiert, wenn Sie es über die Befehlszeile ausführen?
Gibt das Skript das aus, was Sie erwarten, wenn es über die Befehlszeile ausgeführt wird? Wird der Header zuerst ausgegeben, gefolgt von einer Leerzeile? Denken Sie daran, dass dies
STDERR
möglicherweise zusammengeführt wird,STDOUT
wenn Sie sich in einem Terminal befinden (z. B. in einer interaktiven Sitzung), und aufgrund der Pufferung möglicherweise in einer durcheinandergebrachten Reihenfolge angezeigt wird. Aktivieren Sie die Autoflush-Funktion von Perl, indem Sie$|
einen echten Wert festlegen . Normalerweise wird dies$|++;
in CGI-Programmen angezeigt. Einmal eingestellt, geht jeder Druck und jedes Schreiben sofort zur Ausgabe, anstatt gepuffert zu werden. Sie müssen dies für jedes Dateihandle einstellen. Verwenden Sieselect
diese Option, um das Standard-Dateihandle wie folgt zu ändern:In jedem Fall sollte als erstes der CGI-Header gefolgt von einer Leerzeile ausgegeben werden.
Was passiert, wenn Sie es über die Befehlszeile in einer CGI-ähnlichen Umgebung ausführen?
Die Webserverumgebung ist normalerweise viel eingeschränkter als Ihre Befehlszeilenumgebung und enthält zusätzliche Informationen zu der Anforderung. Wenn Ihr Skript über die Befehlszeile einwandfrei ausgeführt wird, können Sie versuchen, eine Webserverumgebung zu simulieren. Wenn das Problem auftritt, liegt ein Umgebungsproblem vor.
Deaktivieren oder entfernen Sie diese Variablen
PATH
LD_LIBRARY_PATH
ORACLE_*
VariablenStellen Sie diese Variablen ein
REQUEST_METHOD
(aufGET
,HEAD
oderPOST
wie geeignet)SERVER_PORT
(normalerweise auf 80 eingestellt)REMOTE_USER
(wenn Sie Sachen mit geschütztem Zugriff machen)Neuere Versionen von
CGI.pm
(> 2.75) erfordern, dass das-debug
Flag das alte (nützliche) Verhalten erhält, sodass Sie es möglicherweise zu IhrenCGI.pm
Importen hinzufügen müssen .Benutzt du
die()
oderwarn
?Diese Funktionen werden gedruckt,
STDERR
sofern Sie sie nicht neu definiert haben. Sie geben auch keinen CGI-Header aus. Sie können die gleiche Funktionalität mit Paketen wie CGI :: Carp erhaltenWas passiert, nachdem Sie den Browser-Cache geleert haben?
Wenn Sie der Meinung sind, dass Ihr Skript das Richtige tut und Sie die Anforderung manuell ausführen, erhalten Sie die richtige Ausgabe. Möglicherweise ist der Browser der Schuldige. Leeren Sie den Cache und setzen Sie die Cache-Größe beim Testen auf Null. Denken Sie daran, dass einige Browser wirklich dumm sind und keine neuen Inhalte neu laden, obwohl Sie dies anweisen. Dies ist besonders häufig der Fall, wenn der URL-Pfad identisch ist, sich der Inhalt jedoch ändert (z. B. dynamische Bilder).
Ist das Skript dort, wo Sie denken, dass es ist?
Der Dateisystempfad zu einem Skript steht nicht unbedingt in direktem Zusammenhang mit dem URL-Pfad zum Skript. Stellen Sie sicher, dass Sie das richtige Verzeichnis haben, auch wenn Sie ein kurzes Testskript schreiben müssen, um dies zu testen. Sind Sie außerdem sicher, dass Sie die richtige Datei ändern? Wenn Sie bei Ihren Änderungen keine Auswirkungen sehen, ändern Sie möglicherweise eine andere Datei oder laden eine Datei an die falsche Stelle hoch. (Dies ist übrigens meine häufigste Ursache für solche Probleme;)
Verwenden Sie
CGI.pm
oder ein Derivat davon?Wenn Ihr Problem bezieht sich die CGI - Eingabe zu parsen und Sie sind nicht ein weit getestetes Modul wie mit
CGI.pm
,CGI::Request
,CGI::Simple
oderCGI::Lite
, um das Modul verwenden und mit dem Leben auszukommen.CGI.pm
verfügt über einencgi-lib.pl
Kompatibilitätsmodus, mit dem Sie Eingabeprobleme aufgrund älterer CGI-Parser-Implementierungen lösen können.Hast du absolute Pfade benutzt?
Wenn Sie externe Befehle mit
system
, Back-Ticks oder anderen IPC-Funktionen ausführen , sollten Sie einen absoluten Pfad zum externen Programm verwenden. Sie wissen nicht nur genau, was Sie ausführen, sondern vermeiden auch einige Sicherheitsprobleme. Wenn Sie Dateien zum Lesen oder Schreiben öffnen, verwenden Sie einen absoluten Pfad. Das CGI-Skript hat möglicherweise eine andere Vorstellung vom aktuellen Verzeichnis als Sie. Alternativ können Sie eine explizitechdir()
Aktion ausführen , um Sie an den richtigen Ort zu bringen.Haben Sie Ihre Rückgabewerte überprüft?
Die meisten Perl-Funktionen zeigen an, ob sie funktioniert haben oder nicht, und setzen
$!
auf Fehler. Haben Sie den Rückgabewert überprüft und$!
auf Fehlermeldungen überprüft ? Haben Sie überprüft,$@
ob Sie verwendet habeneval
?Welche Perl-Version verwenden Sie?
Die neueste stabile Version von Perl ist 5.28 (oder nicht, je nachdem, wann diese zuletzt bearbeitet wurde). Verwenden Sie eine ältere Version? Verschiedene Versionen von Perl haben möglicherweise unterschiedliche Vorstellungen von Warnungen.
Welchen Webserver verwenden Sie?
Verschiedene Server können in derselben Situation unterschiedlich handeln. Das gleiche Serverprodukt kann bei verschiedenen Konfigurationen unterschiedlich funktionieren. Nehmen Sie so viele dieser Informationen wie möglich in jede Hilfeanforderung auf.
Haben Sie die Serverdokumentation überprüft?
Seriöse CGI-Programmierer sollten so viel wie möglich über den Server wissen - einschließlich nicht nur der Serverfunktionen und des Serververhaltens, sondern auch der lokalen Konfiguration. Die Dokumentation für Ihren Server steht Ihnen möglicherweise nicht zur Verfügung, wenn Sie ein kommerzielles Produkt verwenden. Andernfalls sollte sich die Dokumentation auf Ihrem Server befinden. Wenn dies nicht der Fall ist, suchen Sie im Web danach.
Haben Sie die Archive von durchsucht
comp.infosystems.www.authoring.cgi
?Dies war früher nützlich, aber alle guten Plakate sind entweder gestorben oder abgewandert.
Es ist wahrscheinlich, dass jemand Ihr Problem schon einmal hatte und dass jemand (möglicherweise ich) es in dieser Newsgroup beantwortet hat. Obwohl diese Newsgroup ihre Blütezeit hinter sich hat, kann die gesammelte Weisheit aus der Vergangenheit manchmal nützlich sein.
Können Sie das Problem mit einem kurzen Testskript reproduzieren?
In großen Systemen kann es schwierig sein, einen Fehler aufzuspüren, da so viele Dinge passieren. Versuchen Sie, das Problemverhalten mit dem kürzestmöglichen Skript zu reproduzieren. Das Problem zu kennen ist der größte Teil der Lösung. Dies mag sicherlich zeitaufwändig sein, aber Sie haben das Problem noch nicht gefunden und haben keine Optionen mehr. :) :)
Hast du dich entschieden, einen Film anzusehen?
Ernsthaft. Manchmal sind wir so in das Problem verwickelt, dass wir eine "Wahrnehmungsverengung" (Tunnelblick) entwickeln. Wenn Sie eine Pause einlegen, eine Tasse Kaffee trinken oder ein paar Bösewichte in [Duke Nukem, Quake, Doom, Halo, COD] in die Luft jagen, erhalten Sie möglicherweise die neue Perspektive, die Sie benötigen, um das Problem erneut anzugehen.
Haben Sie das Problem ausgesprochen?
Wieder ernsthaft. Manchmal führt uns eine laute Erklärung des Problems zu unseren eigenen Antworten. Sprechen Sie mit dem Pinguin (Plüschtier), weil Ihre Mitarbeiter nicht zuhören. Wenn Sie sich für dieses ernsthafte Debugging-Tool interessieren (und ich empfehle es, wenn Sie das Problem bis jetzt noch nicht gefunden haben), lesen Sie vielleicht auch The Psychology of Computer Programming .
quelle
$|=1
statt$|++
?$|=1
statt$|++
? Es macht keinen wirklichen Unterschied und ist selbst dann$|
magisch.use strict
ist im Allgemeinen jederzeit gut zu verwenden, während die VerwendungfatalsToBrowser
in der Produktion möglicherweise nicht empfohlen wird, insbesondere wenn Sie sie verwendendie
.Ich denke, CGI :: Debug ist ebenfalls erwähnenswert.
quelle
die
Anweisungen und andere schwerwiegende Laufzeit- und Kompilierungsfehler werden gedrucktSTDERR
, die schwer zu finden sind und mit Nachrichten von anderen Webseiten auf Ihrer Site in Konflikt gebracht werden können. Während Sie Ihr Skript debuggen, ist es eine gute Idee, die schwerwiegenden Fehlermeldungen irgendwie in Ihrem Browser anzuzeigen.Eine Möglichkeit, dies zu tun, besteht darin, anzurufen
oben in Ihrem Skript. Dieser Aufruf installiert einen
$SIG{__DIE__}
Handler (siehe Perlvar ), der schwerwiegende Fehler in Ihrem Browser anzeigt und ihm gegebenenfalls einen gültigen Header voranstellt. Ein weiterer CGI-Debugging-Trick, den ich verwendet habe, bevor ich jemals davon gehört habe,CGI::Carp
war die Verwendungeval
derDATA
und__END__
-Funktionen im Skript, um Fehler bei der Kompilierung abzufangen:Diese ausführlichere Technik hat einen kleinen Vorteil gegenüber der Tatsache,
CGI::Carp
dass mehr Fehler bei der Kompilierung abgefangen werden.Update: Ich habe es noch nie benutzt, aber es sieht so aus
CGI::Debug
, als wäre es , wie Mikael S vorgeschlagen hat, auch ein sehr nützliches und konfigurierbares Werkzeug für diesen Zweck.quelle
<DATA>
ist ein magisches Dateihandle, das das aktuelle Skript beginnend mit liest__END__
. Join stellt den Listenkontext bereit, sodass <fh> ein Array zurückgibt, eine Zeile pro Element. Dann setzt join es wieder zusammen (verbindet es mit ''). Zum Schluss eval.eval join(q{}, <DATA>);
Ich frage mich , wie kommt niemand die erwähnte
PERLDB_OPTS
Option genanntRemotePort
; Zugegeben , es gibt nicht viele Arbeitsbeispiele im Web (RemotePort
wird nicht einmal in Perldebug erwähnt ) - und es war ein bisschen problematisch für mich, dieses zu finden, aber hier ist es (es ist ein Linux-Beispiel).Um ein richtiges Beispiel zu machen, brauchte ich zuerst etwas, das eine sehr einfache Simulation eines CGI-Webservers durchführen kann, vorzugsweise über eine einzige Befehlszeile. Nachdem Sie den einfachen Befehlszeilen-Webserver zum Ausführen von cgis gefunden haben. (perlmonks.org) fand ich, dass der IO :: All - A Tiny Web Server für diesen Test geeignet ist .
Hier werde ich im
/tmp
Verzeichnis arbeiten; Das CGI-Skript wird/tmp/test.pl
(siehe unten). Beachten Sie, dass derIO::All
Server nur ausführbare Dateien im selben Verzeichnis wie CGI bereitstellt. Dieschmod +x test.pl
ist hier erforderlich. Um den üblichen CGI-Testlauf durchzuführen, wechsle ich/tmp
in das Verzeichnis im Terminal und führe dort den einzeiligen Webserver aus:Der Webserver-Befehl wird im Terminal blockiert und startet den Webserver ansonsten lokal (unter 127.0.0.1 oder
localhost
). Danach kann ich zu einem Webbrowser gehen und diese Adresse anfordern:... und ich sollte die
print
s beobachten, die durchtest.pl
Laden - und Anzeigen - im Webbrowser erstellt wurden.Um dieses Skript zu debuggen
RemotePort
, benötigen wir zunächst einen Listener im Netzwerk, über den wir mit dem Perl-Debugger interagieren. Wir können das Kommandozeilen-Tool verwendennetcat
(nc
haben das hier gesehen: Perl 如何 Remote-Debug? ). Führen Sie dennetcat
Listener also zuerst in einem Terminal aus - wo er blockiert und auf Verbindungen auf Port 7234 wartet (der unser Debug-Port sein wird):Dann möchten wir
perl
im Debug-Modus mit startenRemotePort
, wenn dertest.pl
aufgerufen wurde (auch im CGI-Modus über den Server). Dies, in Linux kann mit dem folgenden „shebang Wrapper“ Skript durchgeführt werden - was auch hier in sein muss/tmp
, und muss ausführbar gemacht werden:Dies ist eine knifflige Sache - siehe Shell-Skript - Wie kann ich Umgebungsvariablen in meinem Shebang verwenden? - Unix & Linux Stack Exchange . Der Trick hier scheint jedoch nicht darin zu bestehen, den
perl
Interpreter, der damit umgeht, zutest.pl
verzweigen. Wenn wir ihn also einmal getroffen haben, tun wir dies nichtexec
, sondern rufenperl
"einfach" auf und "quellen" unsertest.pl
Skript im Grunde genommen mitdo
(siehe Wie führe ich ein aus?) Perl-Skript aus einem Perl-Skript heraus? ).Jetzt, da wir
perldbgcall.sh
in/tmp
- wir das ändern könnentest.pl
Datei, so dass es auf seiner Shebang - Zeile (statt der üblichen Perl - Interpreter) auf diese ausführbare Datei verweist - hier wird/tmp/test.pl
geändert so:Jetzt sind beide
test.pl
und sein neuer Shebang-Handlerperldbgcall.sh
in/tmp
; und wirnc
warten auf Debug-Verbindungen an Port 7234 - damit wir endlich ein anderes Terminalfenster öffnen, das Verzeichnis in ändern/tmp
und den einzeiligen Webserver (der auf Webverbindungen an Port 8080 wartet) ausführen können:Danach können wir zu unserem Webbrowser gehen und dieselbe Adresse anfordern
http://127.0.0.1:8080/test.pl
. Wenn der Webserver nun versucht, das Skript auszuführen,perldbgcall.sh
geschieht dies jedoch über shebang, dasperl
im Remote-Debugger-Modus gestartet wird . Daher wird die Skriptausführung angehalten - und der Webbrowser wird gesperrt und wartet auf Daten. Wir können jetzt zumnetcat
Terminal wechseln und sollten den bekannten Perl-Debugger-Text sehen - jedoch ausgegeben durchnc
:Wie das Snippet zeigt, verwenden wir es jetzt im Grunde genommen
nc
als "Terminal" - also können wirr
"run" eingeben (und eingeben) - und das Skript wird ausgeführt, um die Haltepunktanweisung auszuführen (siehe auch In Perl, was ist der Unterschied zwischen $ DB :: single = 1 und 2? ), Bevor Sie erneut anhalten (beachten Sie, dass der Browser an dieser Stelle weiterhin gesperrt ist).So, jetzt können wir sagen, Schritt für Schritt durch den Rest
test.pl
durch dasnc
Terminal:... aber auch an dieser Stelle sperrt der Browser und wartet auf Daten. Erst nachdem wir den Debugger beendet haben mit
q
:... stoppt der Browser das Sperren - und zeigt schließlich die (vollständige) Ausgabe von
test.pl
:Natürlich kann diese Art von Debugging auch ohne Ausführen des Webservers durchgeführt werden. Das Schöne dabei ist jedoch, dass wir den Webserver überhaupt nicht berühren. Wir lösen die Ausführung "nativ" (für CGI) über einen Webbrowser aus - und die einzige Änderung, die im CGI-Skript selbst erforderlich ist, ist die Änderung von shebang (und natürlich das Vorhandensein des shebang-Wrapper-Skripts als ausführbare Datei in derselben) Verzeichnis).
Nun, ich hoffe, das hilft jemandem - ich wäre sicher gerne darauf gestoßen, anstatt es selbst zu schreiben.
:)
Prost!
quelle
Für mich benutze ich log4perl . Es ist sehr nützlich und einfach.
quelle
Ehrlich gesagt können Sie all die lustigen Dinge über diesem Beitrag tun. Trotzdem war die einfachste und proaktivste Lösung, die ich gefunden habe, einfach "zu drucken".
Im Beispiel: (Normaler Code)
Um zu sehen, ob es das tut, was ich wirklich möchte: (Fehlerbehebung)
quelle
Es ist wahrscheinlich auch erwähnenswert, dass Perl Ihnen immer mitteilt, in welcher Zeile der Fehler auftritt, wenn Sie das Perl-Skript über die Befehlszeile ausführen. (Eine SSH-Sitzung zum Beispiel)
Ich werde dies normalerweise tun, wenn alles andere fehlschlägt. Ich werde SSH in den Server und das Perl-Skript manuell ausführen. Beispielsweise:
Wenn es ein Problem gibt, wird Perl Sie darüber informieren. Diese Debugging-Methode beseitigt alle Probleme im Zusammenhang mit Dateiberechtigungen oder Webbrowsern oder Webservern.
quelle
Sie können das Perl-CGI-Skript im Terminal mit dem folgenden Befehl ausführen
Es interpretiert den Code und liefert das Ergebnis mit HTML-Code. Es meldet den Fehler, falls vorhanden.
quelle
perl -c filename
wird in der Tat nur die Syntax überprüft. Drucktperl filename
aber die HTML-Ausgabe. Es ist keine Garantie, dass es keinen 500-CGI-Fehler gibt, aber es ist ein guter erster Test.