Hello. I am writing my own library for application development. Now there is a serious question about how to handle errors and exceptions. It was decided to use the methods of registering errors, fatal errors and exceptions. I noticed the oddity that set_error_handler
and register_shutdown_function
with headers already sent by fire twice. The problem now is that I cannot redirect to the error page: Cannot modify header information - headers already sent by
. An error caused specifically in the view to check, that is, after rendering the page.
In general, the task is to display either an error page with details, or an error page without them.
How can I solve the problem of duplicating errors and redirect if necessary?
<?php namespace Core; use Helpers\Config; use Helpers\File; use Helpers\Url; /** * Class ErrorHandler * ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΎΡΠΈΠ±ΠΎΠΊ ΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ * @package Π‘ore */ class ErrorHandler { /** * @var array ΠΠΎΠ½ΡΡΠ°Π½ΡΠ° Π°ΡΡΠΎΡΠΈΠ°ΡΠΈΠΉ ΠΊΠΎΠ΄Π° ΠΎΡΠΈΠ±ΠΎΠΊ ΠΊ ΡΠ΅ΠΊΡΡΡ */ const ERRORS = [ E_ERROR => 'ERROR', E_WARNING => 'WARNING', E_PARSE => 'PARSE', E_NOTICE => 'NOTICE', E_CORE_ERROR => 'CORE_ERROR', E_CORE_WARNING => 'CORE_WARNING', E_COMPILE_ERROR => 'COMPILE_ERROR', E_COMPILE_WARNING => 'COMPILE_WARNING', E_USER_ERROR => 'USER_ERROR', E_USER_WARNING => 'USER_WARNING', E_USER_NOTICE => 'USER_NOTICE', E_STRICT => 'STRICT', E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR', E_DEPRECATED => 'DEPRECATED', E_USER_DEPRECATED => 'USER_DEPRECATED', ]; public static $status; /** * Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ ΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΠΌΠΈ. * ΠΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΠΎΡΠΈΠ±ΠΎΠΊ */ public static function register() { ini_set('display_errors', 1); error_reporting(E_ALL); # Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ set_error_handler([__CLASS__, 'errorHandler']); # Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ°ΡΠ°Π»ΡΠ½ΡΠΌΠΈ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ register_shutdown_function([__CLASS__, 'fatalErrorHandler']); # Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΠΌΠΈ set_exception_handler([__CLASS__, 'exceptionHandler']); } /** * Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ * @param $errno ΠΠΎΠ΄ (Π½ΠΎΠΌΠ΅Ρ) ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errstr Π‘ΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errfile Π€Π°ΠΉΠ» ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errline Π‘ΡΡΠΎΠΊΠ° Π² ΡΠ°ΠΉΠ»Π΅ ΠΎΡΠΈΠΊΠ±ΠΊΠΈ * @return bool ΠΡΠ΅Π΄ΠΎΡΠ²ΡΠ°ΡΠ΅Π½ΠΈΠ΅ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ */ public static function errorHandler($errno, $errstr, $errfile, $errline) { self::show($errno, $errstr, $errfile, $errline); # ΠΠ΅ ΠΏΠ΅ΡΠ΅Π΄Π°Π΅ΡΡΡ ΠΎΡΠΈΠ±ΠΊΠ° Π΄Π°Π»Π΅Π΅ Π½Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ return true; } /** * ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΎΠΊ Π½Π° ΡΠΊΡΠ°Π½ * @param $errno ΠΠΎΠ΄ (Π½ΠΎΠΌΠ΅Ρ) ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errstr Π‘ΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errfile Π€Π°ΠΉΠ» ΠΎΡΠΈΠ±ΠΊΠΈ * @param $errline Π‘ΡΡΠΎΠΊΠ° Π² ΡΠ°ΠΉΠ»Π΅ ΠΎΡΠΈΠΊΠ±ΠΊΠΈ */ private static function show($errno, $errstr, $errfile, $errline) { http_response_code(self::$status); echo "[" . date('Ymd H:i:s') . "] <b>" . self::getErrorName($errno) . "</b> Π² ΡΠ°ΠΉΠ»Π΅ {$errfile} Π½Π° ΡΡΡΠΎΠΊΠ΅ <b>{$errline}</b>:<br>{$errstr}<br>"; $message = "[" . date('Ymd H:i:s') . "]" . self::getErrorName($errno) . " Π² ΡΠ°ΠΉΠ»Π΅ {$errfile} Π½Π° ΡΡΡΠΎΠΊΠ΅ {$errline}:" . PHP_EOL . $errstr . PHP_EOL . PHP_EOL; self::writeLog($message); } /** * ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π½Π°ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΡ ΠΊΠ»Π°ΡΡΠ° ΠΎΡΠΈΠ±ΠΊΠΈ ΠΏΠΎ Π΅Π΅ ΠΊΠΎΠ΄Ρ * @param $error integer ΠΠΎΠΌΠ΅Ρ ΠΎΡΠΈΠ±ΠΊΠΈ * @return string ΠΠ°ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠ»Π°ΡΡΠ° ΠΎΡΠΈΠ±ΠΊΠΈ */ private static function getErrorName($error) { $error_name = $error; if (array_key_exists($error, self::ERRORS)) { $error_name = self::ERRORS[$error]; } return $error_name; } private static function writeLog($message) { $errors_config_section = Config::getSettings('logs', 'errors'); $log_file = File::createFile($errors_config_section['filename'], $errors_config_section['extension'], LOG); File::write($log_file, $message); header("Location: " . Url::to($errors_config_section['controller'], self::$status)); } /** * Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ°ΡΠ°Π»ΡΠ½ΡΠΌΠΈ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌΠΈ * @return bool ΠΡΠ΅Π΄ΠΎΡΠ²ΡΠ°ΡΠ΅Π½ΠΈΠ΅ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ */ public static function fatalErrorHandler(int $status = 500) { self::$status = $status; if (!empty($error = error_get_last()) && $error['type'] && (E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR)) { ob_get_clean(); self::show($error['type'], $error['message'], $error['file'], $error['line']); } return true; } /** * Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΠΌΠΈ * @param \Exception|\Error $ex ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ * @return bool ΠΡΠ΅Π΄ΠΎΡΠ²ΡΠ°ΡΠ΅Π½ΠΈΠ΅ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ */ public static function exceptionHandler($ex, int $status = 500) { self::$status = $status; self::show(get_class($ex), $ex->getMessage(), $ex->getFile(), $ex->getLine()); return true; } }