diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index a4cd1263..00000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "🐛 Bug Report" -about: "If something isn't working as expected 🤔" - ---- - -Version: ?.?.? - -### Bug Description -... A clear and concise description of what the bug is. A good bug report shouldn't leave others needing to chase you up for more information. - -### Steps To Reproduce -... If possible a minimal demo of the problem ... - -### Expected Behavior -... A clear and concise description of what you expected to happen. - -### Possible Solution -... Only if you have suggestions on a fix for the bug diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index d2e21948..00000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: "🚀 Feature Request" -about: "I have a suggestion (and may want to implement it) 🙂" - ---- - -- Is your feature request related to a problem? Please describe. -- Explain your intentions. -- It's up to you to make a strong case to convince the project's developers of the merits of this feature. diff --git a/.github/ISSUE_TEMPLATE/Support_question.md b/.github/ISSUE_TEMPLATE/Support_question.md deleted file mode 100644 index 75c48b6e..00000000 --- a/.github/ISSUE_TEMPLATE/Support_question.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: "🤗 Support Question" -about: "If you have a question 💬, please check out our forum!" - ---- - ---------------^ Click "Preview" for a nicer view! -We primarily use GitHub as an issue tracker; for usage and support questions, please check out these resources below. Thanks! 😁. - -* Nette Forum: https://forum.nette.org -* Nette Gitter: https://gitter.im/nette/nette -* Slack (czech): https://pehapkari.slack.com/messages/C2R30BLKA diff --git a/.github/ISSUE_TEMPLATE/Support_us.md b/.github/ISSUE_TEMPLATE/Support_us.md deleted file mode 100644 index 92d8a4c3..00000000 --- a/.github/ISSUE_TEMPLATE/Support_us.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: "❤️ Support us" -about: "If you would like to support our efforts in maintaining this project 🙌" - ---- - ---------------^ Click "Preview" for a nicer view! - -> https://nette.org/donate - -Help support Nette! - -We develop Nette Framework for more than 14 years. In order to make your life more comfortable. Nette cares about the safety of your sites. Nette saves you time. And gives job opportunities. - -Nette earns you money. And is absolutely free. - -To ensure future development and improving the documentation, we need your donation. - -Whether you are chief of IT company which benefits from Nette, or developer who goes for advice on our forum, if you like Nette, [please make a donation now](https://nette.org/donate). - -Thank you! diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 25adc952..00000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: dg -custom: "https://nette.org/donate" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index f8aa3f40..00000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,11 +0,0 @@ -- bug fix / new feature? -- BC break? yes/no -- doc PR: nette/docs#??? - - diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index 39afa89a..50d857de 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.1 + php-version: 8.0 coverage: none - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none - run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index a051b78b..2289a804 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none - run: composer install --no-progress --prefer-dist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a74590f9..8131aa9b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['8.0'] # sapi: ['php', 'php-cgi'] fail-fast: false @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.2 + php-version: 8.0 coverage: none extensions: fileinfo, intl @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none extensions: fileinfo, intl diff --git a/appveyor.yml b/appveyor.yml index a672440d..d1d28c8d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,7 @@ install: # Install PHP - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php) - IF %PHP%==1 cd c:\php - - IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.2.28-Win32-VC15-x64.zip --output php.zip + - IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-8.0.1-Win32-vs16-x64.zip --output php.zip - IF %PHP%==1 7z x php.zip >nul - IF %PHP%==1 echo extension_dir=ext >> php.ini - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini diff --git a/composer.json b/composer.json index 5f258113..f7a2a077 100644 --- a/composer.json +++ b/composer.json @@ -15,14 +15,14 @@ } ], "require": { - "php": ">=7.2 <8.1", - "nette/utils": "^3.1" + "php": ">=8.0 <8.1", + "nette/utils": "^3.2 || ^4.0" }, "require-dev": { - "nette/di": "^3.0", - "nette/tester": "^2.0", - "nette/security": "^3.0", - "tracy/tracy": "^2.4", + "nette/di": "^4.0", + "nette/tester": "^2.4", + "nette/security": "^4.0", + "tracy/tracy": "^2.8", "phpstan/phpstan": "^0.12" }, "conflict": { @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.0-dev" } } } diff --git a/contributing.md b/contributing.md deleted file mode 100644 index 184152c0..00000000 --- a/contributing.md +++ /dev/null @@ -1,33 +0,0 @@ -How to contribute & use the issue tracker -========================================= - -Nette welcomes your contributions. There are several ways to help out: - -* Create an issue on GitHub, if you have found a bug -* Write test cases for open bug issues -* Write fixes for open bug/feature issues, preferably with test cases included -* Contribute to the [documentation](https://nette.org/en/writing) - -Issues ------- - -Please **do not use the issue tracker to ask questions**. We will be happy to help you -on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette). - -A good bug report shouldn't leave others needing to chase you up for more -information. Please try to be as detailed as possible in your report. - -**Feature requests** are welcome. But take a moment to find out whether your idea -fits with the scope and aims of the project. It's up to *you* to make a strong -case to convince the project's developers of the merits of this feature. - -Contributing ------------- - -If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing). - -The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them. - -Please do not fix whitespace, format code, or make a purely cosmetic patch. - -Thanks! :heart: diff --git a/readme.md b/readme.md index b6db972c..8d97f475 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ Installation composer require nette/http ``` -It requires PHP version 7.2 and supports PHP up to 8.0. +It requires PHP version 8.0. HTTP Request diff --git a/src/Bridges/HttpDI/HttpExtension.php b/src/Bridges/HttpDI/HttpExtension.php index 5a1796c2..10034fe2 100644 --- a/src/Bridges/HttpDI/HttpExtension.php +++ b/src/Bridges/HttpDI/HttpExtension.php @@ -18,8 +18,7 @@ */ class HttpExtension extends Nette\DI\CompilerExtension { - /** @var bool */ - private $cliMode; + private bool $cliMode; public function __construct(bool $cliMode = false) @@ -116,7 +115,7 @@ private function sendHeaders() $this->initialization->addBody('$cspNonce = base64_encode(random_bytes(16));'); $value = Nette\DI\ContainerBuilder::literal( 'str_replace(?, ? . $cspNonce, ?)', - ["'nonce", "'nonce-", $value] + ["'nonce", "'nonce-", $value], ); } $headers['Content-Security-Policy' . ($key === 'csp' ? '' : '-Report-Only')] = $value; @@ -135,7 +134,7 @@ private function sendHeaders() $this->initialization->addBody( 'Nette\Http\Helpers::initCookie($this->getService(?), $response);', - [$this->prefix('request')] + [$this->prefix('request')], ); } diff --git a/src/Bridges/HttpDI/SessionExtension.php b/src/Bridges/HttpDI/SessionExtension.php index 0cba114e..0e962ce7 100644 --- a/src/Bridges/HttpDI/SessionExtension.php +++ b/src/Bridges/HttpDI/SessionExtension.php @@ -19,11 +19,9 @@ */ class SessionExtension extends Nette\DI\CompilerExtension { - /** @var bool */ - private $debugMode; + private bool $debugMode; - /** @var bool */ - private $cliMode; + private bool $cliMode; public function __construct(bool $debugMode = false, bool $cliMode = false) @@ -41,7 +39,7 @@ public function getConfigSchema(): Nette\Schema\Schema 'expiration' => Expect::string()->dynamic(), 'handler' => Expect::string()->dynamic(), 'readAndClose' => Expect::bool(), - 'cookieSamesite' => Expect::anyOf(IResponse::SAME_SITE_LAX, IResponse::SAME_SITE_STRICT, IResponse::SAME_SITE_NONE, true) + 'cookieSamesite' => Expect::anyOf(IResponse::SAME_SITE_LAX, IResponse::SAME_SITE_STRICT, IResponse::SAME_SITE_NONE) ->firstIsDefault(), ])->otherItems('mixed'); } @@ -64,14 +62,6 @@ public function loadConfiguration() if (($config->cookieDomain ?? null) === 'domain') { $config->cookieDomain = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->getUrl()->getDomain(2)'); } - if (isset($config->cookieSecure)) { - trigger_error("The item 'session › cookieSecure' is deprecated, use 'http › cookieSecure' (it has default value 'auto').", E_USER_DEPRECATED); - unset($config->cookieSecure); - } - if ($config->cookieSamesite === true) { - trigger_error("In 'session › cookieSamesite' replace true with 'Lax'.", E_USER_DEPRECATED); - $config->cookieSamesite = IResponse::SAME_SITE_LAX; - } $this->compiler->addExportedType(Nette\Http\IRequest::class); if ($this->debugMode && $config->debugger) { diff --git a/src/Http/Context.php b/src/Http/Context.php index 7962ab30..d0f1ec68 100644 --- a/src/Http/Context.php +++ b/src/Http/Context.php @@ -19,11 +19,9 @@ class Context { use Nette\SmartObject; - /** @var IRequest */ - private $request; + private IRequest $request; - /** @var IResponse */ - private $response; + private IResponse $response; public function __construct(IRequest $request, IResponse $response) @@ -35,9 +33,8 @@ public function __construct(IRequest $request, IResponse $response) /** * Attempts to cache the sent entity by its last modification date. - * @param string|int|\DateTimeInterface $lastModified */ - public function isModified($lastModified = null, string $etag = null): bool + public function isModified(string|int|\DateTimeInterface $lastModified = null, string $etag = null): bool { if ($lastModified) { $this->response->setHeader('Last-Modified', Helpers::formatDate($lastModified)); diff --git a/src/Http/FileUpload.php b/src/Http/FileUpload.php index 3c9ff21e..37f074bd 100644 --- a/src/Http/FileUpload.php +++ b/src/Http/FileUpload.php @@ -30,20 +30,15 @@ final class FileUpload public const IMAGE_MIME_TYPES = ['image/gif', 'image/png', 'image/jpeg', 'image/webp']; - /** @var string */ - private $name; + private string $name; - /** @var string|false|null */ - private $type; + private string|false|null $type = null; - /** @var int */ - private $size; + private int $size; - /** @var string */ - private $tmpName; + private string $tmpName; - /** @var int */ - private $error; + private int $error; public function __construct(?array $value) @@ -169,9 +164,8 @@ public function hasFile(): bool /** * Moves an uploaded file to a new location. If the destination file already exists, it will be overwritten. - * @return static */ - public function move(string $dest) + public function move(string $dest): static { $dir = dirname($dest); Nette\Utils\FileSystem::createDir($dir); @@ -181,7 +175,7 @@ public function move(string $dest) [$this->tmpName, $dest], function (string $message) use ($dest): void { throw new Nette\InvalidStateException("Unable to move uploaded file '$this->tmpName' to '$dest'. $message"); - } + }, ); @chmod($dest, 0666); // @ - possible low permission to chmod $this->tmpName = $dest; diff --git a/src/Http/Helpers.php b/src/Http/Helpers.php index efde3de6..b8e237ef 100644 --- a/src/Http/Helpers.php +++ b/src/Http/Helpers.php @@ -26,9 +26,8 @@ final class Helpers /** * Returns HTTP valid date format. - * @param string|int|\DateTimeInterface $time */ - public static function formatDate($time): string + public static function formatDate(string|int|\DateTimeInterface $time): string { $time = DateTime::from($time)->setTimezone(new \DateTimeZone('GMT')); return $time->format('D, d M Y H:i:s \G\M\T'); @@ -41,7 +40,7 @@ public static function formatDate($time): string public static function ipMatch(string $ip, string $mask): bool { [$mask, $size] = explode('/', $mask . '/'); - $tmp = function (int $n): string { return sprintf('%032b', $n); }; + $tmp = fn(int $n): string => sprintf('%032b', $n); $ip = implode('', array_map($tmp, unpack('N*', inet_pton($ip)))); $mask = implode('', array_map($tmp, unpack('N*', inet_pton($mask)))); $max = strlen($ip); diff --git a/src/Http/IRequest.php b/src/Http/IRequest.php index f263503d..2865b954 100644 --- a/src/Http/IRequest.php +++ b/src/Http/IRequest.php @@ -37,22 +37,19 @@ function getUrl(): UrlScript; /** * Returns variable provided to the script via URL query ($_GET). * If no key is passed, returns the entire array. - * @return mixed */ - function getQuery(string $key = null); + function getQuery(string $key = null): mixed; /** * Returns variable provided to the script via POST method ($_POST). * If no key is passed, returns the entire array. - * @return mixed */ - function getPost(string $key = null); + function getPost(string $key = null): mixed; /** * Returns uploaded file. - * @return FileUpload|array|null */ - function getFile(string $key); + function getFile(string $key): ?FileUpload; /** * Returns uploaded files. @@ -61,9 +58,8 @@ function getFiles(): array; /** * Returns variable provided to the script via HTTP cookies. - * @return mixed */ - function getCookie(string $key); + function getCookie(string $key): mixed; /** * Returns variables provided to the script via HTTP cookies. diff --git a/src/Http/IResponse.php b/src/Http/IResponse.php index d968f8e2..3269d110 100644 --- a/src/Http/IResponse.php +++ b/src/Http/IResponse.php @@ -16,12 +16,6 @@ */ interface IResponse { - /** @deprecated */ - public const PERMANENT = 2116333333; - - /** @deprecated */ - public const BROWSER = 0; - /** HTTP 1.1 response code */ public const S100_CONTINUE = 100, @@ -155,9 +149,8 @@ interface IResponse /** * Sets HTTP response code. - * @return static */ - function setCode(int $code, string $reason = null); + function setCode(int $code, string $reason = null): static; /** * Returns HTTP response code. @@ -166,21 +159,18 @@ function getCode(): int; /** * Sends a HTTP header and replaces a previous one. - * @return static */ - function setHeader(string $name, string $value); + function setHeader(string $name, string $value): static; /** * Adds HTTP header. - * @return static */ - function addHeader(string $name, string $value); + function addHeader(string $name, string $value): static; /** * Sends a Content-type HTTP header. - * @return static */ - function setContentType(string $type, string $charset = null); + function setContentType(string $type, string $charset = null): static; /** * Redirects to a new URL. @@ -189,9 +179,8 @@ function redirect(string $url, int $code = self::S302_FOUND): void; /** * Sets the time (like '20 minutes') before a page cached on a browser expires, null means "must-revalidate". - * @return static */ - function setExpiration(?string $expire); + function setExpiration(?string $expire): static; /** * Checks if headers have been sent. @@ -211,7 +200,6 @@ function getHeaders(): array; /** * Sends a cookie. * @param string|int|\DateTimeInterface $expire time, value null means "until the browser session ends" - * @return static */ function setCookie( string $name, @@ -220,8 +208,8 @@ function setCookie( string $path = null, string $domain = null, bool $secure = null, - bool $httpOnly = null - ); + bool $httpOnly = null, + ): static; /** * Deletes a cookie. diff --git a/src/Http/Request.php b/src/Http/Request.php index 2aaff910..6c92dbd1 100644 --- a/src/Http/Request.php +++ b/src/Http/Request.php @@ -33,31 +33,23 @@ class Request implements IRequest { use Nette\SmartObject; - /** @var string */ - private $method; + private string $method; - /** @var UrlScript */ - private $url; + private UrlScript $url; - /** @var array */ - private $post; + private array $post; - /** @var array */ - private $files; + private array $files; - /** @var array */ - private $cookies; + private array $cookies; - /** @var array */ - private $headers; + private array $headers; - /** @var string|null */ - private $remoteAddress; + private ?string $remoteAddress; - /** @var string|null */ - private $remoteHost; + private ?string $remoteHost; - /** @var callable|null */ + /** @var ?callable */ private $rawBodyCallback; @@ -70,7 +62,7 @@ public function __construct( string $method = null, string $remoteAddress = null, string $remoteHost = null, - callable $rawBodyCallback = null + callable $rawBodyCallback = null, ) { $this->url = $url; $this->post = (array) $post; @@ -86,9 +78,8 @@ public function __construct( /** * Returns a clone with a different URL. - * @return static */ - public function withUrl(UrlScript $url) + public function withUrl(UrlScript $url): static { $dolly = clone $this; $dolly->url = $url; @@ -111,14 +102,11 @@ public function getUrl(): UrlScript /** * Returns variable provided to the script via URL query ($_GET). * If no key is passed, returns the entire array. - * @return mixed */ - public function getQuery(string $key = null) + public function getQuery(string $key = null): mixed { if (func_num_args() === 0) { return $this->url->getQueryParameters(); - } elseif (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); } return $this->url->getQueryParameter($key); } @@ -127,14 +115,11 @@ public function getQuery(string $key = null) /** * Returns variable provided to the script via POST method ($_POST). * If no key is passed, returns the entire array. - * @return mixed */ - public function getPost(string $key = null) + public function getPost(string $key = null): mixed { if (func_num_args() === 0) { return $this->post; - } elseif (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); } return $this->post[$key] ?? null; } @@ -143,9 +128,8 @@ public function getPost(string $key = null) /** * Returns uploaded file. * @param string|string[] $key - * @return ?FileUpload */ - public function getFile($key) + public function getFile($key): ?FileUpload { $res = Nette\Utils\Arrays::get($this->files, $key, null); return $res instanceof FileUpload ? $res : null; @@ -163,13 +147,9 @@ public function getFiles(): array /** * Returns a cookie or `null` if it does not exist. - * @return mixed */ - public function getCookie(string $key) + public function getCookie(string $key): mixed { - if (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); - } return $this->cookies[$key] ?? null; } @@ -209,9 +189,6 @@ public function isMethod(string $method): bool */ public function getHeader(string $header): ?string { - if (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); - } $header = strtolower($header); return $this->headers[$header] ?? null; } diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index 71d8d161..e88bf6ad 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -23,21 +23,18 @@ class RequestFactory /** @internal */ private const CHARS = '\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}'; - /** @var array */ - public $urlFilters = [ + public array $urlFilters = [ 'path' => ['#/{2,}#' => '/'], // '%20' => '' 'url' => [], // '#[.,)]$#D' => '' ]; - /** @var bool */ - private $binary = false; + private bool $binary = false; /** @var string[] */ - private $proxies = []; + private array $proxies = []; - /** @return static */ - public function setBinary(bool $binary = true) + public function setBinary(bool $binary = true): static { $this->binary = $binary; return $this; @@ -46,9 +43,8 @@ public function setBinary(bool $binary = true) /** * @param string|string[] $proxy - * @return static */ - public function setProxy($proxy) + public function setProxy($proxy): static { $this->proxies = (array) $proxy; return $this; @@ -76,9 +72,7 @@ public function fromGlobals(): Request $this->getMethod(), $remoteAddr, $remoteHost, - function (): string { - return file_get_contents('php://input'); - } + fn(): string => file_get_contents('php://input'), ); } @@ -271,9 +265,7 @@ private function getClient(Url $url): array : null; // use real client address and host if trusted proxy is used - $usingTrustedProxy = $remoteAddr && array_filter($this->proxies, function (string $proxy) use ($remoteAddr): bool { - return Helpers::ipMatch($remoteAddr, $proxy); - }); + $usingTrustedProxy = $remoteAddr && array_filter($this->proxies, fn(string $proxy): bool => Helpers::ipMatch($remoteAddr, $proxy)); if ($usingTrustedProxy) { empty($_SERVER['HTTP_FORWARDED']) ? $this->useNonstandardProxy($url, $remoteAddr, $remoteHost) @@ -339,11 +331,13 @@ private function useNonstandardProxy(Url $url, &$remoteAddr, &$remoteHost): void } if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $xForwardedForWithoutProxies = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), function (string $ip): bool { - return !array_filter($this->proxies, function (string $proxy) use ($ip): bool { - return filter_var(trim($ip), FILTER_VALIDATE_IP) !== false && Helpers::ipMatch(trim($ip), $proxy); - }); - }); + $xForwardedForWithoutProxies = array_filter( + explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), + fn(string $ip): bool => !array_filter( + $this->proxies, + fn(string $proxy): bool => filter_var(trim($ip), FILTER_VALIDATE_IP) !== false && Helpers::ipMatch(trim($ip), $proxy), + ), + ); if ($xForwardedForWithoutProxies) { $remoteAddr = trim(end($xForwardedForWithoutProxies)); $xForwardedForRealIpKey = key($xForwardedForWithoutProxies); diff --git a/src/Http/Response.php b/src/Http/Response.php index 1c71bacd..41877c51 100644 --- a/src/Http/Response.php +++ b/src/Http/Response.php @@ -22,26 +22,23 @@ final class Response implements IResponse { use Nette\SmartObject; - /** @var string The domain in which the cookie will be available */ - public $cookieDomain = ''; + /** The domain in which the cookie will be available */ + public string $cookieDomain = ''; - /** @var string The path in which the cookie will be available */ - public $cookiePath = '/'; + /** The path in which the cookie will be available */ + public string $cookiePath = '/'; - /** @var bool Whether the cookie is available only through HTTPS */ - public $cookieSecure = false; + /** Whether the cookie is available only through HTTPS */ + public bool $cookieSecure = false; - /** @deprecated */ - public $cookieHttpOnly; + /** Whether warn on possible problem with data in output buffer */ + public bool $warnOnBuffer = true; - /** @var bool Whether warn on possible problem with data in output buffer */ - public $warnOnBuffer = true; + /** Send invisible garbage for IE 6? */ + private static bool $fixIE = true; - /** @var bool Send invisible garbage for IE 6? */ - private static $fixIE = true; - - /** @var int HTTP response code */ - private $code = self::S200_OK; + /** HTTP response code */ + private int $code = self::S200_OK; public function __construct() @@ -54,11 +51,10 @@ public function __construct() /** * Sets HTTP response code. - * @return static * @throws Nette\InvalidArgumentException if code is invalid * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function setCode(int $code, string $reason = null) + public function setCode(int $code, string $reason = null): static { if ($code < 100 || $code > 599) { throw new Nette\InvalidArgumentException("Bad HTTP response '$code'."); @@ -83,10 +79,9 @@ public function getCode(): int /** * Sends an HTTP header and overwrites previously sent header of the same name. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function setHeader(string $name, ?string $value) + public function setHeader(string $name, ?string $value): static { self::checkHeaders(); if ($value === null) { @@ -102,10 +97,9 @@ public function setHeader(string $name, ?string $value) /** * Sends an HTTP header and doesn't overwrite previously sent header of the same name. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function addHeader(string $name, string $value) + public function addHeader(string $name, string $value): static { self::checkHeaders(); header($name . ': ' . $value, false); @@ -115,10 +109,9 @@ public function addHeader(string $name, string $value) /** * Deletes a previously sent HTTP header. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function deleteHeader(string $name) + public function deleteHeader(string $name): static { self::checkHeaders(); header_remove($name); @@ -128,10 +121,9 @@ public function deleteHeader(string $name) /** * Sends a Content-type HTTP header. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function setContentType(string $type, string $charset = null) + public function setContentType(string $type, string $charset = null): static { $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); return $this; @@ -140,15 +132,14 @@ public function setContentType(string $type, string $charset = null) /** * Response should be downloaded with 'Save as' dialog. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function sendAsFile(string $fileName) + public function sendAsFile(string $fileName): static { $this->setHeader( 'Content-Disposition', 'attachment; filename="' . str_replace('"', '', $fileName) . '"; ' - . "filename*=utf-8''" . rawurlencode($fileName) + . "filename*=utf-8''" . rawurlencode($fileName), ); return $this; } @@ -172,10 +163,9 @@ public function redirect(string $url, int $code = self::S302_FOUND): void /** * Sets the expiration of the HTTP document using the `Cache-Control` and `Expires` headers. * The parameter is either a time interval (as text) or `null`, which disables caching. - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ - public function setExpiration(?string $time) + public function setExpiration(?string $time): static { $this->setHeader('Pragma', null); if (!$time) { // no cache @@ -206,9 +196,6 @@ public function isSent(): bool */ public function getHeader(string $header): ?string { - if (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); - } $header .= ':'; $len = strlen($header); foreach (headers_list() as $item) { @@ -251,7 +238,6 @@ public function __destruct() /** * Sends a cookie. * @param string|int|\DateTimeInterface $time expiration time, value null means "until the browser session ends" - * @return static * @throws Nette\InvalidStateException if HTTP headers have been sent */ public function setCookie( @@ -262,8 +248,8 @@ public function setCookie( string $domain = null, bool $secure = null, bool $httpOnly = null, - string $sameSite = null - ) { + string $sameSite = null, + ): static { self::checkHeaders(); $options = [ 'expires' => $time ? (int) DateTime::from($time)->format('U') : 0, @@ -273,19 +259,7 @@ public function setCookie( 'httponly' => $httpOnly ?? true, 'samesite' => $sameSite = ($sameSite ?? self::SAME_SITE_LAX), ]; - if (PHP_VERSION_ID >= 70300) { - setcookie($name, $value, $options); - } else { - setcookie( - $name, - $value, - $options['expires'], - $options['path'] . ($sameSite ? "; SameSite=$sameSite" : ''), - $options['domain'], - $options['secure'], - $options['httponly'] - ); - } + setcookie($name, $value, $options); return $this; } @@ -309,9 +283,9 @@ private function checkHeaders(): void } elseif ( $this->warnOnBuffer && ob_get_length() && - !array_filter(ob_get_status(true), function (array $i): bool { return !$i['chunk_size']; }) + !array_filter(ob_get_status(true), fn(array $i): bool => !$i['chunk_size']) ) { - trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try Tracy\OutputDebugger or start session earlier.'); + trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try Tracy\OutputDebugger or send cookies/start session earlier.'); } } } diff --git a/src/Http/Session.php b/src/Http/Session.php index 05adba59..0f6e739f 100644 --- a/src/Http/Session.php +++ b/src/Http/Session.php @@ -31,30 +31,26 @@ class Session 'cookie_httponly' => true, // must be enabled to prevent Session Hijacking ]; - /** @var bool has been session ID regenerated? */ - private $regenerated = false; + /** has been session ID regenerated? */ + private bool $regenerated = false; - /** @var bool has been session started by Nette? */ - private $started = false; + /** has been session started by Nette? */ + private bool $started = false; - /** @var array default configuration */ - private $options = [ + /** default configuration */ + private array $options = [ 'cookie_samesite' => IResponse::SAME_SITE_LAX, 'cookie_lifetime' => 0, // for a maximum of 3 hours or until the browser is closed 'gc_maxlifetime' => self::DEFAULT_FILE_LIFETIME, // 3 hours ]; - /** @var IRequest */ - private $request; + private IRequest $request; - /** @var IResponse */ - private $response; + private IResponse $response; - /** @var \SessionHandlerInterface */ - private $handler; + private ?\SessionHandlerInterface $handler = null; - /** @var bool */ - private $readAndClose = false; + private bool $readAndClose = false; public function __construct(IRequest $request, IResponse $response) @@ -231,9 +227,8 @@ public function getId(): string /** * Sets the session name to a specified one. - * @return static */ - public function setName(string $name) + public function setName(string $name): static { if (!preg_match('#[^0-9.][^.]*$#DA', $name)) { throw new Nette\InvalidArgumentException('Session name cannot contain dot.'); @@ -260,7 +255,6 @@ public function getName(): string /** * Returns specified session section. - * @throws Nette\InvalidArgumentException */ public function getSection(string $section, string $class = SessionSection::class): SessionSection { @@ -318,11 +312,10 @@ public function clean(): void /** * Sets session options. - * @return static * @throws Nette\NotSupportedException * @throws Nette\InvalidStateException */ - public function setOptions(array $options) + public function setOptions(array $options): static { $normalized = []; $allowed = ini_get_all('session', false) + ['read_and_close' => 1, 'session.cookie_samesite' => 1]; // for PHP < 7.3 @@ -336,7 +329,7 @@ public function setOptions(array $options) if (!isset($allowed["session.$normKey"])) { $hint = substr((string) Nette\Utils\Helpers::getSuggestion(array_keys($allowed), "session.$normKey"), 8); if ($key !== $normKey) { - $hint = preg_replace_callback('#_(.)#', function ($m) { return strtoupper($m[1]); }, $hint); // snake_case -> camelCase + $hint = preg_replace_callback('#_(.)#', fn($m) => strtoupper($m[1]), $hint); // snake_case -> camelCase } throw new Nette\InvalidStateException("Invalid session configuration option '$key'" . ($hint ? ", did you mean '$hint'?" : '.')); } @@ -403,17 +396,7 @@ private function configure(array $config): void } if ($cookie !== $origCookie) { - if (PHP_VERSION_ID >= 70300) { - @session_set_cookie_params($cookie); // @ may trigger warning when session is active since PHP 7.2 - } else { - @session_set_cookie_params( // @ may trigger warning when session is active since PHP 7.2 - $cookie['lifetime'], - $cookie['path'] . (isset($cookie['samesite']) ? '; SameSite=' . $cookie['samesite'] : ''), - $cookie['domain'], - $cookie['secure'], - $cookie['httponly'] - ); - } + @session_set_cookie_params($cookie); // @ may trigger warning when session is active since PHP 7.2 if (session_status() === PHP_SESSION_ACTIVE) { $this->sendCookie(); } @@ -428,9 +411,8 @@ private function configure(array $config): void /** * Sets the amount of time (like '20 minutes') allowed between requests before the session will be terminated, * null means "for a maximum of 3 hours or until the browser is closed". - * @return static */ - public function setExpiration(?string $time) + public function setExpiration(?string $time): static { if ($time === null) { return $this->setOptions([ @@ -450,14 +432,13 @@ public function setExpiration(?string $time) /** * Sets the session cookie parameters. - * @return static */ public function setCookieParameters( string $path, string $domain = null, bool $secure = null, - string $sameSite = null - ) { + string $sameSite = null, + ): static { return $this->setOptions([ 'cookie_path' => $path, 'cookie_domain' => $domain, @@ -467,19 +448,10 @@ public function setCookieParameters( } - /** @deprecated */ - public function getCookieParameters(): array - { - trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED); - return session_get_cookie_params(); - } - - /** * Sets path of the directory used to save session data. - * @return static */ - public function setSavePath(string $path) + public function setSavePath(string $path): static { return $this->setOptions([ 'save_path' => $path, @@ -489,9 +461,8 @@ public function setSavePath(string $path) /** * Sets user session handler. - * @return static */ - public function setHandler(\SessionHandlerInterface $handler) + public function setHandler(\SessionHandlerInterface $handler): static { if ($this->started) { throw new Nette\InvalidStateException('Unable to set handler when session has been started.'); @@ -515,7 +486,7 @@ private function sendCookie(): void $cookie['domain'], $cookie['secure'], $cookie['httponly'], - $cookie['samesite'] ?? null + $cookie['samesite'] ?? null, ); } } diff --git a/src/Http/SessionSection.php b/src/Http/SessionSection.php index 15a42d34..9a180cb6 100644 --- a/src/Http/SessionSection.php +++ b/src/Http/SessionSection.php @@ -19,14 +19,11 @@ class SessionSection implements \IteratorAggregate, \ArrayAccess { use Nette\SmartObject; - /** @var bool */ - public $warnOnUndefined = false; + public bool $warnOnUndefined = false; - /** @var Session */ - private $session; + private Session $session; - /** @var string */ - private $name; + private string $name; /** @@ -60,9 +57,8 @@ public function __set(string $name, $value): void /** * Gets a variable from this session section. - * @return mixed */ - public function &__get(string $name) + public function &__get(string $name): mixed { $data = &$this->getData(true); if ($this->warnOnUndefined && !array_key_exists($name, $data ?? [])) { @@ -108,9 +104,8 @@ public function offsetSet($name, $value): void /** * Gets a variable from this session section. - * @return mixed */ - public function offsetGet($name) + public function offsetGet($name): mixed { return $this->__get($name); } @@ -136,11 +131,9 @@ public function offsetUnset($name): void /** * Sets the expiration of the section or specific variables. - * @param ?string $time * @param string|string[] $variables list of variables / single variable to expire - * @return static */ - public function setExpiration($time, $variables = null) + public function setExpiration(?string $time, string|array $variables = null): static { $meta = &$this->getMeta(); if ($time) { @@ -165,7 +158,7 @@ public function setExpiration($time, $variables = null) * Removes the expiration from the section or specific variables. * @param string|string[] $variables list of variables / single variable to expire */ - public function removeExpiration($variables = null): void + public function removeExpiration(string|array $variables = null): void { $meta = &$this->getMeta(); foreach (is_array($variables) ? $variables : [$variables] as $variable) { diff --git a/src/Http/Url.php b/src/Http/Url.php index fff7616c..d1814cb1 100644 --- a/src/Http/Url.php +++ b/src/Http/Url.php @@ -45,43 +45,33 @@ class Url implements \JsonSerializable { use Nette\SmartObject; - /** @var array */ - public static $defaultPorts = [ + public static array $defaultPorts = [ 'http' => 80, 'https' => 443, 'ftp' => 21, ]; - /** @var string */ - private $scheme = ''; + private string $scheme = ''; - /** @var string */ - private $user = ''; + private string $user = ''; - /** @var string */ - private $password = ''; + private string $password = ''; - /** @var string */ - private $host = ''; + private string $host = ''; - /** @var int|null */ - private $port; + private ?int $port = null; - /** @var string */ - private $path = ''; + private string $path = ''; - /** @var array */ - private $query = []; + private array $query = []; - /** @var string */ - private $fragment = ''; + private string $fragment = ''; /** - * @param string|self|UrlImmutable $url * @throws Nette\InvalidArgumentException if URL is malformed */ - public function __construct($url = null) + public function __construct(string|self|UrlImmutable $url = null) { if (is_string($url)) { $p = @parse_url($url); // @ - is escalated to exception @@ -100,15 +90,11 @@ public function __construct($url = null) } elseif ($url instanceof UrlImmutable || $url instanceof self) { [$this->scheme, $this->user, $this->password, $this->host, $this->port, $this->path, $this->query, $this->fragment] = $url->export(); - - } elseif ($url !== null) { - throw new Nette\InvalidArgumentException; } } - /** @return static */ - public function setScheme(string $scheme) + public function setScheme(string $scheme): static { $this->scheme = $scheme; return $this; @@ -121,8 +107,7 @@ public function getScheme(): string } - /** @return static */ - public function setUser(string $user) + public function setUser(string $user): static { $this->user = $user; return $this; @@ -135,8 +120,7 @@ public function getUser(): string } - /** @return static */ - public function setPassword(string $password) + public function setPassword(string $password): static { $this->password = $password; return $this; @@ -149,8 +133,7 @@ public function getPassword(): string } - /** @return static */ - public function setHost(string $host) + public function setHost(string $host): static { $this->host = $host; $this->setPath($this->path); @@ -179,8 +162,7 @@ public function getDomain(int $level = 2): string } - /** @return static */ - public function setPort(int $port) + public function setPort(int $port): static { $this->port = $port; return $this; @@ -193,8 +175,7 @@ public function getPort(): ?int } - /** @return static */ - public function setPath(string $path) + public function setPath(string $path): static { $this->path = $path; if ($this->host && substr($this->path, 0, 1) !== '/') { @@ -210,22 +191,14 @@ public function getPath(): string } - /** - * @param string|array $value - * @return static - */ - public function setQuery($query) + public function setQuery(string|array $query): static { $this->query = is_array($query) ? $query : self::parseQuery($query); return $this; } - /** - * @param string|array $value - * @return static - */ - public function appendQuery($query) + public function appendQuery(string|array $query): static { $this->query = is_array($query) ? $query + $this->query @@ -246,29 +219,26 @@ public function getQueryParameters(): array } - /** @return mixed */ - public function getQueryParameter(string $name) + public function getQueryParameter(string $name): mixed { - if (func_num_args() > 1) { - trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); - } return $this->query[$name] ?? null; } - /** - * @param mixed $value null unsets the parameter - * @return static - */ - public function setQueryParameter(string $name, $value) + public function setQueryParameter(string $name, mixed $value): static { $this->query[$name] = $value; return $this; } - /** @return static */ - public function setFragment(string $fragment) + public function removeQueryParameter(string $name): void + { + $this->query[$name] = null; + } + + + public function setFragment(string $fragment): static { $this->fragment = $fragment; return $this; @@ -340,9 +310,8 @@ public function getRelativeUrl(): string /** * URL comparison. - * @param string|self $url */ - public function isEqual($url): bool + public function isEqual(string|self $url): bool { $url = new self($url); $query = $url->query; @@ -363,15 +332,13 @@ public function isEqual($url): bool /** * Transforms URL to canonical form. - * @return static - * @deprecated */ - public function canonicalize() + public function canonicalize(): static { $this->path = preg_replace_callback( '#[^!$&\'()*+,/:;=@%]+#', - function (array $m): string { return rawurlencode($m[0]); }, - self::unescape($this->path, '%/') + fn(array $m): string => rawurlencode($m[0]), + self::unescape($this->path, '%/'), ); $this->host = self::idnHostToUnicode(strtolower($this->host)); return $this; @@ -423,8 +390,8 @@ public static function unescape(string $s, string $reserved = '%;/?:@&=+$,'): st if ($reserved !== '') { $s = preg_replace_callback( '#%(' . substr(chunk_split(bin2hex($reserved), 2, '|'), 0, -1) . ')#i', - function (array $m): string { return '%25' . strtoupper($m[1]); }, - $s + fn(array $m): string => '%25' . strtoupper($m[1]), + $s, ); } return rawurldecode($s); diff --git a/src/Http/UrlImmutable.php b/src/Http/UrlImmutable.php index 2301c662..9efce873 100644 --- a/src/Http/UrlImmutable.php +++ b/src/Http/UrlImmutable.php @@ -42,52 +42,37 @@ class UrlImmutable implements \JsonSerializable { use Nette\SmartObject; - /** @var string */ - private $scheme = ''; + private string $scheme = ''; - /** @var string */ - private $user = ''; + private string $user = ''; - /** @var string */ - private $password = ''; + private string $password = ''; - /** @var string */ - private $host = ''; + private string $host = ''; - /** @var int|null */ - private $port; + private ?int $port = null; - /** @var string */ - private $path = ''; + private string $path = ''; - /** @var array */ - private $query = []; + private array $query = []; - /** @var string */ - private $fragment = ''; + private string $fragment = ''; - /** @var string */ - private $authority = ''; + private string $authority = ''; /** - * @param string|self|Url $url * @throws Nette\InvalidArgumentException if URL is malformed */ - public function __construct($url) + public function __construct(string|self|Url $url) { - if (!$url instanceof Url && !$url instanceof self && !is_string($url)) { - throw new Nette\InvalidArgumentException; - } - $url = is_string($url) ? new Url($url) : $url; [$this->scheme, $this->user, $this->password, $this->host, $this->port, $this->path, $this->query, $this->fragment] = $url->export(); $this->build(); } - /** @return static */ - public function withScheme(string $scheme) + public function withScheme(string $scheme): static { $dolly = clone $this; $dolly->scheme = $scheme; @@ -102,8 +87,7 @@ public function getScheme(): string } - /** @return static */ - public function withUser(string $user) + public function withUser(string $user): static { $dolly = clone $this; $dolly->user = $user; @@ -118,8 +102,7 @@ public function getUser(): string } - /** @return static */ - public function withPassword(string $password) + public function withPassword(string $password): static { $dolly = clone $this; $dolly->password = $password; @@ -134,8 +117,7 @@ public function getPassword(): string } - /** @return static */ - public function withoutUserInfo() + public function withoutUserInfo(): static { $dolly = clone $this; $dolly->user = $dolly->password = ''; @@ -144,8 +126,7 @@ public function withoutUserInfo() } - /** @return static */ - public function withHost(string $host) + public function withHost(string $host): static { $dolly = clone $this; $dolly->host = $host; @@ -172,8 +153,7 @@ public function getDomain(int $level = 2): string } - /** @return static */ - public function withPort(int $port) + public function withPort(int $port): static { $dolly = clone $this; $dolly->port = $port; @@ -188,8 +168,7 @@ public function getPort(): ?int } - /** @return static */ - public function withPath(string $path) + public function withPath(string $path): static { $dolly = clone $this; $dolly->path = $path; @@ -204,11 +183,7 @@ public function getPath(): string } - /** - * @param string|array $query - * @return static - */ - public function withQuery($query) + public function withQuery(string|array $query): static { $dolly = clone $this; $dolly->query = is_array($query) ? $query : Url::parseQuery($query); @@ -223,11 +198,7 @@ public function getQuery(): string } - /** - * @param mixed $value null unsets the parameter - * @return static - */ - public function withQueryParameter(string $name, $value) + public function withQueryParameter(string $name, mixed $value): static { $dolly = clone $this; $dolly->query[$name] = $value; @@ -241,15 +212,13 @@ public function getQueryParameters(): array } - /** @return array|string|null */ - public function getQueryParameter(string $name) + public function getQueryParameter(string $name): array|string|null { return $this->query[$name] ?? null; } - /** @return static */ - public function withFragment(string $fragment) + public function withFragment(string $fragment): static { $dolly = clone $this; $dolly->fragment = $fragment; @@ -300,10 +269,7 @@ public function __toString(): string } - /** - * @param string|Url|self $url - */ - public function isEqual($url): bool + public function isEqual(string|Url|self $url): bool { return (new Url($this))->isEqual($url); } diff --git a/src/Http/UrlScript.php b/src/Http/UrlScript.php index fdc26fae..5fe5b298 100644 --- a/src/Http/UrlScript.php +++ b/src/Http/UrlScript.php @@ -34,23 +34,20 @@ */ class UrlScript extends UrlImmutable { - /** @var string */ - private $scriptPath; + private string $scriptPath; - /** @var string */ - private $basePath; + private string $basePath; - public function __construct($url = '/', string $scriptPath = '') + public function __construct(string|Url $url = '/', string $scriptPath = '') { - parent::__construct($url); $this->scriptPath = $scriptPath; + parent::__construct($url); $this->build(); } - /** @return static */ - public function withPath(string $path, string $scriptPath = '') + public function withPath(string $path, string $scriptPath = ''): static { $dolly = clone $this; $dolly->scriptPath = $scriptPath; diff --git a/src/Http/UserStorage.php b/src/Http/UserStorage.php deleted file mode 100644 index 0f283a53..00000000 --- a/src/Http/UserStorage.php +++ /dev/null @@ -1,185 +0,0 @@ -sessionHandler = $sessionHandler; - } - - - /** - * Sets the authenticated status of this user. - * @return static - */ - public function setAuthenticated(bool $state) - { - $section = $this->getSessionSection(true); - $section->authenticated = $state; - - // Session Fixation defence - $this->sessionHandler->regenerateId(); - - if ($state) { - $section->reason = null; - $section->authTime = time(); // informative value - - } else { - $section->reason = self::MANUAL; - $section->authTime = null; - } - return $this; - } - - - /** - * Is this user authenticated? - */ - public function isAuthenticated(): bool - { - $session = $this->getSessionSection(false); - return $session && $session->authenticated; - } - - - /** - * Sets the user identity. - * @return static - */ - public function setIdentity(?IIdentity $identity) - { - $this->getSessionSection(true)->identity = $identity; - return $this; - } - - - /** - * Returns current user identity, if any. - */ - public function getIdentity(): ?Nette\Security\IIdentity - { - $session = $this->getSessionSection(false); - return $session ? $session->identity : null; - } - - - /** - * Changes namespace; allows more users to share a session. - * @return static - */ - public function setNamespace(string $namespace) - { - if ($this->namespace !== $namespace) { - $this->namespace = $namespace; - $this->sessionSection = null; - } - return $this; - } - - - /** - * Returns current namespace. - */ - public function getNamespace(): string - { - return $this->namespace; - } - - - /** - * Enables log out after inactivity. Accepts flag IUserStorage::CLEAR_IDENTITY. - * @return static - */ - public function setExpiration(?string $time, int $flags = 0) - { - $section = $this->getSessionSection(true); - if ($time) { - $time = Nette\Utils\DateTime::from($time)->format('U'); - $section->expireTime = $time; - $section->expireDelta = $time - time(); - - } else { - unset($section->expireTime, $section->expireDelta); - } - - $section->expireIdentity = (bool) ($flags & self::CLEAR_IDENTITY); - $section->setExpiration($time, 'foo'); // time check - return $this; - } - - - /** - * Why was user logged out? - */ - public function getLogoutReason(): ?int - { - $session = $this->getSessionSection(false); - return $session ? $session->reason : null; - } - - - /** - * Returns and initializes $this->sessionSection. - */ - protected function getSessionSection(bool $need): ?SessionSection - { - if ($this->sessionSection !== null) { - return $this->sessionSection; - } - - if (!$need && !$this->sessionHandler->exists()) { - return null; - } - - $this->sessionSection = $section = $this->sessionHandler->getSection('Nette.Http.UserStorage/' . $this->namespace); - - if (!$section->identity instanceof IIdentity || !is_bool($section->authenticated)) { - $section->remove(); - } - - if ($section->authenticated && $section->expireDelta > 0) { // check time expiration - if ($section->expireTime < time()) { - $section->reason = self::INACTIVITY; - $section->authenticated = false; - if ($section->expireIdentity) { - unset($section->identity); - } - } - $section->expireTime = time() + $section->expireDelta; // sliding expiration - } - - if (!$section->authenticated) { - unset($section->expireTime, $section->expireDelta, $section->expireIdentity, $section->authTime); - } - - return $this->sessionSection; - } -} diff --git a/tests/Http.DI/HttpExtension.csp.phpt b/tests/Http.DI/HttpExtension.csp.phpt index 00f2665d..338a9f48 100644 --- a/tests/Http.DI/HttpExtension.csp.phpt +++ b/tests/Http.DI/HttpExtension.csp.phpt @@ -22,25 +22,25 @@ $compiler = new DI\Compiler; $compiler->addExtension('http', new HttpExtension); $loader = new DI\Config\Loader; $config = $loader->load(Tester\FileMock::create(<<<'EOD' -http: - csp: - default-src: "'self' https://example.com" - upgrade-insecure-requests: - script-src: 'nonce' - style-src: - - self - - https://example.com - - http: - require-sri-for: style - sandbox: allow-forms - plugin-types: application/x-java-applet - - cspReportOnly: - default-src: "'nonce'" - report-uri: https://example.com/report - upgrade-insecure-requests: true - block-all-mixed-content: false -EOD + http: + csp: + default-src: "'self' https://example.com" + upgrade-insecure-requests: + script-src: 'nonce' + style-src: + - self + - https://example.com + - http: + require-sri-for: style + sandbox: allow-forms + plugin-types: application/x-java-applet + + cspReportOnly: + default-src: "'nonce'" + report-uri: https://example.com/report + upgrade-insecure-requests: true + block-all-mixed-content: false + EOD , 'neon')); eval($compiler->addConfig($config)->compile()); diff --git a/tests/Http.DI/HttpExtension.featurePolicy.phpt b/tests/Http.DI/HttpExtension.featurePolicy.phpt index 9a792053..9d3db400 100644 --- a/tests/Http.DI/HttpExtension.featurePolicy.phpt +++ b/tests/Http.DI/HttpExtension.featurePolicy.phpt @@ -22,14 +22,14 @@ $compiler = new DI\Compiler; $compiler->addExtension('http', new HttpExtension); $loader = new DI\Config\Loader; $config = $loader->load(Tester\FileMock::create(<<<'EOD' -http: - featurePolicy: - unsized-media: none - geolocation: - - self - - https://example.com - camera: * -EOD + http: + featurePolicy: + unsized-media: none + geolocation: + - self + - https://example.com + camera: * + EOD , 'neon')); eval($compiler->addConfig($config)->compile()); @@ -38,7 +38,6 @@ $container = new Container; $container->initialize(); $headers = headers_list(); -var_dump($headers); Assert::contains("Feature-Policy: unsized-media 'none'; geolocation 'self' https://example.com; camera *;", $headers); diff --git a/tests/Http.DI/HttpExtension.headers.phpt b/tests/Http.DI/HttpExtension.headers.phpt index cac2a1ce..7d8b2c5c 100644 --- a/tests/Http.DI/HttpExtension.headers.phpt +++ b/tests/Http.DI/HttpExtension.headers.phpt @@ -22,12 +22,12 @@ $compiler = new DI\Compiler; $compiler->addExtension('http', new HttpExtension); $loader = new DI\Config\Loader; $config = $loader->load(Tester\FileMock::create(<<<'EOD' -http: - headers: - A: b - C: - D: 0 -EOD + http: + headers: + A: b + C: + D: 0 + EOD , 'neon')); eval($compiler->addConfig($config)->compile()); diff --git a/tests/Http.DI/HttpExtension.sameSiteProtection.phpt b/tests/Http.DI/HttpExtension.sameSiteProtection.phpt index 842d941d..88b10575 100644 --- a/tests/Http.DI/HttpExtension.sameSiteProtection.phpt +++ b/tests/Http.DI/HttpExtension.sameSiteProtection.phpt @@ -28,5 +28,5 @@ Assert::contains( PHP_VERSION_ID >= 70300 ? 'Set-Cookie: _nss=1; path=/; HttpOnly; SameSite=Strict' : 'Set-Cookie: _nss=1; path=/; SameSite=Strict; HttpOnly', - $headers + $headers, ); diff --git a/tests/Http.DI/SessionExtension.config.phpt b/tests/Http.DI/SessionExtension.config.phpt index 3c59656f..94c54460 100644 --- a/tests/Http.DI/SessionExtension.config.phpt +++ b/tests/Http.DI/SessionExtension.config.phpt @@ -42,5 +42,5 @@ Assert::same( PHP_VERSION_ID >= 70300 ? ['lifetime' => 0, 'path' => '/x', 'domain' => 'nette.org', 'secure' => true, 'httponly' => true, 'samesite' => 'Lax'] : ['lifetime' => 0, 'path' => '/x; SameSite=Lax', 'domain' => 'nette.org', 'secure' => true, 'httponly' => true], - session_get_cookie_params() + session_get_cookie_params(), ); diff --git a/tests/Http/Helpers.phpt b/tests/Http/Helpers.phpt index 8c94b5fa..3ccd3523 100644 --- a/tests/Http/Helpers.phpt +++ b/tests/Http/Helpers.phpt @@ -45,5 +45,5 @@ test('', function () { Assert::same('Tue, 15 Nov 1994 08:12:31 GMT', Helpers::formatDate('1994-11-15T08:12:31+0000')); Assert::same('Tue, 15 Nov 1994 08:12:31 GMT', Helpers::formatDate('1994-11-15T10:12:31+0200')); Assert::same('Tue, 15 Nov 1994 08:12:31 GMT', Helpers::formatDate(new DateTime('1994-11-15T06:12:31-0200'))); - Assert::same('Tue, 15 Nov 1994 08:12:31 GMT', Helpers::formatDate(784887151)); + Assert::same('Tue, 15 Nov 1994 08:12:31 GMT', Helpers::formatDate(784_887_151)); }); diff --git a/tests/Http/Request.getRawBody.phpt b/tests/Http/Request.getRawBody.phpt index d0155969..a6ef5b40 100644 --- a/tests/Http/Request.getRawBody.phpt +++ b/tests/Http/Request.getRawBody.phpt @@ -14,9 +14,7 @@ require __DIR__ . '/../bootstrap.php'; test('', function () { - $request = new Http\Request(new Http\UrlScript, null, null, null, null, null, null, null, function () { - return 'raw body'; - }); + $request = new Http\Request(new Http\UrlScript, null, null, null, null, null, null, null, fn() => 'raw body'); Assert::same('raw body', $request->getRawBody()); }); diff --git a/tests/Http/Response.setCookie.phpt b/tests/Http/Response.setCookie.phpt index e4f342b0..be98ee97 100644 --- a/tests/Http/Response.setCookie.phpt +++ b/tests/Http/Response.setCookie.phpt @@ -36,7 +36,7 @@ Assert::same( PHP_VERSION_ID >= 70300 ? ['Set-Cookie: test=value; path=/; HttpOnly; SameSite=Lax', 'Set-Cookie: test=newvalue; path=/; HttpOnly; SameSite=Lax'] : ['Set-Cookie: test=value; path=/; SameSite=Lax; HttpOnly', 'Set-Cookie: test=newvalue; path=/; SameSite=Lax; HttpOnly'], - $headers + $headers, ); diff --git a/tests/Http/Session.sameSite.phpt b/tests/Http/Session.sameSite.phpt index 6afc49e5..4bc89dd7 100644 --- a/tests/Http/Session.sameSite.phpt +++ b/tests/Http/Session.sameSite.phpt @@ -26,5 +26,5 @@ Assert::contains( PHP_VERSION_ID >= 70300 ? 'Set-Cookie: PHPSESSID=' . $session->getId() . '; path=/; HttpOnly; SameSite=Lax' : 'Set-Cookie: PHPSESSID=' . $session->getId() . '; path=/; SameSite=Lax; HttpOnly', - headers_list() + headers_list(), ); diff --git a/tests/Http/SessionSection.setExpiration().phpt b/tests/Http/SessionSection.setExpiration().phpt index ba02ed97..6ae1f68b 100644 --- a/tests/Http/SessionSection.setExpiration().phpt +++ b/tests/Http/SessionSection.setExpiration().phpt @@ -35,7 +35,7 @@ test('try to expire whole namespace', function () use ($session) { test('try to expire only 1 of the keys', function () use ($session) { $namespace = $session->getSection('expireSingle'); - $namespace->setExpiration(1, 'g'); + $namespace->setExpiration('1 second', 'g'); $namespace->g = 'guava'; $namespace->p = 'plum'; @@ -51,5 +51,5 @@ test('try to expire only 1 of the keys', function () use ($session) { // small expiration Assert::error(function () use ($session) { $namespace = $session->getSection('tmp'); - $namespace->setExpiration(100); + $namespace->setExpiration('100 second'); }, E_USER_NOTICE, 'The expiration time is greater than the session expiration %d% seconds'); diff --git a/tests/Http/SessionSection.setExpirationUnlimited.phpt b/tests/Http/SessionSection.setExpirationUnlimited.phpt index 2fcf7871..57566c08 100644 --- a/tests/Http/SessionSection.setExpirationUnlimited.phpt +++ b/tests/Http/SessionSection.setExpirationUnlimited.phpt @@ -18,6 +18,6 @@ $session->setOptions(['gc_maxlifetime' => '0']); //memcache handler supports unl //try to set section to shorter expiration $namespace = $session->getSection('maxlifetime'); -$namespace->setExpiration(100); +$namespace->setExpiration('100 second'); Assert::same(true, true); // fix Error: This test forgets to execute an assertion. diff --git a/tests/Http/Url.query.phpt b/tests/Http/Url.query.phpt index 15f89043..078abc08 100644 --- a/tests/Http/Url.query.phpt +++ b/tests/Http/Url.query.phpt @@ -17,10 +17,6 @@ $url = new Url('http://hostname/path?arg=value'); Assert::same('arg=value', $url->query); Assert::same(['arg' => 'value'], $url->getQueryParameters()); -$url->appendQuery(null); -Assert::same('arg=value', $url->query); -Assert::same(['arg' => 'value'], $url->getQueryParameters()); - $url->appendQuery([null]); Assert::same('arg=value', $url->query); Assert::same([null, 'arg' => 'value'], $url->getQueryParameters());