X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=mdref%2FExceptionHandler.php;h=b641629f3c9372a63697e29ae2c8ee738ae5af1f;hb=80ea76521e2ccbbfac1ac0f33f91af1739ead561;hp=1c9b7da8a60474c09f9f505e06013e1a38a4b63b;hpb=20206b5cd0c57f3939f106f94b84b7d7be8c009d;p=mdref%2Fmdref diff --git a/mdref/ExceptionHandler.php b/mdref/ExceptionHandler.php index 1c9b7da..b641629 100644 --- a/mdref/ExceptionHandler.php +++ b/mdref/ExceptionHandler.php @@ -5,54 +5,115 @@ namespace mdref; use http\Env as HTTP; /** - * mdref exception handler + * Exception and error handler */ class ExceptionHandler { - function __construct() { + /** + * @var \http\Env\Response + */ + private $response; + + /** + * Set up error/exception/shutdown handler + */ + public function __construct(\http\Env\Response $r) { + $this->response = $r; set_exception_handler($this); set_error_handler($this); + register_shutdown_function($this); } - - function __invoke($e, $msg = null) { - if ($e instanceof \Exception) { + + private static function cleanBuffers() { + while (ob_get_level()) { + if (!@ob_end_clean()) { + break; + } + } + } + + /** + * The exception/error/shutdown handler callback + */ + public function __invoke($e = null, $msg = null) { + if ($e instanceof \Exception || $e instanceof \Throwable) { try { - echo static::html($e); + self::cleanBuffers(); + echo static::htmlException($e); } catch (\Exception $ignore) { headers_sent() or HTTP::setResponseCode(500); + die("FATAL ERROR:\n$e\n$ignore"); } - } else { + } elseif (isset($e, $msg)) { throw new \Exception($msg, $e); + } elseif (($error = error_get_last())) { + switch ($error["type"]) { + case E_PARSE: + case E_ERROR: + case E_USER_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + self::cleanBuffers(); + $message = sprintf("%s in %s at line %d", + $error["message"], $error["file"], $error["line"]); + echo static::htmlError("Application Error", $message, 500, ""); + break; + } } - return true; } - + /** * Format an exception as HTML and send appropriate exception info as HTTP headers - * @param \Exception $e + * @param Throwable $e * @param array $title_tag * @param array $message_tag * @param array $trace_tag * @return string */ - static function html(\Exception $e, array $title_tag = ["h1"], array $message_tag = ["p"], array $trace_tag = ["pre", "style='font-size:smaller'"]) { - if ($e instanceof \http\Controller\Exception) { + public static function htmlException(/*\Throwable*/ $e, array $title_tag = ["h1"], array $message_tag = ["p"], array $trace_tag = ["pre", "style='font-size:smaller;overflow-x:scroll'"]) { + if ($e instanceof Exception) { $code = $e->getCode() ?: 500; - foreach ($e->getHeaders() as $key => $val) { - HTTP::setResponseHeader($key, $val); - } } else { $code = 500; } + + for ($html = ""; $e; $e = $e->getPrevious()) { + $html .= static::htmlError(HTTP::getResponseStatusForCode($code), + $e->getMessage(), $code, $e->getTraceAsString(), + $title_tag, $message_tag, $trace_tag); + } + return $html; + } + + /** + * Format an error as HTML + * @param string $title + * @param string $message + * @param int $code + * @param string $trace + * @param array $title_tag + * @param array $message_tag + * @param array $trace_tag + * @return string + */ + public static function htmlError($title, $message, $code, $trace = null, array $title_tag = ["h1"], array $message_tag = ["p"], array $trace_tag = ["pre", "style='font-size:smaller;overflow-x:scroll'"]) { HTTP::setResponseCode($code); - $name = HTTP::getResponseStatusForCode($code); + $html = sprintf("<%s>%s\n<%s>%s\n", - implode(" ", $title_tag), $name, $title_tag[0], - implode(" ", $message_tag), $e->getMessage(), $message_tag[0]); + implode(" ", $title_tag), $title, $title_tag[0], + implode(" ", $message_tag), $message, $message_tag[0]); if ($trace_tag) { - $html .= sprintf("<%s>%s\n", - implode(" ", $trace_tag), $e->getTraceAsString(), $trace_tag[0]); + if (!isset($trace)) { + ob_start(); + debug_print_backtrace(); + $trace = ob_get_clean(); + } + if (!empty($trace)) { + $html .= sprintf("<%s>%s\n", + implode(" ", $trace_tag), $trace, $trace_tag[0]); + } } + return $html; } }