Upgrade to 3.7.1

This commit is contained in:
Bastian Allgeier
2022-07-12 13:33:21 +02:00
parent 7931eb5e47
commit 1ad1eaf387
377 changed files with 63981 additions and 63824 deletions

View File

@@ -17,221 +17,221 @@ use Kirby\Toolkit\Str;
*/
class Cookie
{
/**
* Key to use for cookie signing
* @var string
*/
public static $key = 'KirbyHttpCookieKey';
/**
* Key to use for cookie signing
* @var string
*/
public static $key = 'KirbyHttpCookieKey';
/**
* Set a new cookie
*
* <code>
*
* cookie::set('mycookie', 'hello', ['lifetime' => 60]);
* // expires in 1 hour
*
* </code>
*
* @param string $key The name of the cookie
* @param string $value The cookie content
* @param array $options Array of options:
* lifetime, path, domain, secure, httpOnly, sameSite
* @return bool true: cookie was created,
* false: cookie creation failed
*/
public static function set(string $key, string $value, array $options = []): bool
{
// modify CMS caching behavior
static::trackUsage($key);
/**
* Set a new cookie
*
* <code>
*
* cookie::set('mycookie', 'hello', ['lifetime' => 60]);
* // expires in 1 hour
*
* </code>
*
* @param string $key The name of the cookie
* @param string $value The cookie content
* @param array $options Array of options:
* lifetime, path, domain, secure, httpOnly, sameSite
* @return bool true: cookie was created,
* false: cookie creation failed
*/
public static function set(string $key, string $value, array $options = []): bool
{
// modify CMS caching behavior
static::trackUsage($key);
// extract options
$expires = static::lifetime($options['lifetime'] ?? 0);
$path = $options['path'] ?? '/';
$domain = $options['domain'] ?? null;
$secure = $options['secure'] ?? false;
$httponly = $options['httpOnly'] ?? true;
$samesite = $options['sameSite'] ?? 'Lax';
// extract options
$expires = static::lifetime($options['lifetime'] ?? 0);
$path = $options['path'] ?? '/';
$domain = $options['domain'] ?? null;
$secure = $options['secure'] ?? false;
$httponly = $options['httpOnly'] ?? true;
$samesite = $options['sameSite'] ?? 'Lax';
// add an HMAC signature of the value
$value = static::hmac($value) . '+' . $value;
// add an HMAC signature of the value
$value = static::hmac($value) . '+' . $value;
// store that thing in the cookie global
$_COOKIE[$key] = $value;
// store that thing in the cookie global
$_COOKIE[$key] = $value;
// store the cookie
$options = compact('expires', 'path', 'domain', 'secure', 'httponly', 'samesite');
return setcookie($key, $value, $options);
}
// store the cookie
$options = compact('expires', 'path', 'domain', 'secure', 'httponly', 'samesite');
return setcookie($key, $value, $options);
}
/**
* Calculates the lifetime for a cookie
*
* @param int $minutes Number of minutes or timestamp
* @return int
*/
public static function lifetime(int $minutes): int
{
if ($minutes > 1000000000) {
// absolute timestamp
return $minutes;
} elseif ($minutes > 0) {
// minutes from now
return time() + ($minutes * 60);
} else {
return 0;
}
}
/**
* Calculates the lifetime for a cookie
*
* @param int $minutes Number of minutes or timestamp
* @return int
*/
public static function lifetime(int $minutes): int
{
if ($minutes > 1000000000) {
// absolute timestamp
return $minutes;
} elseif ($minutes > 0) {
// minutes from now
return time() + ($minutes * 60);
} else {
return 0;
}
}
/**
* Stores a cookie forever
*
* <code>
*
* cookie::forever('mycookie', 'hello');
* // never expires
*
* </code>
*
* @param string $key The name of the cookie
* @param string $value The cookie content
* @param array $options Array of options:
* path, domain, secure, httpOnly
* @return bool true: cookie was created,
* false: cookie creation failed
*/
public static function forever(string $key, string $value, array $options = []): bool
{
// 9999-12-31 if supported (lower on 32-bit servers)
$options['lifetime'] = min(253402214400, PHP_INT_MAX);
return static::set($key, $value, $options);
}
/**
* Stores a cookie forever
*
* <code>
*
* cookie::forever('mycookie', 'hello');
* // never expires
*
* </code>
*
* @param string $key The name of the cookie
* @param string $value The cookie content
* @param array $options Array of options:
* path, domain, secure, httpOnly
* @return bool true: cookie was created,
* false: cookie creation failed
*/
public static function forever(string $key, string $value, array $options = []): bool
{
// 9999-12-31 if supported (lower on 32-bit servers)
$options['lifetime'] = min(253402214400, PHP_INT_MAX);
return static::set($key, $value, $options);
}
/**
* Get a cookie value
*
* <code>
*
* cookie::get('mycookie', 'peter');
* // sample output: 'hello' or if the cookie is not set 'peter'
*
* </code>
*
* @param string|null $key The name of the cookie
* @param string|null $default The default value, which should be returned
* if the cookie has not been found
* @return mixed The found value
*/
public static function get(string $key = null, string $default = null)
{
if ($key === null) {
return $_COOKIE;
}
/**
* Get a cookie value
*
* <code>
*
* cookie::get('mycookie', 'peter');
* // sample output: 'hello' or if the cookie is not set 'peter'
*
* </code>
*
* @param string|null $key The name of the cookie
* @param string|null $default The default value, which should be returned
* if the cookie has not been found
* @return mixed The found value
*/
public static function get(string $key = null, string $default = null)
{
if ($key === null) {
return $_COOKIE;
}
// modify CMS caching behavior
static::trackUsage($key);
// modify CMS caching behavior
static::trackUsage($key);
$value = $_COOKIE[$key] ?? null;
return empty($value) ? $default : static::parse($value);
}
$value = $_COOKIE[$key] ?? null;
return empty($value) ? $default : static::parse($value);
}
/**
* Checks if a cookie exists
*
* @param string $key
* @return bool
*/
public static function exists(string $key): bool
{
return static::get($key) !== null;
}
/**
* Checks if a cookie exists
*
* @param string $key
* @return bool
*/
public static function exists(string $key): bool
{
return static::get($key) !== null;
}
/**
* Creates a HMAC for the cookie value
* Used as a cookie signature to prevent easy tampering with cookie data
*
* @param string $value
* @return string
*/
protected static function hmac(string $value): string
{
return hash_hmac('sha1', $value, static::$key);
}
/**
* Creates a HMAC for the cookie value
* Used as a cookie signature to prevent easy tampering with cookie data
*
* @param string $value
* @return string
*/
protected static function hmac(string $value): string
{
return hash_hmac('sha1', $value, static::$key);
}
/**
* Parses the hashed value from a cookie
* and tries to extract the value
*
* @param string $string
* @return mixed
*/
protected static function parse(string $string)
{
// if no hash-value separator is present, we can't parse the value
if (strpos($string, '+') === false) {
return null;
}
/**
* Parses the hashed value from a cookie
* and tries to extract the value
*
* @param string $string
* @return mixed
*/
protected static function parse(string $string)
{
// if no hash-value separator is present, we can't parse the value
if (strpos($string, '+') === false) {
return null;
}
// extract hash and value
$hash = Str::before($string, '+');
$value = Str::after($string, '+');
// extract hash and value
$hash = Str::before($string, '+');
$value = Str::after($string, '+');
// if the hash or the value is missing at all return null
// $value can be an empty string, $hash can't be!
if (!is_string($hash) || $hash === '' || !is_string($value)) {
return null;
}
// if the hash or the value is missing at all return null
// $value can be an empty string, $hash can't be!
if (!is_string($hash) || $hash === '' || !is_string($value)) {
return null;
}
// compare the extracted hash with the hashed value
// don't accept value if the hash is invalid
if (hash_equals(static::hmac($value), $hash) !== true) {
return null;
}
// compare the extracted hash with the hashed value
// don't accept value if the hash is invalid
if (hash_equals(static::hmac($value), $hash) !== true) {
return null;
}
return $value;
}
return $value;
}
/**
* Remove a cookie
*
* <code>
*
* cookie::remove('mycookie');
* // mycookie is now gone
*
* </code>
*
* @param string $key The name of the cookie
* @return bool true: the cookie has been removed,
* false: the cookie could not be removed
*/
public static function remove(string $key): bool
{
if (isset($_COOKIE[$key])) {
unset($_COOKIE[$key]);
return setcookie($key, '', 1, '/') && setcookie($key, false);
}
/**
* Remove a cookie
*
* <code>
*
* cookie::remove('mycookie');
* // mycookie is now gone
*
* </code>
*
* @param string $key The name of the cookie
* @return bool true: the cookie has been removed,
* false: the cookie could not be removed
*/
public static function remove(string $key): bool
{
if (isset($_COOKIE[$key])) {
unset($_COOKIE[$key]);
return setcookie($key, '', 1, '/') && setcookie($key, false);
}
return false;
}
return false;
}
/**
* Tells the CMS responder that the response relies on a cookie and
* its value (even if the cookie isn't set in the current request);
* this ensures that the response is only cached for visitors who don't
* have this cookie set;
* https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526
*
* @param string $key
* @return void
*/
protected static function trackUsage(string $key): void
{
// lazily request the instance for non-CMS use cases
$kirby = App::instance(null, true);
/**
* Tells the CMS responder that the response relies on a cookie and
* its value (even if the cookie isn't set in the current request);
* this ensures that the response is only cached for visitors who don't
* have this cookie set;
* https://github.com/getkirby/kirby/issues/4423#issuecomment-1166300526
*
* @param string $key
* @return void
*/
protected static function trackUsage(string $key): void
{
// lazily request the instance for non-CMS use cases
$kirby = App::instance(null, true);
if ($kirby) {
$kirby->response()->usesCookie($key);
}
}
if ($kirby) {
$kirby->response()->usesCookie($key);
}
}
}