<?php
class Session
{
private static ?string $sid = null;
private static ?array $data = null;
private static bool $needUpdate = true;
private static function generateSessionId(): void
{
if (self::$sid !== null)
Util::traceError('Error: Asked to generate session id when already set.');
self::$sid = sha1(
mt_rand(0, 65535)
. $_SERVER['REMOTE_ADDR']
. mt_rand(0, 65535)
. $_SERVER['REMOTE_PORT']
. mt_rand(0, 65535)
. $_SERVER['HTTP_USER_AGENT']
. mt_rand(0, 65535)
. microtime(true)
. mt_rand(0, 65535)
);
}
public static function create(): void
{
self::generateSessionId();
self::$data = array();
}
public static function load(): bool
{
// Try to load session id from cookie
if (!self::loadSessionId()) return false;
// Succeded, now try to load session data. If successful, job is done
if (self::readSessionData()) return true;
// Loading session data failed
self::delete();
return false;
}
public static function getUid()
{
return self::get('uid');
}
public static function setUid($value): void
{
if (strlen($value) < 5)
Util::traceError('Invalid user id: ' . $value);
self::set('uid', $value);
}
public static function get($key)
{
if (isset(self::$data[$key]))
return self::$data[$key];
return false;
}
public static function set(string $key, $value): void
{
if (!is_array(self::$data))
Util::traceError('Tried to set session data with no active session');
if (isset(self::$data[$key]) && self::$data[$key] === $value)
return;
self::$data[$key] = $value;
self::$needUpdate = true;
}
private static function loadSessionId(): bool
{
if (self::$sid !== null)
Util::traceError('Error: Asked to load session id when already set.');
if (empty($_COOKIE['sid']))
return false;
$id = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE['sid']);
if (empty($id))
return false;
self::$sid = $id;
return true;
}
public static function delete(): void
{
if (self::$sid === null) return;
Database::exec('DELETE FROM websession WHERE sid = :sid', array('sid' => self::$sid));
setcookie('sid', '', time() - CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true);
self::$sid = null;
self::$data = null;
}
public static function save(): void
{
if (self::$sid === null || self::$data === null || !self::$needUpdate)
return;
$data = json_encode(self::$data);
$ret = Database::exec('INSERT INTO websession (sid, dateline, data) '
. ' VALUES (:sid, UNIX_TIMESTAMP(), :data) '
. ' ON DUPLICATE KEY UPDATE dateline = VALUES(dateline), data = VALUES(data)',
array('sid' => self::$sid, 'data' => $data));
if ($ret === false)
Util::traceError('Storing session data in Dahdähbank failed.');
$ret = setcookie('sid', self::$sid, time() + CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true);
if ($ret === false)
Util::traceError('Error: Could not set Cookie for Client (headers already sent)');
}
public static function readSessionData(): bool
{
if (self::$sid === null || self::$data !== null)
Util::traceError('Tried to readSessionData on an active session!');
$data = Database::queryFirst('SELECT dateline, data FROM websession WHERE sid = :sid LIMIT 1', array('sid' => self::$sid));
if ($data === false) {
return false;
}
if ($data['dateline'] + CONFIG_SESSION_TIMEOUT < time()) {
self::delete();
return false;
}
self::$needUpdate = ($data['dateline'] + 3600 < time());
$data = @json_decode($data['data'], true);
self::$data = is_array($data) ? $data : [];
return true;
}
}