configuredPublicPaths = $publicPaths ?? (defined('APP_PUBLIC_PATHS') ? APP_PUBLIC_PATHS : []); } /** * Check if a path is publicly accessible (no authentication required). */ public function isPublicPath(string $path): bool { $normalizedPath = $this->normalizePath($path); // Root path check if ($normalizedPath === '/') { return in_array('/', $this->configuredPublicPaths, true); } // Check configured public paths if (in_array($normalizedPath, $this->configuredPublicPaths, true)) { return true; } // Check page/ prefix with slug lookup if (str_starts_with($normalizedPath, 'page/')) { $pageSlug = substr($normalizedPath, strlen('page/')); if (in_array($pageSlug, $this->configuredPublicPaths, true)) { return true; } } // Check always-public prefixes foreach (self::ALWAYS_PUBLIC_PREFIXES as $prefix) { if (str_starts_with($normalizedPath, $prefix)) { return true; } } return false; } /** * Redirect to login if the path requires authentication and user is not logged in. * * @return bool True if access is allowed, false if redirected */ public function requireAuthOrRedirect(string $path, bool $isLoggedIn): bool { if ($this->isPublicPath($path) || $isLoggedIn) { return true; } $locale = I18n::$locale ?? I18n::$defaultLocale; Router::redirect(Request::withLocale('login', $locale)); return false; } private function normalizePath(string $path): string { $normalized = trim($path, '/'); return $normalized === '' ? '/' : $normalized; } }