streams/Code/Web/SessionRedis.php

127 lines
3.7 KiB
PHP
Raw Normal View History

2023-11-28 21:07:37 +00:00
<?php
namespace Code\Web;
use SessionHandlerInterface;
use Redis;
use RedisException;
class SessionRedis implements SessionHandlerInterface {
private $redis = null;
function __construct($connection) {
$this->redis = new Redis();
$credentials = parse_url($connection);
try {
if (isset($credentials['path'])) {
$this->redis->connect($credentials['path']);
}
else {
if (isset($credentials['query'])) {
parse_str($credentials['query'], $vars);
}
else {
$vars = [];
}
$this->redis->connect(
(isset($credentials['scheme']) ? $credentials['scheme'] . '://' : '') . $credentials['host'],
(isset($credentials['port']) ? $credentials['port'] : 6379),
(isset($vars['timeout']) ? $vars['timeout'] : 1),
null,
0,
(isset($vars['read_timeout']) ? $vars['read_timeout'] : 0)
);
if (isset($vars['auth'])) {
$this->redis->auth($vars['auth']);
}
}
}
catch(RedisException $ex) {
logger('Error connecting to Redis: ' . $ex->getMessage());
}
}
#[\ReturnTypeWillChange]
function open($s, $n) {
return true;
}
// IMPORTANT: if we read the session and it doesn't exist, create an empty record.
// We rely on this due to differing PHP implementation of session_regenerate_id()
// some which call read explicitly and some that do not. So we call it explicitly
// just after sid regeneration to force a record to exist.
#[\ReturnTypeWillChange]
function read($id) {
if ($id) {
$data = $this->redis->get($id);
if ($data) {
return $data;
}
else {
$this->redis->setEx($id, 300, '');
}
}
return '';
}
#[\ReturnTypeWillChange]
function write($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
// See: https://stackoverflow.com/a/43636110
if (! $id || ! $data) {
return true;
}
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to clean up the hundreds or
// thousands of empty sessions left around from web crawlers which are
// assigned cookies on each page that they never use.
$expire = 300;
if ($_SESSION) {
if (array_key_exists('remember_me',$_SESSION) && intval($_SESSION['remember_me'])) {
$expire = 60 * 60 * 24 * 365;
}
elseif (local_channel()) {
$expire = 60 * 60 * 24 * 3;
}
elseif (remote_channel()) {
$expire = 60 * 60 * 24 * 1;
}
}
$this->redis->setEx($id, $expire, $data);
return true;
}
#[\ReturnTypeWillChange]
function close() {
return true;
}
#[\ReturnTypeWillChange]
function destroy ($id) {
$this->redis->del($id);
return true;
}
#[\ReturnTypeWillChange]
function gc($expire) {
return true;
}
}