| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- <?php
- /**
- * @author Giancarlo Voci
- * @date 25/06/2018
- * @time 16:14
- */
- namespace OpenMind\System;
- use Base;
- class ErrorHandlers
- {
- private const API_PATH_PREFIX = '/api/v1';
- private const JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
- private const LOG_DATE_FORMAT = 'd/m/Y H:i:s';
- private Base $f3;
- /**
- * Initializes the error handler with the current framework instance.
- *
- * @return void
- * @sideEffects Reads the framework singleton.
- */
- public function __construct()
- {
- $this->f3 = Base::instance();
- }
- /**
- * Renders an application error in the response format for the request type.
- *
- * @return null Always returns null for PHP/F3 requests after writing JSON.
- * @sideEffects Clears output buffers, writes a log entry, and renders or exits.
- */
- public function Handler()
- {
- $error = $this->f3->get('ERROR');
- $errorValues = [$error['code'], $error['status'], $error['text']];
- while (ob_get_level() > 0) {
- ob_end_clean();
- }
- $this->writeLog(implode(' - ', $errorValues));
- if ($this->f3->get('CLI')) {
- print_r($errorValues);
- exit(1);
- }
- if ($this->isApiRequest()) {
- $this->f3->status((int) $error['code']);
- }
- header('Content-Type: ' . self::JSON_CONTENT_TYPE);
- echo json_encode(['error' => $error['text']], JSON_THROW_ON_ERROR);
- return null;
- }
- /**
- * Determine whether the current request belongs to the versioned API.
- *
- * @return bool True when the request path is rooted at /api/v1.
- * @sideEffects Reads the current request URI from the framework.
- */
- private function isApiRequest(): bool
- {
- $uri = $this->f3->get('URI');
- if (!is_string($uri)) {
- return false;
- }
- $path = parse_url($uri, PHP_URL_PATH);
- $basePath = $this->f3->get('BASE');
- if (is_string($path) && is_string($basePath)) {
- $basePath = rtrim($basePath, '/');
- if ($basePath !== '' && $basePath !== '/'
- && ($path === $basePath || str_starts_with($path, $basePath . '/'))) {
- $path = substr($path, strlen($basePath)) ?: '/';
- }
- }
- return is_string($path)
- && ($path === self::API_PATH_PREFIX
- || str_starts_with($path, self::API_PATH_PREFIX . '/'));
- }
- /**
- * Writes an error message with the relevant caller context.
- *
- * @param string $message Error message.
- * @param int $traceIndex Caller index in the debug trace.
- * @return void
- * @sideEffects Writes to the application log.
- */
- private function writeLog(string $message, int $traceIndex = 1): void
- {
- $trace = debug_backtrace();
- $context = $trace[$traceIndex] ?? [];
- $prefix = ($context['line'] ?? '') . ':'
- . ($context['class'] ?? '') . ':'
- . ($context['function'] ?? '') . ':';
- $sanitizedMessage = str_replace(["\r", "\n"], '', $message);
- OMUtils::getInstance()->getLogger()->write(
- "{$prefix} {$sanitizedMessage}",
- self::LOG_DATE_FORMAT,
- );
- }
- }
|