Fehlerbehandlung in PHP

  • Da in letzter Zeit öfters Code von TS's gepostet wurde, der Fehlermeldungen ausgespuckt hat, zusammen mit der Frage, was falsch ist, habe ich dieses Tutorial erstellt. Kritik ist willkommen, aber bitte Konstruktiv.

    Fehlerbehandlung in PHP
    Um immer alle Fehler zu sehen, sollte man folgendes an den Anfang seiner PHP-Dateien setzen:

    PHP
    error_reporting(E_ALL);
    ini_set("display_errors", "true");

    Hier werden evtl. viele NOTICE-Errors kommen. Daher sage ich zu denen auch noch was:
    Ein E_NOTICE kommt meistens durch Unstimmigkeiten im Programmcode zustande. z.B.:

    PHP
    <?php
    error_reporting(E_ALL);
    echo $a*5;
    ?>

    Hier wird mit einer nicht-definierten variable gerechnet. Die Zählt PHP normalerweise als Null,
    aber wenn alle Errors an sind, erhält man eine Fehlermeldung.

    Zitat


    Notice: Undefined variable: a in foo.php on line 3

    Hier könnte z.B. eine falsch geschriebene Variable der Grund für ein falsches Ergebnis sein, für das man evtl. seine Rechnung verantwortlich macht.
    Der simpelste Fehler ist der Syntax-Error. Jedoch sind die Meldungen von PHP da nicht immer ganz eindeutig.

    PHP
    <?php
    echo "Hello World;
    ?>

    Das hier ergibt folgende Fehlermeldung:

    Zitat


    Parse error: syntax error, unexpected $end, expecting T_VARIABLE or T_DOLLAR_OPEN_CURLY_BRACES or T_CURLY_OPEN in /users/cptest/www/foo.php on line 3

    PHP sagt uns hier, das Script hört unerwarteterweise auf. Warum? da gibt es doch ein ?>.
    In PHP kann man beliebig viele Zeilenumbrüche in einen String packen. daher parst PHP den Code bis zum >, weil der String nicht geschlossen wurde. Aber beim > hört das Script auf und das ergibt die Fehlermeldung.

    PHP
    <?php
    echo "Hello World";
    ?>

    Hier parst PHP nur bis zum zweiten " und gibt den String aus, kein Fehler.

    Eine komplexere Form des Syntax-Errors wäre z.B. das hier:

    PHP
    <?php
    $foo="DeFbArxYZ";
    if (strToLower(htmlspecialchars(mysql_real_escape_string(substr($_GET['bla'], 3, 4))) == strToLower(substr($foo, 3, 3))) {
     echo "Ja";
    } else {
     echo "Nein";
    }
    ?>

    Und hier verliert man leicht die Übersicht. Da hilft natürlich erstmal ein Editor mit Syntaxhighlighting, der die Klammern hervorhebt. ;)
    Jedenfalls, PHP meckert hier:

    Zitat


    Parse error: syntax error, unexpected '{' in /users/cptest/www/foo.php on line 3

    Da hilft es, zumindest gedanklich die Bedingung auseinanderzunehmen, denn einfach irgendwo eine Klammer setzen macht keinen Sinn.

    Und man erkennt ziemlich schnell, das strToLower im ersten teil der Bedingung nicht geschlossen ist.
    Btw: Wenn das script mit einer Datenbank verbunden ist, ist die Ausgabe: Nein

    Die Fehlermeldung des Typs "Warning" sind ähnlich zu behandeln, sie betreffen aber eher weniger den Code an sich. Ein typischer Fehler dieser Art ist dieser:

    Zitat


    Warning: Cannot modify header information - headers already sent by (output started at foo.php:3) in /users/cptest/www/foo.php on line 4


    Das tritt immer dann auf, wenn man bereits eine Ausgabe gemacht hat, und dann die Funktion header() benutzt. Hier hilft es, das Script von vorne durchzugehen und die erste Ausgabe zu suchen.
    Und weiter zum Tod jedes Scripts, zum Fatal-Error. Der kommt in den meisten Fällen bei Datenbankabfragen, daher nehme ich das im Beispiel.

    Das fuehrt zu einem Fatal-Error bei $query->fetch_array().

    Zitat


    Fatal error: Call to a member function fetch_array() on a non-object in /users/cptest/www/foo.php on line 5

    Da gibts 2 moeglichkeiten, das Problem zu loesen.
    1. Die mysql_* Funktionen benutzen und in diesem Fall nur ein Warning anstadt einem Error zu erhalten\
    2. Pruefen, ob das Query durchgegangen ist und nur dann fetch_array() aufrufen.

    Es ist wohl offensichtlich, dass hier 2. die bessere Idee ist.

    Und damit kommen wir zum 3. Punkt, die Fehler bei SQL-Statements.
    Nun kommt schonmal keine Fehlermeldung mehr, aber wissen, wo das Problem steckt, weis man immernoch nicht. Dazu steht die variable $error im mysqli-Object bzw. die mysql_error() funktion bereit.
    Von den beiden erfahren wir naemlich immer, was gerade falsch lauft.
    Wenn man also von einer If-Abfrage erfaehrt, dass der Query fehlgeschlagen ist, dann immer

    PHP
    echo mysql_error();
    // b.z.w.
    echo $db->error;

    EDIT:
    Hier empfiehlt es sich jedoch, um SQL-Injector Angreiffern das Leben schwerer zu machen, diese Funktion zu benutzen:

    Im allgemeinen: Bitte ALLE Fehlermeldungen GENAU anschauen, mit dem Code abgleichen und dann verbesern ;)

    Der, der weiß dass er nichts weiß, weiß mehr als der, der nicht weiß, dass er nichts weiß.

    Wer nach etwas fragt, geht grundsätzlich das Risiko ein, es auch zu bekommen!

    3 Mal editiert, zuletzt von Tobse (2. Januar 2011 um 04:05)

  • in memoriam banditum möchte ich noch des hier hinzufügen:

  • Wenn man also von einer If-Abfrage erfaehrt, dass der Query fehlgeschlagen ist, dann immer

    PHP
    echo mysql_error();
    // b.z.w.
    echo $db->error;

    Keine gute Idee, wenn man aus irgendeinem Grund eine Injection zulässt, bekommt ein Angreifer so das Tabellenformat wesentlich schneller raus…

    Außerdem sollte man sich auch um E_NOTICE kümmern, das sind echte Performance-Bremsen, auch wenn man sie ignoriert. Aus dem Grund auch das @ nur benutzen, wenn es keine andere Möglichkeit in PHP gibt.

    Auch gut zu gebrauchen:
    http://de3.php.net/manual/en/function.set-error-handler.php
    http://firephp.org

  • Das fachliche ist zwar größtenteils okay, aber wenn man so ein "Tutorial" vielen Leuten zugänglich machen will, dann achtet man doch auf Rechtschreibung, oder? Die ist bei dir unter aller Sau, es gibt kaum einen Satz an dem man beim lesen nicht hängen bleibt weil diverse Rechtschreibfehler drin sind.
    Das mindert den Wert dieses Tutorials massiv!

    wert.TeeeX.de
    Wie gut ist die technische Umsetztung deiner Website wirklich?
    Teste es!

  • Notice sollte man natürlich beachten, nicht nur wegen Performance, sie zeugen unteranderen von schlampigen Programmierstiel

    Klar sollte auch sein, dass Fehler nur in der Testumgebung/Localhost angezeigt werden sollten, in einer Liveumgebung werden alle Fehler unterdrückt (auch Notices) und werden in Logdaten geschrieben.

    Mittels einer einfachen IF könnte man oben das Reporting umschalten

    mfg

  • Was mir jetzt aber neu ist, dass es nur 3 Fehlermeldungen gibt.

    Nicht böse gemeint, aber diesen Beitrag "Tutorial" zu nennen, ist heftig überzogen.

  • Was mir jetzt aber neu ist, dass es nur 3 Fehlermeldungen gibt.

    Nicht böse gemeint, aber diesen Beitrag "Tutorial" zu nennen, ist heftig überzogen.


    Nein, natuerlich gibt es mehr. Aber ein E_NOTICE zu falsch zu bearbeiten ist recht schwierig.

    Keine gute Idee, wenn man aus irgendeinem Grund eine Injection zulässt, bekommt ein Angreifer so das Tabellenformat wesentlich schneller raus…


    Oh, danke das dus sagst. Ich editier den Post gleich und fuege noch was an.


    Außerdem sollte man sich auch um E_NOTICE kümmern, das sind echte Performance-Bremsen, auch wenn man sie ignoriert. Aus dem Grund auch das @ nur benutzen, wenn es keine andere Möglichkeit in PHP gibt.


    Im ersten Code-Tag steht doch im kommentar, dass durch E_ALL viel Zeugs durchkommt, dass man in der Live-Version nicht brauchen kann und daher auf jeden fall unterdruecken sollte, aber beim Programmieren und Debuggen unbedingt beachten muss. E_NOTICE sind meistens wichtige dinge, ja, auch auf den Programmierstil bezogen wie "undefined Variable".

    THX fuer das gute Feedback.

    @Unregistriert: Ja, ich uebe noch, ich versuchs aber noch zu verbessern ;)

    Der, der weiß dass er nichts weiß, weiß mehr als der, der nicht weiß, dass er nichts weiß.

    Wer nach etwas fragt, geht grundsätzlich das Risiko ein, es auch zu bekommen!

  • @Pion
    Naja, manchmal kanns sein, dass die Notice echt nicht schlimm ist und genau das passiert, was man haben will, dann sollte man sich die Mühe wegen der Performance machen…

    Tobse
    Höh? E_NOTICE nicht im Live-Betrieb und den Rest schon??

  • Wenn im Live betrieb was anderes kommt ausser E_NOTICE dann stimmt was nicht und gehoert verbessert, evtl gibts da ein Paar ausnahmen, aber genau dafuer ist ja das @ da ;)

    Der, der weiß dass er nichts weiß, weiß mehr als der, der nicht weiß, dass er nichts weiß.

    Wer nach etwas fragt, geht grundsätzlich das Risiko ein, es auch zu bekommen!

  • Ne, das @ sollte vermieden werden wegen der Performance. Und E_NOTICEs sollten wenn irgend möglich weg. Und schonmal was davon gehört, dass ein Script vllt. mal einen Fehler hat, den man noch nicht entdeckt hat?

  • The User

    Hab ich dir irgentwo wiedersprochen ? Ich glaube nicht :D
    Wollte nur anmerken das eben keinerlei Fehlermeldungen im Livebetrieb ausgegeben werden sollte, dafür in der Testumgebung jeder

    Mittels Seterrorhandler kann man dann im Livebetrieb alle Errors Loggen

  • Ich benutze das @ garnicht. Mir faellt leider momentan kein genaues Beispiel ein, wann man das @ wirklich sinnvoll einsetzen kann, um einen unnoetigen Fehler zurueckzuhalten. Aber es gibt ja vieles, aber im grossen und ganzen stimme ich mit Pion ueberein.

    Der, der weiß dass er nichts weiß, weiß mehr als der, der nicht weiß, dass er nichts weiß.

    Wer nach etwas fragt, geht grundsätzlich das Risiko ein, es auch zu bekommen!

  • http://de.php.net/manual/en/function.shm-has-var.php
    Die Funktion wurde erst in PHP 3 eingeführt, vorher musste man shm_get mit @ abfragen… Sehr ärgerlich, wenn die Shared-Memory-Performance für Fehlerbehandlung draufgeht…