Php fatal error

45. Про перехват и обработку фатальных ошибок (Fatal Error) в PHP

Принято ошибочно считать, что фатальные ошибки в PHP (те, что отображаются как Fatal Error) невозможно перехватить и обработать программно. Действительно, в PHP имеется функция set_error_handler(), позволяющая программисту назначить свою собственную функцию-обработчик на нотисы (NOTICE) и предупреждения (WARNING), однако она не может перехватить управление при наступлении фатальной ошибки — например, вызове неопределенной функции:

скопировать код в буфер обмена

Листинг 1

function myErrorHandler($errno, $errstr, $errfile, $errline) { echo «Error $errno happened! $errstr on $errfile line $errline»; return true; } // Set an error handler for warnings and notices. set_error_handler(‘myErrorHandler’); // Generate a notice. echo $nonExistedVariable; // Generate a fatal error. callToUndefinedFunction();

Запустив этот пример, вы увидите, что перехватчик myErrorHandler() вызвался для первой ошибки (NOTICE), но вторая ошибка (ERROR) не была им обработана, а отобразилась в браузере в стандартном виде.

 

Написано в 2009 году (касается новых версий PHP):
  — Кстати, функция-финализатор, назначенная вызовом register_shutdown_function, прекрасно вызывается в случае фатальной ошибки.
Написано в 2007 году (касается старых версий PHP):
  — Кстати, назначенные по register_shutdown_function функции-финализаторы скрипта не вызываются при наступлении фатальной ошибки.

Тем не менее, способ вызвать PHP-код при наступлении фатальной ошибки все же существует. Для этого следует назначить обработчик выходного потока через ob_start() — он будет вызван в любом случае, даже если программа завершилась аварийно:

скопировать код в буфер обмена

Листинг 2

function myObHandler($str) { return $str . » — output is handled!»; } // Handle the output stream and set a handler function. ob_start(‘myObHandler’); // Generate a fatal error. callToUndefinedFunction();

Вы увидите, что PHP отобразил стандартное сообщение об ошибке, но к нему в конец было приписано » — output is handled!», т.е. наш обработчик сработал.

 

В разделе сайта Кoнструктор имеется библиотека PHP_CodeFilter, упрощающая перехват ошибок по описанному алгоритму, а также позволяющая делать еще некоторые вещи.

Перехват ошибки нехватки памяти

Метод с ob_start() может иногда не сработать, если произошедшая фатальная ошибка — это ошибка нехватки памяти («Allowed memory size of xxx bytes exhausted»). Она возникает, когда PHP пытается затребовать больше памяти, чем ему разрешено настройкой memory_limit файла php.ini.

К счастью, выход есть и в этом случае (правда, он работает не в 100% ситуаций, а только если память выделяется относительно большими кусками):

скопировать код в буфер обмена

Листинг 3

function myObHandler($str) { // Free a piece of memory. unset($GLOBALS[‘tmp_buf’]); // Now we have additional 100K of memory, so — continue to work. return $str . » — output is handled!»; } // Reserve 200K of memory for emergency needs. $GLOBALS[‘tmp_buf’] = str_repeat(‘x’, 1024 * 200); // Handle the output stream and set a handler function. ob_start(‘myObHandler’); // Simulate a memory limit error. echo str_repeat(«Test string!<br>», 500); while(1) $tmp[] = str_repeat(‘a’, 10000);

Итак, мы резервируем некоторый объем памяти во временной переменной, которую освобождаем в первой строке обработчика выходного потока. При этом высвобождается некоторое количество памяти, которого должно хватить на корректное продолжение работы обработчика (он сам по себе может потреблять сколько-то памяти).

Таким образом, можно сделать следующее заключение: при наступлении ошибки memory_limit PHP честно пытается запустить обработчик, однако, если в процессе его работы опять не хватит памяти, выполнение скрипта останавливается уже окончательно. Освободив 200К памяти в самом начале обработчика, мы оказываемся практически застрахованными от такой ситуации.

 

Нужно понимать, что этот метод работает при условии, что память закончилась при выделении достаточно крупного куска (в нашем случае — 10К). В противном случае PHP может не хватить ресурсов даже на то, чтобы просто инициировать запуск обработчика выходного потока.

обсудить статью в форуме

Три способа решения проблемы «Fatal error: Allowed memory size of XXX bytes exhausted»

Что означает «Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate …..»

Allowed memory, лимит памяти, memory_limit, php.ini, htaccess, ошибки

Опубликовал admin, 16-10-2009, 18:19 | | Печать

Очень часто новички в веб строении сталкиваются с проблемами работы скриптов бесплатных и платных.

Сейчас расскажу как побороть ошибку «Fatal error: Allowed memory size of ….»

Примерно она такого вида:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 2298 bytes) in /home/username/public_html/administrator/components/com_virtuemart/classes/class.img2thumb.php on line 151

Эта ошибка взята из скрипта Joomla.

Что это означает ?

Эта ошибка означает, что ваш скрипт (а в контексте Joomla это или сама система или один из ее элементов) для выполнения требует памяти больше, чем разрешено в настройках PHP на сервере хостера. Т.е. запрашиваемое значение превышает максимальное количество оперативной памяти предоставляемого пользовательскому аккаунту виртуальным хостингом. На разных хостингах это значение может отличаться.

Чаще всего данная ошибка возникает в файле /includes/domit/xml_domit_parser.php при обработке xml-файлов (например при просмотре списка компонентов, модулей или мамботов.

Если у вас возникает такая проблема, то можно сделать следующее:

1. Попробовать самостоятельно изменить это значение, добавив в самое начала index.php (расположенного в корне сайта) следующие строчки:

<?php ini_set("memory_limit", "32M"); ?>

это если хостер не отключил поддержку ini_set в настройках сервера

2. Положить в корень сайта файл .htaccess следующего содержания:

Код:

php_value memory_limit 32M

лимит можно изменять самостоятельно, можно поставить и 64M но не наглеть 🙂

Если же такой файл уже есть в корне сайта — просто добавьте в него приведенную выше строку.

Если у хостера PHP работает ка PHP-CGI через suPHP, то это может вызвать ошибку 500, значить использовать директивы php_flag, php_value в файле .htaccess невозможно!

3. Некоторые хостеры поддерживают работу php.ini у клиента, т.е. вы можете самостоятельно делать свои настройки PHP для своей учетной записи.

а значить создайте файл php.ini в корне сайта

и добавте следующий код:

memory_limit = 32M

4. Если это не помогло — обратитесь к администратору хостинга и попросите увеличить количество доступной памяти для PHP.

Chassis intruded! Please check your system Fatal Error… System Halted

На неделе реанимировал сервак на платформе ASUS, простоявший без дела довольно продолжительно время. При включении он вывалил мне на экран сообщение об ошибке Chassis intruded! Please check your system. Fatal Error… System Halted и отказался дальше загружаться.

В некоторые материнские платы встроена специальная защита от вскрытия корпуса.

Если она активирована и открыть корпус системного блока, то при перезагрузке компьютера на экран будет выводиться соответствующее сообщение и дальнейшая загрузка операционной системы блокируется.

Подобная защита, чаще всего встречается на материнских платах производства ASUS и не всегда корректно работает (судя по комментариям в сети) — бывают случаи самопроизвольного срабатывания.

Перехват fatal error или Перехват неперехватываемых ошибок

В ASUS о проблеме знают и выпущены соотвествующие обновления BIOS.

Для начала можно попытаться исправить ситуацию, отключив режим мониторинга вскрытия корпуса в BIOS (ищем что-то типа BIOS Chassis Intrusion, Case Open Warning, Intruder Detection). Следует заметить, что таких опций может и не быть вовсе, в этом случае можно попытаться сбросит настройки BIOS в настройки по умолчанию.

Если заблокирована и сама возможность войти в BIOS или нужных опций в нем найти не удалось (мой случай), остается вскрывать корпус и сверившись с документацией к материнской плате, отключить данную проверку вручную, с помощью джампера CHASSIS (обычно так называется). У меня в сервере действительно стоял датчик открытия корпуса (по всей видимости уже не рабочий), который я благополучно заменил перемычкой на материнской плате.

Если вообще ничего не помогло, остается прибегнуть к аппаратному сбросу установок BIOS, или совсем уж крайней мере — перепрошивке BIOS. Замечу, что на серверных платформах, аппаратный сброс настроек BIOS может несколько отличаться от домашних компьютеров, сверьтесь с документацией.

Если считаете статью полезной,
не ленитесь ставить лайки и делиться с друзьями.

Ошибки в PHP. Ликбез


Неотъемлемой частью программирования является выявление ошибок в коде. Будь программист хоть семь пядей во лбу, все равно, он будет совершать ошибки, иногда даже банальные. Этому способствует сама природа человека. Поэтому за отладкой и выявлением ошибок в коде программист проводит достаточно большую часть времени. Соответственно, чем гибче и удобнее существуют инструменты для выявления ошибок в коде, и чем лучше программист ими владеет, — тем выше его продуктивность.

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

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

Стандартный механизм ошибок PHP довольно прост – если в процессе выполнения сценария интерпретатор PHP сталкивается с какой-либо ошибкой – он пытается известить об этом программиста. Однако настроек этого механизма предусмотрено довольно много, поэтому разобраться в них программисту, познающему PHP, довольно сложно.

Видим ошибки

Так, для того, чтобы PHP отображал ошибки прямо на странице, необходимо установить специальный параметр в коде:

ini_set(‘display_errors’, 1); //display_errors отвечает за отображение ошибок прямиком на странице. Если 0 – ошибки не отображаются

Теперь, при возникновении какой-либо ошибки в скрипте, интерпретатор выведет информацию о ней на странице. Например, если запустить скрипт с несуществующей функцией:

ini_set(‘display_errors’, 1);
echo «

Строка, которая будет отображена

«;
echo abrakadabra();
echo «

Строка, которая не будет отображена из-за ошибки

«;

то на странице отобразится такая ошибка:

Фатальная ошибка. Такого рода ошибка означает, что скрипт прерывает свою работу, и далее идущий код не будет выполнен.

Отображение ошибок скрипта на странице используется только для отладки самого скрипта, поэтому при запуске кода в боевой среде параметру display_errors устанавливают значение 0.

Категории ошибок

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

Значение Константа Описание Возможность
1 E_ERROR Неустранимая ошибка Нет
2 E_WARNING Исправимая ошибка Да
4 E_PARSE Ошибка парсера Нет
8 E_NOTICE Потенциальная ошибка Да
16 E_CORE_ERROR Аналогично E_ERROR, но генерируется ядром PHP Нет
32 E_CORE_WARNING Аналогично E_WARNING, но генерируется ядром PHP Нет
64 E_COMPILE_ERROR Аналогично E_ERROR, но генерируется Zend Engine Нет
128 E_COMPILE_WARNING Аналогично E_WARNING, но генерируется Zend Engine Нет
256 E_USER_ERROR Аналогично E_ERROR, но инициируется вызовом trigger_error() Да
512 E_USER_WARNING Аналогично E_WARNING, но инициируется вызовом trigger_error() Да
1024 E_USER_NOTICE Аналогично E_NOTICE, но инициируется вызовом trigger_error() Да
2048 E_STRICT Сообщение от исполнительной среды с рекомендациями по улучшению качества кода (начиная с PHP5)
4096 E_RECOVERABLE_ERROR Опасная, но не фатальная ошибка(например, несоответствие типа) Да
8192 E_DEPRECATED Предупреждение об использовании устаревшей функции или возможности Да
16384 E_USER_DEPRECATED Предупреждение об использовании устаревшей функции или возможности, инициированное в коде Да
32767 E_ALL Все ошибки Нет

Для удобства предусмотрены константы, которые используются для определения уровня обработки ошибок, построения бит-маски.

Константы имеют «говорящие» имена. Глядя на константу — мы можем сказать, что ошибка уровня E_PARSE возникает в случае синтаксической ошибки, E_NOTICE — это напоминание программисту о нарушении «хорошего стиля» программирования на PHP.

По умолчанию включено значение режима генерации сообщений об ошибках E_ALL & ~E_NOTICE, что соответствует выводу всех сообщений, не относящихся к категории E_NOTICE.

Программист может гибко настроить, какие категории ошибок ему необходимо видеть на странице. Для того, чтобы изменить режим генерации ошибок, необходимо изменить конфигурационный параметр error_reporting. Чтобы включить отображение любых ошибок, необходимо задать данному параметру значение E_ALL:

ini_set(‘error_reporting’, E_ALL);

Например, если запустить следующий код:

ini_set(‘display_errors’, 1);
ini_set(‘error_reporting’, E_ALL);
$db = mysql_connect($db_host, ‘user’, ‘password’);

Мы получим ошибки сразу двух категорий (notice и warning):

Когда используется необъявленная переменная – появляется ошибка E_NOTICE. Когда соединение с базой данных MySQL (или другой) завершается неудачей — интерпретатор PHP сообщает об ошибке уровня E_WARNING.

Логируем ошибки

Если даже конфигурационный параметр display_errors установлен в 0, все равно должна быть возможность просматривать наличие случившихся ошибок в процессе выполнения скрипта. Таким образом, в случае если случится ошибка – мы должны знать, где и почему она случилась. Для этих целей в PHP существуют настройки логирования ошибок.

По умолчанию средствами языка PHP ошибки нигде не логируются. Чтобы это изменить, необходимо изменить конфигурационный параметр log_errors в 1 с 0:

ini_set(‘log_errors’, 1);

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

ini_set(‘error_log’, ‘/var/log/php_errors.log’);

Так, для кода:

ini_set(‘display_errors’, 1);
ini_set(‘error_reporting’, E_ALL);
ini_set(‘log_errors’, 1);
ini_set(‘error_log’, __DIR__ .

Как поймать фатальную ошибку PHP

‘/log.txt’);
$db = mysql_connect($db_host, ‘user’, ‘password’);

В лог-файл записывается аналогичная информация, которая выводится на страницу:

[15-Jun-2016 22:47:58] PHP Notice: Undefined variable: db_host in Z:\home\test\www\index.php on line 7
[15-Jun-2016 22:47:58] PHP Warning: mysql_connect(): Access denied for user ‘user’@’localhost’ (using password: YES) in Z:\home\test\www\index.php on line 7

Обрабатываем ошибки

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

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

Для того, чтобы перехватывать некритические ошибки в коде, достаточно реализовать и объявить собственную функцию и передать ее название в функцию set_error_handler. При этом, в реализованную функцию передаются 5 параметров:

  • уровень ошибки в виде целого числа;
  • сообщение об ошибки в виде строки;
  • имя файла, в котором произошла ошибка, в виде строки;
  • номер строки, в которой произошла ошибка, в виде целого числа;
  • массив всех переменных, существующих в области видимости, где произошла ошибка. Причем, будут включены также и глобальные переменные.

Рассмотрим простой код:

ini_set(‘display_errors’, 0);
ini_set(‘error_reporting’, E_ALL);

// объявляем нашу функцию обработки ошибок
function customErrorHandler($errno, $errstr, $errfile, $errline, $variables){
echo «Сторонняя ошибка: [$errno] $errstr
«;
echo » Ошибка на строке: $errline; в файле: $errfile
«;
}

// устанавливаем нашу функцию обработки ошибок
set_error_handler(«customErrorHandler»);

$db = mysql_connect($db_host, ‘user’, ‘password’); // тут будут ошибки

На странице получим следующее:

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

Сами генерируем ошибки

Программист может генерировать следующие категории ошибок — E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE. Другие ошибки генерировать не получится. Для этого существует функция trigger_error() — с её помощью, программист может сообщать пользователю о происшествии так, как это делает PHP.

Как известно из руководства по PHP — функция trigger_error() принимает два параметра:

void trigger_error ( string error_msg [, int error_type])

Первый параметр — текстовое сообщение об ошибке, например, «файл не найден». Второй параметр — определяет уровень ошибки(по умолчанию будет E_USER_NOTICE) .

Пример:

ini_set(‘display_errors’, 1);
ini_set(‘error_reporting’, E_ALL);

if (!file_exists(‘/home/mysite/news.txt’)) {
trigger_error(‘News file not found’);
}

В результате получим:

Вывод

PHP имеет мощные средства обработки и управления стандартным распространением ошибок. Поэтому отловить ту или иную ошибку не составит труда при условии, что скрипт грамотно сконфигурирован. Знания этой области является неотъемлемыми любого PHP-программиста, поскольку множество кода использует описанный выше механизм

Категория: PHP

 17 июня 2016 г. 0:38

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *