1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6: */
7:
8: namespace Nette\Http;
9:
10: use Nette;
11:
12:
13: /**
14: * Session section.
15: */
16: class SessionSection implements \IteratorAggregate, \ArrayAccess
17: {
18: use Nette\SmartObject;
19:
20: /** @var bool */
21: public $warnOnUndefined = false;
22:
23: /** @var Session */
24: private $session;
25:
26: /** @var string */
27: private $name;
28:
29: /** @var array|null session data storage */
30: private $data;
31:
32: /** @var array|bool session metadata storage */
33: private $meta = false;
34:
35:
36: /**
37: * Do not call directly. Use Session::getSection().
38: */
39: public function __construct(Session $session, $name)
40: {
41: if (!is_string($name)) {
42: throw new Nette\InvalidArgumentException('Session namespace must be a string, ' . gettype($name) . ' given.');
43: }
44:
45: $this->session = $session;
46: $this->name = $name;
47: }
48:
49:
50: private function start()
51: {
52: if ($this->meta === false) {
53: $this->session->start();
54: $this->data = &$_SESSION['__NF']['DATA'][$this->name];
55: $this->meta = &$_SESSION['__NF']['META'][$this->name];
56: }
57: }
58:
59:
60: /**
61: * Returns an iterator over all section variables.
62: * @return \Iterator
63: */
64: public function getIterator()
65: {
66: $this->start();
67: if (isset($this->data)) {
68: return new \ArrayIterator($this->data);
69: } else {
70: return new \ArrayIterator;
71: }
72: }
73:
74:
75: /**
76: * Sets a variable in this session section.
77: * @param string name
78: * @param mixed value
79: * @return void
80: */
81: public function __set($name, $value)
82: {
83: $this->start();
84: $this->data[$name] = $value;
85: }
86:
87:
88: /**
89: * Gets a variable from this session section.
90: * @param string name
91: * @return mixed
92: */
93: public function &__get($name)
94: {
95: $this->start();
96: if ($this->warnOnUndefined && !array_key_exists($name, $this->data)) {
97: trigger_error("The variable '$name' does not exist in session section");
98: }
99:
100: return $this->data[$name];
101: }
102:
103:
104: /**
105: * Determines whether a variable in this session section is set.
106: * @param string name
107: * @return bool
108: */
109: public function __isset($name)
110: {
111: if ($this->session->exists()) {
112: $this->start();
113: }
114: return isset($this->data[$name]);
115: }
116:
117:
118: /**
119: * Unsets a variable in this session section.
120: * @param string name
121: * @return void
122: */
123: public function __unset($name)
124: {
125: $this->start();
126: unset($this->data[$name], $this->meta[$name]);
127: }
128:
129:
130: /**
131: * Sets a variable in this session section.
132: * @param string name
133: * @param mixed value
134: * @return void
135: */
136: public function offsetSet($name, $value)
137: {
138: $this->__set($name, $value);
139: }
140:
141:
142: /**
143: * Gets a variable from this session section.
144: * @param string name
145: * @return mixed
146: */
147: public function offsetGet($name)
148: {
149: return $this->__get($name);
150: }
151:
152:
153: /**
154: * Determines whether a variable in this session section is set.
155: * @param string name
156: * @return bool
157: */
158: public function offsetExists($name)
159: {
160: return $this->__isset($name);
161: }
162:
163:
164: /**
165: * Unsets a variable in this session section.
166: * @param string name
167: * @return void
168: */
169: public function offsetUnset($name)
170: {
171: $this->__unset($name);
172: }
173:
174:
175: /**
176: * Sets the expiration of the section or specific variables.
177: * @param string|int|\DateTimeInterface time
178: * @param mixed optional list of variables / single variable to expire
179: * @return static
180: */
181: public function setExpiration($time, $variables = null)
182: {
183: $this->start();
184: if ($time) {
185: $time = Nette\Utils\DateTime::from($time)->format('U');
186: $max = (int) ini_get('session.gc_maxlifetime');
187: if ($max !== 0 && ($time - time() > $max + 3)) { // 0 - unlimited in memcache handler, 3 - bulgarian constant
188: trigger_error("The expiration time is greater than the session expiration $max seconds");
189: }
190: }
191:
192: foreach (is_array($variables) ? $variables : [$variables] as $variable) {
193: $this->meta[$variable]['T'] = $time ?: null;
194: }
195: return $this;
196: }
197:
198:
199: /**
200: * Removes the expiration from the section or specific variables.
201: * @param mixed optional list of variables / single variable to expire
202: * @return void
203: */
204: public function removeExpiration($variables = null)
205: {
206: $this->start();
207: foreach (is_array($variables) ? $variables : [$variables] as $variable) {
208: unset($this->meta[$variable]['T']);
209: }
210: }
211:
212:
213: /**
214: * Cancels the current session section.
215: * @return void
216: */
217: public function remove()
218: {
219: $this->start();
220: $this->data = null;
221: $this->meta = null;
222: }
223: }
224: