isDebugMode = $isDebugMode ?? (bool)($_ENV['APP_DEBUG'] ?? false); $this->logger = new ErrorLogger($logger); $this->securityHandler = $securityHandler ?? SecurityEventHandler::createDefault($logger); } public function register(): void { set_exception_handler($this->handleException(...)); set_error_handler($this->handleError(...));; register_shutdown_function($this->handleShutdown(...));; } public function createHttpResponse(\Throwable $e, ?MiddlewareContext $context = null): HttpResponse { $errorContext = $this->createErrorContext($e, $context); // Standard Error Logging $this->logger->logError($errorContext); // Security Event Logging delegieren $this->securityHandler->handleIfSecurityException($e, $context); $responseFactory = $this->createResponseFactory(); $isApiRequest = $responseFactory->isApiRequest(); return $responseFactory->createResponse( $errorContext, $this->isDebugMode, $isApiRequest ); } public function handleException(Throwable $e): never { $context = $this->createErrorContext($e); // Logge den Fehler $this->logger->logError($context); // Security Event Logging delegieren $this->securityHandler->handleIfSecurityException($e); // Erstelle ResponseFactory mit dem TemplateRenderer $responseFactory = $this->createResponseFactory(); // Bestimme ob es ein API-Request ist $isApiRequest = $responseFactory->isApiRequest(); // Erstelle eine Response basierend auf dem Kontext $response = $responseFactory->createResponse($context, $this->isDebugMode, $isApiRequest); // Sende die Fehlermeldung $this->emitter->emit($response); exit(1); } public function handleError(int $errno, string $errstr, string $errfile, int $errline): void { $exception = new \ErrorException($errstr, 0, $errno, $errfile, $errline); $this->handleException($exception); } public function handleShutdown(): void { $error = error_get_last(); if ($error && $this->isFatalError($error['type'])) { $exception = new \ErrorException( $error['message'], 0, $error['type'], $error['file'], $error['line'] ); $this->handleException($exception); } } private function isFatalError(int $errno): bool { return in_array($errno, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR], true); } private function createErrorContext(Throwable $exception, ?MiddlewareContext $context = null):ErrorContext { $level = $this->determineErrorLevel($exception); $requestId = $context->requestId ?? $this->requestIdGenerator->generate(); return new ErrorContext( exception: $exception, level: $level, requestId: $requestId, additionalData: [ 'timestamp' => date('c'), 'memory_usage' => memory_get_peak_usage(true), ] ); } private function determineErrorLevel(Throwable $exception):ErrorLevel { return match(true) { $exception instanceof \Error => ErrorLevel::CRITICAL, $exception instanceof \ErrorException => $this->determineErrorExceptionLevel($exception), $exception instanceof SecurityException => $this->determineSecurityErrorLevel($exception), $exception instanceof \RuntimeException => ErrorLevel::ERROR, $exception instanceof \LogicException => ErrorLevel::WARNING, default => ErrorLevel::ERROR, }; } /** * Bestimmt den Error-Level für SecurityExceptions basierend auf dem Security-Level */ private function determineSecurityErrorLevel(SecurityException $exception): ErrorLevel { return match($exception->getSecurityLevel()) { SecurityLogLevel::DEBUG => ErrorLevel::DEBUG, SecurityLogLevel::INFO => ErrorLevel::INFO, SecurityLogLevel::WARN => ErrorLevel::WARNING, SecurityLogLevel::ERROR => ErrorLevel::ERROR, SecurityLogLevel::FATAL => ErrorLevel::CRITICAL, }; } /** * Bestimmt den Fehler-Level basierend auf dem ErrorException-Severity-Level */ private function determineErrorExceptionLevel(\ErrorException $exception): ErrorLevel { return match($exception->getSeverity()) { E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR => ErrorLevel::CRITICAL, E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING => ErrorLevel::WARNING, E_NOTICE, E_USER_NOTICE => ErrorLevel::NOTICE, E_DEPRECATED, E_USER_DEPRECATED => ErrorLevel::INFO, E_STRICT => ErrorLevel::DEBUG, default => ErrorLevel::ERROR, }; } /** * Erstellt eine ErrorResponseFactory mit Renderern * Versucht den TemplateRenderer aus dem Container zu laden, falls vorhanden */ private function createResponseFactory(): ErrorResponseFactory { $templateRenderer = null; // Versuche TemplateRenderer aus Container zu laden if ($this->container && $this->container->has(TemplateRenderer::class)) { try { $templateRenderer = $this->container->get(TemplateRenderer::class); } catch (Throwable $e) { // Falls ein Fehler beim Laden auftritt, verwende Fallback $templateRenderer = null; } } $htmlRenderer = $templateRenderer ? new ErrorTemplateRenderer($templateRenderer) : new ErrorTemplateRenderer(new DummyTemplateRenderer()); $apiRenderer = new ApiErrorRenderer(); return new ErrorResponseFactory($htmlRenderer, $apiRenderer); } }