payload.php 7.9 KB

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