Core MVC, HTTP client, Session, Cookie, Config, HTTPException — 111 PHPUnit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
145 lines
3.3 KiB
PHP
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;
|
|
}
|
|
}
|