it-swarm.com.de

Wie kann ich einen PHP schwerwiegenden Fehler abfangen?

Ich kann set_error_handler() verwenden, um die meisten PHP Fehler abzufangen, aber es funktioniert nicht bei schwerwiegenden (E_ERROR) Fehlern, wie dem Aufrufen einer Funktion, die nicht existiert. Gibt es eine andere Möglichkeit, diese Fehler abzufangen?

Ich versuche, mail() für alle Fehler aufzurufen und führe PHP aus 5.2.3.

533
too much php

Protokollieren Sie schwerwiegende Fehler mit register_shutdown_function, wofür PHP 5.2+ erforderlich ist:

register_shutdown_function( "fatal_handler" );

function fatal_handler() {
    $errfile = "unknown file";
    $errstr  = "shutdown";
    $errno   = E_CORE_ERROR;
    $errline = 0;

    $error = error_get_last();

    if( $error !== NULL) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];

        error_mail(format_error( $errno, $errstr, $errfile, $errline));
    }
}

Sie müssen die Funktionen error_mail und format_error definieren. Zum Beispiel:

function format_error( $errno, $errstr, $errfile, $errline ) {
    $trace = print_r( debug_backtrace( false ), true );

    $content = "
    <table>
        <thead><th>Item</th><th>Description</th></thead>
        <tbody>
            <tr>
                <th>Error</th>
                <td><pre>$errstr</pre></td>
            </tr>
            <tr>
                <th>Errno</th>
                <td><pre>$errno</pre></td>
            </tr>
            <tr>
                <th>File</th>
                <td>$errfile</td>
            </tr>
            <tr>
                <th>Line</th>
                <td>$errline</td>
            </tr>
            <tr>
                <th>Trace</th>
                <td><pre>$trace</pre></td>
            </tr>
        </tbody>
    </table>";
    return $content;
}

Verwenden Sie Swift Mailer , um die Funktion error_mail zu schreiben.

Siehe auch:

617
user259973

Ich habe mir gerade diese Lösung ausgedacht (PHP 5.2.0+):

function shutDownFunction() { 
    $error = error_get_last();
    // fatal error, E_ERROR === 1
    if ($error['type'] === E_ERROR) { 
        //do your stuff     
    } 
}
register_shutdown_function('shutDownFunction');

Verschiedene Fehlertypen definiert unter http://www.php.net/manual/en/errorfunc.constants.php

140
periklis

PHP bietet keine herkömmlichen Mittel zum Auffinden und Wiederherstellen von schwerwiegenden Fehlern. Dies liegt daran, dass die Verarbeitung in der Regel nach einem schwerwiegenden Fehler nicht wiederhergestellt werden sollte. Ein String, der mit einem Ausgabepuffer übereinstimmt (wie vom ursprünglichen Post vorgeschlagen, die auf PHP.net beschriebene Technik), ist definitiv nicht ratsam. Es ist einfach unzuverlässig.

Auch das Aufrufen der mail () - Funktion aus einer Error-Handler-Methode heraus erweist sich als problematisch. Wenn Sie viele Fehler hätten, würde Ihr Mail-Server mit Arbeit geladen sein und Sie könnten sich mit einem knorrigen Posteingang wiederfinden. Um dies zu vermeiden, sollten Sie einen Cron ausführen, um Fehlerprotokolle regelmäßig zu scannen und Benachrichtigungen entsprechend zu senden. Vielleicht möchten Sie sich auch mit Systemüberwachungssoftware befassen, z. B. Nagios .


So sprechen Sie über das Registrieren einer Shutdown-Funktion:

Es stimmt, dass Sie eine Abschaltfunktion registrieren können, und das ist eine gute Antwort.

Der Punkt hier ist, dass wir normalerweise nicht versuchen sollten, schwerwiegende Fehler zu beheben, insbesondere nicht, indem wir einen regulären Ausdruck für Ihren Ausgabepuffer verwenden. Ich habe auf die akzeptierte Antwort geantwortet, die mit einem Vorschlag auf php.net verknüpft ist, der seitdem geändert oder entfernt wurde.

Dieser Vorschlag bestand darin, während der Ausnahmebehandlung einen regulären Ausdruck für den Ausgabepuffer zu verwenden und im Falle eines schwerwiegenden Fehlers (der durch den Abgleich mit dem konfigurierten Fehlertext erkannt wurde, den Sie möglicherweise erwarten) eine Wiederherstellung oder eine fortgesetzte Verarbeitung durchzuführen. Das wäre keine empfohlene Vorgehensweise (ich glaube, deshalb kann ich den ursprünglichen Vorschlag auch nicht finden. Entweder übersah ich ihn oder die PHP-Community hat ihn abgeschossen).

Es kann erwähnenswert sein, dass die neueren Versionen von PHP (um 5.1) die Shutdown-Funktion früher aufzurufen scheinen, bevor der Ausgabepuffer-Callback aufgerufen wird. In Version 5 und früheren Versionen war diese Reihenfolge umgekehrt (auf den Ausgabepuffer-Rückruf folgte die Shutdown-Funktion). Außerdem werden Objekte seit 5.0.5 (das viel früher als die Version 5.2.3 des Fragestellers ist) entladen, bevor eine registrierte Shutdown-Funktion aufgerufen wird, sodass Sie sich nicht auf Ihre speicherinternen Objekte verlassen können viel von allem.

Das Registrieren einer Abschaltfunktion ist also in Ordnung, aber die Art von Aufgaben, die von einer Abschaltfunktion ausgeführt werden sollten, sind wahrscheinlich auf eine Handvoll sanfter Abschaltvorgänge beschränkt.

Der Schlüssel zum Mitnehmen ist hier nur ein paar Worte der Weisheit für jeden, der über diese Frage stolpert und den Rat in der ursprünglich akzeptierten Antwort sieht. Regexen Sie Ihren Ausgabepuffer nicht.

114
keparo

Nun, es scheint möglich zu sein, schwerwiegende Fehler auf andere Weise zu fangen :)

ob_start('fatal_error_handler');

function fatal_error_handler($buffer){
    $error=error_get_last();
    if($error['type'] == 1){
        // type, message, file, line
        $newBuffer='<html><header><title>Fatal Error </title></header>
                    <style>                 
                    .error_content{                     
                        background: ghostwhite;
                        vertical-align: middle;
                        margin:0 auto;
                        padding:10px;
                        width:50%;                              
                     } 
                     .error_content label{color: red;font-family: Georgia;font-size: 16pt;font-style: italic;}
                     .error_content ul li{ background: none repeat scroll 0 0 FloralWhite;                   
                                border: 1px solid AliceBlue;
                                display: block;
                                font-family: monospace;
                                padding: 2%;
                                text-align: left;
                      }
                    </style>
                    <body style="text-align: center;">  
                      <div class="error_content">
                          <label >Fatal Error </label>
                          <ul>
                            <li><b>Line</b> '.$error['line'].'</li>
                            <li><b>Message</b> '.$error['message'].'</li>
                            <li><b>File</b> '.$error['file'].'</li>                             
                          </ul>

                          <a href="javascript:history.back()"> Back </a>                          
                      </div>
                    </body></html>';

        return $newBuffer;

    }

    return $buffer;

}
38
sakhunzai

Ich habe eine Möglichkeit entwickelt, alle Fehlertypen in PHP (fast alle) abzufangen! Ich bin mir nicht sicher über E_CORE_ERROR (ich denke, nur für diesen Fehler wird es nicht funktionieren)! Bei anderen schwerwiegenden Fehlern (E_ERROR, E_PARSE, E_COMPILE ...) funktioniert dies jedoch problemlos mit nur einer Fehlerbehandlungsfunktion! Da geht meine Lösung:

Fügen Sie diesen folgenden Code in Ihre Hauptdatei (index.php) ein:

<?php

define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

define('ENV', 'dev');

//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);

register_shutdown_function('shut');

set_error_handler('handler');

//Function to catch no user error handler function errors...
function shut(){

    $error = error_get_last();

    if($error && ($error['type'] & E_FATAL)){
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }

}

function handler( $errno, $errstr, $errfile, $errline ) {

    switch ($errno){

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_CORE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;

    }

    $message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';

    if(($errno & E_FATAL) && ENV === 'production'){

        header('Location: 500.html');
        header('Status: 500 Internal Server Error');

    }

    if(!($errno & ERROR_REPORTING))
        return;

    if(DISPLAY_ERRORS)
        printf('%s', $message);

    //Logging error on php file error log...
    if(LOG_ERRORS)
        error_log(strip_tags($message), 0);

}

ob_start();

@include 'content.php';

ob_end_flush();

?>

Ich hoffe das hilft vielen Menschen! Ich habe zu lange nach dieser Lösung gesucht und nicht gefunden! Dann habe ich eins entwickelt!

22

Schwerwiegende Fehler oder behebbare schwerwiegende Fehler werfen jetzt Instanzen von Error in PHP 7 oder höheren Versionen . Wie bei allen anderen Ausnahmen können Error Objekte mit einem try/catch Block abgefangen werden.

Beispiel:

<?php
$variable = 'not an object';

try {
    $variable->method(); // Throws an Error object in PHP 7 or higger.
} catch (Error $e) {
    // Handle error
    echo $e->getMessage(); // Call to a member function method() on string
}

https://3v4l.org/67vbk

Oder Sie können die Schnittstelle Throwable verwenden, um alle Ausnahmen abzufangen.

Beispiel:

<?php
    try {
        undefinedFunctionCall();
    } catch (Throwable $e) {
        // Handle error
        echo $e->getMessage(); // Call to undefined function undefinedFunctionCall()
    }

https://3v4l.org/Br0MG

Für weitere Informationen: http://php.net/manual/en/language.errors.php7.php

21
LugiHaue

Sie können schwerwiegende Fehler nicht abfangen/behandeln, aber Sie können sie protokollieren/melden. Zum schnellen Debuggen habe ich eine Antwort auf diesen einfachen Code geändert

function __fatalHandler()
{
    $error = error_get_last();
//check if it's a core/fatal error, otherwise it's a normal shutdown
    if ($error !== NULL && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING,E_RECOVERABLE_ERROR))) {
        echo "<pre>fatal error:\n";
        print_r($error);
        echo "</pre>";
        die;
    }
}

register_shutdown_function('__fatalHandler');
18
zainengineer

Sie können keine Ausnahme innerhalb der registrierten Shutdown-Funktion wie folgt auslösen:

<?php
function shutdown() {
    if (($error = error_get_last())) {
       ob_clean();
       throw new Exception("fatal error");
    }
}

try {
    $x = null;
    $x->method()
} catch(Exception $e) {
    # this won't work
}
?>

Sie können jedoch Anforderungen erfassen und auf eine andere Seite umleiten.

<?php
function shutdown() {
    if (($error = error_get_last())) {
       ob_clean();
       # raport the event, send email etc.
       header("Location: http://localhost/error-capture");
       # from /error-capture, you can use another redirect, to e.g. home page
    }
}
register_shutdown_function('shutdown');

$x = null;
$x->method()
?>
17
hipertracker

Wenn Sie php> = 5.1.0 benutzen, machen Sie einfach so etwas mit der ErrorException-Klasse:

<?php
//define an error handler
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
//set ur error handle
set_error_handler("exception_error_handler");

/* Trigger exception */
try
{
  //try to do something like finding the end of the internet
}
catch(ErrorException $e)
{
  //anything you want to do with $e
}

?>
11
Cyril Tata

Ich muss schwerwiegende Fehler behandeln, damit eine Produktion stattdessen eine statisch gestaltete HTML-Ausgabe mit dem 503-Dienst "Nicht verfügbar" anzeigt. Dies ist sicherlich ein vernünftiger Ansatz, um "schwerwiegende Fehler abzufangen". Das habe ich gemacht:

Ich habe eine benutzerdefinierte Fehlerbehandlungsfunktion "error_handler", die meine HTML-Seite "503 service unavailable" auf allen E_ERROR-, E_USER_ERROR- usw. anzeigt. Dies wird nun für die Shutdown-Funktion aufgerufen, die meinen schwerwiegenden Fehler abfängt.

function fatal_error_handler() {

    if (@is_array($e = @error_get_last())) {
        $code = isset($e['type']) ? $e['type'] : 0;
        $msg = isset($e['message']) ? $e['message'] : '';
        $file = isset($e['file']) ? $e['file'] : '';
        $line = isset($e['line']) ? $e['line'] : '';
        if ($code>0) error_handler($code,$msg,$file,$line);
    }
}
set_error_handler("error_handler");
register_shutdown_function('fatal_error_handler');

wenn in meiner benutzerdefinierten error_handler-Funktion der Fehler E_ERROR oder E_USER_ERROR usw. ist, rufe ich auch @ob_end_clean () auf. um den Puffer zu leeren und so die "fatale Fehlermeldung" von PHP zu entfernen.

Beachten Sie die strengen isset () - Überprüfungs- und @ Silencing-Funktionen, da unsere error_handler-Skripte keine Fehler generieren sollen.

Wenn Sie immer noch mit Keparo einverstanden sind, wird der Zweck von "FATAL error" durch das Abfangen schwerwiegender Fehler außer Kraft gesetzt, sodass Sie nicht wirklich die Absicht haben, die Daten weiterzuverarbeiten. Führen Sie bei diesem Herunterfahren keine mail () -Funktionen aus, da Sie mit Sicherheit den Mailserver oder Ihren Posteingang sichern werden. Protokollieren Sie diese Vorkommnisse lieber in einer Datei und planen Sie einen Cron, um diese error.log-Dateien zu finden und sie per E-Mail an Administratoren zu senden.

8
Prof83

PHP hat auffällige schwerwiegende Fehler. Sie sind als E_RECOVERABLE_ERROR definiert. Das PHP Handbuch beschreibt einen E_RECOVERABLE_ERROR als:

Abfangbarer schwerwiegender Fehler. Dies weist darauf hin, dass ein möglicherweise gefährlicher Fehler aufgetreten ist, der den Motor jedoch nicht in einem instabilen Zustand zurückgelassen hat. Wenn der Fehler nicht von einem benutzerdefinierten Handle abgefangen wird (siehe auch set_error_handler () ), wird die Anwendung als E_ERROR abgebrochen.

Sie können diese "schwerwiegenden" Fehler "abfangen", indem Sie set_error_handler () verwenden und nach E_RECOVERABLE_ERROR suchen. Ich finde es nützlich, eine Ausnahme auszulösen, wenn dieser Fehler abgefangen wird, dann können Sie try/catch verwenden.

Diese Frage und Antwort bietet ein nützliches Beispiel: Wie kann ich einen "abfangbaren, schwerwiegenden Fehler" bei Hinweisen vom Typ PHP abfangen?

E_ERROR-Fehler können jedoch behandelt, aber nicht behoben werden, da sich die Engine in einem instabilen Zustand befindet.

7
J.Money

Nur ein netter Trick, um die aktuelle error_handler-Methode zu erhalten =)

<?php
register_shutdown_function('__fatalHandler');
function __fatalHandler()
{
    $error      = error_get_last();

    //check if it's a core/fatal error, otherwise it's a normal shutdown
    if($error !== NULL && $error['type'] === E_ERROR) {
        //Bit hackish, but the set_exception_handler will return the old handler
        function fakeHandler() { }
        $handler = set_exception_handler('fakeHandler');
        restore_exception_handler();
        if($handler !== null) { 
            call_user_func($handler, new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
        }
        exit;
    }
}
?>

Auch ich werde das nicht bemerken, wenn Sie anrufen

<?php
ini_set('display_errors', false);
?>

PHP zeigt den Fehler nicht mehr an, andernfalls wird der Fehlertext vor dem Fehlerbehandler an den Client gesendet

5
Sander Visser

Da die meisten Antworten hier unnötig ausführlich sind, ist hier meine nicht hässliche Version der Antwort mit den meisten Stimmen:

function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {
    //Do stuff: mail, log, etc
}

function fatalHandler() {
    $error = error_get_last();
    if($error) errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}

set_error_handler("errorHandler")
register_shutdown_function("fatalHandler");
5
Mahn

Nicht wirklich. Schwerwiegende Fehler werden so genannt, weil sie schwerwiegend sind. Du kannst dich nicht von ihnen erholen.

4
troelskn

Es gibt bestimmte Umstände, unter denen sogar schwerwiegende Fehler auftreten können (Sie müssen möglicherweise eine Bereinigung vornehmen, bevor Sie ordnungsgemäß beenden und nicht einfach sterben ..). Ich habe einen pre_system-Hook für meine Codeigniter-Anwendungen implementiert, damit ich meine schwerwiegenden Fehler per E-Mail erhalten kann. Dies hat mir geholfen, Fehler zu finden, die nicht gemeldet wurden (oder nachdem sie behoben wurden, da ich bereits davon wusste :)). Sendemail prüft, ob der Fehler bereits gemeldet wurde, damit Sie nicht mehrfach mit bekannten Fehlern belästigt werden.

class PHPFatalError {

    public function setHandler() {
        register_shutdown_function('handleShutdown');
    }

}

function handleShutdown() {
    if (($error = error_get_last())) {
        ob_start();
        echo "<pre>";
        var_dump($error);
        echo "</pre>";
        $message = ob_get_clean();
        sendEmail($message);
        ob_start();
        echo '{"status":"error","message":"Internal application error!"}';
        ob_flush();
        exit();
    }
}
3
tix3

Ich habe diese Funktion entwickelt, um Sandbox-Code zu erstellen, der einen schwerwiegenden Fehler verursachen kann. Da vom Closure register_shutdown_function ausgelöste Ausnahmen nicht vom Aufrufstapel vor schwerwiegenden Fehlern ausgegeben werden, muss ich nach dieser Funktion beendet werden, um eine einheitliche Verwendungsweise zu gewährleisten.

function superTryCatchFinallyAndExit( Closure $try, Closure $catch = NULL, Closure $finally )
{
    $finished = FALSE;
    register_shutdown_function( function() use ( &$finished, $catch, $finally ) {
        if( ! $finished ) {
            $finished = TRUE;
            print "EXPLODE!".PHP_EOL;
            if( $catch ) {
                superTryCatchFinallyAndExit( function() use ( $catch ) {
                    $catch( new Exception( "Fatal Error!!!" ) );
                }, NULL, $finally );                
            } else {
                $finally();                
            }
        }
    } );
    try {
        $try();
    } catch( Exception $e ) {
        if( $catch ) {
            try {
                $catch( $e );
            } catch( Exception $e ) {}
        }
    }
    $finished = TRUE;
    $finally();
    exit();
}
2
Kendall Hopkins

Ich habe eine Wiki-artige Q & A mit einer Komplettlösung zum Abfangen aller Fehler in PHP verfasst. was angesehen/aufgegriffen/gestohlen/kritisiert werden kann hier .

Die Lösung enthält 5 Methoden, die alle Fehler umschließen, die PHP erzeugen kann, die diese Fehler schließlich an ein 'ErrorHandler'-typisiertes Objekt weiterleiten.

Hoffe, dass einige Leute davon Gebrauch machen. Auch wenn Sie es nicht direkt stehlen, bin ich mir sicher, dass die Lösung zumindest ein gutes Beispiel für den Umgang mit Fehlern in PHP - in jeder Hinsicht ist.

@Lucas Batistussi bekam Punkte für Kreativität - ich schätze, ich könnte auch meine Lösung teilen und nach ähnlichen Punkten schießen ...

1
DigitalJedi805