// SPDX-License-Identifier: GPL-3.0-or-later namespace Icinga\Web; use Icinga\Application\Config; use Icinga\Application\Icinga; use InvalidArgumentException; /** * A HTTP cookie */ class Cookie { /** * Domain of the cookie * * @var string */ protected $domain; /** * The timestamp at which the cookie expires * * @var int */ protected $expire; /** * Whether to protect the cookie against client side script code attempts to read the cookie * * Defaults to true. * * @var bool */ protected $httpOnly = true; /** * Name of the cookie * * @var string */ protected $name; /** * The path on the web server where the cookie is available * * Defaults to the base URL. * * @var string */ protected $path; /** * Whether to send the cookie only over a secure connection * * Defaults to auto-detection so that if the current request was sent over a secure connection the secure flag will * be set to true. * * @var bool */ protected $secure; /** * Value of the cookie * * @var string */ protected $value; /** * Create a new cookie * * @param string $name * @param string $value */ public function __construct($name, $value = null) { if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { throw new InvalidArgumentException(sprintf( 'Cookie name can\'t contain these characters: =,; \t\r\n\013\014 (%s)', $name )); } if (empty($name)) { throw new InvalidArgumentException('The cookie name can\'t be empty'); } $this->name = $name; $this->value = $value; } /** * Get the domain of the cookie * * @return string */ public function getDomain() { if ($this->domain === null) { $this->domain = Config::app()->get('cookie', 'domain'); } return $this->domain; } /** * Set the domain of the cookie * * @param string $domain * * @return $this */ public function setDomain($domain) { $this->domain = $domain; return $this; } /** * Get the timestamp at which the cookie expires * * @return int */ public function getExpire() { return $this->expire; } /** * Set the timestamp at which the cookie expires * * @param int $expire * * @return $this */ public function setExpire($expire) { $this->expire = $expire; return $this; } /** * Get whether to protect the cookie against client side script code attempts to read the cookie * * @return bool */ public function isHttpOnly() { return $this->httpOnly; } /** * Set whether to protect the cookie against client side script code attempts to read the cookie * * @param bool $httpOnly * * @return $this */ public function setHttpOnly($httpOnly) { $this->httpOnly = $httpOnly; return $this; } /** * Get the name of the cookie * * @return string */ public function getName() { return $this->name; } /** * Get the path on the web server where the cookie is available * * If the path has not been set either via {@link setPath()} or via config, the base URL will be returned. * * @return string */ public function getPath() { if ($this->path === null) { $path = Config::app()->get('cookie', 'path'); if ($path === null) { // The following call could be used as default for ConfigObject::get(), but we prevent unnecessary // function calls here, if the path is set in the config $path = Icinga::app()->getRequest()->getBaseUrl() . '/'; // Zend has rtrim($baseUrl, '/') } $this->path = $path; } return $this->path; } /** * Set the path on the web server where the cookie is available * * @param string $path * * @return $this */ public function setPath($path) { $this->path = $path; return $this; } /** * Get whether to send the cookie only over a secure connection * * If the secure flag has not been set either via {@link setSecure()} or via config and if the current request was * sent over a secure connection, true will be returned. * * @return bool */ public function isSecure() { if ($this->secure === null) { $secure = Config::app()->get('cookie', 'secure'); if ($secure === null) { // The following call could be used as default for ConfigObject::get(), but we prevent unnecessary // function calls here, if the secure flag is set in the config $secure = Icinga::app()->getRequest()->isSecure(); } $this->secure = $secure; } return $this->secure; } /** * Set whether to send the cookie only over a secure connection * * @param bool $secure * * @return $this */ public function setSecure($secure) { $this->secure = $secure; return $this; } /** * Get the value of the cookie * * @return string */ public function getValue() { return $this->value; } /** * Set the value of the cookie * * @param string $value * * @return $this */ public function setValue($value) { $this->value = $value; return $this; } /** * Create invalidation cookie * * This method clones the current cookie and sets its value to null and expire time to 1. * That way, the cookie removes itself when it has been sent to and processed by the client. * * We're cloning the current cookie in order to meet the [RFC6265 spec](https://tools.ietf.org/search/rfc6265) * regarding the `Path` and `Domain` attribute: * * > Finally, to remove a cookie, the server returns a Set-Cookie header with an expiration date in the past. * > The server will be successful in removing the cookie only if the Path and the Domain attribute in the * > Set-Cookie header match the values used when the cookie was created. * * Note that the cookie has to be sent to the client. * * # Example Usage * * ```php * $response->setCookie( * $cookie->forgetMe() * ); * ``` * * @return static */ public function forgetMe() { $forgetMe = clone $this; return $forgetMe ->setValue(null) ->setExpire(1); } }