Completed
Push — b0.27.0 ( c529b3...34cc26 )
by Sebastian
05:07
created

Session   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 8
Bugs 4 Features 0
Metric Value
wmc 11
eloc 65
c 8
b 4
f 0
dl 0
loc 232
ccs 67
cts 67
cp 1
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A regenerate() 0 7 1
A refresh() 0 37 3
A commit() 0 6 1
A destroy() 0 14 1
A setSessionData() 0 7 1
A __construct() 0 19 1
A setSessionHandler() 0 4 1
A start() 0 23 2
1
<?php
2
3
/**
4
 * Linna Framework.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Session;
13
14
use ArrayAccess;
15
use SessionHandlerInterface;
16
17
/**
18
 * Manage session lifetime and session data.
19
 *
20
 * @property int   $time      Time of session
21
 * @property array $login     Login information set by Login class
22
 * @property int   $loginTime Login time set by Login class
23
 * @property int   $expire    Login time set for Login class
24
 */
25
class Session implements ArrayAccess
26
{
27
    use PropertyAccessTrait;
28
    use ArrayAccessTrait;
29
30
    /**
31
     * @var int Session expire time in seconds.
32
     */
33
    private int $expire = 1800;
34
35
    /**
36
     * @var string Cookie domain.
37
     */
38
    private string $cookieDomain = '/';
39
40
    /**
41
     * @var string Coockie path.
42
     */
43
    private string $cookiePath = '/';
44
45
    /**
46
     * @var bool Cookie transmitted over https only?.
47
     */
48
    private bool $cookieSecure = false;
49
50
    /**
51
     * @var bool Cookie accessible only through http?.
52
     */
53
    private bool $cookieHttpOnly = true;
54
55
    /**
56
     *
57
     * @var string Cookie same site for cross site requests.
58
     */
59
    private string $cookieSameSite = 'lax';
60
61
    /**
62
     * @var array<mixed> Session data reference property
63
     */
64
    private array $data = [];
65
66
    /**
67
     * @var string Session id
68
     */
69
    public string $id = '';
70
71
    /**
72
     * @var string Session name
73
     */
74
    public string $name = 'linna_session';
75
76
    /**
77
     * @var int session_status function result
78
     */
79
    public int $status = 0;
80
81
    /**
82
     * Constructor.
83
     *
84
     * @param array<mixed> $options
85
     */
86 49
    public function __construct(array $options = [])
87
    {
88
        [
89 49
            'expire'         => $this->expire,
90 49
            'name'           => $this->name,
91 49
            'cookieDomain'   => $this->cookieDomain,
92 49
            'cookiePath'     => $this->cookiePath,
93 49
            'cookieSecure'   => $this->cookieSecure,
94 49
            'cookieHttpOnly' => $this->cookieHttpOnly
95 49
        ] = \array_replace_recursive([
96 49
            'expire'         => $this->expire,
97 49
            'name'           => $this->name,
98 49
            'cookieDomain'   => $this->cookieDomain,
99 49
            'cookiePath'     => $this->cookiePath,
100 49
            'cookieSecure'   => $this->cookieSecure,
101 49
            'cookieHttpOnly' => $this->cookieHttpOnly
102 49
        ], $options);
103
104 49
        $this->status = \session_status();
105 49
    }
106
107
    /**
108
     * Regenerate session_id without double cookie problem.
109
     *
110
     * @return void
111
     */
112 22
    public function regenerate(): void
113
    {
114
        //regenerate session id
115 22
        \session_regenerate_id();
116
117
        //store new session data
118 22
        $this->setSessionData(\time());
119 22
    }
120
121
    /**
122
     * Start session.
123
     *
124
     * @return void
125
     */
126 38
    public function start(): void
127
    {
128 38
        if (\session_status() !== PHP_SESSION_ACTIVE) {
129
130
            //prepare the session start
131 38
            \session_name($this->name);
132
133
            //start session
134 38
            \session_start([
135 38
                'cookie_path'      => $this->cookiePath,
136 38
                'cookie_domain'    => $this->cookieDomain,
137 38
                'cookie_lifetime'  => $this->expire,//($this->expire > 0) ? time() + $this->expire : 0,
138 38
                'cookie_secure'    => $this->cookieSecure,
139 38
                'cookie_httponly'  => $this->cookieHttpOnly,
140 38
                'cookie_samesite'  => $this->cookieSameSite
141
            ]);
142
143
            //link session super global to $data property
144 38
            $this->data = &$_SESSION;
145
        }
146
147
        //refresh session
148 38
        $this->refresh();
149 38
    }
150
151
    /**
152
     * Refresh session.
153
     *
154
     * @return void
155
     */
156 38
    private function refresh(): void
157
    {
158 38
        $time = \time();
159
160 38
        if (isset($this->data['time']) && $this->data['time'] <= ($time - $this->expire)) {
161
162
            //delete session data
163 6
            $this->data = [];
164
165
            //regenerate session
166 6
            $this->regenerate();
167
        }
168
169 38
        $this->setSessionData($time);
170
171
        //it fix the behavior of session that die because it does not refresh
172
        //expiration time, also if present user interaction, with browser.
173
174
        //PHP 7.2 version
175
        /*\setcookie($this->name, $this->id,
176
            $this->expire, //($this->expire > 0) ? time() + $this->expire : 0, //expire
177
            //($time + $this->expire),    //expire
178
            $this->cookiePath,          //path
179
            $this->cookieDomain,        //domain
180
            $this->cookieSecure,        //secure
181
            $this->cookieHttpOnly       //http only
182
        );*/
183
184
        //PHP 7.3 version
185
        //https://www.php.net/manual/en/migration73.other-changes.php
186 38
        \setcookie($this->name, $this->id, [
0 ignored issues
show
Bug introduced by
array('path' => $this->c... $this->cookieSameSite) of type array<string,boolean|integer|string> is incompatible with the type integer expected by parameter $expire of setcookie(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

186
        \setcookie($this->name, $this->id, /** @scrutinizer ignore-type */ [
Loading history...
187 38
            'path'      => $this->cookiePath,
188 38
            'domain'    => $this->cookieDomain,
189 38
            'expires'   => $time + $this->expire,
190 38
            'secure'    => $this->cookieSecure,
191 38
            'httponly'  => $this->cookieHttpOnly,
192 38
            'samesite'  => $this->cookieSameSite
193
        ]);
194 38
    }
195
196
    /**
197
     * Set Session Data.
198
     *
199
     * @param int $time
200
     *
201
     * @return void
202
     */
203 38
    private function setSessionData(int $time): void
204
    {
205 38
        $this->id = \session_id();
206 38
        $this->data['time'] = $time;
207 38
        $this->data['expire'] = $this->expire;
208
        //$this->data['server'] = $_SERVER;
209 38
        $this->status = \session_status();
210 38
    }
211
212
    /**
213
     * Set session handler for new instance.
214
     *
215
     * @param SessionHandlerInterface $handler
216
     *
217
     * @return void
218
     */
219 21
    public function setSessionHandler(SessionHandlerInterface $handler): void
220
    {
221
        //setting a different save handler if passed
222 21
        \session_set_save_handler($handler, true);
223 21
    }
224
225
    /**
226
     * Destroy session.
227
     *
228
     * @return void
229
     */
230 37
    public function destroy(): void
231
    {
232
        //delete session data
233 37
        $this->data = [];
234 37
        $this->id = '';
235
236
        //destroy cookie
237 37
        \setcookie($this->name, 'NothingToSeeHere.', \time());
238
239
        //call session destroy
240 37
        \session_destroy();
241
242
        //update status
243 37
        $this->status = \session_status();
244 37
    }
245
246
    /**
247
     * Write session data and end session.
248
     *
249
     * @return void
250
     */
251 16
    public function commit(): void
252
    {
253 16
        \session_write_close();
254
255
        //update status
256 16
        $this->status = \session_status();
257 16
    }
258
}
259