xref: /webtrees/app/Session.php (revision e6a4376904b85e5b2599c55477c1403313efa232)
131bc7874SGreg Roach<?php
231bc7874SGreg Roach/**
331bc7874SGreg Roach * webtrees: online genealogy
48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team
531bc7874SGreg Roach * This program is free software: you can redistribute it and/or modify
631bc7874SGreg Roach * it under the terms of the GNU General Public License as published by
731bc7874SGreg Roach * the Free Software Foundation, either version 3 of the License, or
831bc7874SGreg Roach * (at your option) any later version.
931bc7874SGreg Roach * This program is distributed in the hope that it will be useful,
1031bc7874SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
1131bc7874SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1231bc7874SGreg Roach * GNU General Public License for more details.
1331bc7874SGreg Roach * You should have received a copy of the GNU General Public License
1431bc7874SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
1531bc7874SGreg Roach */
16e7f56f2aSGreg Roachdeclare(strict_types=1);
17e7f56f2aSGreg Roach
1876692c8bSGreg Roachnamespace Fisharebest\Webtrees;
1931bc7874SGreg Roach
20deb4b685SGreg Roachuse Illuminate\Support\Str;
216ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
224d7dd147SGreg Roachuse function array_map;
234d7dd147SGreg Roachuse function explode;
244d7dd147SGreg Roachuse function implode;
254d7dd147SGreg Roachuse function parse_url;
264d7dd147SGreg Roachuse function session_name;
274d7dd147SGreg Roachuse function session_regenerate_id;
284d7dd147SGreg Roachuse function session_register_shutdown;
294d7dd147SGreg Roachuse function session_set_cookie_params;
304d7dd147SGreg Roachuse function session_set_save_handler;
314d7dd147SGreg Roachuse function session_start;
32fe3a9054SGreg Roachuse function session_status;
334d7dd147SGreg Roachuse const PHP_URL_HOST;
344d7dd147SGreg Roachuse const PHP_URL_PATH;
354d7dd147SGreg Roachuse const PHP_URL_SCHEME;
364c891c40SGreg Roach
3731bc7874SGreg Roach/**
3842af74e7SGreg Roach * Session handling
3931bc7874SGreg Roach */
40c1010edaSGreg Roachclass Session
41c1010edaSGreg Roach{
4231bc7874SGreg Roach    /**
4331bc7874SGreg Roach     * Start a session
44c7ff4153SGreg Roach     *
454d7dd147SGreg Roach     * @param ServerRequestInterface $request
464d7dd147SGreg Roach     *
47c7ff4153SGreg Roach     * @return void
4831bc7874SGreg Roach     */
494d7dd147SGreg Roach    public static function start(ServerRequestInterface $request): void
50c1010edaSGreg Roach    {
514d7dd147SGreg Roach        // Store sessions in the database
524d7dd147SGreg Roach        session_set_save_handler(new SessionDatabaseHandler($request));
534d7dd147SGreg Roach
54add3fa41SGreg Roach        $url    = $request->getAttribute('request_uri');
554d7dd147SGreg Roach        $secure = parse_url($url, PHP_URL_SCHEME) === 'https';
564d7dd147SGreg Roach        $domain = parse_url($url, PHP_URL_HOST);
574d7dd147SGreg Roach        $path   = parse_url($url, PHP_URL_PATH);
58*e6a43769SGreg Roach        $path   = explode('index.php', $path)[0];
5908df3d18SGreg Roach
6008df3d18SGreg Roach        // Paths containing UTF-8 characters need special handling.
6108df3d18SGreg Roach        $path = implode('/', array_map('rawurlencode', explode('/', $path)));
6208df3d18SGreg Roach
6308df3d18SGreg Roach        session_name('WT_SESSION');
6431bc7874SGreg Roach        session_register_shutdown();
654d7dd147SGreg Roach        session_set_cookie_params(0, $path, $domain, $secure, true);
6631bc7874SGreg Roach        session_start();
6708df3d18SGreg Roach
6808df3d18SGreg Roach        // A new session? Prevent session fixation attacks by choosing a new session ID.
6908df3d18SGreg Roach        if (!self::get('initiated')) {
7008df3d18SGreg Roach            self::regenerate(true);
7108df3d18SGreg Roach            self::put('initiated', true);
7208df3d18SGreg Roach        }
7331bc7874SGreg Roach    }
7431bc7874SGreg Roach
7531bc7874SGreg Roach    /**
766ccdf4f0SGreg Roach     * Read a value from the session
7757514a4fSGreg Roach     *
786ccdf4f0SGreg Roach     * @param string $name
796ccdf4f0SGreg Roach     * @param mixed  $default
806ccdf4f0SGreg Roach     *
816ccdf4f0SGreg Roach     * @return mixed
8257514a4fSGreg Roach     */
836ccdf4f0SGreg Roach    public static function get(string $name, $default = null)
84c1010edaSGreg Roach    {
856ccdf4f0SGreg Roach        return $_SESSION[$name] ?? $default;
8657514a4fSGreg Roach    }
8757514a4fSGreg Roach
8857514a4fSGreg Roach    /**
896ccdf4f0SGreg Roach     * After any change in authentication level, we should use a new session ID.
9057514a4fSGreg Roach     *
916ccdf4f0SGreg Roach     * @param bool $destroy
9257514a4fSGreg Roach     *
936ccdf4f0SGreg Roach     * @return void
9457514a4fSGreg Roach     */
956ccdf4f0SGreg Roach    public static function regenerate(bool $destroy = false): void
96c1010edaSGreg Roach    {
976ccdf4f0SGreg Roach        if ($destroy) {
986ccdf4f0SGreg Roach            self::clear();
996ccdf4f0SGreg Roach        }
1006ccdf4f0SGreg Roach
1016ccdf4f0SGreg Roach        if (session_status() === PHP_SESSION_ACTIVE) {
1026ccdf4f0SGreg Roach            session_regenerate_id($destroy);
1036ccdf4f0SGreg Roach        }
10457514a4fSGreg Roach    }
10557514a4fSGreg Roach
10657514a4fSGreg Roach    /**
1076ccdf4f0SGreg Roach     * Remove all stored data from the session.
1086ccdf4f0SGreg Roach     *
1096ccdf4f0SGreg Roach     * @return void
1106ccdf4f0SGreg Roach     */
1116ccdf4f0SGreg Roach    public static function clear(): void
1126ccdf4f0SGreg Roach    {
1136ccdf4f0SGreg Roach        $_SESSION = [];
1146ccdf4f0SGreg Roach    }
1156ccdf4f0SGreg Roach
1166ccdf4f0SGreg Roach    /**
1176ccdf4f0SGreg Roach     * Write a value to the session
1186ccdf4f0SGreg Roach     *
1196ccdf4f0SGreg Roach     * @param string $name
1206ccdf4f0SGreg Roach     * @param mixed  $value
1216ccdf4f0SGreg Roach     *
1226ccdf4f0SGreg Roach     * @return void
1236ccdf4f0SGreg Roach     */
1246ccdf4f0SGreg Roach    public static function put(string $name, $value): void
1256ccdf4f0SGreg Roach    {
1266ccdf4f0SGreg Roach        $_SESSION[$name] = $value;
1276ccdf4f0SGreg Roach    }
1286ccdf4f0SGreg Roach
1296ccdf4f0SGreg Roach    /**
1306ccdf4f0SGreg Roach     * Remove a value from the session
1316ccdf4f0SGreg Roach     *
1326ccdf4f0SGreg Roach     * @param string $name
1336ccdf4f0SGreg Roach     *
1346ccdf4f0SGreg Roach     * @return void
1356ccdf4f0SGreg Roach     */
1366ccdf4f0SGreg Roach    public static function forget(string $name): void
1376ccdf4f0SGreg Roach    {
1386ccdf4f0SGreg Roach        unset($_SESSION[$name]);
1396ccdf4f0SGreg Roach    }
1406ccdf4f0SGreg Roach
1416ccdf4f0SGreg Roach    /**
142a45f9889SGreg Roach     * Cross-Site Request Forgery tokens - ensure that the user is submitting
143a45f9889SGreg Roach     * a form that was generated by the current session.
144a45f9889SGreg Roach     *
145a45f9889SGreg Roach     * @return string
146a45f9889SGreg Roach     */
1478f53f488SRico Sonntag    public static function getCsrfToken(): string
148a45f9889SGreg Roach    {
149e364afe4SGreg Roach        if (!self::has('CSRF_TOKEN')) {
150e364afe4SGreg Roach            self::put('CSRF_TOKEN', Str::random(32));
151a45f9889SGreg Roach        }
152a45f9889SGreg Roach
153e364afe4SGreg Roach        return self::get('CSRF_TOKEN');
154a45f9889SGreg Roach    }
1556ccdf4f0SGreg Roach
1566ccdf4f0SGreg Roach    /**
1576ccdf4f0SGreg Roach     * Does a session variable exist?
1586ccdf4f0SGreg Roach     *
1596ccdf4f0SGreg Roach     * @param string $name
1606ccdf4f0SGreg Roach     *
1616ccdf4f0SGreg Roach     * @return bool
1626ccdf4f0SGreg Roach     */
1636ccdf4f0SGreg Roach    public static function has(string $name): bool
1646ccdf4f0SGreg Roach    {
1656ccdf4f0SGreg Roach        return isset($_SESSION[$name]);
1666ccdf4f0SGreg Roach    }
16731bc7874SGreg Roach}
168