Skip fatal error php

Как обрабатывать Fatal Error в PHP

В одном из наших проектов (социальная генеалогическая сеть), о котором я писал в данном топике, мы используем очередь отложенных событий, реализованную на мемкеше. Ее архитектура такова: приложение записывает в эту очередь различные события и данные, относящиеся к ним (тип события, входящие параметры, и функция обработчик этого события). После чего менеджер(-ы) очереди разбирают эту очередь и выполняют отложенные события. В частности такая очередь используется для сбора статистики, но также и для других более критичных к выполнению задач.
Поэтому очень важно обеспечить high availability для менеджера(-ов) очереди.

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

Для треккинга процессов (демонов), очень удобно пользоваться наблюдателями за процессами, такими как monit, мы используем monit для мониторинга сисстемных демонов. Кстати, на хабре недавно была статья о моните.
Но речь не о нем 🙂

Я попросил одного из разработчиков моей команды сделать нормальный обработчик фатальной ошибки в коде менеджера очереди, а именно форк нового инстанса обработчика и логирование ошибки по типу события. На это я получил ответ, что в php фатальные ошибки обрабатывать в принципе невозможно и позорно об этом не знать и что: «компьютерные науки на текущем этапе своего эволюционного развития еще не располагают алгоритмами способными решить поставленную задачу опираясь на возможности php коректно. »

Читайте также:  Python tkinter frame атрибуты

После этого я написал такой код, который обрабатывает фатальные, а также все другие ошибки в php приложении. Если кому-то еще он поможет, то я буду только рад.

ini_set( «display_errors» , «on» );
error_reporting(E_ALL);
ini_set( ‘html_errors’ , ‘on’ );

function fatal_error_handler($buffer) if (preg_match( «|(Fatal error:)(.+)( file_put_contents( «php://stderr» , «before fork (pid: » . getmypid() . «)\n» );
system( «php tester.php » . getmypid() . » &» );
return «ERROR CAUGHT, check log file» ;
>
return $buffer;
>

//code between ob_start and ob_end_flush is included by MQ Handler, so we know nothing about it, and this code could fire a Fatal Error
if (isset($_SERVER[ «argv» ][1])) file_put_contents( «php://stderr» , «kill : » .var_export(posix_kill($_SERVER[ ‘argv’ ][1], 15), true ). «\n» );
>
ob_start( «fatal_error_handler» );
set_error_handler( «handle_error» );

while ( true ) //Just a Warning
//$a = 9/0;
sleep(10);
file_put_contents( «php://stderr» , «live\n» );
//Fatal error — вызов необъявленной ф-ии
if (rand(1,10) % 2 == 1) ololo(123);
>
>

echo «Program still executing. » ;

* This source code was highlighted with Source Code Highlighter .

Небольшое объяснение по текущему коду.
Fatal Error — мы ловим через буферизацию вывода в ф-ии fatal_error_handler
Остальные ошибки (все кроме фатальных) обрабатываются ф-ией handle_error
Если ошибок нет — код выполняется нормально 🙂

Да, это также не является единственным средством high availability и отказоустойчивости.
Мы пытаемся запустить демон каждую минуту по крону, а код демона начинается ф-ией

if (!checkSingleProcess()) exit;
>

function checkSingleProcess() $res = exec( ‘ps aux | grep mq_manager.php | grep -v grep | grep -v ‘ .getmypid(), $output, $ return );
return $output == array();
>

* This source code was highlighted with Source Code Highlighter .

т.е. если демон запущен, то мы прекращаем выполнение.

Открыт ко всем мнения и по возможности буду отвечать на все комментарии.

UPD: обратите внимание на ini_set(‘html_errors’, ‘on’); я потратил с пол часа времени не понимая почему обработчик не работает из-под CLI. Дело было как раз в HTML-ных ошибках. Т.к. из-под CLI они давались без HTML тегов, и условие preg_match(«|(Fatal error:)(.+)(

UUPD: Немного обновил код, дело в том, что форкая новый процесс через ф-ию system нужно позаботиться о том, чтобы убить процесс который форкал текущий, т.к. функция обработчик будет ждать результата выполнении ф-ии system, а он как извесно не вернется, ведь мы же создаем демона, в связи с этим вы получите кучу процессов, висящих в памяти, которые в конце концов забьют ее полностью.

Источник

Как убрать вывод фатальной ошибки в php?

Решил заняться системой ошибок, настроить логирование exception’ов и накинуть обработчик на E_* ошибки. В случае с не фатальными ошибками всё хорошо, но словить ошибки типа E_ERROR | E_PARSE не получается, а хотелось бы. В общем, нашел подходящую статью на хабре, скопировал весь код и вставил в самом верху документа. Убрал «;» в одной из строчек, но Parse error как была, так и осталась. Код страницы

/** * Обработчик ошибок * @param int $errno уровень ошибки * @param string $errstr сообщение об ошибке * @param string $errfile имя файла, в котором произошла ошибка * @param int $errline номер строки, в которой произошла ошибка * @return boolean */ function error_handler($errno, $errstr, $errfile, $errline) < // если ошибка попадает в отчет (при использовании оператора "@" error_reporting() вернет 0) if (error_reporting() & $errno) < $errors = array( E_ERROR =>'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE', E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING', E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING', E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING', E_USER_NOTICE => 'E_USER_NOTICE', E_STRICT => 'E_STRICT', E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', E_DEPRECATED => 'E_DEPRECATED', E_USER_DEPRECATED => 'E_USER_DEPRECATED', ); // выводим свое сообщение об ошибке echo " [$errno] $errstr ($errfile на $errline строке)
\n"; > // не запускаем внутренний обработчик ошибок PHP return TRUE; > /** * Функция перехвата фатальных ошибок */ function fatal_error_handler() < // если была ошибка и она фатальна if ($error = error_get_last() AND $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR)) < // очищаем буффер (не выводим стандартное сообщение об ошибке) ob_end_clean(); // запускаем обработчик ошибок error_handler($error['type'], $error['message'], $error['file'], $error['line']); >else < // отправка (вывод) буфера и его отключение ob_end_flush(); >> // определеяем уровень протоколирования ошибок error_reporting(E_ALL | E_STRICT); // определяем режим вывода ошибок ini_set('display_errors', 'On'); // включаем буфферизацию вывода (вывод скрипта сохраняется во внутреннем буфере) ob_start(); // устанавливаем пользовательский обработчик ошибок set_error_handler("error_handler"); // регистрируем функцию, которая выполняется после завершения работы скрипта (например, после фатальной ошибки) register_shutdown_function('fatal_error_handler'); echo 1

Источник

Есть ли способ пропустить фатальную ошибку из файла include в php?

Если я включаю файл в php. Если в этом php есть какая-то фатальная ошибка, есть ли способ пропустить это.

Мне нужно включить этот файл somefile.php. Он может вернуть фатальную ошибку для некоторых хостов. Я хочу пропустить этот файл для этого хоста.

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

function my_continuation_func($filename, $arg2) < // On fatal error during include, continue script execution from here. // When this function ends, or if another fatal error occurs, // the execution will stop. >include_try('my_continuation_func', array($filename, $arg2)); $data = include($filename); $error = include_catch(); 

Если возникает фатальная ошибка (например, ошибка синтаксического анализа), выполнение script будет продолжено с my_continuation_func() . В противном случае include_catch() возвращает true , если во время разбора произошла ошибка.

Любой вывод (например, echo ‘something’; ) из include() рассматривается как ошибка. Если вы не включили вывод, передав true в качестве третьего аргумента include_try() .

Этот код автоматически позаботится о возможных изменениях рабочего каталога в функции выключения.

Вы можете использовать это для любого количества включений, но вторая фатальная ошибка, которая возникает, не может быть перехвачена: выполнение остановится.

Функции, которые необходимо включить:

function include_try($cont_func, $cont_param_arr, $output = false) < // Setup shutdown function: static $run = 0; if($run++ === 0) register_shutdown_function('include_shutdown_handler'); // If output is not allowed, capture it: if(!$output) ob_start(); // Reset error_get_last(): @user_error('error_get_last mark'); // Enable shutdown handler and store parameters: $params = array($cont_func, $cont_param_arr, $output, getcwd()) $GLOBALS['_include_shutdown_handler'] = $params; >function include_catch() < $error_get_last = error_get_last(); $output = $GLOBALS['_include_shutdown_handler'][2]; // Disable shutdown handler: $GLOBALS['_include_shutdown_handler'] = NULL; // Check unauthorized outputs or if an error occured: return ($output ? false : ob_get_clean() !== '') || $error_get_last['message'] !== 'error_get_last mark'; >function include_shutdown_handler() < $func = $GLOBALS['_include_shutdown_handler']; if($func !== NULL) < // Cleanup: include_catch(); // Fix potentially wrong working directory: chdir($func[3]); // Call continuation function: call_user_func_array($func[0], $func[1]); >> 

Fatal означает смертельный…
Невозможно оправиться от фатальной ошибки.

PHP не будет терпеть с Fatal Errors. Лучше всего проверить включенный файл и решить его.
На самом деле вы можете попробовать register-shutdown-function, но не рекомендуется убегать от ваших проблем.

 register_shutdown_function(function () < $error = error_get_last(); // to make sure that there is any fatal error if (isset($error) && ($error['type'] == E_ERROR || $error['type'] == E_PARSE || $error['type'] == E_COMPILE_ERROR || $error['type'] == E_CORE_ERROR)) < echoOk(); >>); include "somefile.php"; echoOk(); 

Но вы можете сделать это только один раз. Любая дальнейшая фатальная ошибка прекратит выполнение.

edit: я пропустил слово со смертельным исходом. Как уже говорилось, вы не можете восстановить фатальную ошибку. Если это всего лишь исключение, то будет работать поспешный ответ ниже.

Включение другого php-модуля совпадает с тем, что этот код вставлен в строку, поэтому простой оператор try-catch должен работать:

 catch (Exception $e) < echo 'Caught exception: ', $e->getMessage(), "\n"; > echo "OK"; ?> 

Попробуйте установить функцию set_error_handler(), которая не умирает от фатальных ошибок, но вместо этого Apache разбился. Другими словами, PHP должен умереть, так что система не работает.

Неустранимая ошибка означает, что что-то серьезно не так с кодом включения. Как сказал @Orangepill, нет способа остановить это фатальное сообщение об ошибке. Пожалуйста, просмотрите свое кодирование и найдите ошибку.

Да, есть. Это можно сделать с помощью простого оператора if

Источник

Оцените статью