• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / http / 26789762594

02 Jun 2026 12:03AM UTC coverage: 83.886% (-0.03%) from 83.912%
26789762594

push

github

dg
Helpers: added expirationToSeconds() unifying expiration parsing

A numeric value (including a numeric string) is taken directly as the number of
seconds, a DateTimeInterface or a textual string (e.g. '20 minutes',
'2024-01-01') is resolved as an absolute time, and null means "no value". An
empty string is rejected as it is never meaningful.

The helper is a pure parser and applies no policy - each caller decides what
null or a non-positive result means in its own context:

- Response::setExpiration(): null or a non-positive time disables caching
- Session::setExpiration(): null restores the default lifetime, a non-positive
  time throws (a lifetime in the past makes no sense)
- SessionSection::setExpiration(): null clears the expiration
- Response::setCookie(): null is a session cookie, a non-positive time deletes
  it; passing integer 0 (which used to mean a session cookie) is deprecated in
  favour of null

23 of 31 new or added lines in 4 files covered. (74.19%)

34 existing lines in 3 files now uncovered.

1062 of 1266 relevant lines covered (83.89%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.49
/src/Http/SessionSection.php
1
<?php declare(strict_types=1);
1✔
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 function array_key_exists, func_num_args, ini_get, is_array, is_string, time;
11

12

13
/**
14
 * Session section.
15
 * @implements \IteratorAggregate<string, mixed>
16
 * @implements \ArrayAccess<string, mixed>
17
 */
18
class SessionSection implements \IteratorAggregate, \ArrayAccess
19
{
20
        /** Emits a warning when accessing an undefined variable in this section */
21
        public bool $warnOnUndefined = false;
22

23

24
        /**
25
         * Do not call directly. Use Session::getSection().
26
         */
27
        public function __construct(
1✔
28
                private readonly Session $session,
29
                private readonly string $name,
30
        ) {
31
        }
1✔
32

33

34
        /**
35
         * Returns an iterator over all section variables.
36
         * @return \Iterator<string, mixed>
37
         */
38
        public function getIterator(): \Iterator
39
        {
40
                $this->session->autoStart(forWrite: false);
1✔
41
                return new \ArrayIterator($this->getData() ?? []);
1✔
42
        }
43

44

45
        /**
46
         * Sets a variable in this session section. Passing null removes it.
47
         * The optional $expire sets per-variable expiration as a time string (e.g. '30 seconds').
48
         */
49
        public function set(string $name, mixed $value, ?string $expire = null): void
1✔
50
        {
51
                if ($value === null) {
1✔
UNCOV
52
                        $this->remove($name);
×
53
                } else {
54
                        $this->session->autoStart(forWrite: true);
1✔
55
                        $this->getData()[$name] = $value;
1✔
56
                        $this->setExpiration($expire, $name);
1✔
57
                }
58
        }
1✔
59

60

61
        /**
62
         * Gets a variable from this session section.
63
         */
64
        public function get(string $name): mixed
1✔
65
        {
66
                if (func_num_args() > 1) {
1✔
UNCOV
67
                        throw new \ArgumentCountError(__METHOD__ . '() expects 1 arguments, given more.');
×
68
                }
69

70
                $this->session->autoStart(forWrite: false);
1✔
71
                return $this->getData()[$name] ?? null;
1✔
72
        }
73

74

75
        /**
76
         * Removes a variable or a list of variables from this section. With no argument, removes the entire section.
77
         * @param  string|string[]|null  $name
78
         */
79
        public function remove(string|array|null $name = null): void
1✔
80
        {
81
                $this->session->autoStart(forWrite: false);
1✔
82
                if (func_num_args() > 1) {
1✔
UNCOV
83
                        throw new \ArgumentCountError(__METHOD__ . '() expects at most 1 arguments, given more.');
×
84

85
                } elseif (func_num_args()) {
1✔
86
                        $data = &$this->getData();
1✔
87
                        $meta = &$this->getMeta();
1✔
88
                        foreach ((array) $name as $name) {
1✔
89
                                unset($data[$name], $meta[$name]);
1✔
90
                        }
91
                } else {
92
                        unset($_SESSION['__NF']['DATA'][$this->name], $_SESSION['__NF']['META'][$this->name]);
1✔
93
                }
94
        }
1✔
95

96

97
        /**
98
         * Sets a variable in this session section.
99
         * @deprecated  use set() instead
100
         */
101
        public function __set(string $name, mixed $value): void
102
        {
103
                $this->session->autoStart(forWrite: true);
×
UNCOV
104
                $this->getData()[$name] = $value;
×
105
        }
106

107

108
        /**
109
         * Gets a variable from this session section.
110
         * @deprecated  use get() instead
111
         */
112
        public function &__get(string $name): mixed
113
        {
114
                $this->session->autoStart(forWrite: true);
×
115
                $data = &$this->getData();
×
116
                $data ??= [];
×
117
                if ($this->warnOnUndefined && !array_key_exists($name, $data)) {
×
UNCOV
118
                        trigger_error("The variable '$name' does not exist in session section");
×
119
                }
120

UNCOV
121
                return $data[$name];
×
122
        }
123

124

125
        /**
126
         * Determines whether a variable in this session section is set.
127
         * @deprecated  use get() instead
128
         */
129
        public function __isset(string $name): bool
130
        {
131
                $this->session->autoStart(forWrite: false);
×
UNCOV
132
                return isset($this->getData()[$name]);
×
133
        }
134

135

136
        /**
137
         * Unsets a variable in this session section.
138
         * @deprecated  use remove() instead
139
         */
140
        public function __unset(string $name): void
141
        {
UNCOV
142
                $this->remove($name);
×
143
        }
144

145

146
        /**
147
         * Sets a variable in this session section.
148
         * @deprecated  use set() instead
149
         */
150
        public function offsetSet($name, $value): void
151
        {
152
                assert(is_string($name));
UNCOV
153
                $this->__set($name, $value);
×
154
        }
155

156

157
        /**
158
         * Gets a variable from this session section.
159
         * @deprecated  use get() instead
160
         */
161
        public function offsetGet($name): mixed
162
        {
UNCOV
163
                return $this->get($name);
×
164
        }
165

166

167
        /**
168
         * Determines whether a variable in this session section is set.
169
         * @deprecated  use get() instead
170
         */
171
        public function offsetExists($name): bool
172
        {
UNCOV
173
                return $this->__isset($name);
×
174
        }
175

176

177
        /**
178
         * Unsets a variable in this session section.
179
         * @deprecated  use remove() instead
180
         */
181
        public function offsetUnset($name): void
182
        {
UNCOV
183
                $this->remove($name);
×
184
        }
185

186

187
        /**
188
         * Sets the expiration time for the whole section or for specific variables.
189
         * Pass null to clear the expiration.
190
         * @param  string|string[]|null  $variables  variable name(s) to apply the expiration to; null applies to the whole section
191
         */
192
        public function setExpiration(?string $expire, string|array|null $variables = null): static
1✔
193
        {
194
                $seconds = Helpers::expirationToSeconds($expire);
1✔
195
                $this->session->autoStart($seconds !== null);
1✔
196
                $meta = &$this->getMeta();
1✔
197
                if ($seconds !== null) {
1✔
198
                        $max = (int) ini_get('session.gc_maxlifetime');
1✔
199
                        if (
200
                                $max !== 0 // 0 - unlimited in memcache handler
1✔
201
                                && ($seconds > $max + 3) // 3 - bulgarian constant
1✔
202
                        ) {
203
                                trigger_error("The expiration time is greater than the session expiration $max seconds");
1✔
204
                        }
205
                }
206

207
                $time = $seconds === null ? null : time() + $seconds;
1✔
208
                foreach (is_array($variables) ? $variables : [$variables] as $variable) {
1✔
209
                        $meta[$variable ?? '']['T'] = $time;
1✔
210
                }
211

212
                return $this;
1✔
213
        }
214

215

216
        /**
217
         * Removes the expiration from the whole section or from specific variables.
218
         * @param  string|string[]|null  $variables  variable name(s) to clear expiration for; null applies to the whole section
219
         */
220
        public function removeExpiration(string|array|null $variables = null): void
1✔
221
        {
222
                $this->setExpiration(null, $variables);
1✔
223
        }
1✔
224

225

226
        /** @return ?array<string, mixed> */
227
        private function &getData(): ?array
228
        {
229
                return $_SESSION['__NF']['DATA'][$this->name];
1✔
230
        }
231

232

233
        /** @return ?array<string, array{T?: ?int}> */
234
        private function &getMeta(): ?array
235
        {
236
                return $_SESSION['__NF']['META'][$this->name];
1✔
237
        }
238
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc