it-swarm.com.de

Wie bekomme ich PHP bei Fehlern eine Rückverfolgung erzeugen?

Der Versuch, PHP mit seinen standardmäßigen Nur-Zeilen-Fehlermeldungen zu debuggen, ist schrecklich. Wie kann ich PHP dazu bringen, einen Backtrace (Stack-Trace) zu erzeugen, wenn Fehler auftreten?

48
chaos

Xdebug druckt eine Rückverfolgungstabelle auf Fehler und Sie müssen keinen PHP - Code schreiben, um sie zu implementieren.

Nachteil ist, dass Sie es als Erweiterung PHP installieren müssen.

46
patcoll

Mein Skript zum Installieren eines Fehlerbehandlers, der eine Rückverfolgung erzeugt:

<?php
function process_error_backtrace($errno, $errstr, $errfile, $errline, $errcontext) {
    if(!(error_reporting() & $errno))
        return;
    switch($errno) {
    case E_WARNING      :
    case E_USER_WARNING :
    case E_STRICT       :
    case E_NOTICE       :
    case E_USER_NOTICE  :
        $type = 'warning';
        $fatal = false;
        break;
    default             :
        $type = 'fatal error';
        $fatal = true;
        break;
    }
    $trace = array_reverse(debug_backtrace());
    array_pop($trace);
    if(php_sapi_name() == 'cli') {
        echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        foreach($trace as $item)
            echo '  ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
    } else {
        echo '<p class="error_backtrace">' . "\n";
        echo '  Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
        echo '  <ol>' . "\n";
        foreach($trace as $item)
            echo '    <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
        echo '  </ol>' . "\n";
        echo '</p>' . "\n";
    }
    if(ini_get('log_errors')) {
        $items = array();
        foreach($trace as $item)
            $items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
        $message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
        error_log($message);
    }
    if($fatal)
        exit(1);
}

set_error_handler('process_error_backtrace');
?>

Vorbehalt: Es ist nicht möglich, verschiedene 'PHP Fatal Errors' zu beeinflussen, da Zend in ihrer Weisheit entschieden hat, dass diese set_error_handler() ignorieren. So erhalten Sie immer noch unbrauchbare End-Location-Fehler.

46
chaos

PHP Fehler

Dies ist eine bessere Fehlerberichterstattung für PHP, die in PHP geschrieben wurde. Es sind keine zusätzlichen Erweiterungen erforderlich!

Es ist trivial zu verwenden, wenn alle Fehler für normale AJAXy-Anforderungen (im angehaltenen Zustand) im Browser angezeigt werden. Bei allen Fehlern erhalten Sie dann einen Backtrace- und Code-Kontext über die gesamte Stack-Ablaufverfolgung, einschließlich Funktionsargumenten und Servervariablen.

Alles, was Sie tun müssen, ist, eine einzige Datei einzufügen und die Funktion (am Anfang Ihres Codes) aufzurufen, z.

require('php_error.php');
\php_error\reportErrors();

Siehe die Screenshots:

 PHP Error | Improve Error Reporting for PHP - screenshot of backtrace  PHP Error | Improve Error Reporting for PHP - screenshot of backtrace  PHP Error | Improve Error Reporting for PHP - screenshot of backtrace

GitHub: https://github.com/JosephLenton/PHP-Error

Meine Gabel (mit zusätzlichen Korrekturen): https://github.com/kenorb-contrib/PHP-Error

Debuggen Sie PHP class

Eine vollständige Debugger-Klasse PHP mit Unterstützung für Exception, Fehler, Alerts (vom Benutzer), Codezeilen und Markierungsflags.

Verwendungsbeispiel:

 <?php
        include( dirname(dirname(__FILE__))  . '/src/Debug.php' );
        //Catch all
        Debug::register();

        //Generate an errors
        if( this_function_does_not_exists( ) )
        {
            return false;
        }
    ?>

Fehlerbehandlung in PHP

Das folgende Beispiel zeigt die Behandlung interner Ausnahmen, indem Fehler ausgelöst und mit einer benutzerdefinierten Funktion behandelt werden:

Kürzerer Weg (PHP):

<?php
function e($number, $msg, $file, $line, $vars) {
   print_r(debug_backtrace());
   die();
}
set_error_handler('e');

Längerer Weg (PHP):

// set to the user defined error handler
$old_error_handler = set_error_handler("myErrorHandler");

// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
    if (!(error_reporting() & $errno)) {
        // This error code is not included in error_reporting
        return;
    }

    switch ($errno) {
    case E_USER_ERROR:
        echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
        echo "  Fatal error on line $errline in file $errfile";
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
        echo "Aborting...<br />\n";
        var_dump(debug_backtrace());
        exit(1);
        break;

    case E_USER_WARNING:
        echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
        break;

    case E_USER_NOTICE:
        echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
        break;

    default:
        echo "Unknown error type: [$errno] $errstr<br />\n";
        break;
    }

    /* Don't execute PHP internal error handler */
    return true;
}

Siehe: http://www.php.net/manual/de/function.set-error-handler.php

Hinweis: Sie können jeweils nur eine Fehlerausnahme haben. Wenn Sie die Funktion set_error_handler () aufrufen, wird der Name des alten Fehlerbehandlers zurückgegeben. Sie können dies speichern und von Ihrem Fehlerhandler selbst aufrufen. Auf diese Weise können Sie mehrere Fehlerhandler verwenden.


XDebug

Für eine fortschrittlichere Lösung können Sie XDebug extension für PHP verwenden.

Beim Laden von XDebug sollte standardmäßig die Rückverfolgung im Falle eines schwerwiegenden Fehlers automatisch angezeigt werden. Oder Sie verfolgen in eine Datei (xdebug.auto_trace), um eine sehr große Rückverfolgung der gesamten Anforderung zu erhalten, oder führen Sie die Profilerstellung (xdebug.profiler_enable) oder andere Einstellungen durch. Wenn die Ablaufverfolgungsdatei zu groß ist, können Sie xdebug_start_trace () und xdebug_stop_trace () verwenden, um den Teilablauf zu sichern.

Installation

PECL verwenden:

pecl install xdebug

Unter Linux:

Sudo apt-get install php5-xdebug

Auf dem Mac (mit Homebrew):

brew tap josegonzalez/php
brew search xdebug
php53-xdebug

Beispiel für die Minenkonfiguration:

[xdebug]

; Extensions
extension=xdebug.so
; zend_extension="/YOUR_PATH/php/extensions/no-debug-non-zts-20090626/xdebug.so"
; zend_extension="/Applications/MAMP/bin/php/php5.3.20/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so" ; MAMP

; Data
xdebug.show_exception_trace=1       ; bool: Show a stack trace whenever an exception is raised.
xdebug.collect_vars = 1             ; bool: Gather information about which variables are used in a certain scope.
xdebug.show_local_vars=1            ; int: Generate stack dumps in error situations.
xdebug.collect_assignments=1        ; bool: Controls whether Xdebug should add variable assignments to function traces.
xdebug.collect_params=4             ; int1-4: Collect the parameters passed to functions when a function call is recorded.
xdebug.collect_return=1             ; bool: Write the return value of function calls to the trace files.
xdebug.var_display_max_children=256 ; int: Amount of array children and object's properties are shown.
xdebug.var_display_max_data=1024    ; int: Max string length that is shown when variables are displayed.
xdebug.var_display_max_depth=3      ; int: How many nested levels of array/object elements are displayed.
xdebug.show_mem_delta=0             ; int: Show the difference in memory usage between function calls.

; Trace
xdebug.auto_trace=0                 ; bool: The tracing of function calls will be enabled just before the script is run.
xdebug.trace_output_dir="/var/log/xdebug" ; string: Directory where the tracing files will be written to.
xdebug.trace_output_name="%H%R-%s-%t"     ; string: Name of the file that is used to dump traces into.

; Profiler
xdebug.profiler_enable=0            ; bool: Profiler which creates files read by KCacheGrind.
xdebug.profiler_output_dir="/var/log/xdebug"  ; string: Directory where the profiler output will be written to.
xdebug.profiler_output_name="%H%R-%s-%t"      ; string: Name of the file that is used to dump traces into.
xdebug.profiler_append=0            ; bool: Files will not be overwritten when a new request would map to the same file.

; CLI
xdebug.cli_color=1                  ; bool: Color var_dumps and stack traces output when in CLI mode.

; Remote debugging
xdebug.remote_enable=off            ; bool: Try to contact a debug client which is listening on the Host and port.
xdebug.remote_autostart=off         ; bool: Start a remote debugging session even GET/POST/COOKIE variable is not present.
xdebug.remote_handler=dbgp          ; select: php3/gdb/dbgp: The DBGp protocol is the only supported protocol.
xdebug.remote_Host=localhost        ; string: Host/ip where the debug client is running.
xdebug.remote_port=9000             ; integer: The port to which Xdebug tries to connect on the remote Host.
xdebug.remote_mode=req              ; select(req,jit): Selects when a debug connection is initiated.
xdebug.idekey="xdebug-cli"          ; string: IDE Key Xdebug which should pass on to the DBGp debugger handler.
xdebug.remote_log="/var/log/xdebug.log" ; string: Filename to a file to which all remote debugger communications are logged.

Drupal 6 und 7

Mit aktivierter Devel:

/**
 * Implements hook_watchdog().
 */
function foo_watchdog($log_entry) {
  if ($log_entry['type'] == 'php' && $log_entry['severity'] <= WATCHDOG_WARNING) {
    function_exists('dd') && dd(debug_backtrace());
  }
}

Die obige Funktion protokolliert die Backtraces für jeden Fehler in einer temporären Datei (standardmäßig /tmp/drupal_debug.txt).

Oder suchen Sie die Datei über: drush eval "echo file_directory_temp() . '/drupal_debug.txt'.

Wenn Devel nicht aktiviert ist, verwenden Sie den Old-School-Ansatz: var_dump(debug_backtrace()); anstelle von dd().

26
kenorb

Ich habe gerade versucht, eine Sitzungsvariable zu setzen, die den Inhalt von debug_backtrace () in der fehlerhaften Zeile enthält, und dann mit register_shutdown_function () auszudrucken. Lief wie am Schnürchen. 

7
Tim

Sie können debug_backtrace verwenden.

3
Mythica

Als PHP-Debug-Erweiterungen gibt es Xdebug und PHP DBG . Jeder hat seine Vor- und Nachteile.

2
T0xicCode

Das ist wie man es macht:

set_error_handler(function($errorType){
    if(error_reporting() & $errorType){
        ?><pre><?
        debug_print_backtrace();
        ?></pre><?
    }
}) ;

Es erfordert PHP 5.3+, da es eine Schließung verwendet. Wenn Sie eine niedrigere PHP - Unterstützung benötigen, konvertieren Sie einfach die Schließung in eine normale Funktion.

2
GetFree
$backtrace = debug_backtrace();

ich habe vor einiger Zeit einen kleinen Artikel über Backtracing geschrieben

1
smoove

set_error_handler() + debug_backtrace() + debug_print_backtrace() in PHP5

1

Wenn Sie keinen Debugger installieren können, verwenden Sie diese Funktion, die den schwerwiegenden Fehler umgibt, um den "fatalen Stack" zu erhalten. Überprüfen Sie den Code und das Beispiel unten, in dem die Verwendung erläutert wird:

// Give an extra parameter to the filename
// to save multiple log files
function _fatalog_($extra = false)
{
    static $last_extra;

    // CHANGE THIS TO: A writeable filepath in your system...
    $filepath = '/var/www/html/sites/default/files/fatal-'.($extra === false ? $last_extra : $extra).'.log';

    if ($extra===false) {
        unlink($filepath);
    } else {
        // we write a log file with the debug info
        file_put_contents($filepath, json_encode(debug_backtrace()));
        // saving last extra parameter for future unlink... if possible...
        $last_extra = $extra;
    }
}

Hier ist ein Beispiel, wie man es benutzt:

// A function which will produce a fatal error
function fatal_example()
{
    _fatalog_(time()); // writing the log
    $some_fatal_code = array()/3; // fatality!
    _fatalog_(); // if we get here then delete last file log
}

Schließlich den Inhalt des Protokolls lesen ...

var_dump(json_decode(file_get_contents('/path/to-the-fatal.log')));

Hoffentlich hilft das!

1
Beto Aveiga

PHP DeBugger führt auch eine Rückverfolgung ähnlich PHP durch. Fehler mit mehr Optionen .
Wenn Sie möchten, können Sie mit set_error_handler und debug_backtrace leicht Ihre eigenen erstellen.

set_error_handler ($error_handler, error_reporting);
/**
 * @var int $errno the error number
 * @var string $errstr the error message
 * @var string $errfile the error file
 * @var int $errline the line of the error
 */
$error_handler = function($errno, $errstr, $errfile, $errline){
    $trace = debug_backtrace();
    array_shift($backtrace);//remove the stack about this handler
    foreach($trace as $k => $v){
        //parse your backtrace
    }
}

Beachten Sie auch, dass für interne Stapel im Backtrace einige der Tasten nicht gesetzt werden. Stellen Sie sicher, dass der Schlüssel vorhanden ist, bevor Sie etwas damit anfangen, wenn alle Fehler angezeigt werden :)

0
Yamiko