-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSessionDB.php
93 lines (79 loc) · 2.58 KB
/
SessionDB.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php
namespace core;
/**
* Override default PHP session handler with custom one that uses database.
* Motivation? i.e. share sessions between frontends (high availability)
*/
class SessionDB implements \SessionHandlerInterface
{
private $db = null;
private ?string $savePath = null;
private array $hash = [];
public function __construct($db) {
$this->db = $db;
}
public function open($savePath, $sessionName): bool
{
$this->savePath = ""; //$savePath;
return true;
}
public function close(): bool
{
return true;
}
#[\ReturnTypeWillChange]
public function read($id)
{
if (! self::slug($id)) user_error("invalid session.id=$id");
$data = $this->db->getCell("SELECT value FROM session WHERE path = ?", [$this->getPath($id)]);
if (! $data) $data = ""; // Suppress no result here
$data = trim($data); // Ensure simple string..
$this->hash[$id] = md5($data);
return $data;
}
public function write($id, $data): bool
{
if (! self::slug($id)) user_error("invalid session.id=$id");
if ($data === 'a:0:{}') return true; // no storage for empty data
$data = trim($data);
if (isset($this->hash[$id]) && $this->hash[$id] === md5($data)) return true; // don't overwrite with no change
$now = time();
$this->db->insertUpdate("session",
["value" => $data, "path" => $this->getPath($id), "tm_updated" => $now],
["value" => $data, "tm_updated" => $now],
);
$this->hash[$id] = md5($data);
return true;
}
public function destroy($id): bool
{
if (! self::slug($id)) user_error("invalid session.id=$id");
$path = $this->getPath($id);
$aff = $this->db->delete("session", ["path" => $path]);
if ($aff !== 1) error_log("WARN: Session(%s) could not find in DB", $path);
return true;
}
#[\ReturnTypeWillChange]
public function gc($maxlifetime)
{
// TODO: Warn when getting slow?
$this->db->exec("DELETE FROM session WHERE tm_updated < ?", [time() - $maxlifetime]);
return true;
}
public function getPath($id)
{
return sprintf("%s/%s", $this->savePath, $id);
}
private static function slug($val)
{
return 1 === preg_match("/^[a-z0-9_\-]{2,}$/i", $val);
}
public static function init($db)
{
if (\ini_get("session.serialize_handler") !== "php_serialize") {
\ini_set("session.serialize_handler", "php_serialize"); // use text serializer
}
$handler = new self($db);
\session_set_save_handler($handler, true);
}
}