implement session and CSRF handling
This commit is contained in:
parent
bc83b693a9
commit
bb6fe3612b
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/session.php';
|
||||
|
||||
/**
|
||||
* Context holds the request, response, and shared state for a request
|
||||
*/
|
||||
@ -7,6 +9,7 @@ class Context
|
||||
{
|
||||
public Request $request;
|
||||
public Response $response;
|
||||
public Session $session;
|
||||
public array $state = [];
|
||||
|
||||
/**
|
||||
@ -16,6 +19,8 @@ class Context
|
||||
{
|
||||
$this->request = new Request();
|
||||
$this->response = new Response();
|
||||
$this->session = new Session();
|
||||
$this->session->start();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
186
session.php
Normal file
186
session.php
Normal file
@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Session provides session management with flash messages and CSRF protection
|
||||
*/
|
||||
class Session
|
||||
{
|
||||
private bool $started = false;
|
||||
private array $flashData = [];
|
||||
|
||||
/**
|
||||
* start initializes the session if not already started
|
||||
*/
|
||||
public function start(): void
|
||||
{
|
||||
if ($this->started || session_status() === PHP_SESSION_ACTIVE) {
|
||||
$this->started = true;
|
||||
$this->loadFlashData();
|
||||
return;
|
||||
}
|
||||
|
||||
session_start();
|
||||
$this->started = true;
|
||||
$this->loadFlashData();
|
||||
}
|
||||
|
||||
/**
|
||||
* get retrieves a value from the session
|
||||
*/
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$this->ensureStarted();
|
||||
return $_SESSION[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* set stores a value in the session
|
||||
*/
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
$this->ensureStarted();
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* has checks if a key exists in the session
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
$this->ensureStarted();
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove deletes a value from the session
|
||||
*/
|
||||
public function remove(string $key): void
|
||||
{
|
||||
$this->ensureStarted();
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* flash sets a flash message that will be available only for the next request
|
||||
*/
|
||||
public function flash(string $key, mixed $value): void
|
||||
{
|
||||
$this->ensureStarted();
|
||||
$_SESSION['_flash_new'][$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* getFlash retrieves a flash message (available only for current request)
|
||||
*/
|
||||
public function getFlash(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return $this->flashData[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* hasFlash checks if a flash message exists
|
||||
*/
|
||||
public function hasFlash(string $key): bool
|
||||
{
|
||||
return isset($this->flashData[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* csrfToken generates or retrieves the CSRF token for the session
|
||||
*/
|
||||
public function csrfToken(): string
|
||||
{
|
||||
$this->ensureStarted();
|
||||
|
||||
if (!isset($_SESSION['_csrf_token'])) {
|
||||
$_SESSION['_csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
return $_SESSION['_csrf_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* validateCsrf validates a CSRF token
|
||||
*/
|
||||
public function validateCsrf(string $token): bool
|
||||
{
|
||||
$this->ensureStarted();
|
||||
|
||||
if (!isset($_SESSION['_csrf_token'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hash_equals($_SESSION['_csrf_token'], $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* regenerate regenerates the session ID for security
|
||||
*/
|
||||
public function regenerate(bool $deleteOldSession = true): bool
|
||||
{
|
||||
$this->ensureStarted();
|
||||
return session_regenerate_id($deleteOldSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy destroys the session
|
||||
*/
|
||||
public function destroy(): void
|
||||
{
|
||||
$this->ensureStarted();
|
||||
|
||||
$_SESSION = [];
|
||||
|
||||
if (ini_get("session.use_cookies")) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$params["path"], $params["domain"],
|
||||
$params["secure"], $params["httponly"]
|
||||
);
|
||||
}
|
||||
|
||||
session_destroy();
|
||||
$this->started = false;
|
||||
$this->flashData = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* clear removes all session data but keeps the session active
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->ensureStarted();
|
||||
$_SESSION = [];
|
||||
$this->flashData = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* all returns all session data
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
$this->ensureStarted();
|
||||
$data = $_SESSION;
|
||||
unset($data['_flash_old'], $data['_flash_new'], $data['_csrf_token']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* ensureStarted ensures the session is started
|
||||
*/
|
||||
private function ensureStarted(): void
|
||||
{
|
||||
if (!$this->started) $this->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* loadFlashData loads flash messages and rotates them
|
||||
*/
|
||||
private function loadFlashData(): void
|
||||
{
|
||||
$this->flashData = $_SESSION['_flash_old'] ?? [];
|
||||
|
||||
$_SESSION['_flash_old'] = $_SESSION['_flash_new'] ?? [];
|
||||
unset($_SESSION['_flash_new']);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user