getCode(), $request->headers->all()); $class = $exception->getClass(); $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1)); $layout = 'prod' == MAUTIC_ENV ? 'Error' : 'Exception'; $code = $exception->getStatusCode(); // All valid status codes are within the range of 100 to 599, inclusive // @see https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes if ($code < 100 || $code > 599) { // thrown exception that didn't set a code $code = 500; } // Special handling for oauth and api urls if ( (str_contains($request->getUri(), '/oauth') && !str_contains($request->getUri(), 'authorize')) || RequestHelper::isApiRequest($request) || (!defined('MAUTIC_AJAX_VIEW') && str_contains($request->server->get('HTTP_ACCEPT', ''), 'application/json')) ) { $allowRealMessage = 'dev' === MAUTIC_ENV || str_contains($class, 'UnexpectedValueException') || str_contains($class, 'NotFoundHttpException') || str_contains($class, 'AccessDeniedHttpException'); $message = $allowRealMessage ? $exception->getMessage() : $this->translator->trans( 'mautic.core.error.generic', ['%code%' => $code] ); $dataArray = [ 'errors' => [ [ 'message' => $message, 'code' => $code, 'type' => null, ], ], ]; if ('dev' == MAUTIC_ENV) { $dataArray['trace'] = $exception->getTrace(); } // Normal behavior in Symfony dev mode is to send 200 with error message, // but this is used in prod mode for all "/api" requests too. (#224) return new JsonResponse($dataArray, $code); } if ($request->get('prod')) { $layout = 'Error'; } $anonymous = $this->security->isAnonymous(); $baseTemplate = '@MauticCore/Default/slim.html.twig'; if ($anonymous) { if ($templatePage = $themeHelper->getTheme()->getErrorPageTemplate((string) $code)) { $baseTemplate = $templatePage; } } $template = "@MauticCore/{$layout}/{$code}.html.twig"; if (!$this->get('twig')->getLoader()->exists($template)) { $template = "@MauticCore/{$layout}/base.html.twig"; } $statusText = Response::$statusTexts[$code] ?? ''; $url = $request->getRequestUri(); $urlParts = parse_url($url); return $this->delegateView( [ 'viewParameters' => [ 'baseTemplate' => $baseTemplate, 'status_code' => $code, 'status_text' => $statusText, 'exception' => $exception, 'logger' => $logger, 'currentContent' => $currentContent, 'isPublicPage' => $anonymous, ], 'contentTemplate' => $template, 'passthroughVars' => [ 'error' => [ 'code' => $code, 'text' => $statusText, 'exception' => ('dev' == MAUTIC_ENV) ? $exception->getMessage() : '', 'trace' => ('dev' == MAUTIC_ENV) ? $exception->getTrace() : '', ], 'route' => $urlParts['path'], ], 'responseCode' => $code, ] ); } /** * @param int $startObLevel */ protected function getAndCleanOutputBuffering($startObLevel): string|false { if (ob_get_level() <= $startObLevel) { return ''; } Response::closeOutputBuffers($startObLevel + 1, true); return ob_get_clean(); } }