/library/Zend/Session/Storage/AbstractSessionArrayStorage.php

https://github.com/SocalNick/zf2 · PHP · 471 lines · 229 code · 56 blank · 186 comment · 38 complexity · e412b6ea4e7c6710b1e27708bb6eca9b MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Session\Storage;
  10. use ArrayIterator;
  11. use IteratorAggregate;
  12. use Zend\Session\Exception;
  13. /**
  14. * Session storage in $_SESSION
  15. *
  16. * Replaces the $_SESSION superglobal with an ArrayObject that allows for
  17. * property access, metadata storage, locking, and immutability.
  18. */
  19. abstract class AbstractSessionArrayStorage implements IteratorAggregate, StorageInterface
  20. {
  21. /**
  22. * Constructor
  23. *
  24. * @param array|null $input
  25. */
  26. public function __construct($input = null)
  27. {
  28. if ((null === $input) && isset($_SESSION)) {
  29. $input = $_SESSION;
  30. if (is_object($input) && !$_SESSION instanceof \ArrayObject) {
  31. $input = (array) $input;
  32. }
  33. } elseif (null === $input) {
  34. $input = array();
  35. }
  36. $_SESSION = $input;
  37. $this->setRequestAccessTime(microtime(true));
  38. }
  39. /**
  40. * Get Offset
  41. *
  42. * @param mixed $key
  43. * @return mixed
  44. */
  45. public function __get($key)
  46. {
  47. return $this->offsetGet($key);
  48. }
  49. /**
  50. * Set Offset
  51. *
  52. * @param mixed $key
  53. * @param mixed $value
  54. * @return void
  55. */
  56. public function __set($key, $value)
  57. {
  58. return $this->offsetSet($key, $value);
  59. }
  60. /**
  61. * Isset Offset
  62. *
  63. * @param mixed $key
  64. * @return boolean
  65. */
  66. public function __isset($key)
  67. {
  68. return $this->offsetExists($key);
  69. }
  70. /**
  71. * Unset Offset
  72. *
  73. * @param mixed $key
  74. * @return void
  75. */
  76. public function __unset($key)
  77. {
  78. return $this->offsetUnset($key);
  79. }
  80. /**
  81. * Destructor
  82. *
  83. * @return void
  84. */
  85. public function __destruct()
  86. {
  87. return ;
  88. }
  89. /**
  90. * Offset Exists
  91. *
  92. * @param mixed $key
  93. * @return boolean
  94. */
  95. public function offsetExists($key)
  96. {
  97. return isset($_SESSION[$key]);
  98. }
  99. /**
  100. * Offset Get
  101. *
  102. * @param mixed $key
  103. * @return mixed
  104. */
  105. public function offsetGet($key)
  106. {
  107. if (isset($_SESSION[$key])) {
  108. return $_SESSION[$key];
  109. }
  110. return null;
  111. }
  112. /**
  113. * Offset Set
  114. *
  115. * @param mixed $key
  116. * @param mixed $value
  117. * @return void
  118. */
  119. public function offsetSet($key, $value)
  120. {
  121. $_SESSION[$key] = $value;
  122. }
  123. /**
  124. * Offset Unset
  125. *
  126. * @param mixed $key
  127. * @return void
  128. */
  129. public function offsetUnset($key)
  130. {
  131. unset($_SESSION[$key]);
  132. }
  133. /**
  134. * Count
  135. *
  136. * @return int
  137. */
  138. public function count()
  139. {
  140. return count($_SESSION);
  141. }
  142. /**
  143. * Seralize
  144. *
  145. * @return string
  146. */
  147. public function serialize()
  148. {
  149. return serialize($_SESSION);
  150. }
  151. /**
  152. * Unserialize
  153. *
  154. * @param string $session
  155. * @return mixed
  156. */
  157. public function unserialize($session)
  158. {
  159. return unserialize($session);
  160. }
  161. /**
  162. * Get Iterator
  163. *
  164. * @return ArrayIterator
  165. */
  166. public function getIterator()
  167. {
  168. return new ArrayIterator($_SESSION);
  169. }
  170. /**
  171. * Load session object from an existing array
  172. *
  173. * Ensures $_SESSION is set to an instance of the object when complete.
  174. *
  175. * @param array $array
  176. * @return SessionStorage
  177. */
  178. public function fromArray(array $array)
  179. {
  180. $ts = $this->getRequestAccessTime();
  181. $_SESSION = $array;
  182. $this->setRequestAccessTime($ts);
  183. return $this;
  184. }
  185. /**
  186. * Mark object as isImmutable
  187. *
  188. * @return SessionStorage
  189. */
  190. public function markImmutable()
  191. {
  192. $_SESSION['_IMMUTABLE'] = true;
  193. return $this;
  194. }
  195. /**
  196. * Determine if this object is isImmutable
  197. *
  198. * @return bool
  199. */
  200. public function isImmutable()
  201. {
  202. return (isset($_SESSION['_IMMUTABLE']) && $_SESSION['_IMMUTABLE']);
  203. }
  204. /**
  205. * Lock this storage instance, or a key within it
  206. *
  207. * @param null|int|string $key
  208. * @return ArrayStorage
  209. */
  210. public function lock($key = null)
  211. {
  212. if (null === $key) {
  213. $this->setMetadata('_READONLY', true);
  214. return $this;
  215. }
  216. if (isset($_SESSION[$key])) {
  217. $this->setMetadata('_LOCKS', array($key => true));
  218. }
  219. return $this;
  220. }
  221. /**
  222. * Is the object or key marked as locked?
  223. *
  224. * @param null|int|string $key
  225. * @return bool
  226. */
  227. public function isLocked($key = null)
  228. {
  229. if ($this->isImmutable()) {
  230. // isImmutable trumps all
  231. return true;
  232. }
  233. if (null === $key) {
  234. // testing for global lock
  235. return $this->getMetadata('_READONLY');
  236. }
  237. $locks = $this->getMetadata('_LOCKS');
  238. $readOnly = $this->getMetadata('_READONLY');
  239. if ($readOnly && !$locks) {
  240. // global lock in play; all keys are locked
  241. return true;
  242. }
  243. if ($readOnly && $locks) {
  244. return array_key_exists($key, $locks);
  245. }
  246. // test for individual locks
  247. if (!$locks) {
  248. return false;
  249. }
  250. return array_key_exists($key, $locks);
  251. }
  252. /**
  253. * Unlock an object or key marked as locked
  254. *
  255. * @param null|int|string $key
  256. * @return ArrayStorage
  257. */
  258. public function unlock($key = null)
  259. {
  260. if (null === $key) {
  261. // Unlock everything
  262. $this->setMetadata('_READONLY', false);
  263. $this->setMetadata('_LOCKS', false);
  264. return $this;
  265. }
  266. $locks = $this->getMetadata('_LOCKS');
  267. if (!$locks) {
  268. if (!$this->getMetadata('_READONLY')) {
  269. return $this;
  270. }
  271. $array = $this->toArray();
  272. $keys = array_keys($array);
  273. $locks = array_flip($keys);
  274. unset($array, $keys);
  275. }
  276. if (array_key_exists($key, $locks)) {
  277. unset($locks[$key]);
  278. $this->setMetadata('_LOCKS', $locks, true);
  279. }
  280. return $this;
  281. }
  282. /**
  283. * Set storage metadata
  284. *
  285. * Metadata is used to store information about the data being stored in the
  286. * object. Some example use cases include:
  287. * - Setting expiry data
  288. * - Maintaining access counts
  289. * - localizing session storage
  290. * - etc.
  291. *
  292. * @param string $key
  293. * @param mixed $value
  294. * @param bool $overwriteArray Whether to overwrite or merge array values; by default, merges
  295. * @return ArrayStorage
  296. * @throws Exception\RuntimeException
  297. */
  298. public function setMetadata($key, $value, $overwriteArray = false)
  299. {
  300. if ($this->isImmutable()) {
  301. throw new Exception\RuntimeException(sprintf(
  302. 'Cannot set key "%s" as storage is marked isImmutable', $key
  303. ));
  304. }
  305. if (!isset($_SESSION['__ZF'])) {
  306. $_SESSION['__ZF'] = array();
  307. }
  308. if (isset($_SESSION['__ZF'][$key]) && is_array($value)) {
  309. if ($overwriteArray) {
  310. $_SESSION['__ZF'][$key] = $value;
  311. } else {
  312. $_SESSION['__ZF'][$key] = array_replace_recursive($_SESSION['__ZF'][$key], $value);
  313. }
  314. } else {
  315. if ((null === $value) && isset($_SESSION['__ZF'][$key])) {
  316. $array = $_SESSION['__ZF'];
  317. unset($array[$key]);
  318. $_SESSION['__ZF'] = $array;
  319. unset($array);
  320. } elseif (null !== $value) {
  321. $_SESSION['__ZF'][$key] = $value;
  322. }
  323. }
  324. return $this;
  325. }
  326. /**
  327. * Retrieve metadata for the storage object or a specific metadata key
  328. *
  329. * Returns false if no metadata stored, or no metadata exists for the given
  330. * key.
  331. *
  332. * @param null|int|string $key
  333. * @return mixed
  334. */
  335. public function getMetadata($key = null)
  336. {
  337. if (!isset($_SESSION['__ZF'])) {
  338. return false;
  339. }
  340. if (null === $key) {
  341. return $_SESSION['__ZF'];
  342. }
  343. if (!array_key_exists($key, $_SESSION['__ZF'])) {
  344. return false;
  345. }
  346. return $_SESSION['__ZF'][$key];
  347. }
  348. /**
  349. * Clear the storage object or a subkey of the object
  350. *
  351. * @param null|int|string $key
  352. * @return ArrayStorage
  353. * @throws Exception\RuntimeException
  354. */
  355. public function clear($key = null)
  356. {
  357. if ($this->isImmutable()) {
  358. throw new Exception\RuntimeException('Cannot clear storage as it is marked immutable');
  359. }
  360. if (null === $key) {
  361. $this->fromArray(array());
  362. return $this;
  363. }
  364. if (!isset($_SESSION[$key])) {
  365. return $this;
  366. }
  367. // Clear key data
  368. unset($_SESSION[$key]);
  369. // Clear key metadata
  370. $this->setMetadata($key, null)
  371. ->unlock($key);
  372. return $this;
  373. }
  374. /**
  375. * Retrieve the request access time
  376. *
  377. * @return float
  378. */
  379. public function getRequestAccessTime()
  380. {
  381. return $this->getMetadata('_REQUEST_ACCESS_TIME');
  382. }
  383. /**
  384. * Set the request access time
  385. *
  386. * @param float $time
  387. * @return ArrayStorage
  388. */
  389. protected function setRequestAccessTime($time)
  390. {
  391. $this->setMetadata('_REQUEST_ACCESS_TIME', $time);
  392. return $this;
  393. }
  394. /**
  395. * Cast the object to an array
  396. *
  397. * @param bool $metaData Whether to include metadata
  398. * @return array
  399. */
  400. public function toArray($metaData = false)
  401. {
  402. if (isset($_SESSION)) {
  403. $values = $_SESSION;
  404. } else {
  405. $values = array();
  406. }
  407. if ($metaData) {
  408. return $values;
  409. }
  410. if (isset($values['__ZF'])) {
  411. unset($values['__ZF']);
  412. }
  413. return $values;
  414. }
  415. }