'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Page Not Found', 409 => 'Conflict', 500 => 'Internal Server Error', 503 => 'Service Unavailable', ]; protected $allowedStatusCodeList = [ 200, 201, 400, 401, 403, 404, 409, 500, 503, ]; protected $ignorePrintXStatusReasonExceptionClassNameList = [ 'PDOException', ]; protected $request; protected $route; public function __construct(Request $request, ?string $route = null) { $this->request = $request; $this->route = $route; } public function process(Response $response, Throwable $exception, bool $toPrintBody = false) { $message = $exception->getMessage() ?? ''; $statusCode = $exception->getCode(); if ($this->route) { $this->processRoute($response, $exception); } $logLevel = 'error'; $messageLineFile = null; $messageLineFile = 'line: ' . $exception->getLine() . ', file: ' . $exception->getFile(); if (!empty($exception->logLevel)) { $logLevel = $exception->logLevel; } $logMessageItemList = []; if ($message) { $logMessageItemList[] = "{$message}"; } $logMessageItemList[] = $this->request->getMethod() . ' ' . $this->request->getResourcePath(); if ($messageLineFile) { $logMessageItemList[] = $messageLineFile; } $logMessage = "($statusCode) " . implode("; ", $logMessageItemList); $GLOBALS['log']->log($logLevel, $logMessage); $toPrintBodyXStatusReason = true; if ( in_array( get_class($exception), $this->ignorePrintXStatusReasonExceptionClassNameList ) ) { $toPrintBodyXStatusReason = false; } if (!in_array($statusCode, $this->allowedStatusCodeList)) { $statusCode = 500; } $response->setStatus($statusCode); if ($toPrintBodyXStatusReason) { $response->setHeader('X-Status-Reason', $this->stripInvalidCharactersFromHeaderValue($message)); } if ($this->doesExceptionHaveBody($exception)) { $response->writeBody($exception->getBody()); $toPrintBody = false; } if ($toPrintBody) { $statusText = $this->getCodeDescription($statusCode); $statusText = isset($statusText) ? $statusCode . ' '. $statusText : 'HTTP ' . $statusCode; if ($message) { $message = htmlspecialchars($message); } $response->writeBody(self::generateErrorBody($statusText, $message)); } } protected function doesExceptionHaveBody(Throwable $exception) : bool { if ( ! $exception instanceof Error && ! $exception instanceof Conflict ) { return false; } $exceptionBody = null; if (method_exists($exception, 'getBody')) { $exceptionBody = $exception->getBody(); } return $exceptionBody !== null; } protected function getCodeDescription(int $statusCode) : ?string { if (isset($this->errorDescriptions[$statusCode])) { return $this->errorDescriptions[$statusCode]; } return null; } protected function clearPasswords(string $string) : string { return preg_replace('/"(.*?password.*?)":".*?"/i', '"$1":"*****"', $string); } protected static function generateErrorBody(string $header, string $text) : string { $body = "