%PDF- %PDF-
| Direktori : /www/varak.net/dmarc.varak.net/classes/ |
| Current File : //www/varak.net/dmarc.varak.net/classes/Session.php |
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2025 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This file contains the class Session
*
* @category API
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
declare(strict_types=1);
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Exception\RuntimeException;
/**
* The class is for managing the state of the user session
*/
class Session
{
private const COOKIE_NAME = 'session';
private const LIFETIME_DURATION = 900;
private const MIGRATE_DURATION = 120;
private const DATA_KEYS = [ 'user', 's_id', 's_time' ];
/**
* Returns data of the session
*
* @return array
*/
public function getData(): array
{
if (!$this->isStarted()) {
$this->start();
}
return $this->userData();
}
/**
* Stores the passed data to the session
*
* @param array $data Array of data to store
*
* @return void
*/
public function setData(array $data): void
{
if (!$this->isStarted()) {
$this->start();
}
foreach (self::DATA_KEYS as $key) {
if (isset($data[$key])) {
$_SESSION[$key] = $data[$key];
}
}
}
/**
* Saves and closes the user session
*
* @return void
*/
public function commit(): void
{
if ($this->isStarted()) {
\session_write_close();
}
}
/**
* Closes the user session
*
* @return void
*/
public function close(): void
{
if ($this->isStarted()) {
\session_abort();
}
}
/**
* Destroys the user session and its data
*
* @return void
*/
public function destroy(): void
{
if (!$this->isStarted()) {
$this->strictStart();
}
if (\intval(\ini_get('session.use_cookies')) == 1) {
$scp = \session_get_cookie_params();
$cep = [
'expires' => time() - 42000,
'path' => $scp['path'],
'domain' => $scp['domain'],
'secure' => $scp['secure'],
'httponly' => $scp['httponly'],
'samesite' => $scp['samesite']
];
\setcookie(self::COOKIE_NAME, '', $cep);
}
\session_unset();
\session_destroy();
\session_write_close();
}
/**
* Checks if the session is started
*
* @return bool
*/
private function isStarted(): bool
{
return \session_status() === PHP_SESSION_ACTIVE;
}
/**
* Starts the user session
*
* @return void
*/
private function start(): void
{
\ini_set('session.use_strict_mode', '1');
$this->strictStart();
// Session control
if (!isset($_SESSION['_started'])) {
// Looks like a new session
$_SESSION['_started'] = \time();
} elseif (isset($_SESSION['_expired'])) {
// Session is outdated
\session_abort();
if ($_SESSION['_expired'] > \time() - self::MIGRATE_DURATION && isset($_SESSION['_new_session_id'])) {
$s_id = $_SESSION['_new_session_id'];
} else {
$s_id = session_create_id();
\ini_set('session.use_strict_mode', '0');
}
\session_id($s_id);
$this->strictStart();
} elseif ($_SESSION['_started'] <= \time() - self::LIFETIME_DURATION) {
$this->migrate();
}
}
/**
* Starts a safety-optioned session
*
* @throws RuntimeException
*
* @return void
*/
private function strictStart(): void
{
if (!\session_start([
'name' => self::COOKIE_NAME,
'cookie_path' => \dirname($_SERVER['REQUEST_URI']),
'cookie_httponly' => true,
'cookie_samesite' => 'Strict'
])) {
throw new RuntimeException('Failed to start a new session');
}
}
/**
* Creates a new session and moves all data into it
*
* @return void
*/
private function migrate(): void
{
$udata = $this->userData();
$ct = \time();
if (!isset($_SESSION['_expired'])) {
$_SESSION['_expired'] = $ct;
}
$new_id = \session_create_id();
$_SESSION['_new_session_id'] = $new_id;
\session_write_close();
\ini_set('session.use_strict_mode', '0');
\session_id($new_id);
$this->strictStart();
$_SESSION = $udata;
$_SESSION['_started'] = $ct;
}
/**
* Returns all session data except session control data
*
* @return array
*/
private function userData(): array
{
$res = [];
foreach (self::DATA_KEYS as $key) {
if (isset($_SESSION[$key])) {
$res[$key] = $_SESSION[$key];
}
}
return $res;
}
}