Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

873 lines
30KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\web;
  8. use Yii;
  9. use yii\base\Component;
  10. use yii\base\InvalidConfigException;
  11. use yii\base\InvalidParamException;
  12. /**
  13. * Session provides session data management and the related configurations.
  14. *
  15. * Session is a Web application component that can be accessed via `Yii::$app->session`.
  16. *
  17. * To start the session, call [[open()]]; To complete and send out session data, call [[close()]];
  18. * To destroy the session, call [[destroy()]].
  19. *
  20. * Session can be used like an array to set and get session data. For example,
  21. *
  22. * ```php
  23. * $session = new Session;
  24. * $session->open();
  25. * $value1 = $session['name1']; // get session variable 'name1'
  26. * $value2 = $session['name2']; // get session variable 'name2'
  27. * foreach ($session as $name => $value) // traverse all session variables
  28. * $session['name3'] = $value3; // set session variable 'name3'
  29. * ```
  30. *
  31. * Session can be extended to support customized session storage.
  32. * To do so, override [[useCustomStorage]] so that it returns true, and
  33. * override these methods with the actual logic about using custom storage:
  34. * [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
  35. * [[destroySession()]] and [[gcSession()]].
  36. *
  37. * Session also supports a special type of session data, called *flash messages*.
  38. * A flash message is available only in the current request and the next request.
  39. * After that, it will be deleted automatically. Flash messages are particularly
  40. * useful for displaying confirmation messages. To use flash messages, simply
  41. * call methods such as [[setFlash()]], [[getFlash()]].
  42. *
  43. * @property array $allFlashes Flash messages (key => message or key => [message1, message2]). This property
  44. * is read-only.
  45. * @property array $cookieParams The session cookie parameters. This property is read-only.
  46. * @property integer $count The number of session variables. This property is read-only.
  47. * @property string $flash The key identifying the flash message. Note that flash messages and normal session
  48. * variables share the same name space. If you have a normal session variable using the same name, its value will
  49. * be overwritten by this method. This property is write-only.
  50. * @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is
  51. * started on every session initialization, defaults to 1 meaning 1% chance.
  52. * @property boolean $hasSessionId Whether the current request has sent the session ID.
  53. * @property string $id The current session ID.
  54. * @property boolean $isActive Whether the session has started. This property is read-only.
  55. * @property SessionIterator $iterator An iterator for traversing the session variables. This property is
  56. * read-only.
  57. * @property string $name The current session name.
  58. * @property string $savePath The current session save path, defaults to '/tmp'.
  59. * @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up.
  60. * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
  61. * @property boolean|null $useCookies The value indicating whether cookies should be used to store session
  62. * IDs.
  63. * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
  64. * @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to
  65. * false.
  66. *
  67. * @author Qiang Xue <qiang.xue@gmail.com>
  68. * @since 2.0
  69. */
  70. class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable
  71. {
  72. /**
  73. * @var string the name of the session variable that stores the flash message data.
  74. */
  75. public $flashParam = '__flash';
  76. /**
  77. * @var \SessionHandlerInterface|array an object implementing the SessionHandlerInterface or a configuration array. If set, will be used to provide persistency instead of build-in methods.
  78. */
  79. public $handler;
  80. /**
  81. * @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function
  82. * Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httponly'
  83. * @see http://www.php.net/manual/en/function.session-set-cookie-params.php
  84. */
  85. private $_cookieParams = ['httponly' => true];
  86. /**
  87. * Initializes the application component.
  88. * This method is required by IApplicationComponent and is invoked by application.
  89. */
  90. public function init()
  91. {
  92. parent::init();
  93. register_shutdown_function([$this, 'close']);
  94. if ($this->getIsActive()) {
  95. Yii::warning("Session is already started", __METHOD__);
  96. $this->updateFlashCounters();
  97. }
  98. }
  99. /**
  100. * Returns a value indicating whether to use custom session storage.
  101. * This method should be overridden to return true by child classes that implement custom session storage.
  102. * To implement custom session storage, override these methods: [[openSession()]], [[closeSession()]],
  103. * [[readSession()]], [[writeSession()]], [[destroySession()]] and [[gcSession()]].
  104. * @return boolean whether to use custom storage.
  105. */
  106. public function getUseCustomStorage()
  107. {
  108. return false;
  109. }
  110. /**
  111. * Starts the session.
  112. */
  113. public function open()
  114. {
  115. if ($this->getIsActive()) {
  116. return;
  117. }
  118. $this->registerSessionHandler();
  119. $this->setCookieParamsInternal();
  120. @session_start();
  121. if ($this->getIsActive()) {
  122. Yii::info('Session started', __METHOD__);
  123. $this->updateFlashCounters();
  124. } else {
  125. $error = error_get_last();
  126. $message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
  127. Yii::error($message, __METHOD__);
  128. }
  129. }
  130. /**
  131. * Registers session handler.
  132. * @throws \yii\base\InvalidConfigException
  133. */
  134. protected function registerSessionHandler()
  135. {
  136. if ($this->handler !== null) {
  137. if (!is_object($this->handler)) {
  138. $this->handler = Yii::createObject($this->handler);
  139. }
  140. if (!$this->handler instanceof \SessionHandlerInterface) {
  141. throw new InvalidConfigException('"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.');
  142. }
  143. @session_set_save_handler($this->handler, false);
  144. } elseif ($this->getUseCustomStorage()) {
  145. @session_set_save_handler(
  146. [$this, 'openSession'],
  147. [$this, 'closeSession'],
  148. [$this, 'readSession'],
  149. [$this, 'writeSession'],
  150. [$this, 'destroySession'],
  151. [$this, 'gcSession']
  152. );
  153. }
  154. }
  155. /**
  156. * Ends the current session and store session data.
  157. */
  158. public function close()
  159. {
  160. if ($this->getIsActive()) {
  161. @session_write_close();
  162. }
  163. }
  164. /**
  165. * Frees all session variables and destroys all data registered to a session.
  166. */
  167. public function destroy()
  168. {
  169. if ($this->getIsActive()) {
  170. @session_unset();
  171. $sessionId = session_id();
  172. @session_destroy();
  173. @session_id($sessionId);
  174. }
  175. }
  176. /**
  177. * @return boolean whether the session has started
  178. */
  179. public function getIsActive()
  180. {
  181. return session_status() == PHP_SESSION_ACTIVE;
  182. }
  183. private $_hasSessionId;
  184. /**
  185. * Returns a value indicating whether the current request has sent the session ID.
  186. * The default implementation will check cookie and $_GET using the session name.
  187. * If you send session ID via other ways, you may need to override this method
  188. * or call [[setHasSessionId()]] to explicitly set whether the session ID is sent.
  189. * @return boolean whether the current request has sent the session ID.
  190. */
  191. public function getHasSessionId()
  192. {
  193. if ($this->_hasSessionId === null) {
  194. $name = $this->getName();
  195. $request = Yii::$app->getRequest();
  196. if (!empty($_COOKIE[$name]) && ini_get('session.use_cookies')) {
  197. $this->_hasSessionId = true;
  198. } elseif (!ini_get('session.use_only_cookies') && ini_get('session.use_trans_sid')) {
  199. $this->_hasSessionId = $request->get($name) != '';
  200. } else {
  201. $this->_hasSessionId = false;
  202. }
  203. }
  204. return $this->_hasSessionId;
  205. }
  206. /**
  207. * Sets the value indicating whether the current request has sent the session ID.
  208. * This method is provided so that you can override the default way of determining
  209. * whether the session ID is sent.
  210. * @param boolean $value whether the current request has sent the session ID.
  211. */
  212. public function setHasSessionId($value)
  213. {
  214. $this->_hasSessionId = $value;
  215. }
  216. /**
  217. * Gets the session ID.
  218. * This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
  219. * @return string the current session ID
  220. */
  221. public function getId()
  222. {
  223. return session_id();
  224. }
  225. /**
  226. * Sets the session ID.
  227. * This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
  228. * @param string $value the session ID for the current session
  229. */
  230. public function setId($value)
  231. {
  232. session_id($value);
  233. }
  234. /**
  235. * Updates the current session ID with a newly generated one .
  236. * Please refer to <http://php.net/session_regenerate_id> for more details.
  237. * @param boolean $deleteOldSession Whether to delete the old associated session file or not.
  238. */
  239. public function regenerateID($deleteOldSession = false)
  240. {
  241. // add @ to inhibit possible warning due to race condition
  242. // https://github.com/yiisoft/yii2/pull/1812
  243. @session_regenerate_id($deleteOldSession);
  244. }
  245. /**
  246. * Gets the name of the current session.
  247. * This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
  248. * @return string the current session name
  249. */
  250. public function getName()
  251. {
  252. return session_name();
  253. }
  254. /**
  255. * Sets the name for the current session.
  256. * This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
  257. * @param string $value the session name for the current session, must be an alphanumeric string.
  258. * It defaults to "PHPSESSID".
  259. */
  260. public function setName($value)
  261. {
  262. session_name($value);
  263. }
  264. /**
  265. * Gets the current session save path.
  266. * This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
  267. * @return string the current session save path, defaults to '/tmp'.
  268. */
  269. public function getSavePath()
  270. {
  271. return session_save_path();
  272. }
  273. /**
  274. * Sets the current session save path.
  275. * This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
  276. * @param string $value the current session save path. This can be either a directory name or a path alias.
  277. * @throws InvalidParamException if the path is not a valid directory
  278. */
  279. public function setSavePath($value)
  280. {
  281. $path = Yii::getAlias($value);
  282. if (is_dir($path)) {
  283. session_save_path($path);
  284. } else {
  285. throw new InvalidParamException("Session save path is not a valid directory: $value");
  286. }
  287. }
  288. /**
  289. * @return array the session cookie parameters.
  290. * @see http://php.net/manual/en/function.session-get-cookie-params.php
  291. */
  292. public function getCookieParams()
  293. {
  294. return array_merge(session_get_cookie_params(), array_change_key_case($this->_cookieParams));
  295. }
  296. /**
  297. * Sets the session cookie parameters.
  298. * The cookie parameters passed to this method will be merged with the result
  299. * of `session_get_cookie_params()`.
  300. * @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httponly`.
  301. * @throws InvalidParamException if the parameters are incomplete.
  302. * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
  303. */
  304. public function setCookieParams(array $value)
  305. {
  306. $this->_cookieParams = $value;
  307. }
  308. /**
  309. * Sets the session cookie parameters.
  310. * This method is called by [[open()]] when it is about to open the session.
  311. * @throws InvalidParamException if the parameters are incomplete.
  312. * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
  313. */
  314. private function setCookieParamsInternal()
  315. {
  316. $data = $this->getCookieParams();
  317. extract($data);
  318. if (isset($lifetime, $path, $domain, $secure, $httponly)) {
  319. session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
  320. } else {
  321. throw new InvalidParamException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httponly.');
  322. }
  323. }
  324. /**
  325. * Returns the value indicating whether cookies should be used to store session IDs.
  326. * @return boolean|null the value indicating whether cookies should be used to store session IDs.
  327. * @see setUseCookies()
  328. */
  329. public function getUseCookies()
  330. {
  331. if (ini_get('session.use_cookies') === '0') {
  332. return false;
  333. } elseif (ini_get('session.use_only_cookies') === '1') {
  334. return true;
  335. } else {
  336. return null;
  337. }
  338. }
  339. /**
  340. * Sets the value indicating whether cookies should be used to store session IDs.
  341. * Three states are possible:
  342. *
  343. * - true: cookies and only cookies will be used to store session IDs.
  344. * - false: cookies will not be used to store session IDs.
  345. * - null: if possible, cookies will be used to store session IDs; if not, other mechanisms will be used (e.g. GET parameter)
  346. *
  347. * @param boolean|null $value the value indicating whether cookies should be used to store session IDs.
  348. */
  349. public function setUseCookies($value)
  350. {
  351. if ($value === false) {
  352. ini_set('session.use_cookies', '0');
  353. ini_set('session.use_only_cookies', '0');
  354. } elseif ($value === true) {
  355. ini_set('session.use_cookies', '1');
  356. ini_set('session.use_only_cookies', '1');
  357. } else {
  358. ini_set('session.use_cookies', '1');
  359. ini_set('session.use_only_cookies', '0');
  360. }
  361. }
  362. /**
  363. * @return float the probability (percentage) that the GC (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
  364. */
  365. public function getGCProbability()
  366. {
  367. return (float) (ini_get('session.gc_probability') / ini_get('session.gc_divisor') * 100);
  368. }
  369. /**
  370. * @param float $value the probability (percentage) that the GC (garbage collection) process is started on every session initialization.
  371. * @throws InvalidParamException if the value is not between 0 and 100.
  372. */
  373. public function setGCProbability($value)
  374. {
  375. if ($value >= 0 && $value <= 100) {
  376. // percent * 21474837 / 2147483647 ≈ percent * 0.01
  377. ini_set('session.gc_probability', floor($value * 21474836.47));
  378. ini_set('session.gc_divisor', 2147483647);
  379. } else {
  380. throw new InvalidParamException('GCProbability must be a value between 0 and 100.');
  381. }
  382. }
  383. /**
  384. * @return boolean whether transparent sid support is enabled or not, defaults to false.
  385. */
  386. public function getUseTransparentSessionID()
  387. {
  388. return ini_get('session.use_trans_sid') == 1;
  389. }
  390. /**
  391. * @param boolean $value whether transparent sid support is enabled or not.
  392. */
  393. public function setUseTransparentSessionID($value)
  394. {
  395. ini_set('session.use_trans_sid', $value ? '1' : '0');
  396. }
  397. /**
  398. * @return integer the number of seconds after which data will be seen as 'garbage' and cleaned up.
  399. * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
  400. */
  401. public function getTimeout()
  402. {
  403. return (int) ini_get('session.gc_maxlifetime');
  404. }
  405. /**
  406. * @param integer $value the number of seconds after which data will be seen as 'garbage' and cleaned up
  407. */
  408. public function setTimeout($value)
  409. {
  410. ini_set('session.gc_maxlifetime', $value);
  411. }
  412. /**
  413. * Session open handler.
  414. * This method should be overridden if [[useCustomStorage]] returns true.
  415. * Do not call this method directly.
  416. * @param string $savePath session save path
  417. * @param string $sessionName session name
  418. * @return boolean whether session is opened successfully
  419. */
  420. public function openSession($savePath, $sessionName)
  421. {
  422. return true;
  423. }
  424. /**
  425. * Session close handler.
  426. * This method should be overridden if [[useCustomStorage]] returns true.
  427. * Do not call this method directly.
  428. * @return boolean whether session is closed successfully
  429. */
  430. public function closeSession()
  431. {
  432. return true;
  433. }
  434. /**
  435. * Session read handler.
  436. * This method should be overridden if [[useCustomStorage]] returns true.
  437. * Do not call this method directly.
  438. * @param string $id session ID
  439. * @return string the session data
  440. */
  441. public function readSession($id)
  442. {
  443. return '';
  444. }
  445. /**
  446. * Session write handler.
  447. * This method should be overridden if [[useCustomStorage]] returns true.
  448. * Do not call this method directly.
  449. * @param string $id session ID
  450. * @param string $data session data
  451. * @return boolean whether session write is successful
  452. */
  453. public function writeSession($id, $data)
  454. {
  455. return true;
  456. }
  457. /**
  458. * Session destroy handler.
  459. * This method should be overridden if [[useCustomStorage]] returns true.
  460. * Do not call this method directly.
  461. * @param string $id session ID
  462. * @return boolean whether session is destroyed successfully
  463. */
  464. public function destroySession($id)
  465. {
  466. return true;
  467. }
  468. /**
  469. * Session GC (garbage collection) handler.
  470. * This method should be overridden if [[useCustomStorage]] returns true.
  471. * Do not call this method directly.
  472. * @param integer $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
  473. * @return boolean whether session is GCed successfully
  474. */
  475. public function gcSession($maxLifetime)
  476. {
  477. return true;
  478. }
  479. /**
  480. * Returns an iterator for traversing the session variables.
  481. * This method is required by the interface [[\IteratorAggregate]].
  482. * @return SessionIterator an iterator for traversing the session variables.
  483. */
  484. public function getIterator()
  485. {
  486. $this->open();
  487. return new SessionIterator;
  488. }
  489. /**
  490. * Returns the number of items in the session.
  491. * @return integer the number of session variables
  492. */
  493. public function getCount()
  494. {
  495. $this->open();
  496. return count($_SESSION);
  497. }
  498. /**
  499. * Returns the number of items in the session.
  500. * This method is required by [[\Countable]] interface.
  501. * @return integer number of items in the session.
  502. */
  503. public function count()
  504. {
  505. return $this->getCount();
  506. }
  507. /**
  508. * Returns the session variable value with the session variable name.
  509. * If the session variable does not exist, the `$defaultValue` will be returned.
  510. * @param string $key the session variable name
  511. * @param mixed $defaultValue the default value to be returned when the session variable does not exist.
  512. * @return mixed the session variable value, or $defaultValue if the session variable does not exist.
  513. */
  514. public function get($key, $defaultValue = null)
  515. {
  516. $this->open();
  517. return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
  518. }
  519. /**
  520. * Adds a session variable.
  521. * If the specified name already exists, the old value will be overwritten.
  522. * @param string $key session variable name
  523. * @param mixed $value session variable value
  524. */
  525. public function set($key, $value)
  526. {
  527. $this->open();
  528. $_SESSION[$key] = $value;
  529. }
  530. /**
  531. * Removes a session variable.
  532. * @param string $key the name of the session variable to be removed
  533. * @return mixed the removed value, null if no such session variable.
  534. */
  535. public function remove($key)
  536. {
  537. $this->open();
  538. if (isset($_SESSION[$key])) {
  539. $value = $_SESSION[$key];
  540. unset($_SESSION[$key]);
  541. return $value;
  542. } else {
  543. return null;
  544. }
  545. }
  546. /**
  547. * Removes all session variables
  548. */
  549. public function removeAll()
  550. {
  551. $this->open();
  552. foreach (array_keys($_SESSION) as $key) {
  553. unset($_SESSION[$key]);
  554. }
  555. }
  556. /**
  557. * @param mixed $key session variable name
  558. * @return boolean whether there is the named session variable
  559. */
  560. public function has($key)
  561. {
  562. $this->open();
  563. return isset($_SESSION[$key]);
  564. }
  565. /**
  566. * Updates the counters for flash messages and removes outdated flash messages.
  567. * This method should only be called once in [[init()]].
  568. */
  569. protected function updateFlashCounters()
  570. {
  571. $counters = $this->get($this->flashParam, []);
  572. if (is_array($counters)) {
  573. foreach ($counters as $key => $count) {
  574. if ($count > 0) {
  575. unset($counters[$key], $_SESSION[$key]);
  576. } elseif ($count == 0) {
  577. $counters[$key]++;
  578. }
  579. }
  580. $_SESSION[$this->flashParam] = $counters;
  581. } else {
  582. // fix the unexpected problem that flashParam doesn't return an array
  583. unset($_SESSION[$this->flashParam]);
  584. }
  585. }
  586. /**
  587. * Returns a flash message.
  588. * @param string $key the key identifying the flash message
  589. * @param mixed $defaultValue value to be returned if the flash message does not exist.
  590. * @param boolean $delete whether to delete this flash message right after this method is called.
  591. * If false, the flash message will be automatically deleted in the next request.
  592. * @return mixed the flash message or an array of messages if addFlash was used
  593. * @see setFlash()
  594. * @see addFlash()
  595. * @see hasFlash()
  596. * @see getAllFlashes()
  597. * @see removeFlash()
  598. */
  599. public function getFlash($key, $defaultValue = null, $delete = false)
  600. {
  601. $counters = $this->get($this->flashParam, []);
  602. if (isset($counters[$key])) {
  603. $value = $this->get($key, $defaultValue);
  604. if ($delete) {
  605. $this->removeFlash($key);
  606. } elseif ($counters[$key] < 0) {
  607. // mark for deletion in the next request
  608. $counters[$key] = 1;
  609. $_SESSION[$this->flashParam] = $counters;
  610. }
  611. return $value;
  612. } else {
  613. return $defaultValue;
  614. }
  615. }
  616. /**
  617. * Returns all flash messages.
  618. *
  619. * You may use this method to display all the flash messages in a view file:
  620. *
  621. * ```php
  622. * <?php
  623. * foreach (Yii::$app->session->getAllFlashes() as $key => $message) {
  624. * echo '<div class="alert alert-' . $key . '">' . $message . '</div>';
  625. * } ?>
  626. * ```
  627. *
  628. * With the above code you can use the [bootstrap alert][] classes such as `success`, `info`, `danger`
  629. * as the flash message key to influence the color of the div.
  630. *
  631. * Note that if you use [[addFlash()]], `$message` will be an array, and you will have to adjust the above code.
  632. *
  633. * [bootstrap alert]: http://getbootstrap.com/components/#alerts
  634. *
  635. * @param boolean $delete whether to delete the flash messages right after this method is called.
  636. * If false, the flash messages will be automatically deleted in the next request.
  637. * @return array flash messages (key => message or key => [message1, message2]).
  638. * @see setFlash()
  639. * @see addFlash()
  640. * @see getFlash()
  641. * @see hasFlash()
  642. * @see removeFlash()
  643. */
  644. public function getAllFlashes($delete = false)
  645. {
  646. $counters = $this->get($this->flashParam, []);
  647. $flashes = [];
  648. foreach (array_keys($counters) as $key) {
  649. if (array_key_exists($key, $_SESSION)) {
  650. $flashes[$key] = $_SESSION[$key];
  651. if ($delete) {
  652. unset($counters[$key], $_SESSION[$key]);
  653. } elseif ($counters[$key] < 0) {
  654. // mark for deletion in the next request
  655. $counters[$key] = 1;
  656. }
  657. } else {
  658. unset($counters[$key]);
  659. }
  660. }
  661. $_SESSION[$this->flashParam] = $counters;
  662. return $flashes;
  663. }
  664. /**
  665. * Sets a flash message.
  666. * A flash message will be automatically deleted after it is accessed in a request and the deletion will happen
  667. * in the next request.
  668. * If there is already an existing flash message with the same key, it will be overwritten by the new one.
  669. * @param string $key the key identifying the flash message. Note that flash messages
  670. * and normal session variables share the same name space. If you have a normal
  671. * session variable using the same name, its value will be overwritten by this method.
  672. * @param mixed $value flash message
  673. * @param boolean $removeAfterAccess whether the flash message should be automatically removed only if
  674. * it is accessed. If false, the flash message will be automatically removed after the next request,
  675. * regardless if it is accessed or not. If true (default value), the flash message will remain until after
  676. * it is accessed.
  677. * @see getFlash()
  678. * @see addFlash()
  679. * @see removeFlash()
  680. */
  681. public function setFlash($key, $value = true, $removeAfterAccess = true)
  682. {
  683. $counters = $this->get($this->flashParam, []);
  684. $counters[$key] = $removeAfterAccess ? -1 : 0;
  685. $_SESSION[$key] = $value;
  686. $_SESSION[$this->flashParam] = $counters;
  687. }
  688. /**
  689. * Adds a flash message.
  690. * If there are existing flash messages with the same key, the new one will be appended to the existing message array.
  691. * @param string $key the key identifying the flash message.
  692. * @param mixed $value flash message
  693. * @param boolean $removeAfterAccess whether the flash message should be automatically removed only if
  694. * it is accessed. If false, the flash message will be automatically removed after the next request,
  695. * regardless if it is accessed or not. If true (default value), the flash message will remain until after
  696. * it is accessed.
  697. * @see getFlash()
  698. * @see setFlash()
  699. * @see removeFlash()
  700. */
  701. public function addFlash($key, $value = true, $removeAfterAccess = true)
  702. {
  703. $counters = $this->get($this->flashParam, []);
  704. $counters[$key] = $removeAfterAccess ? -1 : 0;
  705. $_SESSION[$this->flashParam] = $counters;
  706. if (empty($_SESSION[$key])) {
  707. $_SESSION[$key] = [$value];
  708. } else {
  709. if (is_array($_SESSION[$key])) {
  710. $_SESSION[$key][] = $value;
  711. } else {
  712. $_SESSION[$key] = [$_SESSION[$key], $value];
  713. }
  714. }
  715. }
  716. /**
  717. * Removes a flash message.
  718. * @param string $key the key identifying the flash message. Note that flash messages
  719. * and normal session variables share the same name space. If you have a normal
  720. * session variable using the same name, it will be removed by this method.
  721. * @return mixed the removed flash message. Null if the flash message does not exist.
  722. * @see getFlash()
  723. * @see setFlash()
  724. * @see addFlash()
  725. * @see removeAllFlashes()
  726. */
  727. public function removeFlash($key)
  728. {
  729. $counters = $this->get($this->flashParam, []);
  730. $value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null;
  731. unset($counters[$key], $_SESSION[$key]);
  732. $_SESSION[$this->flashParam] = $counters;
  733. return $value;
  734. }
  735. /**
  736. * Removes all flash messages.
  737. * Note that flash messages and normal session variables share the same name space.
  738. * If you have a normal session variable using the same name, it will be removed
  739. * by this method.
  740. * @see getFlash()
  741. * @see setFlash()
  742. * @see addFlash()
  743. * @see removeFlash()
  744. */
  745. public function removeAllFlashes()
  746. {
  747. $counters = $this->get($this->flashParam, []);
  748. foreach (array_keys($counters) as $key) {
  749. unset($_SESSION[$key]);
  750. }
  751. unset($_SESSION[$this->flashParam]);
  752. }
  753. /**
  754. * Returns a value indicating whether there are flash messages associated with the specified key.
  755. * @param string $key key identifying the flash message type
  756. * @return boolean whether any flash messages exist under specified key
  757. */
  758. public function hasFlash($key)
  759. {
  760. return $this->getFlash($key) !== null;
  761. }
  762. /**
  763. * This method is required by the interface [[\ArrayAccess]].
  764. * @param mixed $offset the offset to check on
  765. * @return boolean
  766. */
  767. public function offsetExists($offset)
  768. {
  769. $this->open();
  770. return isset($_SESSION[$offset]);
  771. }
  772. /**
  773. * This method is required by the interface [[\ArrayAccess]].
  774. * @param integer $offset the offset to retrieve element.
  775. * @return mixed the element at the offset, null if no element is found at the offset
  776. */
  777. public function offsetGet($offset)
  778. {
  779. $this->open();
  780. return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
  781. }
  782. /**
  783. * This method is required by the interface [[\ArrayAccess]].
  784. * @param integer $offset the offset to set element
  785. * @param mixed $item the element value
  786. */
  787. public function offsetSet($offset, $item)
  788. {
  789. $this->open();
  790. $_SESSION[$offset] = $item;
  791. }
  792. /**
  793. * This method is required by the interface [[\ArrayAccess]].
  794. * @param mixed $offset the offset to unset element
  795. */
  796. public function offsetUnset($offset)
  797. {
  798. $this->open();
  799. unset($_SESSION[$offset]);
  800. }
  801. }