1: <?php
2: /**
3: * Database Session save handler. Allows saving session information into a model.
4: *
5: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6: * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7: *
8: * Licensed under The MIT License
9: * For full copyright and license information, please see the LICENSE.txt
10: * Redistributions of files must retain the above copyright notice.
11: *
12: * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13: * @link http://cakephp.org CakePHP(tm) Project
14: * @package Cake.Model.Datasource.Session
15: * @since CakePHP(tm) v 2.0
16: * @license http://www.opensource.org/licenses/mit-license.php MIT License
17: */
18:
19: App::uses('CakeSessionHandlerInterface', 'Model/Datasource/Session');
20: App::uses('ClassRegistry', 'Utility');
21:
22: /**
23: * DatabaseSession provides methods to be used with CakeSession.
24: *
25: * @package Cake.Model.Datasource.Session
26: */
27: class DatabaseSession implements CakeSessionHandlerInterface {
28:
29: /**
30: * Reference to the model handling the session data
31: *
32: * @var Model
33: */
34: protected $_model;
35:
36: /**
37: * Number of seconds to mark the session as expired
38: *
39: * @var int
40: */
41: protected $_timeout;
42:
43: /**
44: * Constructor. Looks at Session configuration information and
45: * sets up the session model.
46: */
47: public function __construct() {
48: $modelName = Configure::read('Session.handler.model');
49:
50: if (empty($modelName)) {
51: $settings = array(
52: 'class' => 'Session',
53: 'alias' => 'Session',
54: 'table' => 'cake_sessions',
55: );
56: } else {
57: $settings = array(
58: 'class' => $modelName,
59: 'alias' => 'Session',
60: );
61: }
62: $this->_model = ClassRegistry::init($settings);
63: $this->_timeout = Configure::read('Session.timeout') * 60;
64: }
65:
66: /**
67: * Method called on open of a database session.
68: *
69: * @return bool Success
70: */
71: public function open() {
72: return true;
73: }
74:
75: /**
76: * Method called on close of a database session.
77: *
78: * @return bool Success
79: */
80: public function close() {
81: return true;
82: }
83:
84: /**
85: * Method used to read from a database session.
86: *
87: * @param int|string $id The key of the value to read
88: * @return mixed The value of the key or false if it does not exist
89: */
90: public function read($id) {
91: $row = $this->_model->find('first', array(
92: 'conditions' => array($this->_model->primaryKey => $id)
93: ));
94:
95: if (empty($row[$this->_model->alias]['data'])) {
96: return false;
97: }
98:
99: return $row[$this->_model->alias]['data'];
100: }
101:
102: /**
103: * Helper function called on write for database sessions.
104: *
105: * Will retry, once, if the save triggers a PDOException which
106: * can happen if a race condition is encountered
107: *
108: * @param int $id ID that uniquely identifies session in database
109: * @param mixed $data The value of the data to be saved.
110: * @return bool True for successful write, false otherwise.
111: */
112: public function write($id, $data) {
113: if (!$id) {
114: return false;
115: }
116: $expires = time() + $this->_timeout;
117: $record = compact('id', 'data', 'expires');
118: $record[$this->_model->primaryKey] = $id;
119:
120: $options = array(
121: 'validate' => false,
122: 'callbacks' => false,
123: 'counterCache' => false
124: );
125: try {
126: return $this->_model->save($record, $options);
127: } catch (PDOException $e) {
128: return $this->_model->save($record, $options);
129: }
130: }
131:
132: /**
133: * Method called on the destruction of a database session.
134: *
135: * @param int $id ID that uniquely identifies session in database
136: * @return bool True for successful delete, false otherwise.
137: */
138: public function destroy($id) {
139: return $this->_model->delete($id);
140: }
141:
142: /**
143: * Helper function called on gc for database sessions.
144: *
145: * @param int $expires Timestamp (defaults to current time)
146: * @return bool Success
147: */
148: public function gc($expires = null) {
149: if (!$expires) {
150: $expires = time();
151: } else {
152: $expires = time() - $expires;
153: }
154: return $this->_model->deleteAll(array($this->_model->alias . ".expires <" => $expires), false, false);
155: }
156:
157: }
158: