PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/vendorci/libraries/Session/drivers/Session_files_driver.php

https://gitlab.com/gundambison/secure
PHP | 363 lines | 213 code | 27 blank | 123 comment | 20 complexity | 7d4897d4dc7946da913116c096ed1a7e MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link http://codeigniter.com
  35. * @since Version 3.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * CodeIgniter Session Files Driver
  41. *
  42. * @package CodeIgniter
  43. * @subpackage Libraries
  44. * @category Sessions
  45. * @author Andrey Andreev
  46. * @link http://codeigniter.com/user_guide/libraries/sessions.html
  47. */
  48. class CI_Session_files_driver extends CI_Session_driver implements SessionHandlerInterface {
  49. /**
  50. * Save path
  51. *
  52. * @var string
  53. */
  54. protected $_save_path;
  55. /**
  56. * File handle
  57. *
  58. * @var resource
  59. */
  60. protected $_file_handle;
  61. /**
  62. * File name
  63. *
  64. * @var resource
  65. */
  66. protected $_file_path;
  67. /**
  68. * File new flag
  69. *
  70. * @var bool
  71. */
  72. protected $_file_new;
  73. // ------------------------------------------------------------------------
  74. /**
  75. * Class constructor
  76. *
  77. * @param array $params Configuration parameters
  78. * @return void
  79. */
  80. public function __construct(&$params)
  81. {
  82. parent::__construct($params);
  83. if (isset($this->_config['save_path']))
  84. {
  85. $this->_config['save_path'] = rtrim($this->_config['save_path'], '/\\');
  86. ini_set('session.save_path', $this->_config['save_path']);
  87. }
  88. else
  89. {
  90. $this->_config['save_path'] = rtrim(ini_get('session.save_path'), '/\\');
  91. }
  92. }
  93. // ------------------------------------------------------------------------
  94. /**
  95. * Open
  96. *
  97. * Sanitizes the save_path directory.
  98. *
  99. * @param string $save_path Path to session files' directory
  100. * @param string $name Session cookie name
  101. * @return bool
  102. */
  103. public function open($save_path, $name)
  104. {
  105. if ( $save_path=='')return true;
  106. if ( ! is_dir($save_path))
  107. {
  108. if ( ! mkdir($save_path, 0700, TRUE))
  109. {
  110. throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created.");
  111. }
  112. }
  113. elseif ( ! is_writable($save_path))
  114. {
  115. throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not writable by the PHP process.");
  116. }
  117. $this->_config['save_path'] = $save_path;
  118. $this->_file_path = $this->_config['save_path'].DIRECTORY_SEPARATOR
  119. .$name // we'll use the session cookie name as a prefix to avoid collisions
  120. .($this->_config['match_ip'] ? md5($_SERVER['REMOTE_ADDR']) : '');
  121. return TRUE;
  122. }
  123. // ------------------------------------------------------------------------
  124. /**
  125. * Read
  126. *
  127. * Reads session data and acquires a lock
  128. *
  129. * @param string $session_id Session ID
  130. * @return string Serialized session data
  131. */
  132. public function read($session_id)
  133. {
  134. // This might seem weird, but PHP 5.6 introduces session_reset(),
  135. // which re-reads session data
  136. if ($this->_file_handle === NULL)
  137. {
  138. // Just using fopen() with 'c+b' mode would be perfect, but it is only
  139. // available since PHP 5.2.6 and we have to set permissions for new files,
  140. // so we'd have to hack around this ...
  141. if (($this->_file_new = ! file_exists($this->_file_path.$session_id)) === TRUE)
  142. {
  143. if (($this->_file_handle = fopen($this->_file_path.$session_id, 'w+b')) === FALSE)
  144. {
  145. log_message('error', "Session: File '".$this->_file_path.$session_id."' doesn't exist and cannot be created.");
  146. return FALSE;
  147. }
  148. }
  149. elseif (($this->_file_handle = fopen($this->_file_path.$session_id, 'r+b')) === FALSE)
  150. {
  151. log_message('error', "Session: Unable to open file '".$this->_file_path.$session_id."'.");
  152. return FALSE;
  153. }
  154. if (flock($this->_file_handle, LOCK_EX) === FALSE)
  155. {
  156. log_message('error', "Session: Unable to obtain lock for file '".$this->_file_path.$session_id."'.");
  157. fclose($this->_file_handle);
  158. $this->_file_handle = NULL;
  159. return FALSE;
  160. }
  161. // Needed by write() to detect session_regenerate_id() calls
  162. $this->_session_id = $session_id;
  163. if ($this->_file_new)
  164. {
  165. chmod($this->_file_path.$session_id, 0600);
  166. $this->_fingerprint = md5('');
  167. return '';
  168. }
  169. }
  170. else
  171. {
  172. rewind($this->_file_handle);
  173. }
  174. $session_data = '';
  175. for ($read = 0, $length = filesize($this->_file_path.$session_id); $read < $length; $read += strlen($buffer))
  176. {
  177. if (($buffer = fread($this->_file_handle, $length - $read)) === FALSE)
  178. {
  179. break;
  180. }
  181. $session_data .= $buffer;
  182. }
  183. $this->_fingerprint = md5($session_data);
  184. return $session_data;
  185. }
  186. // ------------------------------------------------------------------------
  187. /**
  188. * Write
  189. *
  190. * Writes (create / update) session data
  191. *
  192. * @param string $session_id Session ID
  193. * @param string $session_data Serialized session data
  194. * @return bool
  195. */
  196. public function write($session_id, $session_data)
  197. {
  198. // If the two IDs don't match, we have a session_regenerate_id() call
  199. // and we need to close the old handle and open a new one
  200. if ($session_id !== $this->_session_id && ( ! $this->close() OR $this->read($session_id) === FALSE))
  201. {
  202. return FALSE;
  203. }
  204. if ( ! is_resource($this->_file_handle))
  205. {
  206. return FALSE;
  207. }
  208. elseif ($this->_fingerprint === md5($session_data))
  209. {
  210. return ($this->_file_new)
  211. ? TRUE
  212. : touch($this->_file_path.$session_id);
  213. }
  214. if ( ! $this->_file_new)
  215. {
  216. ftruncate($this->_file_handle, 0);
  217. rewind($this->_file_handle);
  218. }
  219. if (($length = strlen($session_data)) > 0)
  220. {
  221. for ($written = 0; $written < $length; $written += $result)
  222. {
  223. if (($result = fwrite($this->_file_handle, substr($session_data, $written))) === FALSE)
  224. {
  225. break;
  226. }
  227. }
  228. if ( ! is_int($result))
  229. {
  230. $this->_fingerprint = md5(substr($session_data, 0, $written));
  231. log_message('error', 'Session: Unable to write data.');
  232. return FALSE;
  233. }
  234. }
  235. $this->_fingerprint = md5($session_data);
  236. return TRUE;
  237. }
  238. // ------------------------------------------------------------------------
  239. /**
  240. * Close
  241. *
  242. * Releases locks and closes file descriptor.
  243. *
  244. * @return bool
  245. */
  246. public function close()
  247. {
  248. if (is_resource($this->_file_handle))
  249. {
  250. flock($this->_file_handle, LOCK_UN);
  251. fclose($this->_file_handle);
  252. $this->_file_handle = $this->_file_new = $this->_session_id = NULL;
  253. return TRUE;
  254. }
  255. return TRUE;
  256. }
  257. // ------------------------------------------------------------------------
  258. /**
  259. * Destroy
  260. *
  261. * Destroys the current session.
  262. *
  263. * @param string $session_id Session ID
  264. * @return bool
  265. */
  266. public function destroy($session_id)
  267. {
  268. if ($this->close())
  269. {
  270. return file_exists($this->_file_path.$session_id)
  271. ? (unlink($this->_file_path.$session_id) && $this->_cookie_destroy())
  272. : TRUE;
  273. }
  274. elseif ($this->_file_path !== NULL)
  275. {
  276. clearstatcache();
  277. return file_exists($this->_file_path.$session_id)
  278. ? (unlink($this->_file_path.$session_id) && $this->_cookie_destroy())
  279. : TRUE;
  280. }
  281. return FALSE;
  282. }
  283. // ------------------------------------------------------------------------
  284. /**
  285. * Garbage Collector
  286. *
  287. * Deletes expired sessions
  288. *
  289. * @param int $maxlifetime Maximum lifetime of sessions
  290. * @return bool
  291. */
  292. public function gc($maxlifetime)
  293. {
  294. if ( ! is_dir($this->_config['save_path']) OR ($directory = opendir($this->_config['save_path'])) === FALSE)
  295. {
  296. log_message('debug', "Session: Garbage collector couldn't list files under directory '".$this->_config['save_path']."'.");
  297. return FALSE;
  298. }
  299. $ts = time() - $maxlifetime;
  300. $pattern = sprintf(
  301. '/^%s[0-9a-f]{%d}$/',
  302. preg_quote($this->_config['cookie_name'], '/'),
  303. ($this->_config['match_ip'] === TRUE ? 72 : 40)
  304. );
  305. while (($file = readdir($directory)) !== FALSE)
  306. {
  307. // If the filename doesn't match this pattern, it's either not a session file or is not ours
  308. if ( ! preg_match($pattern, $file)
  309. OR ! is_file($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)
  310. OR ($mtime = filemtime($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)) === FALSE
  311. OR $mtime > $ts)
  312. {
  313. continue;
  314. }
  315. unlink($this->_config['save_path'].DIRECTORY_SEPARATOR.$file);
  316. }
  317. closedir($directory);
  318. return TRUE;
  319. }
  320. }