",); $html = str_replace($search, $replace, $html); $dom = new DOMDocument(); $dom->loadHTML($html);
Часто слышал о такой проблеме от других пользователей. Одним из-за хостера нужно скрыть появляющиеся ошибки, другим наоборот - понять, что происходит с их кодом, потому что ни одна ошибка не показывается. В этой статье постараюсь показать все основные способы отобразить / скрыть ошибки.
В скрипте PHP
1)
В PHP есть всего лишь один оператор, который поддерживает систему управления ошибками - это
знак @
. Он позволяет проигнорировать сообщение любое сообщение об ошибке. Его нужно ставить ПЕРЕД выражением, которое может её содержать.
В примере специально допущена ошибка, но она НЕ будет отображена
$value = @$var[$key];
2)
Также можно перед проверяемым скриптом PHP можно вставить настройку параметра отображения ошибок (display_errors
). Он может приобретать значение либо On (показывать), либо Off (скрыть).
Ini_set("display_errors","On");
error_reporting("E_ALL");
И соответственно после кода, который проверялся на ошибки, выставить параметр обратно.
Ini_set("display_errors","Off");
Например, Вы хотите увидеть ошибки в скрипте
Ini_set("display_errors", "On"); // сообщения с ошибками будут показываться
error_reporting(E_ALL); // E_ALL - отображаем ВСЕ ошибки
$value = $var[$key]; // пример ошибки
ini_set("display_errors", "Off"); // теперь сообщений НЕ будет
Можно выставить наоборот (в верхнем off, а в нижнем on), чтобы в конкретном отрезке кода ошибки НЕ отображались.
В файле.htaccess
Чаще всего проблему решают именно указанием настроек в файле
.htaccess
, который располагается в корневой директории сайта. В строке php_flag display_errors нужно также выставить On или Off
Php_flag display_errors On
#показать все ошибки кроме предупреждений (Notice)
php_value error_reporting "E_ALL & ~E_NOTICE"
В файле php.ini
Как видите, параметр можно указать в нескольких местах. Однако, если у Вы хотите, чтобы целиком на сайте этот параметр имел определённое значение, то проще выставить его в файле php.ini.(к нему на хостинге не всегда может быть доступ), но в этом случае можно будет даже обойти настройки всего хостинга
В php.ini
:
Error_reporting = E_ALL
display_errors On
В верхней строке выбираем все виды ошибок, в нижней даём добро на их отображение.
После правок необходимо перезапустить Apache, чтобы настройки были изменены и вступили в силу (graceful или restart):
Sudo apachectl -k graceful
В каком порядке обрабатывается параметр ошибок
В самом начале учитывается параметр php.ini , затем.htaccess , а после то, что указано непосредственно в скрипте PHP. Так что если что-то не сработало, то смотрим по цепочку выше, возможно, там настройка другая.
Как обычно спасибо за внимание и удачи! Надеюсь статья была полезна!
PHP поддерживает один оператор управления ошибками: знак @.
В случае, если он предшествует какому-либо выражению в PHP-коде, любые
сообщения об ошибках, генерируемые этим выражением, будут проигнорированы.
Если вы установили собственную функцию обработки ошибок с помощью
set_error_handler()
, то она все равно будет вызвана,
однако, если внутри этой функции будет вызвана функция
error_reporting()
, то она вернет 0, если функция,
вызвавшая данную ошибку, была подавлена с помощью @.
В случае, если установлена опция track_errors
,
все генерируемые сообщения об ошибках будут сохраняться в переменной
$php_errormsg .
Эта переменная будет перезаписываться при каждой новой ошибке,
поэтому в случае необходимости проверяйте ее сразу же.
// Преднамеренная ошибка при работе с файлами
$my_file
= @
file
("non_existent_file"
) or
die ("Ошибка при открытии файла: сообщение об ошибке было таким: "
$php_errormsg
""
);
// работает для любых выражений, а не только для функций
$value
= @
$cache
[
$key
];
// В случае если ключа $key нет, сообщение об ошибке (notice) не будет отображено
?>
Замечание
:
Оператор @ работает только с
выражениями .
Есть простое правило: если что-то возвращает
значение, значит вы можете использовать перед ним оператор
@. Например, вы можете использовать @ перед
именем переменной, произвольной функцией или вызовом include
,
константой и так далее. В то же время вы не можете использовать этот оператор
перед определением функции или класса, условными конструкциями, такими как if
,
foreach и т.д.
Также ознакомьтесь с описанием функции error_reporting()
и разделом руководства
Обработка ошибок и функции логирования .
Внимание
На сегодняшний день оператор "@" подавляет вывод сообщений даже о критических
ошибках, прерывающих работу скрипта. Помимо всего прочего, это означает, что если вы
использовали "@" для подавления ошибок, возникающих при работе какой-либо
функции, в случае если она недоступна или написана неправильно, дальнейшая
работа скрипта будет остановлена без каких-либо уведомлений.
12 years ago
To suppress errors for a new class/object:
// Tested: PHP 5.1.2 ~ 2006-10-13
// Typical Example
$var
= @
some_function
();
// Class/Object Example
$var
= @new
some_class
();
// Does NOT Work!
//$var = new @some_class(); // syntax error
?>
I found this most useful when connecting to a
database, where i wanted to control the errors
and warnings displayed to the client, while still
using the class style of access.
14 years ago
Better use the function trigger_error() ()
to display defined notices, warnings and errors than check the error level your self. this lets you write messages to logfiles if defined in the php.ini, output
messages in dependency to the error_reporting() level and suppress output using the @-sign.
8 years ago
If you use the ErrorException exception to have a unified error management, I"ll advise you to test against error_reporting in the error handler, not in the exception handler as you might encounter some headaches like blank pages as error_reporting might not be transmitted to exception handler.
{
}
function
catchException
($e
)
{
{
return;
}
// Do some stuff
}
?>
It would be better to do:
Function
exception_error_handler
($errno
,
$errstr
,
$errfile
,
$errline
)
{
if (error_reporting
() ===
0
)
{
return;
}
Throw new
ErrorException
($errstr
,
0
,
$errno
,
$errfile
,
$errline
);
}
Set_error_handler
("exception_error_handler"
);
function
catchException
($e
)
{
// Do some stuff
}
Set_exception_handler
("catchException"
);
?>
4 years ago
While you should definitely not be too liberal with the @ operator, I also disagree with people who claim it"s the ultimate sin.
For example, a very reasonable use is to suppress the notice-level error generated by parse_ini_file() if you know the .ini file may be missing.
In my case getting the FALSE return value was enough to handle that situation, but I didn"t want notice errors being output by my API.
TL;DR: Use it, but only if you know what you"re suppressing and why.
2 years ago
What is PHP"s behavior for a variable that is assigned the return value of an expression protected by the Error Control Operator when the expression encounteres an error?
Based on the following code, the result is NULL (but it would be nice if this were confirmed to be true in all cases).
$var
=
3
;
$arr
= array();
$var
= @
$arr
[
"x"
];
// what is the value of $var after this assignment?
// is it its previous value (3) as if the assignment never took place?
// is it FALSE or NULL?
// is it some kind of exception or error message or error number?
Var_dump
($var
);
// prints "NULL"
?>
5 years ago
I was wondering if anyone (else) might find a directive to disable/enable to error operator would be a useful addition. That is, instead of something like (which I have seen for a few places in some code):
If (defined
(PRODUCTION
)) {
@function();
}
else {
function();
}
?>
There could be something like this:
If (defined
(PRODUCTION
)) {
ini_set
("error.silent"
,
TRUE
);
}
else {
ini_set
("error.silent"
,
FALSE
);
}
?>
12 years ago
If you want to log all the error messages for a php script from a session you can use something like this:
session_start
();
function
error
($error
,
$return
=
FALSE
) {
global
$php_errormsg
;
if(isset($_SESSION
[
"php_errors"
])) {
$_SESSION
[
"php_errors"
] = array();
}
$_SESSION
[
"php_errors"
] =
$error
;
// Maybe use $php_errormsg
if($return
==
TRUE
) {
$message
=
""
;
foreach($_SESSION
[
"php_errors"
] as
$php_error
) {
$messages
.=
$php_error
.
"\n"
;
}
return
$messages
;
// Or you can use use $_SESSION["php_errors"]
}
}
?>
Hope this helps someone...
PHP предоставляет прекрасную возможность контролировать возникающие ошибки. Здесь мы поговорим о том, как обработать ошибку — сообщить (или не сообщить) о происшествии пользователю, в случае необходимости — сообщить администратору с помощью электронной почты, записать информацию о происшествии в log-файл.
Итак, для начала давайте определимся, что такое ошибки в PHP.
PHP поддерживает следующие уровни ошибок:
E_ERROR
E_WARNING
E_PARSE
E_NOTICE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_WARNING
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
E_ALL
E_STRICT
На самом деле — это просто константы, которые используются для определения уровня обработки ошибок, построения бит-маски. Константы имеют "говорящие" имена. Глядя на константу — мы можем сказать, что ошибка уровня E_PARSE возникает в случае синтаксической ошибки, E_NOTICE — это напоминание программисту о нарушении "хорошего стиля" программирования на PHP.
Несколько примеров:
Когда соединение с базой данных MySQL (или другой) завершается неудачей — интерпретатор PHP сообщает об ошибке уровня E_WARNING
Warning: mysql_connect(): Access denied for user: "VVingless@localhost" (Using password: YES)
In /home/mysite/index.php (line 83)
Замечание: Для того чтобы интерпретатор PHP сообщал об ошибках — PHP должен быть настроен соответствующим образом: флаг display_errors должен быть включен — 1, директива error_reporting должна указывать на то, что необходимо отображать ошибки уровня E_WARNING (желательно конечно и другие). Если значения этих директив не удовлетворяют вашим требованиям — вы можете попробовать установить их самостоятельно, положив в папку со скриптом файл.htaccess (точка в начале имени обязательна) примерно такого содержания:
Php_flag display_errors on
php_value error_reporting "E_ALL & ~E_NOTICE"
Это означает, что сообщения об ошибках будут показываться, причем всех уровней, кроме E_NOTICE
Когда программист допускает синтаксическую ошибку — интерпретатор PHP сообщает об ошибке уровня E_PARSE
Parse error: parse error, unexpected ‘(‘, expecting T_STRING in /home/mysite/index.php on line 150
Но самые интересные для нас уровни ошибок — E_USER_ERROR и E_USER_WARNING. Как становится понятно из названия — это уровни ошибок, которые может устанавливать пользователь. Для этого существует функция trigger_error() — с её помощью, Вы можете сообщать пользователю о происшествии так, как это делает PHP.
Как известно из руководства по PHP — функция trigger_error() принимает два параметра.
void trigger_error (string error_msg [, int error_type])
Первый параметр — текстовое сообщение об ошибке, например "файл не найден". Второй параметр — определяет уровень ошибки. Функция trigger_error() работает только с семейством ошибок E_USER — это значит, что вы можете установить ошибку уровня E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE и не можете установить ошибку уровня E_WARNING. Второй параметр является не обязательным, и по умолчанию принимает значение E_USER_NOTICE.
Давайте попробуем:
Допустим, наши данные для ленты новостей хранятся в файле news.txt, и если файл не найден — необходимо сообщить об ошибке. Текст программы будет выглядеть примерно так:
if (!file_exists(‘/home/mysite/news.txt’)) {
trigger_error(‘News file not found’);
}
В результате интерпретатор PHP сообщит об ошибке уровня E_USER_NOTICE
Notice: News file not found in /home/mysite/index.php on line 47
Но что нам это даёт? Для начала то, что если в php.ini или файле.htaccess были установлены директивы
php_value log_errors "1"
php_value log_errors_max_len "1024"
php_value error_log "/home/mysite/my.log"
То в файл /home/mysite/my.log автоматически будет добавлена запись о происшествии.
PHP Notice: News file not found in /home/mysite/index.php on line 47
Далее, с помощью функции set_error_handler() мы можем установить свой собственный обработчик ошибок возникающих во время выполнения PHP скрипта.
Как известно из мануала — в PHP 4 функция принимает один единственный строковый параметр — имя функции, которая будет выполняться каждый раз, когда происходит ошибка. PHP 5 даёт возможность установить ещё один параметр — тип ошибок которые будут обрабатываться с помощью нашего обработчика. Функция возвращает строку — имя функции обработчика, который был установлен до этого момента.
string set_error_handler (callback error_handler [, int error_types])
устанавливаем так
set_error_handler ("my_error_handler");
Пользовательская функция, которая будет обрабатывать ошибки, может принимать следующие входные параметры:
— код уровня ошибки
— строковая интерпретация ошибки
— имя файла, в котором произошла ошибка
— строка, в которой произошла ошибка
Следует так же заметить, что эта функция не может обрабатывать ошибки уровней E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
Это связанно с тем, что ошибки перечисленных уровней происходят до того, как интерпретатор получает информацию о пользовательском обработчике ошибок.
Итак, объявляем нашу функцию
function my_error_handler($code, $msg, $file, $line) {
}
Замечание: каждый более-менее объемный скрипт обычно разделяется на несколько файлов для удобства работы с ним. Как организовывать модульность программы — тема отдельно разговора. Сейчас же, я хочу лишь посоветовать выделять общие настройки в отдельный файл, который будет подключаться в начале программы с помощью инструкции include, либо с помощью директивы auto_prepend_file. В этот файл можно поместит и наш обработчик. Установка обработчика ошибок должна осуществится как можно ближе к началу программы, желательно в самом начале.
Для того чтобы убедится что это действительно работает — создадим новый PHP файл, и попробуем запустить его
Содержимое файла myerrortest.php
n";
echo "$file ($line)";
}
set_error_handler("my_error_handler");
if (!file_exists("/home/mysite/news.txt")) {
trigger_error("News file not found");
}
?>
Результат обработки данного файла будет таким:
Произошла ошибка News file not found (1024)
/home/mysite/myerrortest.php (12)
Теперь у нас есть функция, которая получает данные обо всех происходящих ошибках. Подумаем, как мы можем это использовать.
Будем обрабатывать ошибки уровней
E_ERROR
E_WARNING
E_NOTICE
E_USER_ERROR
E_USER_NOTICE
Первые три ошибки в хорошей законченной программе не должны происходить вообще, поэтому о них мы будем только сообщать пользователю выводом текста ошибки на экран. Так можно работать, пока скрипт в состоянии разработки, затем сообщения о них можно либо отключить, либо записывать в log-файл.
Что касается остальных двух — как Вы уже догадались — они могу там пригодиться. Мы сами будем вызывать ошибки этих уровней в случае необходимости. Допустим — ошибки уровня E_USER_ERROR — будем вызывать в случае, когда сообщение об ошибке должно попасть в log-файл и быть отправлено на e-mail администратору (например — ошибка при выполнении SQL запроса, или отсутствии парв доступа к необходимому файлу). Ошибки уровня E_USER_NOTICE будут вызываться при возникновении "лёгких" ошибок (например — пользователь некорректно заполнил форму, или запросил из базы несуществующую запись).
Теперь наша функция обработки ошибок будет выглядеть примерно так:
// Немного предварительных настроек
// устанавливаем режим отображения ошибок
// отображать все ошибки, кроме E_NOTICE
error_reporting (E_ALL & ~E_NOTICE);
// эта константа отвечает за
// включение/выключение режима отладки
// во время отладки - сообщения не отсылаются
// по почте, а просто печатаются на экран
define("DEBUG", 0);
// это глобальная переменная, в которой
// будет храниться сообщение, которое
// должен видеть пользователь
$MSG = "";
// e-mail разработчика, куда отправлять ошибки
define("ADM_EMAIL","[email protected]");
// log-файл
define("LOGFILE","/home/mysite/mylog.log");
// разница во времени с сервером (в секундах)
define("TIMEOFFSET", 0);
// сама функция
function my_error_handler($code, $msg, $file, $line)
{
// глобальная переменная, в которую будет
// записываться сообщение об ошибке.
global $MSG;
// пропускаем ошибки уровня E_NOTICE
// и игнорируем ошибки, если режим сообщения об ошибках отключен
if (($code == E_NOTICE) or (error_reporting() == 0)) {
return;
}
// если мы вызвали ошибку уровня E_USER_NOTICE - просто
// записать текст ошибки в глобальную переменную $MSG
// и прекратить выполнение функции
if ($code == E_USER_NOTICE) {
$MSG = $msg;
Return;
}
// если ошибка уровня E_ERROR - печатаем текст ошибки
// и завершаем выполнение скрипта
if ($code == E_ERROR) {
die ("
ERROR: ".$msg."
In ".$file." (line ".$line.")
");
}
// если ошибка уровня E_WARNING - печатаем текст ошибки
// и прекращаем выполнение функции
if ($code == E_WARNING) {
echo "
WARNING: ".$msg."
In ".$file." (line ".$line.")
";
Return;
}
// если ошибка уровня E_USER_ERROR
if ($code == E_USER_ERROR) {
// записываем в переменную $MSG текст, о том что произошла ошибка,
// причины сообщать не будем, только сообщим что подробности
// отправлены на e-mail кому следует.
$MSG = "Критическая Ошибка: действие выполнено небыло.
Сообщение об ошибке было отправлено разработчику.";
// подробности записываем в переменную $text
$text = $msg."
"."Файл: ".$file." (".$line.")";
// Если константа DEBUG установлена в 1 - печатаем информацию об
// ошибке на экран, если нет - отправляем текст ошибки почтой
// функция error_mail() и пишем в log - функция error_writelog()
if (DEBUG == 1) {
error_print($text);
} else {
error_mail($text);
error_writelog($text);
}
Return;
}
}
// устанавливаем обработчик
set_error_handler("my_error_handler");
Теперь описываем служебные функции
// ф-я печатает ошибку на экран
function error_print($text)
{
echo $text."
";
}
// ф-я отправляет ошибку почтой
function error_mail($text)
{
$text = str_replace("
", "n", $text);
$info = "Время: ".get_datetime()."nRemote IP:".get_ip()."n";
mail(ADM_EMAIL, "Error reporting", $info.$text);
}
// ф-я пишет ошибку в лог
function error_writelog($text)
{
$text = str_replace("
", "t", $text);
if (@$fh = fopen(LOGFILE, "a+")) {
fputs($fh, get_datetime()."t".get_ip()."t".$text."n");
fclose($fh);
}
}
// получаем время, с учётом разницы во времени
function get_time()
{
return(date("H:i", time () + TIMEOFFSET));
}
// получаем дату, с учётом разницы во времени
function get_date()
{
return(date("Y-m-d", time () + TIMEOFFSET));
}
// получаем дату и время, с учётом разницы во времени
function get_datetime()
{
return get_date()." ".get_time();
}
// получаем IP
function get_ip()
{
return($_SERVER["REMOTE_ADDR"]);
}
И наконец пример использования
// ф-я записывает новость в файл
function write_news($title, $text)
{
$news_file = "/home/mysite/news.txt";
// проверяем наличие заголовка - ошибка не критическая
if (!trim($title)) {
// для того чтобы определить что функция завершилась
// неудачей - необходимо вернуть false. Функция
// trigger_error() - возвращает true, мы будем
// возвращать её инвертированный результат
return !trigger_error("Необходимо указать заголовок новости");
}
// проверяем наличие текста новости - ошибка не критическая
if (!trim($text)) {
return !trigger_error("Необходимо указать текст новости");
}
// проверяем наличие файла в который будем писать
// если файл не найден - возникает критическая ошибка
if (!file_exists($news_file)) {
return !trigger_error("Файл базы новостей не найден!", E_USER_ERROR);
}
// ...тут предварительная обработка данных...
// записываем новость
$fh = fopen($news_file, "a+");
fputs($fh, $title."t".$text."n");
fclose($fh);
// если всё нормально - функция возвращает true
return true;
}
// пытаемся записать новость
// эти данные могут приходить из web-формы
$res = write_news("Моя новость", "Текст моей новости");
if ($res === false) {
// если вернулся false - печатаем ошибку
echo $MSG;
} else {
// если всё в порядке - можно сообщить об этом
// а лучше отфорвардить пользователя куда-нибудь.
echo "Новость была добавлена";
}
Для того чтобы пример заработал — просто скопируйте в PHP-файл три предыдущих блока кода. Не забудьте установить права доступа на log-файл 777 для того чтобы скрипт мог с ним работать, прописать правильные пути и указать свой e-mail. Вы можете включить режим отладки установкой переменной DEBUG в 1.