blob: 9e74605bce9d17d34b09b427e03c07b6b6240b44 [file] [log] [blame]
Andrey Andreev47a47fb2014-05-31 16:08:30 +03001<?php
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.2.4 or newer
6 *
7 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
19 * @package CodeIgniter
20 * @author Andrey Andreev
21 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
22 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
23 * @link http://codeigniter.com
24 * @since Version 3.0
25 * @filesource
26 */
27defined('BASEPATH') OR exit('No direct script access allowed');
28
29/**
30 * CodeIgniter Session Database Driver
31 *
32 * @package CodeIgniter
33 * @subpackage Libraries
34 * @category Sessions
35 * @author Andrey Andreev
36 * @link http://codeigniter.com/user_guide/libraries/sessions.html
37 */
38class CI_Session_database_driver extends CI_Session_driver implements SessionHandlerInterface {
39
40 /**
41 * DB object
42 *
43 * @var object
44 */
45 protected $_db;
46
47 /**
Andrey Andreev47a47fb2014-05-31 16:08:30 +030048 * Row exists flag
49 *
50 * @var bool
51 */
52 protected $_row_exists = FALSE;
53
54 /**
55 * Lock "driver" flag
56 *
57 * @var string
58 */
Andrey Andreev93d9fa72014-08-27 22:14:36 +030059 protected $_lock_driver = 'semaphore';
Andrey Andreev47a47fb2014-05-31 16:08:30 +030060
61 // ------------------------------------------------------------------------
62
63 /**
64 * Class constructor
65 *
66 * @param array $params Configuration parameters
67 * @return void
68 */
69 public function __construct(&$params)
70 {
71 parent::__construct($params);
72
73 $CI =& get_instance();
74 isset($CI->db) OR $CI->load->database();
75 $this->_db =& $CI->db;
76
77 if ( ! $this->_db instanceof CI_DB_query_builder)
78 {
79 throw new Exception('Query Builder not enabled for the configured database. Aborting.');
80 }
81 elseif ($this->_db->pconnect)
82 {
83 throw new Exception('Configured database connection is persistent. Aborting.');
84 }
85
86 $db_driver = $this->_db->dbdriver.(empty($this->_db->subdriver) ? '' : '_'.$this->_db->subdriver);
87 if (strpos($db_driver, 'mysql') !== FALSE)
88 {
Andrey Andreeve1b96652014-06-02 10:09:56 +030089 $this->_lock_driver = 'mysql';
Andrey Andreev47a47fb2014-05-31 16:08:30 +030090 }
91 elseif (in_array($db_driver, array('postgre', 'pdo_pgsql'), TRUE))
92 {
Andrey Andreeve1b96652014-06-02 10:09:56 +030093 $this->_lock_driver = 'postgre';
Andrey Andreev47a47fb2014-05-31 16:08:30 +030094 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +030095
Andrey Andreevdfb39be2014-10-06 01:50:14 +030096 isset($this->_config['save_path']) OR $this->_config['save_path'] = config_item('sess_table_name');
Andrey Andreev47a47fb2014-05-31 16:08:30 +030097 }
98
99 // ------------------------------------------------------------------------
100
101 public function open($save_path, $name)
102 {
103 return empty($this->_db->conn_id)
104 ? ( ! $this->_db->autoinit && $this->_db->db_connect())
105 : TRUE;
106 }
107
108 // ------------------------------------------------------------------------
109
110 public function read($session_id)
111 {
Andrey Andreevd069b9b2014-09-16 10:18:16 +0300112 if ($this->_get_lock($session_id) !== FALSE)
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300113 {
Andrey Andreev7474a672014-10-31 23:35:32 +0200114 // Needed by write() to detect session_regenerate_id() calls
115 $this->_session_id = $session_id;
116
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300117 $this->_db
118 ->select('data')
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300119 ->from($this->_config['save_path'])
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300120 ->where('id', $session_id);
121
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300122 if ($this->_config['match_ip'])
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300123 {
124 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
125 }
126
127 if (($result = $this->_db->get()->row()) === NULL)
128 {
129 $this->_fingerprint = md5('');
130 return '';
131 }
132
133 $this->_fingerprint = md5(rtrim($result->data));
134 $this->_row_exists = TRUE;
135 return $result->data;
136 }
137
138 $this->_fingerprint = md5('');
139 return '';
140 }
141
142 public function write($session_id, $session_data)
143 {
144 if ($this->_lock === FALSE)
145 {
146 return FALSE;
147 }
Andrey Andreev7474a672014-10-31 23:35:32 +0200148 // Was the ID regenerated?
149 elseif ($session_id !== $this->_session_id)
150 {
151 if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
152 {
153 return FALSE;
154 }
155
156 $this->_row_exists = FALSE;
157 $this->_session_id = $session_id;
158 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300159
160 if ($this->_row_exists === FALSE)
161 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300162 if ($this->_db->insert($this->_config['save_path'], array('id' => $session_id, 'ip_address' => $_SERVER['REMOTE_ADDR'], 'timestamp' => time(), 'data' => $session_data)))
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300163 {
164 $this->_fingerprint = md5($session_data);
165 return $this->_row_exists = TRUE;
166 }
167
168 return FALSE;
169 }
170
171 $this->_db->where('id', $session_id);
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300172 if ($this->_config['match_ip'])
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300173 {
174 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
175 }
176
177 $update_data = ($this->_fingerprint === md5($session_data))
178 ? array('timestamp' => time())
179 : array('timestamp' => time(), 'data' => $session_data);
180
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300181 if ($this->_db->update($this->_config['save_path'], $update_data))
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300182 {
183 $this->_fingerprint = md5($session_data);
184 return TRUE;
185 }
186
187 return FALSE;
188 }
189
190 // ------------------------------------------------------------------------
191
192 public function close()
193 {
194 return ($this->_lock)
195 ? $this->_release_lock()
196 : TRUE;
197 }
198
199 // ------------------------------------------------------------------------
200
201 public function destroy($session_id)
202 {
203 if ($this->_lock)
204 {
205 $this->_db->where('id', $session_id);
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300206 if ($this->_config['match_ip'])
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300207 {
208 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
209 }
210
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300211 return $this->_db->delete($this->_config['save_path'])
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300212 ? ($this->close() && $this->_cookie_destroy())
213 : FALSE;
214 }
215
216 return ($this->close() && $this->_cookie_destroy());
217 }
218
219 // ------------------------------------------------------------------------
220
221 public function gc($maxlifetime)
222 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300223 return $this->_db->delete($this->_config['save_path'], 'timestamp < '.(time() - $maxlifetime));
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300224 }
225
226 // ------------------------------------------------------------------------
227
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300228 protected function _get_lock($session_id)
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300229 {
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300230 if ($this->_lock_driver === 'mysql')
231 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300232 $arg = $session_id.($this->_config['match_ip'] ? '_'.$_SERVER['REMOTE_ADDR'] : '');
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300233 if ($this->_db->query("SELECT GET_LOCK('".$arg."', 10) AS ci_session_lock")->row()->ci_session_lock)
234 {
235 $this->_lock = $arg;
236 return TRUE;
237 }
238
239 return FALSE;
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300240 }
241 elseif ($this->_lock_driver === 'postgre')
242 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300243 $arg = "hashtext('".$session_id."')".($this->_config['match_ip'] ? ", hashtext('".$_SERVER['REMOTE_ADDR']."')" : '');
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300244 if ($this->_db->simple_query('SELECT pg_advisory_lock('.$arg.')'))
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300245 {
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300246 $this->_lock = $arg;
247 return TRUE;
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300248 }
249
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300250 return FALSE;
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300251 }
252
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300253 return parent::_get_lock($session_id);
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300254 }
255
256 // ------------------------------------------------------------------------
257
258 protected function _release_lock()
259 {
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300260 if ( ! $this->_lock)
261 {
262 return TRUE;
263 }
264
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300265 if ($this->_lock_driver === 'mysql')
266 {
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300267 if ($this->_db->query("SELECT RELEASE_LOCK('".$this->_lock."') AS ci_session_lock")->row()->ci_session_lock)
268 {
269 $this->_lock = FALSE;
270 return TRUE;
271 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300272
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300273 return FALSE;
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300274 }
275 elseif ($this->_lock_driver === 'postgre')
276 {
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300277 if ($this->_db->simple_query('SELECT pg_advisory_unlock('.$this->_lock.')'))
278 {
279 $this->_lock = FALSE;
280 return TRUE;
281 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300282
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300283 return FALSE;
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300284 }
285
Andrey Andreev93d9fa72014-08-27 22:14:36 +0300286 return parent::_release_lock();
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300287 }
288
289}
290
291/* End of file Session_database_driver.php */
292/* Location: ./system/libraries/Session/drivers/Session_database_driver.php */