1: <?php
2: /**
3: * Slim - a micro PHP 5 framework
4: *
5: * @author Josh Lockhart <info@slimframework.com>
6: * @copyright 2011 Josh Lockhart
7: * @link http://www.slimframework.com
8: * @license http://www.slimframework.com/license
9: * @version 2.2.0
10: * @package Slim
11: *
12: * MIT LICENSE
13: *
14: * Permission is hereby granted, free of charge, to any person obtaining
15: * a copy of this software and associated documentation files (the
16: * "Software"), to deal in the Software without restriction, including
17: * without limitation the rights to use, copy, modify, merge, publish,
18: * distribute, sublicense, and/or sell copies of the Software, and to
19: * permit persons to whom the Software is furnished to do so, subject to
20: * the following conditions:
21: *
22: * The above copyright notice and this permission notice shall be
23: * included in all copies or substantial portions of the Software.
24: *
25: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28: * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29: * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30: * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31: * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32: */
33: namespace Slim\Middleware;
34:
35: /**
36: * Session Cookie
37: *
38: * This class provides an HTTP cookie storage mechanism
39: * for session data. This class avoids using a PHP session
40: * and instead serializes/unserializes the $_SESSION global
41: * variable to/from an HTTP cookie.
42: *
43: * If a secret key is provided with this middleware, the HTTP
44: * cookie will be checked for integrity to ensure the client-side
45: * cookie is not changed.
46: *
47: * You should NEVER store sensitive data in a client-side cookie
48: * in any format, encrypted or not. If you need to store sensitive
49: * user information in a session, you should rely on PHP's native
50: * session implementation, or use other middleware to store
51: * session data in a database or alternative server-side cache.
52: *
53: * Because this class stores serialized session data in an HTTP cookie,
54: * you are inherently limtied to 4 Kb. If you attempt to store
55: * more than this amount, serialization will fail.
56: *
57: * @package Slim
58: * @author Josh Lockhart
59: * @since 1.6.0
60: */
61: class SessionCookie extends \Slim\Middleware
62: {
63: /**
64: * @var array
65: */
66: protected $settings;
67:
68: /**
69: * Constructor
70: *
71: * @param array $settings
72: */
73: public function __construct($settings = array())
74: {
75: $this->settings = array_merge(array(
76: 'expires' => '20 minutes',
77: 'path' => '/',
78: 'domain' => null,
79: 'secure' => false,
80: 'httponly' => false,
81: 'name' => 'slim_session',
82: 'secret' => 'CHANGE_ME',
83: 'cipher' => MCRYPT_RIJNDAEL_256,
84: 'cipher_mode' => MCRYPT_MODE_CBC
85: ), $settings);
86: if (is_string($this->settings['expires'])) {
87: $this->settings['expires'] = strtotime($this->settings['expires']);
88: }
89:
90: /**
91: * Session
92: *
93: * We must start a native PHP session to initialize the $_SESSION superglobal.
94: * However, we won't be using the native session store for persistence, so we
95: * disable the session cookie and cache limiter. We also set the session
96: * handler to this class instance to avoid PHP's native session file locking.
97: */
98: ini_set('session.use_cookies', 0);
99: session_cache_limiter(false);
100: session_set_save_handler(
101: array($this, 'open'),
102: array($this, 'close'),
103: array($this, 'read'),
104: array($this, 'write'),
105: array($this, 'destroy'),
106: array($this, 'gc')
107: );
108: }
109:
110: /**
111: * Call
112: */
113: public function call()
114: {
115: $this->loadSession();
116: $this->next->call();
117: $this->saveSession();
118: }
119:
120: /**
121: * Load session
122: * @param array $env
123: */
124: protected function loadSession()
125: {
126: if (session_id() === '') {
127: session_start();
128: }
129:
130: $value = \Slim\Http\Util::decodeSecureCookie(
131: $this->app->request()->cookies($this->settings['name']),
132: $this->settings['secret'],
133: $this->settings['cipher'],
134: $this->settings['cipher_mode']
135: );
136: if ($value) {
137: $_SESSION = unserialize($value);
138: } else {
139: $_SESSION = array();
140: }
141: }
142:
143: /**
144: * Save session
145: */
146: protected function saveSession()
147: {
148: $value = \Slim\Http\Util::encodeSecureCookie(
149: serialize($_SESSION),
150: $this->settings['expires'],
151: $this->settings['secret'],
152: $this->settings['cipher'],
153: $this->settings['cipher_mode']
154: );
155: if (strlen($value) > 4096) {
156: $this->app->getLog()->error('WARNING! Slim\Middleware\SessionCookie data size is larger than 4KB. Content save failed.');
157: } else {
158: $this->app->response()->setCookie($this->settings['name'], array(
159: 'value' => $value,
160: 'domain' => $this->settings['domain'],
161: 'path' => $this->settings['path'],
162: 'expires' => $this->settings['expires'],
163: 'secure' => $this->settings['secure'],
164: 'httponly' => $this->settings['httponly']
165: ));
166: }
167: session_destroy();
168: }
169:
170: /********************************************************************************
171: * Session Handler
172: *******************************************************************************/
173:
174: public function open($savePath, $sessionName)
175: {
176: return true;
177: }
178:
179: public function close()
180: {
181: return true;
182: }
183:
184: public function read($id)
185: {
186: return '';
187: }
188:
189: public function write($id, $data)
190: {
191: return true;
192: }
193:
194: public function destroy($id)
195: {
196: return true;
197: }
198:
199: public function gc($maxlifetime)
200: {
201: return true;
202: }
203: }
204: