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; 22*4d7dd147SGreg Roachuse function array_map; 23*4d7dd147SGreg Roachuse function explode; 24*4d7dd147SGreg Roachuse function implode; 25*4d7dd147SGreg Roachuse function parse_url; 26*4d7dd147SGreg Roachuse function session_name; 27*4d7dd147SGreg Roachuse function session_regenerate_id; 28*4d7dd147SGreg Roachuse function session_register_shutdown; 29*4d7dd147SGreg Roachuse function session_set_cookie_params; 30*4d7dd147SGreg Roachuse function session_set_save_handler; 31*4d7dd147SGreg Roachuse function session_start; 32fe3a9054SGreg Roachuse function session_status; 33*4d7dd147SGreg Roachuse const PHP_URL_HOST; 34*4d7dd147SGreg Roachuse const PHP_URL_PATH; 35*4d7dd147SGreg 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 * 45*4d7dd147SGreg Roach * @param ServerRequestInterface $request 46*4d7dd147SGreg Roach * 47c7ff4153SGreg Roach * @return void 4831bc7874SGreg Roach */ 49*4d7dd147SGreg Roach public static function start(ServerRequestInterface $request): void 50c1010edaSGreg Roach { 51*4d7dd147SGreg Roach // Store sessions in the database 52*4d7dd147SGreg Roach session_set_save_handler(new SessionDatabaseHandler($request)); 53*4d7dd147SGreg Roach 54*4d7dd147SGreg Roach $url = (string) $request->getUri(); 55*4d7dd147SGreg Roach $secure = parse_url($url, PHP_URL_SCHEME) === 'https'; 56*4d7dd147SGreg Roach $domain = parse_url($url, PHP_URL_HOST); 57*4d7dd147SGreg Roach $path = parse_url($url, PHP_URL_PATH); 5808df3d18SGreg Roach 5908df3d18SGreg Roach // Paths containing UTF-8 characters need special handling. 6008df3d18SGreg Roach $path = implode('/', array_map('rawurlencode', explode('/', $path))); 6108df3d18SGreg Roach 6208df3d18SGreg Roach session_name('WT_SESSION'); 6331bc7874SGreg Roach session_register_shutdown(); 64*4d7dd147SGreg Roach session_set_cookie_params(0, $path, $domain, $secure, true); 6531bc7874SGreg Roach session_start(); 6608df3d18SGreg Roach 6708df3d18SGreg Roach // A new session? Prevent session fixation attacks by choosing a new session ID. 6808df3d18SGreg Roach if (!self::get('initiated')) { 6908df3d18SGreg Roach self::regenerate(true); 7008df3d18SGreg Roach self::put('initiated', true); 7108df3d18SGreg Roach } 7231bc7874SGreg Roach } 7331bc7874SGreg Roach 7431bc7874SGreg Roach /** 756ccdf4f0SGreg Roach * Read a value from the session 7657514a4fSGreg Roach * 776ccdf4f0SGreg Roach * @param string $name 786ccdf4f0SGreg Roach * @param mixed $default 796ccdf4f0SGreg Roach * 806ccdf4f0SGreg Roach * @return mixed 8157514a4fSGreg Roach */ 826ccdf4f0SGreg Roach public static function get(string $name, $default = null) 83c1010edaSGreg Roach { 846ccdf4f0SGreg Roach return $_SESSION[$name] ?? $default; 8557514a4fSGreg Roach } 8657514a4fSGreg Roach 8757514a4fSGreg Roach /** 886ccdf4f0SGreg Roach * After any change in authentication level, we should use a new session ID. 8957514a4fSGreg Roach * 906ccdf4f0SGreg Roach * @param bool $destroy 9157514a4fSGreg Roach * 926ccdf4f0SGreg Roach * @return void 9357514a4fSGreg Roach */ 946ccdf4f0SGreg Roach public static function regenerate(bool $destroy = false): void 95c1010edaSGreg Roach { 966ccdf4f0SGreg Roach if ($destroy) { 976ccdf4f0SGreg Roach self::clear(); 986ccdf4f0SGreg Roach } 996ccdf4f0SGreg Roach 1006ccdf4f0SGreg Roach if (session_status() === PHP_SESSION_ACTIVE) { 1016ccdf4f0SGreg Roach session_regenerate_id($destroy); 1026ccdf4f0SGreg Roach } 10357514a4fSGreg Roach } 10457514a4fSGreg Roach 10557514a4fSGreg Roach /** 1066ccdf4f0SGreg Roach * Remove all stored data from the session. 1076ccdf4f0SGreg Roach * 1086ccdf4f0SGreg Roach * @return void 1096ccdf4f0SGreg Roach */ 1106ccdf4f0SGreg Roach public static function clear(): void 1116ccdf4f0SGreg Roach { 1126ccdf4f0SGreg Roach $_SESSION = []; 1136ccdf4f0SGreg Roach } 1146ccdf4f0SGreg Roach 1156ccdf4f0SGreg Roach /** 1166ccdf4f0SGreg Roach * Write a value to the session 1176ccdf4f0SGreg Roach * 1186ccdf4f0SGreg Roach * @param string $name 1196ccdf4f0SGreg Roach * @param mixed $value 1206ccdf4f0SGreg Roach * 1216ccdf4f0SGreg Roach * @return void 1226ccdf4f0SGreg Roach */ 1236ccdf4f0SGreg Roach public static function put(string $name, $value): void 1246ccdf4f0SGreg Roach { 1256ccdf4f0SGreg Roach $_SESSION[$name] = $value; 1266ccdf4f0SGreg Roach } 1276ccdf4f0SGreg Roach 1286ccdf4f0SGreg Roach /** 1296ccdf4f0SGreg Roach * Remove a value from the session 1306ccdf4f0SGreg Roach * 1316ccdf4f0SGreg Roach * @param string $name 1326ccdf4f0SGreg Roach * 1336ccdf4f0SGreg Roach * @return void 1346ccdf4f0SGreg Roach */ 1356ccdf4f0SGreg Roach public static function forget(string $name): void 1366ccdf4f0SGreg Roach { 1376ccdf4f0SGreg Roach unset($_SESSION[$name]); 1386ccdf4f0SGreg Roach } 1396ccdf4f0SGreg Roach 1406ccdf4f0SGreg Roach /** 141a45f9889SGreg Roach * Cross-Site Request Forgery tokens - ensure that the user is submitting 142a45f9889SGreg Roach * a form that was generated by the current session. 143a45f9889SGreg Roach * 144a45f9889SGreg Roach * @return string 145a45f9889SGreg Roach */ 1468f53f488SRico Sonntag public static function getCsrfToken(): string 147a45f9889SGreg Roach { 148e364afe4SGreg Roach if (!self::has('CSRF_TOKEN')) { 149e364afe4SGreg Roach self::put('CSRF_TOKEN', Str::random(32)); 150a45f9889SGreg Roach } 151a45f9889SGreg Roach 152e364afe4SGreg Roach return self::get('CSRF_TOKEN'); 153a45f9889SGreg Roach } 1546ccdf4f0SGreg Roach 1556ccdf4f0SGreg Roach /** 1566ccdf4f0SGreg Roach * Does a session variable exist? 1576ccdf4f0SGreg Roach * 1586ccdf4f0SGreg Roach * @param string $name 1596ccdf4f0SGreg Roach * 1606ccdf4f0SGreg Roach * @return bool 1616ccdf4f0SGreg Roach */ 1626ccdf4f0SGreg Roach public static function has(string $name): bool 1636ccdf4f0SGreg Roach { 1646ccdf4f0SGreg Roach return isset($_SESSION[$name]); 1656ccdf4f0SGreg Roach } 16631bc7874SGreg Roach} 167