<?php namespace Xentral\Core\ErrorHandler; use Throwable; final class ErrorHandler { /** @var array Error types that halts execution */ const THROWABLE_ERROR_TYPES = [ E_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_error.php */ E_PARSE, /** @see http://www.bbminfo.com/Tutor/php_error_e_parse.php */ E_CORE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_core_error.php */ E_COMPILE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_compile_error.php */ E_USER_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_user_error.php */ E_RECOVERABLE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_recoverable_error.php */ ]; /** @var string[] */ private const DELETE_FILE_FOLDERS = [ 'www/pages', 'www/lib/versandarten', 'www/lib/zahlungsweisen', ]; /** * @return void */ public function register() { register_shutdown_function([$this, 'onShutdown']); // Use own error output function ini_set('display_errors', true); set_error_handler([$this, 'handleError']); set_exception_handler([$this, 'handleException']); } /** * @return void */ public function onShutdown() { $error = error_get_last(); if ($error === null) { return; } if ($this->isErrorTypeHaltingExecution((int)$error['type'])) { // Try to free memory; in case of exhausted memory limit @gc_enable(); @gc_collect_cycles(); $this->handleError((int)$error['type'], $error['message'], $error['file'], $error['line']); } } /** * @param int $code * @param string $message * @param string $file * @param int $line * * @return bool */ public function handleError($code, $message, $file, $line) { if ($this->isErrorTypeHaltingExecution($code)) { $type = (string)$this->translateErrorType($code); $exception = new PhpErrorException(sprintf('%s: %s', $type, $message), (int)$code); $exception->setFile($file); $exception->setLine($line); $this->handleException($exception); die(); // Necessary for E_RECOVERABLE_ERROR } return true; // Don't execute PHP internal error handler } /** * @param Throwable $exception */ public function handleException($exception) { $title = null; $data = new ErrorPageData($exception, $title); $renderer = new ErrorPageRenderer($data); header('HTTP/1.1 500 Internal Server Error'); header('Content-Type: text/html; charset=utf-8'); echo $renderer->renderErrorPage(); } /** * @see https://secure.php.net/manual/en/errorfunc.constants.php * * @param int $type * * @return string|null */ private function translateErrorType($type) { $errors = [ E_ERROR => 'Fatal Error', E_PARSE => 'Parse Error', E_CORE_ERROR => 'Core Error', E_COMPILE_ERROR => 'Compile Error', E_USER_ERROR => 'Fatal User Error', E_RECOVERABLE_ERROR => 'Recoverable Error', ]; return $errors[(int)$type]; } /** * @param int $type * * @return bool */ private function isErrorTypeHaltingExecution($type) { return in_array((int)$type, self::THROWABLE_ERROR_TYPES, true); } }