PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.0
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 year ago
DbTable.php
174 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 * @return boolean
56 */
57 public function open($save_path, $name) : bool
58 {
59 Db::get()->getConnection();
60 return \true;
61 }
62 /**
63 * Close Session - free resources
64 *
65 * @return boolean
66 */
67 public function close() : bool
68 {
69 return \true;
70 }
71 /**
72 * Read session data
73 *
74 * @param string $id
75 * @return string
76 */
77 #[\ReturnTypeWillChange]
78 public function read($id)
79 {
80 $id = $this->hashSessionId($id);
81 $sql = 'SELECT ' . $this->config['dataColumn'] . ' FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?' . ' AND ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' >= ?';
82 $result = $this->fetchOne($sql, array($id, time()));
83 if (!$result) {
84 $result = '';
85 }
86 return $result;
87 }
88 private function fetchOne($sql, $bind)
89 {
90 try {
91 $result = Db::get()->fetchOne($sql, $bind);
92 } catch (Exception $e) {
93 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
94 $this->migrateToDbSessionTable();
95 $result = Db::get()->fetchOne($sql, $bind);
96 } else {
97 throw $e;
98 }
99 }
100 return $result;
101 }
102 private function query($sql, $bind)
103 {
104 try {
105 $result = Db::get()->query($sql, $bind);
106 } catch (Exception $e) {
107 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
108 $this->migrateToDbSessionTable();
109 $result = Db::get()->query($sql, $bind);
110 } else {
111 throw $e;
112 }
113 }
114 return $result;
115 }
116 /**
117 * Write Session - commit data to resource
118 *
119 * @param string $id
120 * @param mixed $data
121 * @return boolean
122 */
123 public function write($id, $data) : bool
124 {
125 $id = $this->hashSessionId($id);
126 $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'] . ' = ?';
127 $this->query($sql, array($id, time(), $this->maxLifetime, $data, time(), $this->maxLifetime, $data));
128 return \true;
129 }
130 /**
131 * Destroy Session - remove data from resource for
132 * given session id
133 *
134 * @param string $id
135 * @return boolean
136 */
137 public function destroy($id) : bool
138 {
139 $id = $this->hashSessionId($id);
140 $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?';
141 $this->query($sql, array($id));
142 return \true;
143 }
144 /**
145 * Garbage Collection - remove old session data older
146 * than $maxlifetime (in seconds)
147 *
148 * @param int $maxlifetime timestamp in seconds
149 * @return bool always true
150 */
151 #[\ReturnTypeWillChange]
152 public function gc($maxlifetime)
153 {
154 $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' < ?';
155 $this->query($sql, array(time()));
156 return \true;
157 }
158 private function migrateToDbSessionTable()
159 {
160 // happens when updating from Piwik 1.4 or earlier to Matomo 3.7+
161 // in this case on update it will change the session handler to dbtable, but it hasn't performed
162 // the DB updates just yet which means the session table won't be available as it was only added in
163 // Piwik 1.5 => results in a sql error the session table does not exist
164 try {
165 $sql = DbHelper::getTableCreateSql(self::TABLE_NAME);
166 Db::query($sql);
167 } catch (Exception $e) {
168 if (!Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
169 throw $e;
170 }
171 }
172 }
173 }
174