1: <?php namespace Laravel\Session;
2:
3: use Laravel\Str;
4: use Laravel\Config;
5: use Laravel\Cookie;
6: use Laravel\Session;
7: use Laravel\Session\Drivers\Driver;
8: use Laravel\Session\Drivers\Sweeper;
9:
10: class Payload {
11:
12: /**
13: * The session array that is stored by the driver.
14: *
15: * @var array
16: */
17: public $session;
18:
19: /**
20: * The session driver used to retrieve and store the session payload.
21: *
22: * @var Driver
23: */
24: public $driver;
25:
26: /**
27: * Indicates if the session already exists in storage.
28: *
29: * @var bool
30: */
31: public $exists = true;
32:
33: /**
34: * Create a new session payload instance.
35: *
36: * @param Driver $driver
37: * @return void
38: */
39: public function __construct(Driver $driver)
40: {
41: $this->driver = $driver;
42: }
43:
44: /**
45: * Load the session for the current request.
46: *
47: * @param string $id
48: * @return void
49: */
50: public function load($id)
51: {
52: if ( ! is_null($id)) $this->session = $this->driver->load($id);
53:
54: // If the session doesn't exist or is invalid we will create a new session
55: // array and mark the session as being non-existent. Some drivers, such as
56: // the database driver, need to know whether it exists.
57: if (is_null($this->session) or static::expired($this->session))
58: {
59: $this->exists = false;
60:
61: $this->session = $this->driver->fresh();
62: }
63:
64: // A CSRF token is stored in every session. The token is used by the Form
65: // class and the "csrf" filter to protect the application from cross-site
66: // request forgery attacks. The token is simply a random string.
67: if ( ! $this->has(Session::csrf_token))
68: {
69: $this->put(Session::csrf_token, Str::random(40));
70: }
71: }
72:
73: /**
74: * Determine if the session payload instance is valid.
75: *
76: * The session is considered valid if it exists and has not expired.
77: *
78: * @param array $session
79: * @return bool
80: */
81: protected static function expired($session)
82: {
83: $lifetime = Config::get('session.lifetime');
84:
85: return (time() - $session['last_activity']) > ($lifetime * 60);
86: }
87:
88: /**
89: * Determine if the session or flash data contains an item.
90: *
91: * @param string $key
92: * @return bool
93: */
94: public function has($key)
95: {
96: return ( ! is_null($this->get($key)));
97: }
98:
99: /**
100: * Get an item from the session.
101: *
102: * The session flash data will also be checked for the requested item.
103: *
104: * <code>
105: * // Get an item from the session
106: * $name = Session::get('name');
107: *
108: * // Return a default value if the item doesn't exist
109: * $name = Session::get('name', 'Taylor');
110: * </code>
111: *
112: * @param string $key
113: * @param mixed $default
114: * @return mixed
115: */
116: public function get($key, $default = null)
117: {
118: $session = $this->session['data'];
119:
120: // We check for the item in the general session data first, and if it
121: // does not exist in that data, we will attempt to find it in the new
122: // and old flash data, or finally return the default value.
123: if ( ! is_null($value = array_get($session, $key)))
124: {
125: return $value;
126: }
127: elseif ( ! is_null($value = array_get($session[':new:'], $key)))
128: {
129: return $value;
130: }
131: elseif ( ! is_null($value = array_get($session[':old:'], $key)))
132: {
133: return $value;
134: }
135:
136: return value($default);
137: }
138:
139: /**
140: * Write an item to the session.
141: *
142: * <code>
143: * // Write an item to the session payload
144: * Session::put('name', 'Taylor');
145: * </code>
146: *
147: * @param string $key
148: * @param mixed $value
149: * @return void
150: */
151: public function put($key, $value)
152: {
153: array_set($this->session['data'], $key, $value);
154: }
155:
156: /**
157: * Write an item to the session flash data.
158: *
159: * Flash data only exists for the current and next request to the application.
160: *
161: * <code>
162: * // Write an item to the session payload's flash data
163: * Session::flash('name', 'Taylor');
164: * </code>
165: *
166: * @param string $key
167: * @param mixed $value
168: * @return void
169: */
170: public function flash($key, $value)
171: {
172: array_set($this->session['data'][':new:'], $key, $value);
173: }
174:
175: /**
176: * Keep all of the session flash data from expiring after the request.
177: *
178: * @return void
179: */
180: public function reflash()
181: {
182: $old = $this->session['data'][':old:'];
183:
184: $this->session['data'][':new:'] = array_merge($this->session['data'][':new:'], $old);
185: }
186:
187: /**
188: * Keep a session flash item from expiring at the end of the request.
189: *
190: * <code>
191: * // Keep the "name" item from expiring from the flash data
192: * Session::keep('name');
193: *
194: * // Keep the "name" and "email" items from expiring from the flash data
195: * Session::keep(array('name', 'email'));
196: * </code>
197: *
198: * @param string|array $keys
199: * @return void
200: */
201: public function keep($keys)
202: {
203: foreach ((array) $keys as $key)
204: {
205: $this->flash($key, $this->get($key));
206: }
207: }
208:
209: /**
210: * Remove an item from the session data.
211: *
212: * @param string $key
213: * @return void
214: */
215: public function forget($key)
216: {
217: array_forget($this->session['data'], $key);
218: }
219:
220: /**
221: * Remove all of the items from the session.
222: *
223: * The CSRF token will not be removed from the session.
224: *
225: * @return void
226: */
227: public function flush()
228: {
229: $token = $this->token();
230:
231: $session = array(Session::csrf_token => $token, ':new:' => array(), ':old:' => array());
232:
233: $this->session['data'] = $session;
234: }
235:
236: /**
237: * Assign a new, random ID to the session.
238: *
239: * @return void
240: */
241: public function regenerate()
242: {
243: $this->session['id'] = $this->driver->id();
244:
245: $this->exists = false;
246: }
247:
248: /**
249: * Get the CSRF token that is stored in the session data.
250: *
251: * @return string
252: */
253: public function token()
254: {
255: return $this->get(Session::csrf_token);
256: }
257:
258: /**
259: * Get the last activity for the session.
260: *
261: * @return int
262: */
263: public function activity()
264: {
265: return $this->session['last_activity'];
266: }
267:
268: /**
269: * Store the session payload in storage.
270: *
271: * This method will be called automatically at the end of the request.
272: *
273: * @return void
274: */
275: public function save()
276: {
277: $this->session['last_activity'] = time();
278:
279: // Session flash data is only available during the request in which it
280: // was flashed and the following request. We will age the data so that
281: // it expires at the end of the user's next request.
282: $this->age();
283:
284: $config = Config::get('session');
285:
286: // The responsibility of actually storing the session information in
287: // persistent storage is delegated to the driver instance being used
288: // by the session payload.
289: //
290: // This allows us to keep the payload very generic, while moving the
291: // platform or storage mechanism code into the specialized drivers,
292: // keeping our code very dry and organized.
293: $this->driver->save($this->session, $config, $this->exists);
294:
295: // Next we'll write out the session cookie. This cookie contains the
296: // ID of the session, and will be used to determine the owner of the
297: // session on the user's subsequent requests to the application.
298: $this->cookie($config);
299:
300: // Some session drivers implement the Sweeper interface meaning that
301: // they must clean up expired sessions manually. Here we'll calculate
302: // if we need to run garbage collection.
303: $sweepage = $config['sweepage'];
304:
305: if (mt_rand(1, $sweepage[1]) <= $sweepage[0])
306: {
307: $this->sweep();
308: }
309: }
310:
311: /**
312: * Clean up expired sessions.
313: *
314: * If the session driver is a sweeper, it must clean up expired sessions
315: * from time to time. This method triggers garbage collection.
316: *
317: * @return void
318: */
319: public function sweep()
320: {
321: if ($this->driver instanceof Sweeper)
322: {
323: $this->driver->sweep(time() - (Config::get('session.lifetime') * 60));
324: }
325: }
326:
327: /**
328: * Age the session flash data.
329: *
330: * @return void
331: */
332: protected function age()
333: {
334: $this->session['data'][':old:'] = $this->session['data'][':new:'];
335:
336: $this->session['data'][':new:'] = array();
337: }
338:
339: /**
340: * Send the session ID cookie to the browser.
341: *
342: * @param array $config
343: * @return void
344: */
345: protected function cookie($config)
346: {
347: extract($config, EXTR_SKIP);
348:
349: $minutes = ( ! $expire_on_close) ? $lifetime : 0;
350:
351: Cookie::put($cookie, $this->session['id'], $minutes, $path, $domain, $secure);
352: }
353:
354: }