session = $session; $this->config = array_merge([ 'cookie_name' => self::REMEMBER_COOKIE, 'cookie_lifetime' => self::REMEMBER_DURATION, 'cookie_path' => '/', 'cookie_domain' => '', 'cookie_secure' => false, 'cookie_httponly' => true, 'cookie_samesite' => 'Lax' ], $config); $this->initializeFromSession(); } /** * Login with externally verified user data */ public function login(array $userData, bool $remember = false): void { $this->user = new User($userData); $this->session->set(self::SESSION_KEY, $userData); $this->session->regenerate(); if ($remember) { $this->createRememberToken($userData); } } /** * Login using user data directly */ public function loginUser(User $user, bool $remember = false): void { $this->user = $user; $this->session->set(self::SESSION_KEY, $user->toArray()); $this->session->regenerate(); if ($remember) { $this->createRememberToken($user->toArray()); } } /** * Logout the current user */ public function logout(): void { $this->user = null; $this->session->remove(self::SESSION_KEY); $this->session->regenerate(); $this->clearRememberCookie(); } /** * Check if user is authenticated */ public function check(): bool { return $this->user() !== null; } /** * Check if user is guest (not authenticated) */ public function guest(): bool { return !$this->check(); } /** * Get the currently authenticated user */ public function user(): ?User { if ($this->user) { return $this->user; } // Try to load from session $userData = $this->session->get(self::SESSION_KEY); if ($userData) { $this->user = new User($userData); return $this->user; } // Try to load from remember cookie $userData = $this->getUserDataFromRememberCookie(); if ($userData) { $this->user = new User($userData); $this->session->set(self::SESSION_KEY, $userData); } return $this->user; } /** * Get user ID */ public function id(): int|string|null { return $this->user()?->getId(); } /** * Set user data after external verification */ public function setUserData(array $userData): void { $this->user = new User($userData); $this->session->set(self::SESSION_KEY, $userData); } /** * Hash a password */ public function hashPassword(string $password): string { return password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]); } /** * Verify a password against hash */ public function verifyPassword(string $password, string $hash): bool { return password_verify($password, $hash); } /** * Initialize user from session */ private function initializeFromSession(): void { $this->session->start(); $this->user(); } /** * Create remember token for user */ private function createRememberToken(array $userData): void { $token = $this->generateRememberToken(); $hashedToken = hash('sha256', $token); $userData['remember_token'] = $hashedToken; $this->session->set('remember_user_data', $userData); $this->setRememberCookie($userData['id'] . '|' . $token); } /** * Generate a random remember token */ private function generateRememberToken(): string { return bin2hex(random_bytes(32)); } /** * Set remember cookie */ private function setRememberCookie(string $value): void { setcookie( $this->config['cookie_name'], $value, [ 'expires' => time() + $this->config['cookie_lifetime'], 'path' => $this->config['cookie_path'], 'domain' => $this->config['cookie_domain'], 'secure' => $this->config['cookie_secure'], 'httponly' => $this->config['cookie_httponly'], 'samesite' => $this->config['cookie_samesite'] ] ); } /** * Clear remember cookie */ private function clearRememberCookie(): void { setcookie( $this->config['cookie_name'], '', [ 'expires' => time() - 3600, 'path' => $this->config['cookie_path'], 'domain' => $this->config['cookie_domain'], 'secure' => $this->config['cookie_secure'], 'httponly' => $this->config['cookie_httponly'], 'samesite' => $this->config['cookie_samesite'] ] ); } /** * Get user data from remember cookie */ private function getUserDataFromRememberCookie(): ?array { $cookie = $_COOKIE[$this->config['cookie_name']] ?? null; if (!$cookie || !str_contains($cookie, '|')) { return null; } [$id, $token] = explode('|', $cookie, 2); $hashedToken = hash('sha256', $token); $userData = $this->session->get('remember_user_data'); if (!$userData || $userData['id'] != $id || ($userData['remember_token'] ?? null) !== $hashedToken) { $this->clearRememberCookie(); return null; } return $userData; } /** * Clear user data and session */ public function clear(): void { $this->user = null; $this->session->remove(self::SESSION_KEY); $this->session->remove('remember_user_data'); $this->clearRememberCookie(); } }