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'); } // ИСПРАВЛЕНИЕ #3: Замена mysqli::ping() на mysqli::stat() для устранения Deprecated private function ensureConnection(): bool { if (!($this->mysql_connect instanceof mysqli) || !$this->mysql_connect->stat()) { $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; } } // ИСПРАВЛЕНИЕ #2: Убран префикс '_' для соответствия SessionHandlerInterface public function open(string $path, string $name): bool { return true; } // ИСПРАВЛЕНИЕ #2: Убран префикс '_' для соответствия SessionHandlerInterface 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; } // ИСПРАВЛЕНИЕ #2: Убран префикс '_' для соответствия SessionHandlerInterface 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; } // ИСПРАВЛЕНИЕ #2: Убран префикс '_' для соответствия SessionHandlerInterface 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; } // ИСПРАВЛЕНИЕ #2: Убран префикс '_' для соответствия SessionHandlerInterface 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; } // ИСПРАВЛЕНИЕ #4: Возвращаемый тип изменен на int|false и возвращается affected_rows public function gc(int $maxlifetime): int|false { 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) { // Возвращаем количество удаленных строк (требование интерфейса) $deleted_rows = $stmt->affected_rows; $stmt->close(); return $deleted_rows; } else { // Ошибка выполнения error_log("Execute failed in gc: " . $stmt->error); $stmt->close(); return false; } } 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; } } ?>