Overview

Packages

  • SessionHandler

Classes

  • Horde_SessionHandler
  • Horde_SessionHandler_Exception
  • Horde_SessionHandler_Storage
  • Horde_SessionHandler_Storage_Builtin
  • Horde_SessionHandler_Storage_External
  • Horde_SessionHandler_Storage_File
  • Horde_SessionHandler_Storage_Memcache
  • Horde_SessionHandler_Storage_Sql
  • Horde_SessionHandler_Storage_Stack
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Horde_SessionHandler implementation for memcache.
  4:  *
  5:  * Copyright 2005-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * See the enclosed file COPYING for license information (LGPL). If you
  8:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
  9:  *
 10:  * @author   Rong-En Fan <rafan@infor.org>
 11:  * @author   Michael Slusarz <slusarz@horde.org>
 12:  * @category Horde
 13:  * @package  SessionHandler
 14:  */
 15: class Horde_SessionHandler_Storage_Memcache extends Horde_SessionHandler_Storage
 16: {
 17:     /**
 18:      * Memcache object.
 19:      *
 20:      * @var Horde_Memcache
 21:      */
 22:     protected $_memcache;
 23: 
 24:     /**
 25:      * Current session ID.
 26:      *
 27:      * @var string
 28:      */
 29:     protected $_id;
 30: 
 31:     /**
 32:      * The ID used for session tracking.
 33:      *
 34:      * @var string
 35:      */
 36:     protected $_trackID = 'horde_memcache_sessions_track';
 37: 
 38:     /**
 39:      * Constructor.
 40:      *
 41:      * @param array $params  Parameters:
 42:      * <pre>
 43:      * 'memcache' - (Horde_Memcache) [REQUIRED] A memcache object.
 44:      * 'track' - (boolean) Track active sessions?
 45:      * 'track_lifetime' - (integer) The number of seconds after which tracked
 46:      *                    sessions will be treated as expired.
 47:      * </pre>
 48:      *
 49:      * @throws InvalidArgumentException
 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:             // Do a replace - the only time it should fail is if we are
125:             // writing a session for the first time.  If that is the case,
126:             // update the session tracker.
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:         // Memcache does its own garbage collection.
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:      * Do garbage collection for session tracking information.
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: 
API documentation generated by ApiGen