payload.php 7.6 KB

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