2010-10-01 1 views
23

Я бы хотел уловить die() и exit() сообщений. Это возможно? Я надеюсь на что-то похожее на set_error_handler и set_exception_handler. Я просмотрел register_shutdown_function(), но, похоже, не содержит контекста для оскорбительных звонков die() и exit().Могу ли я поймать сообщения exit() и die()?

Я понимаю, что die() и exit() - это плохие способы обработки ошибок. Я не хочу, чтобы мне сказали не делать этого. :) Я создаю общую систему и хочу иметь возможность изящно записывать exit() и die(), если по какой-то причине кто-то (а не я) решает, что это хорошая идея.

ответ

4

Как можно лучше, это невозможно. Некоторые из решений, размещенных здесь, могут работать, но они требуют много дополнительной работы или многих зависимостей. Невозможно легко и надежно зафиксировать сообщения die() и exit().

+0

Ну, это возможно, переписав скрипт во время его чтения. Следующий пример tokenizes вход и перезаписывает exit ($ code) и die $ code to php_exit ($ code): EDIT: stackoverflow не позволяет мне добавлять код здесь, см. Этот пост для вдохновения: http://stackoverflow.com/вопросы/31182968/лексема-получить всю-спину к PHP-источник, как-к – user1135940

7

В соответствии с PHP manual функции выключения должны быть уведомлены при вызове функции die() или exit().

Shutdown functions и object destructors всегда выполняются, даже если вызывается exit().

Невозможно получить статус, отправленный при выходе (статус $). Если вы не можете использовать буферизацию вывода для ее захвата, но я не уверен, как вы узнаете, когда позвонить ob_start().

+3

Я думаю, проблема OP заключается в том, что он хотел бы получить сообщение об ошибке из функции выключения. – casablanca

+0

Вызывается функция выключения, но я не уверен, что/как я могу получить контекст exit/die в этой точке. Если уж на то пошло, было неясно, могу ли я даже знать, является ли выход/смерть причиной вызванной функции выключения. (похоже, что функция shutdown вызывается на die, но она вызывается, когда процесс завершается после успешного запуска ...) –

5

Может override_function() может быть интересно, если APD доступен

+0

Это интересная идея! Надеюсь на лучшее решение, отличное от APD. –

+0

Я не думаю, что это сработает. 'die' и' exit' - это языковые конструкции, а не функции. –

-2

да: написать функцию и использовать вместо.

function kill($msg){ 
    // Do your logging.. 
    exit($msg); 
} 
+7

Я ценю ответ, но это совсем не полезно. Я хочу поймать exit() и die() в случае, если какой-то код, который я не написал, называет их. –

+0

Я знаю, но это самое близкое к вам, просто одна новая функция и простой поиск и замена из exit и die to kill. –

0

Почему бы не использовать специальную обработку ошибок вместо этого? Если нет, вы всегда можете использовать LD_PRELOAD и C Code injection, чтобы поймать его :) Или перекомпилируйте php с настройками: P

7

Да, вы можете, но вам нужно ob_start, ob_get_contents, ob_end_clean и register_shutdown_function

function onDie(){ 
    $message = ob_get_contents(); // Capture 'Doh' 
    ob_end_clean(); // Cleans output buffer 
    callWhateverYouWant(); 
} 
register_shutdown_function('onDie'); 
//... 
ob_start(); // You need this to turn on output buffering before using die/exit 
@$dumbVar = 1000/0 or die('Doh'); // "@" prevent warning/error from php 
//... 
ob_end_clean(); // Remember clean your buffer before you need to use echo/print 
0

Если вы используете одну точку входа метода. (Index.php), я могу рекомендовать для обработки ошибок:

Короткая версия:

ob_start(); 
register_shutdown_function('shutdownHandler'); 

include('something'); 

define(CLEAN_EXIT, true); 

function shutdownHandler() { 
    if(!defined("CLEAN_EXIT") || !CLEAN_EXIT) { 
     $msg = "Script stopped unexpectedly: ".ob_get_contents(); 
     //Handle premature die()/exit() here 
    } 
} 

Дополнительные шаги и детальнее:

Грубо мой способ сделать это. Я еще больше занимаюсь тем, что я показываю здесь (обработка транзакций базы данных/откат/отправка электронной почты/запись журналов/отображение дружественных сообщений об ошибках/сообщений об ошибках пользователей и т. Д.), Но это основная идея всего этого).
Надеюсь, это поможет кому-то.

<?php 

    //Some initialization 

    //starting output buffering. (fatalErrorHandler is optional, but I recommend using it) 
    ob_start('fatalErrorHandler'); 

    //Execute code right at the end. Catch exit() and die() here. But also all other terminations inside PHPs control 
    register_shutdown_function('shutdownHandler'); 

    //handling other errors: Also optional 
    set_error_handler('errorHandler'); 



    try { 
     //Include of offensive code 
     include(...); 
    } 
    catch (Exception $ex) { 
     //Handling exception. Be careful to not raise exceptions here again. As you can end up in a cycle. 
    } 

    //Code reached this point, so it was a clean exit. 
    define(CLEAN_EXIT, true); 


    //Gets called when the script engine shuts down. 
    function shutdownHandler() { 

     $status = connection_status(); 

     $statusText = ""; 

     switch ($status) { 
      case 0: 
       if (!defined("CLEAN_EXIT") || !CLEAN_EXIT) { 
            $msg = "Script stopped unexpectedly: ".ob_get_contents(); 
        //Handle premature die()/exit() here 
       } 
       else { 
        //Clean exit. Just return 
        return; 
       } 
      case 1: $statusText = "ABORTED (1)"; break; 
      case 2: $statusText = "TIMEOUT (2)"; break; 
      case 3: $statusText = "ABORTED & TIMEOUT (3)"; break; 

      default : $statusText = "UNKNOWN ($status)"; break; 
     } 

     //Handle other exit variants saved in $statusText here 
    } 

    // error handler function (This is optional in your case) 
    function errorHandler($errno, $errstr, $errfile, $errline) { 

     $msg = "[$errno] $errstr\nOn line $errline in file $errfile"; 

     switch ($errno) { 
      case E_ERROR:    $msg = "[E_ERROR] ".$msg;    break; 
      case E_WARNING:    $msg = "[E_WARNING] ".$msg;    break; 
      case E_PARSE:    $msg = "[E_PARSE] ".$msg;    break; 
      case E_NOTICE:    $msg = "[E_NOTICE] ".$msg;    break; 
      case E_CORE_ERROR:   $msg = "[E_CORE_ERROR] ".$msg;   break; 
      case E_CORE_WARNING:  $msg = "[E_CORE_WARNING] ".$msg;  break; 
      case E_COMPILE_ERROR:  $msg = "[E_COMPILE_ERROR] ".$msg;  break; 
      case E_COMPILE_WARNING:  $msg = "[E_COMPILE_WARNING] ".$msg;  break; 
      case E_USER_ERROR:   $msg = "[E_USER_ERROR] ".$msg;   break; 
      case E_USER_WARNING:  $msg = "[E_USER_WARNING] ".$msg;  break; 
      case E_USER_NOTICE:   $msg = "[E_USER_NOTICE] ".$msg;   break; 
      case E_STRICT:    $msg = "[E_STRICT] ".$msg;    break; 
      case E_RECOVERABLE_ERROR: $msg = "[E_RECOVERABLE_ERROR] ".$msg; break; 
      case E_DEPRECATED:   $msg = "[E_DEPRECIATED] ".$msg;   break; 
      case E_USER_DEPRICIATED: $msg = "[E_USER_DEPRICIATED] ".$msg; break; 
      default:     $msg = "[UNKNOWN] ".$msg;    break; 
     } 

     //Handle Normal error/notice/warning here. 
     $handled = ... 

     if ($handled) 
      return true; //handled. Proceed execution 
     else 
      throw Exception($msg); //Be careful. this might quickly become cyclic. Be sure to have code that catches and handles exceptions. Else die() here after logging/reporting the error. 

    } 

    function fatalErrorHandler(&$buffer) { 

     $matches = null; 
     //Checking if the output contains a fatal error 
     if (preg_match('/<br \/>\s*<b>([^<>].*)error<\/b>:(.*)<br \/>$/', $buffer, $matches)) { 

      $msg = preg_replace('/<.*?>/','',$matches[2]); 

      //Handle Fatal error here 

      return "There was an unexpected situation that resulted in an error. We have been informed and will look into it." 
     } 

     //No fatal exception. Return buffer and continue 
     return $buffer; 
    } 
Смежные вопросы