payload.php 7.8 KB

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