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