Added error handler

This commit is contained in:
Visman 2018-08-21 21:12:17 +07:00
parent 2b80012658
commit d1f0e4360f
4 changed files with 205 additions and 7 deletions

191
app/Core/ErrorHandler.php Normal file
View file

@ -0,0 +1,191 @@
<?php
namespace ForkBB\Core;
class ErrorHandler
{
/**
* Уровень буфера вывода на котором работает обработчик
* @var int
*/
protected $obLevel;
/**
* Описание ошибки
* @var array
*/
protected $error;
/**
* Флаг отправки сообщения в лог
* @var bool
*/
protected $logged = false;
/**
* Список ошибок
* @var array
*/
protected $type = [
0 => 'OTHER_ERROR',
\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',
];
/**
* Конструктор
*/
public function __construct()
{
\set_error_handler([$this, 'errorHandler']);
\set_exception_handler([$this, 'exceptionHandler']);
\register_shutdown_function([$this, 'shutdownHandler']);
\ob_start();
$this->obLevel = \ob_get_level();
}
/**
* Деструктор
*/
public function __destruct()
{
\restore_error_handler();
\restore_exception_handler();
//????
}
/**
* Обрабатыет перехватываемые ошибки
*
* @param int $type
* @param string $message
* @param string $file
* @param string $line
*
* @return bool
*/
public function errorHandler($type, $message, $file, $line)
{
$error = [
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line,
];
$this->log($error);
if ($type & \error_reporting()) {
$this->error = $error;
exit(1);
}
$this->logged = false;
return true;
}
/**
* Обрабатывает не перехваченные исключения
*
* @param Exception|Throwable $e
*/
public function exceptionHandler($e)
{
$this->error = [
'type' => 0, //????
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
];
}
/**
* Окончательно обрабатывает ошибки (в том числе фатальные) и исключения
*/
public function shutdownHandler()
{
if (isset($this->error['type'])) {
$show = true;
} else {
$show = false;
$this->error = \error_get_last();
if (isset($this->error['type'])) {
switch ($this->error['type']) {
case \E_ERROR:
case \E_PARSE:
case \E_CORE_ERROR:
case \E_CORE_WARNING:
case \E_COMPILE_ERROR:
case \E_COMPILE_WARNING:
$show = true;
break;
}
}
}
if (isset($this->error['type']) && ! $this->logged) {
$this->log($this->error);
}
while (\ob_get_level() > $this->obLevel) {
\ob_end_clean();
}
if (\ob_get_level() === $this->obLevel) {
if ($show) {
\ob_end_clean();
$this->show($this->error);
} else {
\ob_end_flush();
}
}
}
/**
* Отправляет сообщение в лог
*
* @param array $error
*/
protected function log(array $error)
{
$this->logged = true;
$type = isset($this->type[$error['type']]) ? $this->type[$error['type']] : $this->type[0];
$message = "PHP {$type}: \"{$error['message']}\" in {$error['file']}:[{$error['line']}]";
$message = \preg_replace('%[\x00-\x1F]%', ' ', $message);
\error_log($message);
}
/**
* Выводит сообщение об ошибке
*
* @param array $error
*/
protected function show(array $error)
{
\header('HTTP/1.1 500 Internal Server Error');
if (1 == \ini_get('display_errors')) {
$type = isset($this->type[$error['type']]) ? $this->type[$error['type']] : $this->type[0];
echo "PHP {$type}: \"{$error['message']}\" in {$error['file']}:[{$error['line']}]";
} else {
echo 'Oops';
}
}
}

View file

@ -3,16 +3,12 @@
namespace ForkBB;
use ForkBB\Core\Container;
use ForkBB\Core\ErrorHandler;
use ForkBB\Models\Page;
use RuntimeException;
// боевой
#\error_reporting(E_ALL);
#\ini_set('display_errors', 0);
#\ini_set('log_errors', 1);
// разраб
\error_reporting(E_ALL);
\ini_set('display_errors', 1);
\error_reporting(\E_ALL ^ \E_NOTICE);
\ini_set('display_errors', 0);
\ini_set('log_errors', 1);
\mb_language('uni');
@ -21,6 +17,8 @@ use RuntimeException;
require __DIR__ . '/../vendor/autoload.php';
$errorHandler = new ErrorHandler();
if (\is_file(__DIR__ . '/config/main.php')) {
$c = new Container(include __DIR__ . '/config/main.php');
} elseif (\is_file(__DIR__ . '/config/install.php')) {

View file

@ -1,5 +1,9 @@
<?php
\error_reporting(\E_ALL);
\ini_set('display_errors', 1);
\ini_set('log_errors', 1);
return [
'BASE_URL' => 'http://forkbb.local',
'DEBUG' => 0,

View file

@ -1,5 +1,10 @@
<?php
# development
#\error_reporting(\E_ALL);
#\ini_set('display_errors', 1);
#\ini_set('log_errors', 1);
return [
'BASE_URL' => '_BASE_URL_',
'EOL' => PHP_EOL, // Define line breaks in mail headers; possible values can be PHP_EOL, "\r\n", "\n" or "\r"