blob: 24847456c8a2577d22f7ebe871f9be6b31bbcad9 [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 /**
48 * DB table
49 *
50 * @var string
51 */
52 protected $_table;
53
54 /**
55 * Session ID
56 *
57 * @var string
58 */
59 protected $_session_id;
60
61 /**
62 * Row exists flag
63 *
64 * @var bool
65 */
66 protected $_row_exists = FALSE;
67
68 /**
69 * Lock "driver" flag
70 *
71 * @var string
72 */
73 protected $_lock_driver;
74
75 /**
76 * Lock status flag
77 *
78 * @var bool
79 */
80 protected $_lock = FALSE;
81
82 /**
83 * Semaphore ID
84 *
85 * Used for locking if the database doesn't support advisory locks
86 *
87 * @var resource
88 */
89 protected $_sem;
90
91 // ------------------------------------------------------------------------
92
93 /**
94 * Class constructor
95 *
96 * @param array $params Configuration parameters
97 * @return void
98 */
99 public function __construct(&$params)
100 {
101 parent::__construct($params);
102
103 $CI =& get_instance();
104 isset($CI->db) OR $CI->load->database();
105 $this->_db =& $CI->db;
106
107 if ( ! $this->_db instanceof CI_DB_query_builder)
108 {
109 throw new Exception('Query Builder not enabled for the configured database. Aborting.');
110 }
111 elseif ($this->_db->pconnect)
112 {
113 throw new Exception('Configured database connection is persistent. Aborting.');
114 }
115
116 $db_driver = $this->_db->dbdriver.(empty($this->_db->subdriver) ? '' : '_'.$this->_db->subdriver);
117 if (strpos($db_driver, 'mysql') !== FALSE)
118 {
119 $this->_lock_type = 'mysql';
120 }
121 elseif (in_array($db_driver, array('postgre', 'pdo_pgsql'), TRUE))
122 {
123 $this->_lock_type = 'postgre';
124 }
125 elseif (extension_loaded('sysvsem'))
126 {
127 $this->_lock_type = 'semaphore';
128 }
129
130 isset($this->_table) OR $this->_table = config_item('sess_table_name');
131 }
132
133 // ------------------------------------------------------------------------
134
135 public function open($save_path, $name)
136 {
137 return empty($this->_db->conn_id)
138 ? ( ! $this->_db->autoinit && $this->_db->db_connect())
139 : TRUE;
140 }
141
142 // ------------------------------------------------------------------------
143
144 public function read($session_id)
145 {
146 $this->_session_id = $session_id;
147 if (($this->_lock = $this->_get_lock()) !== FALSE)
148 {
149 $this->_db
150 ->select('data')
151 ->from($this->_table)
152 ->where('id', $session_id);
153
154 if ($this->_match_ip)
155 {
156 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
157 }
158
159 if (($result = $this->_db->get()->row()) === NULL)
160 {
161 $this->_fingerprint = md5('');
162 return '';
163 }
164
165 $this->_fingerprint = md5(rtrim($result->data));
166 $this->_row_exists = TRUE;
167 return $result->data;
168 }
169
170 $this->_fingerprint = md5('');
171 return '';
172 }
173
174 public function write($session_id, $session_data)
175 {
176 if ($this->_lock === FALSE)
177 {
178 return FALSE;
179 }
180
181 if ($this->_row_exists === FALSE)
182 {
183 if ($this->_db->insert($this->_table, array('id' => $session_id, 'ip_address' => $_SERVER['REMOTE_ADDR'], 'timestamp' => time(), 'data' => $session_data)))
184 {
185 $this->_fingerprint = md5($session_data);
186 return $this->_row_exists = TRUE;
187 }
188
189 return FALSE;
190 }
191
192 $this->_db->where('id', $session_id);
193 if ($this->_match_ip)
194 {
195 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
196 }
197
198 $update_data = ($this->_fingerprint === md5($session_data))
199 ? array('timestamp' => time())
200 : array('timestamp' => time(), 'data' => $session_data);
201
202 if ($this->_db->update($this->_table, $update_data))
203 {
204 $this->_fingerprint = md5($session_data);
205 return TRUE;
206 }
207
208 return FALSE;
209 }
210
211 // ------------------------------------------------------------------------
212
213 public function close()
214 {
215 return ($this->_lock)
216 ? $this->_release_lock()
217 : TRUE;
218 }
219
220 // ------------------------------------------------------------------------
221
222 public function destroy($session_id)
223 {
224 if ($this->_lock)
225 {
226 $this->_db->where('id', $session_id);
227 if ($this->_match_ip)
228 {
229 $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
230 }
231
232 return $this->_db->delete($this->_table)
233 ? ($this->close() && $this->_cookie_destroy())
234 : FALSE;
235 }
236
237 return ($this->close() && $this->_cookie_destroy());
238 }
239
240 // ------------------------------------------------------------------------
241
242 public function gc($maxlifetime)
243 {
244 return $this->_db->delete($this->_table, 'timestamp < '.(time() - $maxlifetime));
245 }
246
247 // ------------------------------------------------------------------------
248
249 protected function _get_lock()
250 {
251 $arg = $this->_session_id
252 .($this->_match_ip ? '_'.$_SERVER['REMOTE_ADDR'] : '');
253
254 if ($this->_lock_driver === 'mysql')
255 {
256 return (bool) $this->_db
257 ->query("SELECT GET_LOCK('".$session_id."', 10) AS ci_session_lock")
258 ->row()
259 ->ci_session_lock;
260 }
261 elseif ($this->_lock_driver === 'postgre')
262 {
263 return (bool) $this->_db->simple_query('SELECT pg_advisory_lock('.$arg.')');
264 }
265 elseif ($this->_lock_driver === 'semaphore')
266 {
267 if (($this->_sem = sem_get($arg, 1, 0644)) === FALSE)
268 {
269 return FALSE;
270 }
271
272 if ( ! sem_acquire($this->_sem))
273 {
274 sem_remove($this->_sem);
275 return FALSE;
276 }
277
278 return TRUE;
279 }
280
281 return TRUE;
282 }
283
284 // ------------------------------------------------------------------------
285
286 protected function _release_lock()
287 {
288 if ($this->_lock_driver === 'mysql')
289 {
290 $arg = $this->_session_id
291 .($this->_match_ip ? '_'.$_SERVER['REMOTE_ADDR'] : '');
292
293 return (bool) $this->_db
294 ->query("SELECT RELEASE_LOCK('".$arg."') AS ci_session_lock")
295 ->row()
296 ->ci_session_lock;
297 }
298 elseif ($this->_lock_driver === 'postgre')
299 {
300 $arg = "hashtext('".$this->_session_id."')"
301 .($this->_match_ip ? ", hashtext('".$_SERVER['REMOTE_ADDR']."')" : '');
302
303 return (bool) $this->_db->simple_query('SELECT pg_advisory_unlock('.$arg.')');
304 }
305 elseif ($this->_lock_driver === 'semaphore')
306 {
307 sem_release($this->_sem);
308 sem_remove($this->_sem);
309 }
310
311 return TRUE;
312 }
313
314}
315
316/* End of file Session_database_driver.php */
317/* Location: ./system/libraries/Session/drivers/Session_database_driver.php */