blob: a4f1b9f2f8f158f05793d75cf948e2831856ad71 [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 Files 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_files_driver extends CI_Session_driver implements SessionHandlerInterface {
39
40 /**
41 * Save path
42 *
43 * @var string
44 */
45 protected $_save_path;
46
47 /**
48 * File handle
49 *
50 * @var resource
51 */
52 protected $_file_handle;
53
54 /**
55 * File name
56 *
57 * @var resource
58 */
59 protected $_file_path;
60
61 /**
62 * File new flag
63 *
64 * @var bool
65 */
66 protected $_file_new;
67
68 // ------------------------------------------------------------------------
69
70 /**
71 * Class constructor
72 *
73 * @param array $params Configuration parameters
74 * @return void
75 */
76 public function __construct(&$params)
77 {
78 parent::__construct($params);
79
Andrey Andreevdfb39be2014-10-06 01:50:14 +030080 if (isset($this->_config['save_path']))
Andrey Andreev47a47fb2014-05-31 16:08:30 +030081 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +030082 $this->_config['save_path'] = rtrim($this->_config['save_path'], '/\\');
83 ini_set('session.save_path', $this->_config['save_path']);
Andrey Andreev47a47fb2014-05-31 16:08:30 +030084 }
85 else
86 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +030087 $this->_config['save_path'] = rtrim(ini_get('session.save_path'), '/\\');
Andrey Andreev47a47fb2014-05-31 16:08:30 +030088 }
89 }
90
91 // ------------------------------------------------------------------------
92
93 public function open($save_path, $name)
94 {
95 if ( ! is_dir($save_path) && ! mkdir($save_path, 0700, TRUE))
96 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +030097 log_message('error', "Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created.");
Andrey Andreev47a47fb2014-05-31 16:08:30 +030098 return FALSE;
99 }
100
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300101 $this->_config['save_path'] = $save_path;
102 $this->_file_path = $this->_config['save_path'].DIRECTORY_SEPARATOR
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300103 .$name // we'll use the session cookie name as a prefix to avoid collisions
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300104 .($this->_config['match_ip'] ? md5($_SERVER['REMOTE_ADDR']) : '');
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300105
106 return TRUE;
107 }
108
109 // ------------------------------------------------------------------------
110
111 public function read($session_id)
112 {
113 // This might seem weird, but PHP 5.6 introduces session_reset(),
114 // which re-reads session data
115 if ($this->_file_handle === NULL)
116 {
117 $this->_file_path .= $session_id;
118
119 // Just using fopen() with 'c+b' mode would be perfect, but it is only
120 // available since PHP 5.2.6 and we have to set permissions for new files,
121 // so we'd have to hack around this ...
122 if (($this->_file_new = ! file_exists($this->_file_path)) === TRUE)
123 {
124 if (($this->_file_handle = fopen($this->_file_path, 'w+b')) === FALSE)
125 {
126 log_message('error', "Session: File '".$this->_file_path."' doesn't exist and cannot be created.");
127 return FALSE;
128 }
129 }
130 elseif (($this->_file_handle = fopen($this->_file_path, 'r+b')) === FALSE)
131 {
132 log_message('error', "Session: Unable to open file '".$this->_file_path."'.");
133 return FALSE;
134 }
135
136 if (flock($this->_file_handle, LOCK_EX) === FALSE)
137 {
138 log_message('error', "Session: Unable to obtain lock for file '".$this->_file_path."'.");
139 fclose($this->_file_handle);
140 $this->_file_handle = NULL;
141 return FALSE;
142 }
143
144 if ($this->_file_new)
145 {
146 chmod($this->_file_path, 0600);
147 $this->_fingerprint = md5('');
148 return '';
149 }
150 }
151 else
152 {
153 rewind($this->_file_handle);
154 }
155
156 $session_data = '';
157 for ($read = 0, $length = filesize($this->_file_path); $read < $length; $read += strlen($buffer))
158 {
159 if (($buffer = fread($this->_file_handle, $length - $read)) === FALSE)
160 {
161 break;
162 }
163
164 $session_data .= $buffer;
165 }
166
167 $this->_fingerprint = md5($session_data);
168 return $session_data;
169 }
170
171 public function write($session_id, $session_data)
172 {
173 if ( ! is_resource($this->_file_handle))
174 {
175 return FALSE;
176 }
177 elseif ($this->_fingerprint === md5($session_data))
178 {
179 return ($this->_file_new)
180 ? TRUE
181 : touch($this->_file_path);
182 }
183
184 if ( ! $this->_file_new)
185 {
186 ftruncate($this->_file_handle, 0);
187 rewind($this->_file_handle);
188 }
189
Andrey Andreev5995e082014-06-03 15:33:51 +0300190 if (($length = strlen($session_data)) > 0)
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300191 {
Andrey Andreev5995e082014-06-03 15:33:51 +0300192 for ($written = 0; $written < $length; $written += $result)
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300193 {
Andrey Andreev5995e082014-06-03 15:33:51 +0300194 if (($result = fwrite($this->_file_handle, substr($session_data, $written))) === FALSE)
195 {
196 break;
197 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300198 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300199
Andrey Andreev5995e082014-06-03 15:33:51 +0300200 if ( ! is_int($result))
201 {
202 $this->_fingerprint = md5(substr($session_data, 0, $written));
203 log_message('error', 'Session: Unable to write data.');
204 return FALSE;
205 }
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300206 }
207
208 $this->_fingerprint = md5($session_data);
209 return TRUE;
210 }
211
212 // ------------------------------------------------------------------------
213
214 public function close()
215 {
216 if (is_resource($this->_file_handle))
217 {
218 flock($this->_file_handle, LOCK_UN);
219 fclose($this->_file_handle);
220
221 $this->_file_handle = $this->_file_new = NULL;
222 return TRUE;
223 }
224
225 return FALSE;
226 }
227
228 // ------------------------------------------------------------------------
229
230 public function destroy($session_id)
231 {
232 if ($this->close())
233 {
234 return unlink($this->_file_path) && $this->_cookie_destroy();
235 }
236 elseif ($this->_file_path !== NULL)
237 {
238 clearstatcache();
239 return file_exists($this->_file_path)
240 ? (unlink($this->_file_path) && $this->_cookie_destroy())
241 : TRUE;
242 }
243
244 return FALSE;
245 }
246
247 // ------------------------------------------------------------------------
248
249 public function gc($maxlifetime)
250 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300251 if ( ! is_dir($this->_config['save_path']) OR ($files = scandir($this->_config['save_path'])) === FALSE)
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300252 {
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300253 log_message('debug', "Session: Garbage collector couldn't list files under directory '".$this->_config['save_path']."'.");
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300254 return FALSE;
255 }
256
257 $ts = time() - $maxlifetime;
258
259 foreach ($files as $file)
260 {
261 // If the filename doesn't match this pattern, it's either not a session file or is not ours
262 if ( ! preg_match('/(?:[0-9a-f]{32})?[0-9a-f]{40}$/i', $file)
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300263 OR ! is_file($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)
264 OR ($mtime = filemtime($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)) === FALSE
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300265 OR $mtime > $ts)
266 {
267 continue;
268 }
269
Andrey Andreevdfb39be2014-10-06 01:50:14 +0300270 unlink($this->_config['save_path'].DIRECTORY_SEPARATOR.$file);
Andrey Andreev47a47fb2014-05-31 16:08:30 +0300271 }
272
273 return TRUE;
274 }
275
276}
277
278/* End of file Session_files_driver.php */
279/* Location: ./system/libraries/Session/drivers/Session_files_driver.php */