Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.69% covered (success)
87.69%
57 / 65
87.50% covered (success)
87.50%
14 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
SessionNamespace
87.69% covered (success)
87.69%
57 / 65
87.50% covered (success)
87.50%
14 / 16
35.03
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 setNamespace
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getNamespace
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTimedValue
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 setRequestValue
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 init
57.14% covered (warning)
57.14%
8 / 14
0.00% covered (danger)
0.00%
0 / 1
5.26
 kill
75.00% covered (success)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
5.39
 checkRequest
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 checkRequests
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 checkExpiration
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 checkExpirations
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 toArray
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 __set
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 __isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __unset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Session;
15
16/**
17 * Session namespace class
18 *
19 * @category   Pop
20 * @package    Pop\Session
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    4.0.0
25 */
26class SessionNamespace extends AbstractSession
27{
28
29    /**
30     * Session namespace
31     * @var ?string
32     */
33    private ?string $namespace = null;
34
35    /**
36     * Constructor
37     *
38     * Private method to instantiate the session object
39     *
40     * @param  string $namespace
41     * @throws Exception
42     */
43    public function __construct(string $namespace)
44    {
45        if ($namespace == '_POP_SESSION_') {
46            throw new Exception("Error: Cannot use the reserved namespace '_POP_SESSION_'.");
47        }
48        $this->setNamespace($namespace);
49        $sess = Session::getInstance();
50        if (!isset($sess[$namespace])) {
51            $sess[$namespace] = [];
52        }
53        $this->init();
54    }
55
56    /**
57     * Set current namespace
58     *
59     * @param  string $namespace
60     * @return SessionNamespace
61     */
62    public function setNamespace(string $namespace): SessionNamespace
63    {
64        $this->namespace = $namespace;
65        return $this;
66    }
67
68    /**
69     * Get current namespace
70     *
71     * @return string
72     */
73    public function getNamespace(): string
74    {
75        return $this->namespace;
76    }
77
78    /**
79     * Set a time-based value
80     *
81     * @param  string $key
82     * @param  mixed  $value
83     * @param  int    $expire
84     * @return SessionNamespace
85     */
86    public function setTimedValue(string $key, mixed $value, int $expire = 300): SessionNamespace
87    {
88        $_SESSION[$this->namespace][$key] = $value;
89        $_SESSION['_POP_SESSION_'][$this->namespace]['expirations'][$key] = time() + (int)$expire;
90        return $this;
91    }
92
93    /**
94     * Set a request-based value
95     *
96     * @param  string $key
97     * @param  mixed  $value
98     * @param  int    $hops
99     * @return SessionNamespace
100     */
101    public function setRequestValue(string $key, mixed $value, int $hops = 1): SessionNamespace
102    {
103        $_SESSION[$this->namespace][$key] = $value;
104        $_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key] = [
105            'current' => 0,
106            'limit'   => (int)$hops
107        ];
108        return $this;
109    }
110
111    /**
112     * Init the session
113     *
114     * @return void
115     */
116    private function init(): void
117    {
118        if (!isset($_SESSION['_POP_SESSION_'])) {
119            $_SESSION['_POP_SESSION_'] = [
120                $this->namespace => [
121                    'requests'    => [],
122                    'expirations' => []
123                ]
124            ];
125        } else if (isset($_SESSION['_POP_SESSION_']) && !isset($_SESSION['_POP_SESSION_'][$this->namespace])) {
126            $_SESSION['_POP_SESSION_'][$this->namespace] = [
127                'requests'    => [],
128                'expirations' => []
129            ];
130        } else {
131            $this->checkRequests();
132            $this->checkExpirations();
133        }
134    }
135
136    /**
137     * Kill the session namespace
138     *
139     * @param  bool $all
140     * @return void
141     */
142    public function kill(bool $all = false): void
143    {
144        if ($all) {
145            $sess = Session::getInstance();
146            $sess->kill();
147        } else if (isset($_SESSION[$this->namespace])) {
148            if (isset($_SESSION['_POP_SESSION_'][$this->namespace])) {
149                unset($_SESSION['_POP_SESSION_'][$this->namespace]);
150            }
151            if (isset($_SESSION[$this->namespace])) {
152                unset($_SESSION[$this->namespace]);
153            }
154        }
155    }
156
157    /**
158     * Check the request-based session value
159     *
160     * @return void
161     */
162    private function checkRequest($key): void
163    {
164        if (isset($_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key])) {
165            $_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key]['current']++;
166            $current = $_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key]['current'];
167            $limit   = $_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key]['limit'];
168            if ($current > $limit) {
169                unset($_SESSION[$this->namespace][$key]);
170                unset($_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key]);
171            }
172        }
173    }
174
175    /**
176     * Check the request-based session values
177     *
178     * @return void
179     */
180    private function checkRequests(): void
181    {
182        foreach ($_SESSION[$this->namespace] as $key => $value) {
183            $this->checkRequest($key);
184        }
185    }
186
187    /**
188     * Check the time-based session value
189     *
190     * @return void
191     */
192    private function checkExpiration($key): void
193    {
194        if (isset($_SESSION['_POP_SESSION_'][$this->namespace]['expirations'][$key]) &&
195            (time() > $_SESSION['_POP_SESSION_'][$this->namespace]['expirations'][$key])) {
196            unset($_SESSION[$this->namespace][$key]);
197            unset($_SESSION['_POP_SESSION_'][$this->namespace]['expirations'][$key]);
198        }
199    }
200
201    /**
202     * Check the time-based session values
203     *
204     * @return void
205     */
206    private function checkExpirations(): void
207    {
208        foreach ($_SESSION[$this->namespace] as $key => $value) {
209            $this->checkExpiration($key);
210        }
211    }
212
213    /**
214     * Get the session values as an array
215     *
216     * @return array
217     */
218    public function toArray(): array
219    {
220        $session = $_SESSION;
221
222        if (isset($session['_POP_SESSION_'])) {
223            unset($session['_POP_SESSION_']);
224        }
225
226        return $session[$this->namespace] ?? [];
227    }
228
229    /**
230     * Set a property in the session object that is linked to the $_SESSION global variable
231     *
232     * @param  string $name
233     * @param  mixed $value
234     * @return void
235     */
236    public function __set(string $name, mixed $value): void
237    {
238        $_SESSION[$this->namespace][$name] = $value;
239    }
240
241    /**
242     * Get method to return the value of the $_SESSION global variable
243     *
244     * @param  string $name
245     * @return mixed
246     */
247    public function __get(string $name): mixed
248    {
249        return (isset($_SESSION[$this->namespace][$name])) ? $_SESSION[$this->namespace][$name] : null;
250    }
251
252    /**
253     * Return the isset value of the $_SESSION global variable
254     *
255     * @param  string $name
256     * @return bool
257     */
258    public function __isset(string $name): bool
259    {
260        return isset($_SESSION[$this->namespace][$name]);
261    }
262
263    /**
264     * Unset the $_SESSION global variable
265     *
266     * @param  string $name
267     * @return void
268     */
269    public function __unset(string $name): void
270    {
271        $_SESSION[$this->namespace][$name] = null;
272        unset($_SESSION[$this->namespace][$name]);
273    }
274
275}