Bicycle/System/Classes/Session.php
Egor Isaev b516ca07dc Initial commit: Bicycle PHP MVC micro-framework
Core MVC, HTTP client, Session, Cookie, Config, HTTPException — 111 PHPUnit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:04:19 +03:00

145 lines
3.3 KiB
PHP

<?php
/**
* @package Bicycle
* @author Egor Isaev
* @description Session.php
* @copyright (c) 04/06/2026
*/
namespace System\Classes;
class Session
{
private static array $instances = [];
protected bool $_destroyed = false;
protected string $_name = 'main';
protected int $_lifetime = 0;
protected array $_data = [];
private function __construct(string $name, array $config)
{
$this->_name = $name;
$this->_lifetime = $config['lifetime'] ?? 0;
session_write_close();
session_name($this->_name);
session_set_cookie_params([
'lifetime' => $this->_lifetime > 0 ? 300 : 0,
'path' => '/',
'secure' => $config['secure'] ?? false,
'httponly' => $config['httponly'] ?? true,
'samesite' => $config['samesite'] ?? 'Lax',
]);
$this->read();
}
public static function instance(string $name = 'main'): static
{
$name = strtolower($name);
if (!isset(self::$instances[$name])) {
self::$instances[$name] = new static($name, []);
}
return self::$instances[$name];
}
public function read(): void
{
session_cache_limiter(false);
session_start();
$_SESSION['start_time'] = (int)($_SESSION['start_time'] ?? time());
$gc_lifetime = (int)ini_get('session.gc_maxlifetime');
if ($_SESSION['start_time'] + $gc_lifetime < time()) {
$this->destroy();
}
$this->_data = &$_SESSION;
}
public function get(string $key, mixed $default = null): mixed
{
return array_key_exists($key, $this->_data) ? $this->_data[$key] : $default;
}
public function set(string $key, mixed $value): static
{
$this->_data[$key] = $value;
return $this;
}
public function delete(string $key): static
{
unset($this->_data[$key]);
return $this;
}
public function destroy(): bool
{
if (!$this->_destroyed) {
session_unset();
session_destroy();
setcookie(session_name(), '', 0, '/');
Cookie::delete($this->_name);
if ($this->_destroyed = !session_id()) {
$this->_data = [];
}
}
return $this->_destroyed;
}
public function regenerate(): false|string
{
session_regenerate_id(true);
$new_id = session_id();
Cookie::set($this->_name, $new_id, $this->_lifetime);
return $new_id;
}
public function write(): bool
{
if ($this->_destroyed || headers_sent()) {
return false;
}
session_write_close();
return true;
}
public function bind(string $key, mixed &$value): static
{
$this->_data[$key] = &$value;
return $this;
}
public function id(): false|string
{
return session_id();
}
public function getData(): array
{
return $this->_data;
}
public static function getDeviceHash(): string
{
$hash = Cookie::get('device_hash');
if (!$hash) {
$hash = md5(($_SERVER['HTTP_USER_AGENT'] ?? '') . uniqid('', true));
Cookie::set('device_hash', $hash, 365 * 24 * 3600);
}
return $hash;
}
}