Nasıl bir PHP Ölümcül Hata yakalamak yapmak

12 Cevap php

I set_error_handler() en PHP hataları yakalamak için kullanabilirsiniz, ancak bu tür yok bir işlevi çağırarak olarak ölümcül (E\_ERROR) hataları için çalışmaz. Bu hataları yakalamak için başka bir yolu var mı?

Ben tüm hatalar için mail() aramak çalışıyorum ve PHP 5.2.3 kullanıyorum.

12 Cevap

PHP 5.2 + gerektirir, register_shutdown_function kullanarak ölümcül hataları günlüğe:

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 ) );
}

Sen error_mail ve format_error işlevleri tanımlamak zorunda kalacak. Örneğin:

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

  $content  = "<table><thead bgcolor='#c8c8c8'><th>Item</th><th>Description</th></thead><tbody>";
  $content .= "<tr valign='top'><td><b>Error</b></td><td><pre>$errstr</pre></td></tr>";
  $content .= "<tr valign='top'><td><b>Errno</b></td><td><pre>$errno</pre></td></tr>";
  $content .= "<tr valign='top'><td><b>File</b></td><td>$errfile</td></tr>";
  $content .= "<tr valign='top'><td><b>Line</b></td><td>$errline</td></tr>";
  $content .= "<tr valign='top'><td><b>Trace</b></td><td><pre>$trace</pre></td></tr>";
  $content .= '</tbody></table>';

  return $content;
}

Swift Mailer error_mail işlevi yazmak için kullanın.

Ayrıca bkz:

PHP ölümcül hataları yakalamak için herhangi bir konvansiyonel araçlarla size vermeyecektir çünkü onlar gerçekten shouldn't be caught. Demek ki, bir ölümcül hata kurtarmak için çalışmamalısınız. Bir çıktı tamponu eşleşen dize kesinlikle kötü tavsiye edilir.

Bir hata işleyicisi yöntemi içinde mail arama () fonksiyonu çok sorunlu olduğunu kanıtlayabilir. Eğer hataları bir sürü olsaydı, posta sunucusu çalışma ile yüklenmiş olacaktır, ve bir budaklı gelen kutusu ile kendinizi bulabiliriz. Bunu önlemek için, periyodik hata günlükleri tarama ve buna göre bildirimleri göndermek için bir cron çalışan düşünebilirsiniz. Ayrıca, Nagios gibi, sistem izleme yazılımı içine bakmak isteyebilirsiniz.


Bir kapatma işlevi kayıt hakkında biraz konuşmak için:

Bu bir kapatma işlevi kayıt doğrudur, ve bu iyi bir cevap.

Burada nokta size çıkış tamponuna karşı normal bir ifade kullanarak, ölümcül hataları kurtarmak için özellikle çalışın gerektiğidir. O zamandan beri değiştirilmiş veya kaldırılmıştır php.net bir öneri bağlantılı accepted answer, yanıt olarak geldi.

Bu öneri durum işleme sırasında çıkış tamponuna karşı bir regex kullanımı idi, ve (sizi bekliyor olabilir yapılandırılmış olursa olsun hata metni karşı eşleşen tarafından algılanan) ölümcül bir hata durumunda, bazı kurtarma çeşit veya sürekli işlem yapmak için çalışın. Yani (Ben de o bakan ediyorum. Ben de, özgün öneri bulamıyorum bu yüzden inanıyorum ya php topluluk aşağı vurdu) tavsiye edilen bir uygulama olmaz.

Bu (5.1 civarında) PHP daha yeni sürümleri çıktı tamponlama geri envoked önce, erken kapatma işlevini çağırmak gibi fazlalaştı olabilir. Sürüm 5 ve daha önceki, o emri (çıkış tamponlama arama kapatma işlevi izledi) tersiydi. Yapmanız bellek içindeki nesnelere güvenmek mümkün olmayacaktır böylece Ayrıca, yaklaşık 5.0.5 (çok daha önce sorunu olanın sürümü 5.2.3 az olduğu), nesnelerin kayıtlı kapanma fonksiyonu önce iyice boşaltılır beri, denir çok şey.

Yani kapatma işlevi kayıt gayet iyi, ama gereken bir kapatma fonksiyonu ile yapılacak görevlerin tür muhtemelen yumuşak kapatma prosedürleri bir avuç sınırlıdır.

Burada anahtar take-away bu soruya stumbles ve başlangıçta kabul cevap tavsiye görür herkes için bilgelik sadece bazı kelimeler olduğunu. Çıktı tamponunu regex etmeyin.

Sadece bu çözüm (php 5.2.0 +) ile geldi:

register_shutdown_function('shutdownFunction');

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

http://www.php.net/manual/en/errorfunc.constants.php tanımlanan farklı hata türleri

Peki Ölümcül Hatalar başka bir yol yakalamak mümkün görünüyor :)

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;

}

Böyle kayıtlı kapanma fonksiyonu içinde istisna değil:

<?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
}
?>

Ama yakalamak ve başka bir sayfaya istek yönlendirebilirsiniz.

<?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()
?>

PHP tüm hata tipleri (hemen hemen tüm) yakalamak için bir yol geliştirdi! (Ben bu hata için çalışır olmayacağını düşünüyorum) E_CORE_ERROR konusunda hiç emin var! Ancak, diğer ölümcül hatalar (E_ERROR, E_PARSE, E_COMPILE ...) için bir hata işleyicisi işlevini sadece kullanmadan çalışıyor! Benim çözüm oraya gider:

Ana dosyası (index.php) bu aşağıdaki kodu koyun:

<?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();

>

Bu birçok kişi yardımcı olur umarım! Ben bu çözüm çok uzun zamandır arıyor ve bulamadık! Sonra geliştirdi!

Ben yerine statik 503 Hizmet kullanılamıyor HTML çıktısı tarz göstermek için bir üretim için ölümcül hataları işlemek gerekir. Bu "ölümcül hataları yakalamak" elbette makul bir yaklaşımdır. Bu benim yaptığım budur:

Ben Bu artık benim ölümcül hata yakalama kapanma fonksiyonu çağrılacak E_USER_ERROR vb herhangi E_ERROR benim "503 servisi kullanılamıyor" HTML sayfası, görüntüler bir özel hata fonksiyonu "error_handler" var.

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');

Hata E_ERROR veya E_USER_ERROR vb ise benim özel error_handler fonksiyonu, ben de) (ob_end_clean @ diyoruz; böylece PHP'nin "ölümcül hata" mesajı kaldırma, tampon boş.

Bizim error_handler komut hataları oluşturmak istemiyorum beri sıkı isset () kontrol ve işlevlerini susturulması @ önemli not alın.

Hala keparo ile kabul olarak, ölümcül hataları yakalamak daha fazla işlem yapmak için onun gerçekten uygun değildir yani "ölümcül hata" amacı yenilgi yok. Kesinlikle posta sunucusu veya kutunuzu yedeklemek gibi bu kapatma işleminde () işlevleri herhangi bir posta çalıştırmayın. Aksine, bu olaylar dosyaya giriş ve bu error.log dosyaları bulmak ve yöneticiler onları posta bir cron zamanlama.

Gerçekten değil. Onlar ölümcül çünkü ölümcül hataları, bu denir. Sen onlardan kurtarmak değil.

Ben mümkün ölümcül bir hataya neden olabilir "sandbox" kod yapmak için bu fonksiyonu geliştirdi. Kapatılması atılan istisnalar register_shutdown_function öncesi ölümcül hata çağrı yığını yayılan alamadım, ben bunu kullanarak düzgün bir şekilde sağlamak için bu işlev sonra çıkmak zorunda kalıyorum.

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();
}

PHP catchable ölümcül hatalar var. Bunlar E_RECOVERABLE_ERROR olarak tanımlanır. PHP manuel olarak E_RECOVERABLE_ERROR açıklar:

Yakalanabilir ölümcül hata. Bu muhtemelen tehlikeli bir hata oluştu gösterir, ancak dengesiz bir durumda motoru yazmadı. Hata bir kullanıcı tanımlı kolu tarafından yakalanmış ise (ayrıca bkz set_error_handler()), uygulama, E_ERROR olarak iptal eder.

Sen set_error_handler() kullanarak ve E_RECOVERABLE_ERROR denetleyerek bu "ölümcül" hataları "yakalamak" olabilir. Ben bu hata yakalandığı zaman bir özel durum için yararlıdır, o zaman try / catch kullanabilirsiniz bulabilirsiniz.

Bu soru ve cevap yararlı bir örnek sağlar: How can I catch a "catchable fatal error" on PHP type hinting?

E_ERROR hataları, ancak, ele, ama motor dengesiz bir durumda olduğu gibi kurtarıldı değil edilebilir.

Sadece güzel bir akım error_handler yöntemi almak için hile =)

<?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;
    }
}
?>

Ayrıca ben not wan't ki eğer arama

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

Php, aksi takdirde hata metin öncesinde hata işleyicisi için müşteri göndermek olacak, hatayı görüntüleyen durdurur