165 lines
5.6 KiB
PHP
165 lines
5.6 KiB
PHP
<?php
|
||
|
||
/**
|
||
* AVE.cms
|
||
*
|
||
* @package AVE.cms
|
||
* @version 4.x (PHP 8+ compatible)
|
||
* @filesource
|
||
* @copyright © 2007-2025 AVE.cms, https://www.ave.gitget.ru
|
||
*
|
||
* @license GPL v.2
|
||
*/
|
||
|
||
// Класс уже объявлен с implements SessionHandlerInterface - это правильно.
|
||
class AVE_Session implements SessionHandlerInterface
|
||
{
|
||
|
||
// Типизация $sess_lifetime должна быть int для PHP 8.1+, но оставлю без типа, чтобы не вызвать новых ошибок
|
||
public $sess_lifetime;
|
||
|
||
function __construct()
|
||
{
|
||
// ini_set('session.save_handler', 'user'); // Этот вызов устарел; session_set_save_handler() уже выполняет эту роль.
|
||
|
||
$this->sess_lifetime = (defined('SESSION_LIFETIME') && is_numeric(SESSION_LIFETIME))
|
||
? SESSION_LIFETIME
|
||
: (get_cfg_var("session.gc_maxlifetime") < 1440 ? 1440 : get_cfg_var("session.gc_maxlifetime"));
|
||
|
||
return true;
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' для соответствия SessionHandlerInterface
|
||
public function open(string $path, string $name): bool
|
||
{
|
||
global $sess_save_path, $sess_session_name;
|
||
|
||
// $path - это путь, переданный PHP, но CMS использует свой путь:
|
||
$sess_save_path = BASE_DIR . '/tmp/session';
|
||
$sess_session_name = $name;
|
||
|
||
// Создание папки, если ее нет
|
||
if (!is_dir($sess_save_path)) {
|
||
@mkdir($sess_save_path, 0777, true);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' для соответствия SessionHandlerInterface
|
||
public function close(): bool
|
||
{
|
||
// Вызываем gc, чтобы не полагаться на system gc (хотя open/close не должны это делать)
|
||
$this->gc($this->sess_lifetime);
|
||
return true;
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' для соответствия SessionHandlerInterface
|
||
public function read(string $id): string|false
|
||
{
|
||
global $sess_save_path, $sess_session_name, $sess_session_id;
|
||
|
||
$sess_session_id = $id;
|
||
$sess_file = $this->_folder() . '/' . $id . '.sess';
|
||
|
||
if (!file_exists($sess_file)) return "";
|
||
|
||
// Используем file_get_contents для более чистой работы с файлами
|
||
$sess_data = @file_get_contents($sess_file);
|
||
|
||
// _read должен возвращать строку или false. Возвращаем пустую строку при ошибке.
|
||
return ($sess_data !== false) ? $sess_data : '';
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' для соответствия SessionHandlerInterface
|
||
public function write (string $id, string $sess_data): bool
|
||
{
|
||
global $sess_session_id;
|
||
|
||
$sess_session_id = $id;
|
||
$sess_folder = $this->_folder();
|
||
$sess_file = $sess_folder . '/' . $id . '.sess';
|
||
|
||
if(!file_exists($sess_folder))
|
||
@mkdir($sess_folder, 0777, true);
|
||
|
||
// Используем file_put_contents для более чистой записи
|
||
return (bool)@file_put_contents($sess_file, $sess_data);
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' для соответствия SessionHandlerInterface
|
||
public function destroy (string $id): bool
|
||
{
|
||
global $sess_session_id;
|
||
|
||
$sess_session_id = $id;
|
||
$sess_dir = $this->_folder();
|
||
$sess_file = $sess_dir . '/' . $id . '.sess';
|
||
|
||
return @unlink($sess_file);
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Убран префикс '_' и изменен возвращаемый тип на int|false
|
||
public function gc (int $maxlifetime): int|false
|
||
{
|
||
global $sess_save_path;
|
||
|
||
// Убеждаемся, что путь к сессиям установлен
|
||
if (!isset($sess_save_path)) {
|
||
$sess_save_path = BASE_DIR . '/tmp/session';
|
||
}
|
||
|
||
// Вызываем модифицированную функцию _clear, которая теперь возвращает count
|
||
$deleted_count = $this->_clear($sess_save_path, 'sess', $maxlifetime);
|
||
|
||
// Возвращаем количество удаленных файлов (требование интерфейса)
|
||
return $deleted_count;
|
||
}
|
||
|
||
// ИСПРАВЛЕНИЕ: Модифицирована для подсчета и возврата удаленных файлов
|
||
private function _clear(string $dir, string $mask, int $maxlifetime): int
|
||
{
|
||
$deleted_count = 0;
|
||
|
||
// Проверка существования каталога перед glob
|
||
if (!is_dir($dir)) return 0;
|
||
|
||
foreach(glob($dir . '/*') as $filename)
|
||
{
|
||
if (strtolower(substr($filename, strlen($filename) - strlen($mask), strlen($mask))) == strtolower($mask))
|
||
{
|
||
if ((filemtime($filename) + $maxlifetime) < time()) {
|
||
if (@unlink($filename)) {
|
||
$deleted_count++; // Увеличиваем счетчик
|
||
}
|
||
}
|
||
}
|
||
|
||
if (is_dir($filename)) {
|
||
// Сначала рекурсивно очищаем вложенные папки
|
||
$deleted_count += $this->_clear($filename, $mask, $maxlifetime);
|
||
|
||
// Удаляем пустую папку после очистки
|
||
if (!count(glob($filename.'/*'))) {
|
||
@rmdir($filename);
|
||
}
|
||
}
|
||
}
|
||
|
||
return $deleted_count; // Возвращаем общее количество удаленных
|
||
}
|
||
|
||
private function _folder(): string
|
||
{
|
||
global $sess_session_id, $sess_save_path;
|
||
|
||
return $sess_save_path . '/' . mb_substr($sess_session_id, 0, 3);
|
||
}
|
||
|
||
function __destruct ()
|
||
{
|
||
// Оставляем как есть, хотя в современном PHP не требуется
|
||
register_shutdown_function('session_write_close');
|
||
}
|
||
}
|
||
?>
|