url = $url; $this->post = (array) $post; $this->files = (array) $files; $this->cookies = (array) $cookies; $this->headers = \array_change_key_case((array) $headers, \CASE_LOWER); $this->method = $method ?: 'GET'; $this->remoteAddress = $remoteAddress; $this->remoteHost = $remoteHost; $this->rawBodyCallback = $rawBodyCallback; } /** * Returns a clone with a different URL. * @return static */ public function withUrl(UrlScript $url) { $dolly = clone $this; $dolly->url = $url; return $dolly; } /** * Returns the URL of the request. */ public function getUrl() : UrlScript { return $this->url; } /********************* query, post, files & cookies ****************d*g**/ /** * 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) { 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); } /** * 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) { 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; } /** * Returns uploaded file. * @param string|string[] $key * @return ?FileUpload */ public function getFile($key) { $res = \Packetery\Nette\Utils\Arrays::get($this->files, $key, null); return $res instanceof FileUpload ? $res : null; } /** * Returns tree of upload files in a normalized structure, with each leaf an instance of \Packetery\Nette\Http\FileUpload. */ public function getFiles() : array { return $this->files; } /** * Returns a cookie or `null` if it does not exist. * @return mixed */ public function getCookie(string $key) { if (\func_num_args() > 1) { \trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', \E_USER_DEPRECATED); } return $this->cookies[$key] ?? null; } /** * Returns all cookies. */ public function getCookies() : array { return $this->cookies; } /********************* method & headers ****************d*g**/ /** * Returns the HTTP method with which the request was made (GET, POST, HEAD, PUT, ...). */ public function getMethod() : string { return $this->method; } /** * Checks the HTTP method with which the request was made. The parameter is case-insensitive. */ public function isMethod(string $method) : bool { return \strcasecmp($this->method, $method) === 0; } /** * Returns an HTTP header or `null` if it does not exist. The parameter is case-insensitive. */ 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; } /** * Returns all HTTP headers as associative array. */ public function getHeaders() : array { return $this->headers; } /** * What URL did the user come from? Beware, it is not reliable at all. * @deprecated deprecated in favor of the getOrigin() */ public function getReferer() : ?UrlImmutable { return isset($this->headers['referer']) ? new UrlImmutable($this->headers['referer']) : null; } /** * What origin did the user come from? It contains scheme, hostname and port. */ public function getOrigin() : ?UrlImmutable { $header = $this->headers['origin'] ?? 'null'; try { return $header === 'null' ? null : new UrlImmutable($header); } catch (\Packetery\Nette\InvalidArgumentException $e) { return null; } } /** * Is the request sent via secure channel (https)? */ public function isSecured() : bool { return $this->url->getScheme() === 'https'; } /** * Is the request coming from the same site and is initiated by clicking on a link? */ public function isSameSite() : bool { return isset($this->cookies[Helpers::StrictCookieName]); } /** * Is it an AJAX request? */ public function isAjax() : bool { return $this->getHeader('X-Requested-With') === 'XMLHttpRequest'; } /** * Returns the IP address of the remote client. */ public function getRemoteAddress() : ?string { return $this->remoteAddress; } /** * Returns the host of the remote client. */ public function getRemoteHost() : ?string { if ($this->remoteHost === null && $this->remoteAddress !== null) { $this->remoteHost = \gethostbyaddr($this->remoteAddress); } return $this->remoteHost; } /** * Returns raw content of HTTP request body. */ public function getRawBody() : ?string { return $this->rawBodyCallback ? ($this->rawBodyCallback)() : null; } /** * Returns basic HTTP authentication credentials. * @return array{string, string}|null */ public function getBasicCredentials() : ?array { return \preg_match('~^Basic (\\S+)$~', $this->headers['authorization'] ?? '', $t) && ($t = \base64_decode($t[1], \true)) && ($t = \explode(':', $t, 2)) && \count($t) === 2 ? $t : null; } /** * Returns the most preferred language by browser. Uses the `Accept-Language` header. If no match is reached, it returns `null`. * @param string[] $langs supported languages */ public function detectLanguage(array $langs) : ?string { $header = $this->getHeader('Accept-Language'); if (!$header) { return null; } $s = \strtolower($header); // case insensitive $s = \strtr($s, '_', '-'); // cs_CZ means cs-CZ \rsort($langs); // first more specific \preg_match_all('#(' . \implode('|', $langs) . ')(?:-[^\\s,;=]+)?\\s*(?:;\\s*q=([0-9.]+))?#', $s, $matches); if (!$matches[0]) { return null; } $max = 0; $lang = null; foreach ($matches[1] as $key => $value) { $q = $matches[2][$key] === '' ? 1.0 : (float) $matches[2][$key]; if ($q > $max) { $max = $q; $lang = $value; } } return $lang; } }