1: <?php
2: /**
3: * SessionHandler storage implementation that will loop through a list of
4: * storage drivers to handle the session information.
5: * This driver allows for use of caching backends on top of persistent
6: * backends, for example.
7: *
8: * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
9: *
10: * See the enclosed file COPYING for license information (LGPL). If you
11: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
12: *
13: * @author Michael Slusarz <slusarz@horde.org>
14: * @category Horde
15: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
16: * @package SessionHandler
17: */
18: class Horde_SessionHandler_Storage_Stack extends Horde_SessionHandler_Storage
19: {
20: /**
21: * Stack of storage objects.
22: *
23: * @var array
24: */
25: protected $_stack = array();
26:
27: /**
28: * Constructor.
29: *
30: * @param array $params Parameters:
31: * <pre>
32: * stack - (array) [REQUIRED] A list of storage objects to loop
33: * through, in order of priority. The last entry is considered
34: * the "master" server.
35: * </pre>
36: *
37: * @throws InvalidArgumentException
38: */
39: public function __construct(array $params = array())
40: {
41: if (!isset($params['stack'])) {
42: throw new InvalidArgumentException('Missing stack parameter.');
43: }
44:
45: $this->_stack = $params['stack'];
46: unset($params['stack']);
47:
48: parent::__construct($params);
49: }
50:
51: /**
52: * Set the logger object.
53: *
54: * @param Horde_Log_Logger $log The logger instance.
55: */
56: public function setLogger(Horde_Log_Logger $log)
57: {
58: parent::setLogger($log);
59:
60: foreach ($this->_stack as $ob) {
61: $ob->setLogger($log);
62: }
63: }
64:
65: /**
66: */
67: public function open($save_path = null, $session_name = null)
68: {
69: foreach ($this->_stack as $val) {
70: $val->open($save_path, $session_name);
71: }
72: }
73:
74: /**
75: */
76: public function close()
77: {
78: foreach ($this->_stack as $val) {
79: $val->close();
80: }
81: }
82:
83: /**
84: */
85: public function read($id)
86: {
87: foreach ($this->_stack as $val) {
88: $result = $val->read($id);
89: if ($result === false) {
90: break;
91: }
92: }
93:
94: return $result;
95: }
96:
97: /**
98: */
99: public function write($id, $session_data)
100: {
101: /* Do writes in *reverse* order - it is OK if a write to one of the
102: * non-master backends fails. */
103: $master = true;
104:
105: foreach (array_reverse($this->_stack) as $val) {
106: $result = $val->write($id, $session_data);
107: if ($result === false) {
108: if ($master) {
109: return false;
110: }
111: /* Attempt to invalidate cache if write failed. */
112: $val->destroy($id);
113: }
114: $master = false;
115: }
116:
117: return true;
118: }
119:
120: /**
121: */
122: public function destroy($id)
123: {
124: /* Only report success from master. */
125: $master = $success = true;
126:
127: foreach (array_reverse($this->_stack) as $val) {
128: $result = $val->destroy($id);
129: if ($master && ($result === false)) {
130: $success = false;
131: }
132: $master = false;
133: }
134:
135: return $success;
136: }
137:
138: /**
139: */
140: public function gc($maxlifetime = 300)
141: {
142: /* Only report GC results from master. */
143: foreach ($this->_stack as $val) {
144: $result = $val->gc($maxlifetime);
145: }
146:
147: return $result;
148: }
149:
150: /**
151: */
152: public function getSessionIDs()
153: {
154: /* Grab session ID list from the master. */
155: $ob = end($this->_stack);
156: return $ob->getSessionIDs();
157: }
158:
159: }
160: