PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.1.4
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.1.4
5.13.0 5.12.1 5.12.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 2 years ago
DbTable.php
173 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 use Zend_Session_SaveHandler_Interface;
18 /**
19 * Database-backed session save handler
20 *
21 */
22 class DbTable implements Zend_Session_SaveHandler_Interface
23 {
24 public static $wasSessionToLargeToRead = false;
25 protected $config;
26 protected $maxLifetime;
27 public const TABLE_NAME = 'session';
28 public const TOKEN_HASH_ALGO = 'sha512';
29 /**
30 * @param array $config
31 */
32 public function __construct($config)
33 {
34 $this->config = $config;
35 $this->maxLifetime = ini_get('session.gc_maxlifetime');
36 }
37 private function hashSessionId($id)
38 {
39 $salt = SettingsPiwik::getSalt();
40 return hash(self::TOKEN_HASH_ALGO, $id . $salt);
41 }
42 /**
43 * Destructor
44 *
45 * @return void
46 */
47 public function __destruct()
48 {
49 Zend_Session::writeClose();
50 }
51 /**
52 * Open Session - retrieve resources
53 *
54 * @param string $save_path
55 * @param string $name
56 * @return boolean
57 */
58 public function open($save_path, $name)
59 {
60 Db::get()->getConnection();
61 return true;
62 }
63 /**
64 * Close Session - free resources
65 *
66 * @return boolean
67 */
68 public function close()
69 {
70 return true;
71 }
72 /**
73 * Read session data
74 *
75 * @param string $id
76 * @return string
77 */
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)
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)
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 public function gc($maxlifetime)
152 {
153 $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' < ?';
154 $this->query($sql, array(time()));
155 return true;
156 }
157 private function migrateToDbSessionTable()
158 {
159 // happens when updating from Piwik 1.4 or earlier to Matomo 3.7+
160 // in this case on update it will change the session handler to dbtable, but it hasn't performed
161 // the DB updates just yet which means the session table won't be available as it was only added in
162 // Piwik 1.5 => results in a sql error the session table does not exist
163 try {
164 $sql = DbHelper::getTableCreateSql(self::TABLE_NAME);
165 Db::query($sql);
166 } catch (Exception $e) {
167 if (!Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
168 throw $e;
169 }
170 }
171 }
172 }
173