PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.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 5 years ago
DbTable.php
213 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9
10 namespace Piwik\Session\SaveHandler;
11
12 use Piwik\Db;
13 use Piwik\DbHelper;
14 use Exception;
15 use Piwik\SettingsPiwik;
16 use Piwik\Updater\Migration;
17 use Zend_Session;
18 use Zend_Session_SaveHandler_Interface;
19
20 /**
21 * Database-backed session save handler
22 *
23 */
24 class DbTable implements Zend_Session_SaveHandler_Interface
25 {
26 protected $config;
27 protected $maxLifetime;
28
29 const TABLE_NAME = 'session';
30 const TOKEN_HASH_ALGO = 'sha512';
31
32 /**
33 * @param array $config
34 */
35 public function __construct($config)
36 {
37 $this->config = $config;
38 $this->maxLifetime = ini_get('session.gc_maxlifetime');
39 }
40
41 private function hashSessionId($id)
42 {
43 $salt = SettingsPiwik::getSalt();
44 return hash(self::TOKEN_HASH_ALGO, $id . $salt);
45 }
46
47
48 /**
49 * Destructor
50 *
51 * @return void
52 */
53 public function __destruct()
54 {
55 Zend_Session::writeClose();
56 }
57
58 /**
59 * Open Session - retrieve resources
60 *
61 * @param string $save_path
62 * @param string $name
63 * @return boolean
64 */
65 public function open($save_path, $name)
66 {
67 Db::get()->getConnection();
68
69 return true;
70 }
71
72 /**
73 * Close Session - free resources
74 *
75 * @return boolean
76 */
77 public function close()
78 {
79 return true;
80 }
81
82 /**
83 * Read session data
84 *
85 * @param string $id
86 * @return string
87 */
88 public function read($id)
89 {
90 $id = $this->hashSessionId($id);
91 $sql = 'SELECT ' . $this->config['dataColumn'] . ' FROM ' . $this->config['name']
92 . ' WHERE ' . $this->config['primary'] . ' = ?'
93 . ' AND ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' >= ?';
94
95 $result = $this->fetchOne($sql, array($id, time()));
96
97 if (!$result) {
98 $result = '';
99 }
100
101 return $result;
102 }
103
104 private function fetchOne($sql, $bind)
105 {
106 try {
107 $result = Db::get()->fetchOne($sql, $bind);
108 } catch (Exception $e) {
109 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
110 $this->migrateToDbSessionTable();
111 $result = Db::get()->fetchOne($sql, $bind);
112 } else {
113 throw $e;
114 }
115 }
116 return $result;
117 }
118
119 private function query($sql, $bind)
120 {
121 try {
122 $result = Db::get()->query($sql, $bind);
123 } catch (Exception $e) {
124 if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
125 $this->migrateToDbSessionTable();
126 $result = Db::get()->query($sql, $bind);
127 } else {
128 throw $e;
129 }
130 }
131 return $result;
132 }
133
134 /**
135 * Write Session - commit data to resource
136 *
137 * @param string $id
138 * @param mixed $data
139 * @return boolean
140 */
141 public function write($id, $data)
142 {
143 $id = $this->hashSessionId($id);
144
145 $sql = 'INSERT INTO ' . $this->config['name']
146 . ' (' . $this->config['primary'] . ','
147 . $this->config['modifiedColumn'] . ','
148 . $this->config['lifetimeColumn'] . ','
149 . $this->config['dataColumn'] . ')'
150 . ' VALUES (?,?,?,?)'
151 . ' ON DUPLICATE KEY UPDATE '
152 . $this->config['modifiedColumn'] . ' = ?,'
153 . $this->config['lifetimeColumn'] . ' = ?,'
154 . $this->config['dataColumn'] . ' = ?';
155
156 $this->query($sql, array($id, time(), $this->maxLifetime, $data, time(), $this->maxLifetime, $data));
157
158 return true;
159 }
160
161 /**
162 * Destroy Session - remove data from resource for
163 * given session id
164 *
165 * @param string $id
166 * @return boolean
167 */
168 public function destroy($id)
169 {
170 $id = $this->hashSessionId($id);
171
172 $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?';
173
174 $this->query($sql, array($id));
175
176 return true;
177 }
178
179 /**
180 * Garbage Collection - remove old session data older
181 * than $maxlifetime (in seconds)
182 *
183 * @param int $maxlifetime timestamp in seconds
184 * @return bool always true
185 */
186 public function gc($maxlifetime)
187 {
188 $sql = 'DELETE FROM ' . $this->config['name']
189 . ' WHERE ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' < ?';
190
191 $this->query($sql, array(time()));
192
193 return true;
194 }
195
196 private function migrateToDbSessionTable()
197 {
198 // happens when updating from Piwik 1.4 or earlier to Matomo 3.7+
199 // in this case on update it will change the session handler to dbtable, but it hasn't performed
200 // the DB updates just yet which means the session table won't be available as it was only added in
201 // Piwik 1.5 => results in a sql error the session table does not exist
202 try {
203 $sql = DbHelper::getTableCreateSql(self::TABLE_NAME);
204 Db::query($sql);
205 } catch (Exception $e) {
206 if (!Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
207 throw $e;
208 }
209 }
210 }
211
212 }
213