PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Session / SaveHandler / DbTable.php
matomo / app / core / Session / SaveHandler Last commit date
DbTable.php 1 month ago
DbTable.php
178 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik\Session\SaveHandler;
10
11 use Piwik\Db;
12 use Piwik\DbHelper;
13 use Exception;
14 use Piwik\SettingsPiwik;
15 use Piwik\Updater\Migration;
16 use Zend_Session;
17 /**
18 * Database-backed session save handler
19 *
20 */
21 class DbTable implements \SessionHandlerInterface
22 {
23 public static $wasSessionToLargeToRead = \false;
24 protected $config;
25 protected $maxLifetime;
26 public const TABLE_NAME = 'session';
27 public const TOKEN_HASH_ALGO = 'sha512';
28 /**
29 * @param array $config
30 */
31 public function __construct($config)
32 {
33 $this->config = $config;
34 $this->maxLifetime = ini_get('session.gc_maxlifetime');
35 }
36 private function hashSessionId($id)
37 {
38 $salt = SettingsPiwik::getSalt();
39 return hash(self::TOKEN_HASH_ALGO, $id . $salt);
40 }
41 /**
42 * Destructor
43 *
44 * @return void
45 */
46 public function __destruct()
47 {
48 Zend_Session::writeClose();
49 }
50 /**
51 * Open Session - retrieve resources
52 *
53 * @param string $save_path
54 * @param string $name
55 */
56 public function open($save_path, $name) : bool
57 {
58 Db::get()->getConnection();
59 return \true;
60 }
61 /**
62 * Close Session - free resources
63 */
64 public function close() : bool
65 {
66 return \true;
67 }
68 /**
69 * Read session data
70 *
71 * @param string $id
72 * @return string
73 */
74 #[\ReturnTypeWillChange]
75 public function read($id)
76 {
77 $id = $this->hashSessionId($id);
78 $sql = 'SELECT ' . $this->config['dataColumn'] . ' FROM `' . $this->config['name'] . '`' . ' WHERE ' . $this->config['primary'] . ' = ?' . ' AND ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' >= ?';
79 $result = $this->fetchOne($sql, [$id, time()]);
80 if (!$result) {
81 $result = '';
82 }
83 return $result;
84 }
85 private function fetchOne($sql, $bind)
86 {
87 try {
88 $result = Db::get()->fetchOne($sql, $bind);
89 } catch (Exception $e) {
90 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
91 $this->migrateToDbSessionTable();
92 $result = Db::get()->fetchOne($sql, $bind);
93 } else {
94 throw $e;
95 }
96 }
97 return $result;
98 }
99 private function query($sql, $bind)
100 {
101 try {
102 $result = Db::get()->query($sql, $bind);
103 } catch (Exception $e) {
104 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
105 $this->migrateToDbSessionTable();
106 $result = Db::get()->query($sql, $bind);
107 } else {
108 throw $e;
109 }
110 }
111 return $result;
112 }
113 /**
114 * Write Session - commit data to resource
115 *
116 * @param string $id
117 * @param mixed $data
118 */
119 public function write($id, $data) : bool
120 {
121 $id = $this->hashSessionId($id);
122 $sql = 'INSERT INTO ' . $this->config['name'] . ' (' . $this->config['primary'] . ',' . $this->config['modifiedColumn'] . ',' . $this->config['lifetimeColumn'] . ',' . $this->config['dataColumn'] . ')' . ' VALUES (?,?,?,?)' . ' ON DUPLICATE KEY UPDATE ' . $this->config['modifiedColumn'] . ' = ?,' . $this->config['lifetimeColumn'] . ' = ?,' . $this->config['dataColumn'] . ' = ?';
123 $this->query($sql, [$id, time(), $this->maxLifetime, $data, time(), $this->maxLifetime, $data]);
124 return \true;
125 }
126 /**
127 * Destroy Session - remove data from resource for
128 * given session id
129 *
130 * @param string $id
131 */
132 public function destroy($id) : bool
133 {
134 $id = $this->hashSessionId($id);
135 $sql = 'DELETE FROM `' . $this->config['name'] . '` WHERE ' . $this->config['primary'] . ' = ?';
136 $this->query($sql, [$id]);
137 return \true;
138 }
139 /**
140 * Destroys all Sessions - removes all rows in Session table
141 */
142 public function destroyAll() : bool
143 {
144 $sql = 'TRUNCATE TABLE `' . $this->config['name'] . '`';
145 $this->query($sql, []);
146 return \true;
147 }
148 /**
149 * Garbage Collection - remove old session data older
150 * than $maxlifetime (in seconds)
151 *
152 * @param int $maxlifetime timestamp in seconds
153 * @return bool always true
154 */
155 #[\ReturnTypeWillChange]
156 public function gc($maxlifetime)
157 {
158 $sql = 'DELETE FROM `' . $this->config['name'] . '`' . ' WHERE ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' < ?';
159 $this->query($sql, [time()]);
160 return \true;
161 }
162 private function migrateToDbSessionTable()
163 {
164 // happens when updating from Piwik 1.4 or earlier to Matomo 3.7+
165 // in this case on update it will change the session handler to dbtable, but it hasn't performed
166 // the DB updates just yet which means the session table won't be available as it was only added in
167 // Piwik 1.5 => results in a sql error the session table does not exist
168 try {
169 $sql = DbHelper::getTableCreateSql(self::TABLE_NAME);
170 Db::query($sql);
171 } catch (Exception $e) {
172 if (!Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
173 throw $e;
174 }
175 }
176 }
177 }
178