1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: class Horde_SessionHandler_Storage_Memcache extends Horde_SessionHandler_Storage
16: {
17: 18: 19: 20: 21:
22: protected $_memcache;
23:
24: 25: 26: 27: 28:
29: protected $_id;
30:
31: 32: 33: 34: 35:
36: protected $_trackID = 'horde_memcache_sessions_track';
37:
38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
51: public function __construct(array $params = array())
52: {
53: if (empty($params['memcache'])) {
54: throw new InvalidArgumentException('Missing memcache argument.');
55: }
56:
57: $this->_memcache = $params['memcache'];
58: unset($params['memcache']);
59:
60: parent::__construct($params);
61:
62: if (empty($this->_params['track_lifetime'])) {
63: $this->_params['track_lifetime'] = ini_get('session.gc_maxlifetime');
64: }
65:
66: if (!empty($this->_params['track']) && (rand(0, 999) == 0)) {
67: register_shutdown_function(array($this, 'trackGC'));
68: }
69: }
70:
71: 72:
73: public function open($save_path = null, $session_name = null)
74: {
75: }
76:
77: 78:
79: public function close()
80: {
81: if (isset($this->_id)) {
82: $this->_memcache->unlock($this->_id);
83: }
84: }
85:
86: 87:
88: public function read($id)
89: {
90: if (!$this->readonly) {
91: $this->_memcache->lock($id);
92: }
93: $result = $this->_memcache->get($id);
94:
95: if ($result === false) {
96: if (!$this->readonly) {
97: $this->_memcache->unlock($id);
98: }
99:
100: if ($result === false) {
101: if ($this->_logger) {
102: $this->_logger->log('Error retrieving session data (id = ' . $id . ')', 'DEBUG');
103: }
104: return '';
105: }
106: }
107:
108: if (!$this->readonly) {
109: $this->_id = $id;
110: }
111:
112: if ($this->_logger) {
113: $this->_logger->log('Read session data (id = ' . $id . ')', 'DEBUG');
114: }
115:
116: return $result;
117: }
118:
119: 120:
121: public function write($id, $session_data)
122: {
123: if (!empty($this->_params['track'])) {
124:
125:
126:
127: $res = $this->_memcache->replace($id, $session_data);
128: $track = !$res;
129: } else {
130: $res = $track = false;
131: }
132:
133: if (!$res &&
134: !$this->_memcache->set($id, $session_data)) {
135: if ($this->_logger) {
136: $this->_logger->log('Error writing session data (id = ' . $id . ')', 'ERR');
137: }
138: return false;
139: }
140:
141: if ($track) {
142: $this->_memcache->lock($this->_trackID);
143: $ids = $this->_memcache->get($this->_trackID);
144: if ($ids === false) {
145: $ids = array();
146: }
147:
148: $ids[$id] = time();
149: $this->_memcache->set($this->_trackID, $ids);
150: $this->_memcache->unlock($this->_trackID);
151: }
152:
153: if ($this->_logger) {
154: $this->_logger->log('Wrote session data (id = ' . $id . ')', 'DEBUG');
155: }
156:
157: return true;
158: }
159:
160: 161:
162: public function destroy($id)
163: {
164: $result = $this->_memcache->delete($id);
165: $this->_memcache->unlock($id);
166:
167: if ($result === false) {
168: if ($this->_logger) {
169: $this->_logger->log('Failed to delete session (id = ' . $id . ')', 'DEBUG');
170: }
171: return false;
172: }
173:
174: if (!empty($this->_params['track'])) {
175: $this->_memcache->lock($this->_trackID);
176: $ids = $this->_memcache->get($this->_trackID);
177: if ($ids !== false) {
178: unset($ids[$id]);
179: $this->_memcache->set($this->_trackID, $ids);
180: }
181: $this->_memcache->unlock($this->_trackID);
182: }
183:
184: if ($this->_logger) {
185: $this->_logger->log('Deleted session data (id = ' . $id . ')', 'DEBUG');
186: }
187:
188: return true;
189: }
190:
191: 192:
193: public function gc($maxlifetime = 300)
194: {
195:
196: return true;
197: }
198:
199: 200:
201: public function getSessionIDs()
202: {
203: if (empty($this->_params['track'])) {
204: throw new Horde_SessionHandler_Exception('Memcache session tracking not enabled.');
205: }
206:
207: $this->trackGC();
208:
209: $ids = $this->_memcache->get($this->_trackID);
210:
211: return ($ids === false)
212: ? array()
213: : array_keys($ids);
214: }
215:
216: 217: 218:
219: public function trackGC()
220: {
221: $this->_memcache->lock($this->_trackID);
222: $ids = $this->_memcache->get($this->_trackID);
223: if (empty($ids)) {
224: $this->_memcache->unlock($this->_trackID);
225: return;
226: }
227:
228: $tstamp = time() - $this->_params['track_lifetime'];
229: $alter = false;
230:
231: foreach ($ids as $key => $val) {
232: if ($tstamp > $val) {
233: unset($ids[$key]);
234: $alter = true;
235: }
236: }
237:
238: if ($alter) {
239: $this->_memcache->set($this->_trackID, $ids);
240: }
241:
242: $this->_memcache->unlock($this->_trackID);
243: }
244:
245: }
246: