update
This commit is contained in:
224
inc/Hura8/System/Security/Session.php
Normal file
224
inc/Hura8/System/Security/Session.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\System\Security;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* PHP-Cookie (https://github.com/delight-im/PHP-Cookie)
|
||||
* Copyright (c) delight.im (https://www.delight.im/)
|
||||
* Licensed under the MIT License (https://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Session management with improved cookie handling
|
||||
*
|
||||
* You can start a session using the static method `Session::start(...)` which is compatible to PHP's built-in `session_start()` function
|
||||
*
|
||||
* Note that sessions must always be started before the HTTP headers are sent to the client, i.e. before the actual output starts
|
||||
*/
|
||||
final class Session
|
||||
{
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or resumes a session in a way compatible to PHP's built-in `session_start()` function
|
||||
*
|
||||
* @param string|null $sameSiteRestriction indicates that the cookie should not be sent along with cross-site requests (either `null`, `None`, `Lax` or `Strict`)
|
||||
*/
|
||||
public static function start($sameSiteRestriction = Cookie::SAME_SITE_RESTRICTION_LAX)
|
||||
{
|
||||
// run PHP's built-in equivalent
|
||||
\session_start();
|
||||
|
||||
// intercept the cookie header (if any) and rewrite it
|
||||
self::rewriteCookieHeader($sameSiteRestriction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or sets the ID of the current session
|
||||
*
|
||||
* In order to change the current session ID, pass the new ID as the only argument to this method
|
||||
*
|
||||
* Please note that there is rarely a need for the version of this method that *updates* the ID
|
||||
*
|
||||
* For most purposes, you may find the method `regenerate` from this same class more helpful
|
||||
*
|
||||
* @param string|null $newId (optional) a new session ID to replace the current session ID
|
||||
* @return string the (old) session ID or an empty string
|
||||
*/
|
||||
public static function id($newId = null)
|
||||
{
|
||||
if ($newId === null) {
|
||||
return \session_id();
|
||||
} else {
|
||||
return \session_id($newId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-generates the session ID in a way compatible to PHP's built-in `session_regenerate_id()` function
|
||||
*
|
||||
* @param bool $deleteOldSession whether to delete the old session or not
|
||||
* @param string|null $sameSiteRestriction indicates that the cookie should not be sent along with cross-site requests (either `null`, `None`, `Lax` or `Strict`)
|
||||
*/
|
||||
public static function regenerate($deleteOldSession = false, $sameSiteRestriction = Cookie::SAME_SITE_RESTRICTION_LAX)
|
||||
{
|
||||
// run PHP's built-in equivalent
|
||||
\session_regenerate_id($deleteOldSession);
|
||||
|
||||
// intercept the cookie header (if any) and rewrite it
|
||||
self::rewriteCookieHeader($sameSiteRestriction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a value for the specified key exists in the session
|
||||
*
|
||||
* @param string $key the key to check
|
||||
* @return bool whether there is a value for the specified key or not
|
||||
*/
|
||||
public static function has($key)
|
||||
{
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested value from the session or, if not found, the specified default value
|
||||
*
|
||||
* @param string $key the key to retrieve the value for
|
||||
* @param mixed $defaultValue the default value to return if the requested value cannot be found
|
||||
* @return mixed the requested value or the default value
|
||||
*/
|
||||
public static function get($key, $defaultValue = null)
|
||||
{
|
||||
if(isset($_SESSION[$key])) {
|
||||
return $_SESSION[$key];
|
||||
} else {
|
||||
return $defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested value and removes it from the session
|
||||
*
|
||||
* This is identical to calling `get` first and then `remove` for the same key
|
||||
*
|
||||
* @param string $key the key to retrieve and remove the value for
|
||||
* @param mixed $defaultValue the default value to return if the requested value cannot be found
|
||||
* @return mixed the requested value or the default value
|
||||
*/
|
||||
public static function take($key, $defaultValue = null)
|
||||
{
|
||||
if (isset($_SESSION[$key])) {
|
||||
$value = $_SESSION[$key];
|
||||
|
||||
unset($_SESSION[$key]);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return $defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for the specified key to the given value
|
||||
*
|
||||
* Any data that already exists for the specified key will be overwritten
|
||||
*
|
||||
* @param string $key the key to set the value for
|
||||
* @param mixed $value the value to set
|
||||
*/
|
||||
public static function set($key, $value)
|
||||
{
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the value for the specified key from the session
|
||||
*
|
||||
* @param string $key the key to remove the value for
|
||||
*/
|
||||
public static function delete($key)
|
||||
{
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercepts and rewrites the session cookie header
|
||||
*
|
||||
* @param string|null $sameSiteRestriction indicates that the cookie should not be sent along with cross-site requests (either `null`, `None`, `Lax` or `Strict`)
|
||||
*/
|
||||
private static function rewriteCookieHeader($sameSiteRestriction = Cookie::SAME_SITE_RESTRICTION_LAX)
|
||||
{
|
||||
// get and remove the original cookie header set by PHP
|
||||
$originalCookieHeader = Session::takeHeaderCookie('Set-Cookie', \session_name() . '=');
|
||||
|
||||
// if a cookie header has been found
|
||||
if (isset($originalCookieHeader)) {
|
||||
// parse it into a cookie instance
|
||||
$parsedCookie = Cookie::parse($originalCookieHeader);
|
||||
|
||||
// if the cookie has successfully been parsed
|
||||
if (isset($parsedCookie)) {
|
||||
// apply the supplied same-site restriction
|
||||
$parsedCookie->setSameSiteRestriction($sameSiteRestriction);
|
||||
|
||||
if ($parsedCookie->getSameSiteRestriction() === Cookie::SAME_SITE_RESTRICTION_NONE && !$parsedCookie->isSecureOnly()) {
|
||||
\trigger_error('You may have to enable the \'session.cookie_secure\' directive in the configuration in \'php.ini\' or via the \'ini_set\' function', \E_USER_WARNING);
|
||||
}
|
||||
|
||||
// save the cookie
|
||||
$parsedCookie->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and removes the header with the specified name (and optional value prefix)
|
||||
*
|
||||
* @param string $name the name of the header
|
||||
* @param string $valuePrefix the optional string to match at the beginning of the header's value
|
||||
* @return string|null the header (if found) or `null`
|
||||
*/
|
||||
private static function takeHeaderCookie($name, $valuePrefix = '') {
|
||||
if (empty($name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$nameLength = \strlen($name);
|
||||
$headers = \headers_list();
|
||||
|
||||
$first = null;
|
||||
$homonyms = [];
|
||||
|
||||
foreach ($headers as $header) {
|
||||
if (\strcasecmp(\substr($header, 0, $nameLength + 1), ($name . ':')) === 0) {
|
||||
$headerValue = \trim(\substr($header, $nameLength + 1), "\t ");
|
||||
|
||||
if ((empty($valuePrefix) || \substr($headerValue, 0, \strlen($valuePrefix)) === $valuePrefix) && $first === null) {
|
||||
$first = $header;
|
||||
}
|
||||
else {
|
||||
$homonyms[] = $header;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($first !== null) {
|
||||
\header_remove($name);
|
||||
|
||||
foreach ($homonyms as $homonym) {
|
||||
\header($homonym, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $first;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user