Passed
Push — master ( d44668...8246ff )
by Greg
05:07
created

Session::pull()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 6
rs 10
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use Illuminate\Support\Str;
23
use Psr\Http\Message\ServerRequestInterface;
24
25
use function array_map;
26
use function explode;
27
use function implode;
28
use function parse_url;
29
use function session_name;
30
use function session_regenerate_id;
31
use function session_register_shutdown;
32
use function session_set_cookie_params;
33
use function session_set_save_handler;
34
use function session_start;
35
use function session_status;
36
37
use const PHP_URL_HOST;
38
use const PHP_URL_PATH;
39
use const PHP_URL_SCHEME;
40
41
/**
42
 * Session handling
43
 */
44
class Session
45
{
46
    private const SESSION_NAME = 'WT2_SESSION';
47
    /**
48
     * Start a session
49
     *
50
     * @param ServerRequestInterface $request
51
     *
52
     * @return void
53
     */
54
    public static function start(ServerRequestInterface $request): void
55
    {
56
        // Store sessions in the database
57
        session_set_save_handler(new SessionDatabaseHandler($request));
58
59
        $url    = $request->getAttribute('base_url');
60
        $secure = parse_url($url, PHP_URL_SCHEME) === 'https';
61
        $domain = parse_url($url, PHP_URL_HOST);
62
        $path   = parse_url($url, PHP_URL_PATH) ?? '';
63
64
        // Paths containing UTF-8 characters need special handling.
65
        $path = implode('/', array_map('rawurlencode', explode('/', $path)));
66
67
        session_name(self::SESSION_NAME);
68
        session_register_shutdown();
69
        session_set_cookie_params(0, $path . '/', $domain, $secure, true);
70
        session_start();
71
72
        // A new session? Prevent session fixation attacks by choosing a new session ID.
73
        if (self::get('initiated') !== true) {
74
            self::regenerate(true);
75
            self::put('initiated', true);
76
        }
77
    }
78
79
    /**
80
     * Read a value from the session
81
     *
82
     * @param string $name
83
     * @param mixed  $default
84
     *
85
     * @return mixed
86
     */
87
    public static function get(string $name, $default = null)
88
    {
89
        return $_SESSION[$name] ?? $default;
90
    }
91
92
    /**
93
     * Read a value from the session and remove it.
94
     *
95
     * @param string $name
96
     * @param mixed  $default
97
     *
98
     * @return mixed
99
     */
100
    public static function pull(string $name, $default = null)
101
    {
102
        $value = self::get($name, $default);
103
        self::forget($name);
104
105
        return $value;
106
    }
107
108
    /**
109
     * After any change in authentication level, we should use a new session ID.
110
     *
111
     * @param bool $destroy
112
     *
113
     * @return void
114
     */
115
    public static function regenerate(bool $destroy = false): void
116
    {
117
        if ($destroy) {
118
            self::clear();
119
        }
120
121
        if (session_status() === PHP_SESSION_ACTIVE) {
122
            session_regenerate_id($destroy);
123
        }
124
    }
125
126
    /**
127
     * Remove all stored data from the session.
128
     *
129
     * @return void
130
     */
131
    public static function clear(): void
132
    {
133
        $_SESSION = [];
134
    }
135
136
    /**
137
     * Write a value to the session
138
     *
139
     * @param string $name
140
     * @param mixed  $value
141
     *
142
     * @return void
143
     */
144
    public static function put(string $name, $value): void
145
    {
146
        $_SESSION[$name] = $value;
147
    }
148
149
    /**
150
     * Remove a value from the session
151
     *
152
     * @param string $name
153
     *
154
     * @return void
155
     */
156
    public static function forget(string $name): void
157
    {
158
        unset($_SESSION[$name]);
159
    }
160
161
    /**
162
     * Cross-Site Request Forgery tokens - ensure that the user is submitting
163
     * a form that was generated by the current session.
164
     *
165
     * @return string
166
     */
167
    public static function getCsrfToken(): string
168
    {
169
        if (!self::has('CSRF_TOKEN')) {
170
            self::put('CSRF_TOKEN', Str::random(32));
171
        }
172
173
        return self::get('CSRF_TOKEN');
174
    }
175
176
    /**
177
     * Does a session variable exist?
178
     *
179
     * @param string $name
180
     *
181
     * @return bool
182
     */
183
    public static function has(string $name): bool
184
    {
185
        return isset($_SESSION[$name]);
186
    }
187
}
188