Files
ave-cms-alt/class/class.session.php
2025-09-18 17:05:50 +05:00

217 lines
5.9 KiB
PHP

<?php
/**
* AVE.cms
*
* @package AVE.cms
* @version 4.x
* @filesource
* @copyright © 2007-2025 AVE.cms, https://www.ave.gitget.ru
*
* @license GPL v.2
*/
class AVE_Session_DB
{
public int $sess_lifetime;
protected string $db_host;
protected string $db_user;
protected string $db_pass;
protected string $db_dbase;
protected string $db_prefix;
private ?mysqli $mysql_connect = null;
public function __construct()
{
require BASE_DIR . '/config/db.config.php';
$this->db_host = $config['dbhost'];
$this->db_user = $config['dbuser'];
$this->db_pass = $config['dbpass'];
$this->db_dbase = $config['dbname'];
$this->db_prefix = $config['dbpref'];
$this->sess_lifetime = (defined('SESSION_LIFETIME') && is_numeric(SESSION_LIFETIME))
? (int)SESSION_LIFETIME
: (get_cfg_var("session.gc_maxlifetime") < 1440 ? 1440 : (int)get_cfg_var("session.gc_maxlifetime"));
$this->connect();
}
private function connect(): void
{
$this->mysql_connect = new mysqli($this->db_host, $this->db_user, $this->db_pass, $this->db_dbase);
if ($this->mysql_connect->connect_error) {
$this->error();
}
$this->mysql_connect->set_charset('utf8');
}
private function ensureConnection(): bool
{
if (!($this->mysql_connect instanceof mysqli) || !$this->mysql_connect->ping()) {
$this->connect();
if (!$this->mysql_connect || $this->mysql_connect->connect_error) {
return false;
}
}
return true;
}
public function __destruct()
{
if ($this->mysql_connect instanceof mysqli) {
$this->mysql_connect->close();
$this->mysql_connect = null;
}
}
public function _open(string $path, string $name): bool
{
return true;
}
public function _close(): bool
{
if (!$this->ensureConnection()) {
return false;
}
$sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE expiry < ?";
$stmt = $this->mysql_connect->prepare($sql);
if (!$stmt) {
error_log("Prepare failed in _close: " . $this->mysql_connect->error);
return false;
}
$now = time();
$stmt->bind_param('i', $now);
$stmt->execute();
$stmt->close();
// Соединение не закрываем!
return true;
}
public function _read(string $ses_id): string
{
if (!$this->ensureConnection()) {
return '';
}
$sql = "SELECT value, Ip FROM " . $this->db_prefix . "_sessions WHERE sesskey = ? AND expiry > ?";
$stmt = $this->mysql_connect->prepare($sql);
if (!$stmt) {
error_log("Prepare failed in _read: " . $this->mysql_connect->error);
return '';
}
$now = time();
$stmt->bind_param('si', $ses_id, $now);
$stmt->execute();
$stmt->bind_result($value, $ip);
$result = '';
if ($stmt->fetch() && $ip === ($_SERVER['REMOTE_ADDR'] ?? '')) {
$result = $value;
}
$stmt->close();
return $result;
}
public function _write(string $ses_id, string $data): bool
{
if (!$this->ensureConnection()) {
return false;
}
$expiry = time() + $this->sess_lifetime;
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';
$sql = "INSERT INTO " . $this->db_prefix . "_sessions (sesskey, expiry, value, Ip, expire_datum)
VALUES (?, ?, ?, ?, FROM_UNIXTIME(?,'%d.%m.%Y, %H:%i:%s'))
ON DUPLICATE KEY UPDATE
expiry = VALUES(expiry),
value = VALUES(value),
Ip = VALUES(Ip),
expire_datum = VALUES(expire_datum)";
$stmt = $this->mysql_connect->prepare($sql);
if (!$stmt) {
error_log("Prepare failed in _write: " . $this->mysql_connect->error);
return false;
}
$stmt->bind_param('sisss', $ses_id, $expiry, $data, $remoteAddr, $expiry);
$result = $stmt->execute();
if (!$result) {
error_log("Execute failed in _write: " . $stmt->error);
}
$stmt->close();
return $result;
}
public function _destroy(string $ses_id): bool
{
if (!$this->ensureConnection()) {
return false;
}
$sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE sesskey = ?";
$stmt = $this->mysql_connect->prepare($sql);
if (!$stmt) {
error_log("Prepare failed in _destroy: " . $this->mysql_connect->error);
return false;
}
$stmt->bind_param('s', $ses_id);
$result = $stmt->execute();
if (!$result) {
error_log("Execute failed in _destroy: " . $stmt->error);
}
$stmt->close();
return $result;
}
public function _gc(int $maxlifetime): bool
{
if (!$this->ensureConnection()) {
return false;
}
$threshold = time() - $maxlifetime;
$sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE expiry < ?";
$stmt = $this->mysql_connect->prepare($sql);
if (!$stmt) {
error_log("Prepare failed in _gc: " . $this->mysql_connect->error);
return false;
}
$stmt->bind_param('i', $threshold);
$result = $stmt->execute();
if (!$result) {
error_log("Execute failed in _gc: " . $stmt->error);
}
$stmt->close();
return $result;
}
private function error(): void
{
ob_start();
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
header('Retry-After: 3600');
header('X-Powered-By:');
echo "Error connect to MySQL.";
die;
}
}