• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / http / 20543149098

27 Dec 2025 07:05PM UTC coverage: 83.579% (+0.2%) from 83.425%
20543149098

push

github

dg
added CLAUDE.md

906 of 1084 relevant lines covered (83.58%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.55
/src/Http/Request.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\Http;
11

12
use Nette;
13
use function array_change_key_case, base64_decode, count, explode, func_num_args, gethostbyaddr, implode, preg_match, preg_match_all, rsort, strcasecmp, strtolower, strtr;
14
use const CASE_LOWER;
15

16

17
/**
18
 * HttpRequest provides access scheme for request sent via HTTP.
19
 *
20
 * @property-read UrlScript $url
21
 * @property-read array $query
22
 * @property-read array $post
23
 * @property-read array $files
24
 * @property-read array $cookies
25
 * @property-read string $method
26
 * @property-read array $headers
27
 * @property-read UrlImmutable|null $referer
28
 * @property-read bool $secured
29
 * @property-read bool $ajax
30
 * @property-read string|null $remoteAddress
31
 * @property-read string|null $remoteHost
32
 * @property-read string|null $rawBody
33
 */
34
class Request implements IRequest
35
{
36
        use Nette\SmartObject;
37

38
        /** @var string[] */
39
        private readonly array $headers;
40

41
        private readonly ?\Closure $rawBodyCallback;
42

43

44
        public function __construct(
1✔
45
                private UrlScript $url,
46
                private readonly array $post = [],
47
                private readonly array $files = [],
48
                private readonly array $cookies = [],
49
                array $headers = [],
50
                private readonly string $method = 'GET',
51
                private readonly ?string $remoteAddress = null,
52
                private ?string $remoteHost = null,
53
                ?callable $rawBodyCallback = null,
54
        ) {
55
                $this->headers = array_change_key_case($headers, CASE_LOWER);
1✔
56
                $this->rawBodyCallback = $rawBodyCallback ? $rawBodyCallback(...) : null;
1✔
57
        }
1✔
58

59

60
        /**
61
         * Returns a clone with a different URL.
62
         */
63
        public function withUrl(UrlScript $url): static
1✔
64
        {
65
                $dolly = clone $this;
1✔
66
                $dolly->url = $url;
1✔
67
                return $dolly;
1✔
68
        }
69

70

71
        /**
72
         * Returns the URL of the request.
73
         */
74
        public function getUrl(): UrlScript
75
        {
76
                return $this->url;
1✔
77
        }
78

79

80
        /********************* query, post, files & cookies ****************d*g**/
81

82

83
        /**
84
         * Returns variable provided to the script via URL query ($_GET).
85
         * If no key is passed, returns the entire array.
86
         */
87
        public function getQuery(?string $key = null): mixed
1✔
88
        {
89
                if (func_num_args() === 0) {
1✔
90
                        return $this->url->getQueryParameters();
1✔
91
                }
92

93
                return $this->url->getQueryParameter($key);
1✔
94
        }
95

96

97
        /**
98
         * Returns variable provided to the script via POST method ($_POST).
99
         * If no key is passed, returns the entire array.
100
         */
101
        public function getPost(?string $key = null): mixed
1✔
102
        {
103
                if (func_num_args() === 0) {
1✔
104
                        return $this->post;
1✔
105
                }
106

107
                return $this->post[$key] ?? null;
1✔
108
        }
109

110

111
        /**
112
         * Returns uploaded file.
113
         * @param  string|string[]  $key
114
         */
115
        public function getFile($key): ?FileUpload
116
        {
117
                $res = Nette\Utils\Arrays::get($this->files, $key, null);
1✔
118
                return $res instanceof FileUpload ? $res : null;
1✔
119
        }
120

121

122
        /**
123
         * Returns tree of upload files in a normalized structure, with each leaf an instance of Nette\Http\FileUpload.
124
         */
125
        public function getFiles(): array
126
        {
127
                return $this->files;
1✔
128
        }
129

130

131
        /**
132
         * Returns a cookie or `null` if it does not exist.
133
         */
134
        public function getCookie(string $key): mixed
1✔
135
        {
136
                return $this->cookies[$key] ?? null;
1✔
137
        }
138

139

140
        /**
141
         * Returns all cookies.
142
         */
143
        public function getCookies(): array
144
        {
145
                return $this->cookies;
1✔
146
        }
147

148

149
        /********************* method & headers ****************d*g**/
150

151

152
        /**
153
         * Returns the HTTP method with which the request was made (GET, POST, HEAD, PUT, ...).
154
         */
155
        public function getMethod(): string
156
        {
157
                return $this->method;
1✔
158
        }
159

160

161
        /**
162
         * Checks the HTTP method with which the request was made. The parameter is case-insensitive.
163
         */
164
        public function isMethod(string $method): bool
165
        {
166
                return strcasecmp($this->method, $method) === 0;
×
167
        }
168

169

170
        /**
171
         * Returns an HTTP header or `null` if it does not exist. The parameter is case-insensitive.
172
         */
173
        public function getHeader(string $header): ?string
1✔
174
        {
175
                $header = strtolower($header);
1✔
176
                return $this->headers[$header] ?? null;
1✔
177
        }
178

179

180
        /**
181
         * Returns all HTTP headers as associative array.
182
         * @return string[]
183
         */
184
        public function getHeaders(): array
185
        {
186
                return $this->headers;
1✔
187
        }
188

189

190
        /**
191
         * What URL did the user come from? Beware, it is not reliable at all.
192
         * @deprecated  deprecated in favor of the getOrigin()
193
         */
194
        public function getReferer(): ?UrlImmutable
195
        {
196
                return isset($this->headers['referer'])
×
197
                        ? new UrlImmutable($this->headers['referer'])
×
198
                        : null;
×
199
        }
200

201

202
        /**
203
         * What origin did the user come from? It contains scheme, hostname and port.
204
         */
205
        public function getOrigin(): ?UrlImmutable
206
        {
207
                $header = $this->headers['origin'] ?? '';
1✔
208
                if (!preg_match('~^[a-z][a-z0-9+.-]*://[^/]+$~i', $header)) {
1✔
209
                        return null;
1✔
210
                }
211
                return new UrlImmutable($header);
1✔
212
        }
213

214

215
        /**
216
         * Is the request sent via secure channel (https)?
217
         */
218
        public function isSecured(): bool
219
        {
220
                return $this->url->getScheme() === 'https';
1✔
221
        }
222

223

224
        /**
225
         * Is the request coming from the same site and is initiated by clicking on a link?
226
         */
227
        public function isSameSite(): bool
228
        {
229
                return isset($this->cookies[Helpers::StrictCookieName]);
×
230
        }
231

232

233
        /**
234
         * Is it an AJAX request?
235
         */
236
        public function isAjax(): bool
237
        {
238
                return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
×
239
        }
240

241

242
        /**
243
         * Returns the IP address of the remote client.
244
         */
245
        public function getRemoteAddress(): ?string
246
        {
247
                return $this->remoteAddress;
1✔
248
        }
249

250

251
        /**
252
         * Returns the host of the remote client.
253
         */
254
        public function getRemoteHost(): ?string
255
        {
256
                if ($this->remoteHost === null && $this->remoteAddress !== null) {
1✔
257
                        $this->remoteHost = gethostbyaddr($this->remoteAddress);
1✔
258
                }
259

260
                return $this->remoteHost;
1✔
261
        }
262

263

264
        /**
265
         * Returns raw content of HTTP request body.
266
         */
267
        public function getRawBody(): ?string
268
        {
269
                return $this->rawBodyCallback ? ($this->rawBodyCallback)() : null;
1✔
270
        }
271

272

273
        /**
274
         * Returns basic HTTP authentication credentials.
275
         * @return array{string, string}|null
276
         */
277
        public function getBasicCredentials(): ?array
278
        {
279
                return preg_match(
1✔
280
                        '~^Basic (\S+)$~',
1✔
281
                        $this->headers['authorization'] ?? '',
1✔
282
                        $t,
1✔
283
                )
284
                        && ($t = base64_decode($t[1], strict: true))
1✔
285
                        && ($t = explode(':', $t, 2))
1✔
286
                        && (count($t) === 2)
1✔
287
                        ? $t
1✔
288
                        : null;
1✔
289
        }
290

291

292
        /**
293
         * Returns the most preferred language by browser. Uses the `Accept-Language` header. If no match is reached, it returns `null`.
294
         * @param  string[]  $langs  supported languages
295
         */
296
        public function detectLanguage(array $langs): ?string
1✔
297
        {
298
                $header = $this->getHeader('Accept-Language');
1✔
299
                if (!$header) {
1✔
300
                        return null;
1✔
301
                }
302

303
                $s = strtolower($header);  // case insensitive
1✔
304
                $s = strtr($s, '_', '-');  // cs_CZ means cs-CZ
1✔
305
                rsort($langs);             // first more specific
1✔
306
                preg_match_all('#(' . implode('|', $langs) . ')(?:-[^\s,;=]+)?\s*(?:;\s*q=([0-9.]+))?#', $s, $matches);
1✔
307

308
                if (!$matches[0]) {
1✔
309
                        return null;
1✔
310
                }
311

312
                $max = 0;
1✔
313
                $lang = null;
1✔
314
                foreach ($matches[1] as $key => $value) {
1✔
315
                        $q = $matches[2][$key] === '' ? 1.0 : (float) $matches[2][$key];
1✔
316
                        if ($q > $max) {
1✔
317
                                $max = $q;
1✔
318
                                $lang = $value;
1✔
319
                        }
320
                }
321

322
                return $lang;
1✔
323
        }
324
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc