implement session and CSRF handling
This commit is contained in:
parent
bc83b693a9
commit
bb6fe3612b
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context holds the request, response, and shared state for a request
|
* Context holds the request, response, and shared state for a request
|
||||||
*/
|
*/
|
||||||
@ -7,6 +9,7 @@ class Context
|
|||||||
{
|
{
|
||||||
public Request $request;
|
public Request $request;
|
||||||
public Response $response;
|
public Response $response;
|
||||||
|
public Session $session;
|
||||||
public array $state = [];
|
public array $state = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,6 +19,8 @@ class Context
|
|||||||
{
|
{
|
||||||
$this->request = new Request();
|
$this->request = new Request();
|
||||||
$this->response = new Response();
|
$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