/libraries/src/Session/Storage/JoomlaStorage.php

https://github.com/Hackwar/joomla-cms · PHP · 313 lines · 137 code · 44 blank · 132 comment · 19 complexity · d0e0a3b2215f6bb899409252ac12e9ec MD5 · raw file

  1. <?php
  2. /**
  3. * Joomla! Content Management System
  4. *
  5. * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
  6. * @license GNU General Public License version 2 or later; see LICENSE
  7. */
  8. namespace Joomla\CMS\Session\Storage;
  9. \defined('JPATH_PLATFORM') or die;
  10. use Joomla\CMS\Factory;
  11. use Joomla\Input\Input;
  12. use Joomla\Registry\Registry;
  13. use Joomla\Session\Storage\NativeStorage;
  14. /**
  15. * Service provider for the application's session dependency
  16. *
  17. * @since 4.0.0
  18. */
  19. class JoomlaStorage extends NativeStorage
  20. {
  21. /**
  22. * Internal data store for the session data
  23. *
  24. * @var Registry
  25. * @since 4.0.0
  26. */
  27. private $data;
  28. /**
  29. * Force cookies to be SSL only
  30. *
  31. * @var boolean
  32. * @since 4.0.0
  33. */
  34. private $forceSSL = false;
  35. /**
  36. * Input object
  37. *
  38. * @var Input
  39. * @since 4.0.0
  40. */
  41. private $input;
  42. /**
  43. * Constructor
  44. *
  45. * @param Input $input Input object
  46. * @param \SessionHandlerInterface $handler Session save handler
  47. * @param array $options Session options
  48. *
  49. * @since 4.0.0
  50. */
  51. public function __construct(Input $input, \SessionHandlerInterface $handler = null, array $options = [])
  52. {
  53. // Disable transparent sid support and default use cookies
  54. $options += [
  55. 'use_cookies' => 1,
  56. 'use_trans_sid' => 0,
  57. ];
  58. if (!headers_sent() && !$this->isActive())
  59. {
  60. session_cache_limiter('none');
  61. }
  62. $this->setOptions($options);
  63. $this->setHandler($handler);
  64. $this->setCookieParams();
  65. $this->data = new Registry;
  66. $this->input = $input;
  67. // Register our function as shutdown method, so we can manipulate it
  68. register_shutdown_function([$this, 'close']);
  69. }
  70. /**
  71. * Retrieves all variables from the session store
  72. *
  73. * @return array
  74. *
  75. * @since 4.0.0
  76. */
  77. public function all(): array
  78. {
  79. return $this->data->toArray();
  80. }
  81. /**
  82. * Clears all variables from the session store
  83. *
  84. * @return void
  85. *
  86. * @since 4.0.0
  87. */
  88. public function clear(): void
  89. {
  90. $session_name = $this->getName();
  91. /*
  92. * In order to kill the session altogether, such as to log the user out, the session id
  93. * must also be unset. If a cookie is used to propagate the session id (default behavior),
  94. * then the session cookie must be deleted.
  95. */
  96. if (isset($_COOKIE[$session_name]))
  97. {
  98. $app = Factory::getApplication();
  99. $cookie_domain = $app->get('cookie_domain', '');
  100. $cookie_path = $app->get('cookie_path', '/');
  101. $cookie = session_get_cookie_params();
  102. setcookie($session_name, '', time() - 42000, $cookie_path, $cookie_domain, $cookie['secure'], true);
  103. }
  104. $this->data = new Registry;
  105. }
  106. /**
  107. * Writes session data and ends session
  108. *
  109. * @return void
  110. *
  111. * @see session_write_close()
  112. * @since 4.0.0
  113. */
  114. public function close(): void
  115. {
  116. // Before storing data to the session, we serialize and encode the Registry
  117. $_SESSION['joomla'] = base64_encode(serialize(clone $this->data));
  118. parent::close();
  119. }
  120. /**
  121. * Get data from the session store
  122. *
  123. * @param string $name Name of a variable
  124. * @param mixed $default Default value of a variable if not set
  125. *
  126. * @return mixed Value of a variable
  127. *
  128. * @since 4.0.0
  129. */
  130. public function get(string $name, $default)
  131. {
  132. if (!$this->isStarted())
  133. {
  134. $this->start();
  135. }
  136. return $this->data->get($name, $default);
  137. }
  138. /**
  139. * Check whether data exists in the session store
  140. *
  141. * @param string $name Name of variable
  142. *
  143. * @return boolean True if the variable exists
  144. *
  145. * @since 4.0.0
  146. */
  147. public function has(string $name): bool
  148. {
  149. if (!$this->isStarted())
  150. {
  151. $this->start();
  152. }
  153. return $this->data->exists($name);
  154. }
  155. /**
  156. * Unset a variable from the session store
  157. *
  158. * @param string $name Name of variable
  159. *
  160. * @return mixed The value from session or NULL if not set
  161. *
  162. * @since 4.0.0
  163. */
  164. public function remove(string $name)
  165. {
  166. if (!$this->isStarted())
  167. {
  168. $this->start();
  169. }
  170. $old = $this->data->get($name);
  171. unset($this->data[$name]);
  172. return $old;
  173. }
  174. /**
  175. * Set data into the session store
  176. *
  177. * @param string $name Name of a variable.
  178. * @param mixed $value Value of a variable.
  179. *
  180. * @return mixed Old value of a variable.
  181. *
  182. * @since 4.0.0
  183. */
  184. public function set(string $name, $value = null)
  185. {
  186. if (!$this->isStarted())
  187. {
  188. $this->start();
  189. }
  190. $old = $this->data->get($name);
  191. $this->data->set($name, $value);
  192. return $old;
  193. }
  194. /**
  195. * Set session cookie parameters
  196. *
  197. * @return void
  198. *
  199. * @since 4.0.0
  200. */
  201. protected function setCookieParams(): void
  202. {
  203. if (headers_sent() || $this->isActive())
  204. {
  205. return;
  206. }
  207. $cookie = session_get_cookie_params();
  208. if ($this->forceSSL)
  209. {
  210. $cookie['secure'] = true;
  211. }
  212. $app = Factory::getApplication();
  213. if ($app->get('cookie_domain', '') != '')
  214. {
  215. $cookie['domain'] = $app->get('cookie_domain');
  216. }
  217. if ($app->get('cookie_path', '') != '')
  218. {
  219. $cookie['path'] = $app->get('cookie_path');
  220. }
  221. session_set_cookie_params($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true);
  222. }
  223. /**
  224. * Sets session options
  225. *
  226. * @param array $options Session ini directives array(key => value).
  227. *
  228. * @return $this
  229. *
  230. * @see http://php.net/session.configuration
  231. * @since 4.0.0
  232. */
  233. public function setOptions(array $options): NativeStorage
  234. {
  235. if (isset($options['force_ssl']))
  236. {
  237. $this->forceSSL = (bool) $options['force_ssl'];
  238. }
  239. return parent::setOptions($options);
  240. }
  241. /**
  242. * Start a session
  243. *
  244. * @return void
  245. *
  246. * @since 4.0.0
  247. */
  248. public function start(): void
  249. {
  250. $session_name = $this->getName();
  251. // Get the cookie object
  252. $cookie = $this->input->cookie;
  253. if (\is_null($cookie->get($session_name)))
  254. {
  255. $session_clean = $this->input->getString($session_name);
  256. if ($session_clean)
  257. {
  258. $this->setId($session_clean);
  259. $cookie->set($session_name, '', time() - 3600);
  260. }
  261. }
  262. parent::start();
  263. // Try loading data from the session
  264. if (isset($_SESSION['joomla']) && !empty($_SESSION['joomla']))
  265. {
  266. $this->data = unserialize(base64_decode($_SESSION['joomla']));
  267. }
  268. }
  269. }