217 lines
5.9 KiB
PHP
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;
|
|
}
|
|
}
|