Моя компания наконец-то перешла на PHP, и нам потребовались пользовательские сеансы, управляемые базой данных. Итак, я создал класс, который вставляю ниже (без чувствительных имен баз данных / таблиц)
Проблема, с которой я столкнулся сейчас, заключается в том, что мы хотели бы реализовать систему выгрузки файлов с проверкой прогресса через встроенную систему session.upload_progress, но пользовательский сеанс уничтожает эту функциональность. Когда я использую базовый сеанс, он работает, когда я использую этот сеанс, это не так. Я предполагаю, что я могу обойти это путем расширения SessionHandler и использования родительских методов, кажется ли это правильным или я все это делаю неправильно? (Очень плохо знаком с PHP, поэтому я подумал, что спрашивать не повредит).
<?php
class Session {
private $user_id;
private $last_login;
private $database;
public $user;
public $username;
public const MAX_LOGIN_AGE = 60 * 60 * 24; // 1 day
// Constructor which attaches pseudo magic methods to php sessions
public function __construct()
{
session_set_save_handler(
array($this, '_open'),
array($this, '_close'),
array($this, '_read'),
array($this, '_write'),
array($this, '_destroy'),
array($this, '_clean')
);
session_start();
$this->check_stored_login();
}
public function _open()
{
if ($session_db = db_connect(DB_DEV)) {
$this->database = $session_db;
return true;
}
return false;
}
public function _close()
{
// print "Session closed.\n";
return $this->database->close();
}
public function _read($id)
{
$id = $this->database->escape_string($id);
// print "Session read.\n";
// print "Sess_ID: $id\n";
$sql = "SELECT data
FROM sessions
WHERE id = '{$id}'";
if ($result = $this->database->query($sql)) {
if ($result->num_rows) {
$record = $result->fetch_assoc();
return $record['data'];
}
}
return '';
}
public function _write($id, $data)
{
$access = time();
$id = $this->database->escape_string($id);
$access = $this->database->escape_string($access);
$data = $this->database->escape_string($data);
// print "Session value written.\n";
// print "Sess_ID: $id\n";
// print "Data: $data\n\n";
$sql = "REPLACE
INTO sessions (`id`, `access`, `data`)
VALUES ('{$id}', '{$access}', '{$data}')";
$this->database->query($sql);
return true;
}
public function _destroy($id)
{
$id = $this->database->escape_string($id);
// print "Session destroy called.\n";
$sql = "DELETE
FROM sessions
WHERE id='{$id}'";
return $this->database->query($sql);
}
public function _clean($max)
{
$old = $time() - $max;
$this->database->escape_string($old);
$sql = "DELETE
FROM sessions
WHERE access < '{$old}'";
return $this->database->query($sql);
}
public function login($user)
{
if ($user) {
// prevent session fixation attacks
session_regenerate_id();
$this->user_id = $_SESSION['user_id'] = $user->id = $user->id;
$this->username = $_SESSION['username'] = $user->first_name;
$this->last_login = $_SESSION['last_login'] = time();
$this->user = $_SESSION['user'] = $user;
$_SESSION['search_text'] = '';
$_SESSION['search_product_id'] = '';
$args["last_login"] = date("Y-m-d H:m:s");
$user->merge_attributes($args);
$user->save();
}
}
public function is_logged_in()
{
if (!isset($this->user_id) || !$this->last_login_recent()) {
redirect_to(url_for('/index.php?logout'));
}
return true;
}
public function logout()
{
unset($_SESSION['user_id']);
unset($_SESSION['username']);
unset($_SESSION['last_login']);
unset($_SESSION['user']);
unset($this->user_id);
unset($this->username);
unset($this->last_login);
unset($this->user);
session_destroy();
return true;
}
private function check_stored_login()
{
if (isset($_SESSION['user_id'])) {
$this->user_id = $_SESSION['user_id'];
$this->username = $_SESSION['username'];
$this->last_login = $_SESSION['last_login'];
$this->user = $_SESSION['user'];
}
}
private function last_login_recent()
{
if (!isset($this->last_login)) {
return false;
} elseif ($this->last_login + self::MAX_LOGIN_AGE < time()) {
return false;
} else {
return true;
}
}
public function message($msg = '')
{
if (!empty($msg)) {
$_SESSION['message'] = $msg;
} else {
return $_SESSION['message'];
}
}
}
?>