ServerRequest::getParam()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11
 * @link          https://cakephp.org CakePHP(tm) Project
12
 * @since         2.0.0
13
 * @license       https://opensource.org/licenses/mit-license.php MIT License
14
 */
15
namespace Cake\Http;
16
17
use ArrayAccess;
18
use BadMethodCallException;
19
use Cake\Core\Configure;
20
use Cake\Http\Cookie\CookieCollection;
21
use Cake\Http\Exception\MethodNotAllowedException;
22
use Cake\Http\Session;
23
use Cake\Utility\Hash;
24
use InvalidArgumentException;
25
use Psr\Http\Message\ServerRequestInterface;
26
use Psr\Http\Message\StreamInterface;
27
use Psr\Http\Message\UploadedFileInterface;
28
use Psr\Http\Message\UriInterface;
29
use Zend\Diactoros\PhpInputStream;
30
use Zend\Diactoros\Stream;
31
use Zend\Diactoros\UploadedFile;
32
33
/**
34
 * A class that helps wrap Request information and particulars about a single request.
35
 * Provides methods commonly used to introspect on the request headers and request body.
36
 */
37
class ServerRequest implements ArrayAccess, ServerRequestInterface
38
{
39
    /**
40
     * Array of parameters parsed from the URL.
41
     *
42
     * @var array
43
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.
44
     */
45
    protected $params = [
46
        'plugin' => null,
47
        'controller' => null,
48
        'action' => null,
49
        '_ext' => null,
50
        'pass' => [],
51
    ];
52
53
    /**
54
     * Array of POST data. Will contain form data as well as uploaded files.
55
     * In PUT/PATCH/DELETE requests this property will contain the form-urlencoded
56
     * data.
57
     *
58
     * @var array|object|null
59
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.
60
     */
61
    protected $data = [];
62
63
    /**
64
     * Array of query string arguments
65
     *
66
     * @var array
67
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.
68
     */
69
    protected $query = [];
70
71
    /**
72
     * Array of cookie data.
73
     *
74
     * @var array
75
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.
76
     */
77
    protected $cookies = [];
78
79
    /**
80
     * Array of environment data.
81
     *
82
     * @var array
83
     */
84
    protected $_environment = [];
85
86
    /**
87
     * The URL string used for the request.
88
     *
89
     * @var string
90
     * @deprecated 3.6.0 This public property will be removed in 4.0.0. Use getPath() instead.
91
     */
92
    protected $url;
93
94
    /**
95
     * Base URL path.
96
     *
97
     * @var string
98
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead.
99
     */
100
    protected $base;
101
102
    /**
103
     * webroot path segment for the request.
104
     *
105
     * @var string
106
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('webroot') instead.
107
     */
108
    protected $webroot = '/';
109
110
    /**
111
     * The full address to the current request
112
     *
113
     * @var string
114
     * @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('here') or getUri()->getPath() instead.
115
     */
116
    protected $here;
117
118
    /**
119
     * Whether or not to trust HTTP_X headers set by most load balancers.
120
     * Only set to true if your application runs behind load balancers/proxies
121
     * that you control.
122
     *
123
     * @var bool
124
     */
125
    public $trustProxy = false;
126
127
    /**
128
     * Trusted proxies list
129
     *
130
     * @var string[]
131
     */
132
    protected $trustedProxies = [];
133
134
    /**
135
     * Contents of php://input
136
     *
137
     * @var string
138
     */
139
    protected $_input;
140
141
    /**
142
     * The built in detectors used with `is()` can be modified with `addDetector()`.
143
     *
144
     * There are several ways to specify a detector, see \Cake\Http\ServerRequest::addDetector() for the
145
     * various formats and ways to define detectors.
146
     *
147
     * @var array
148
     */
149
    protected static $_detectors = [
150
        'get' => ['env' => 'REQUEST_METHOD', 'value' => 'GET'],
151
        'post' => ['env' => 'REQUEST_METHOD', 'value' => 'POST'],
152
        'put' => ['env' => 'REQUEST_METHOD', 'value' => 'PUT'],
153
        'patch' => ['env' => 'REQUEST_METHOD', 'value' => 'PATCH'],
154
        'delete' => ['env' => 'REQUEST_METHOD', 'value' => 'DELETE'],
155
        'head' => ['env' => 'REQUEST_METHOD', 'value' => 'HEAD'],
156
        'options' => ['env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'],
157
        'ssl' => ['env' => 'HTTPS', 'options' => [1, 'on']],
158
        'ajax' => ['env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'],
159
        'flash' => ['env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'],
160
        'requested' => ['param' => 'requested', 'value' => 1],
161
        'json' => ['accept' => ['application/json'], 'param' => '_ext', 'value' => 'json'],
162
        'xml' => ['accept' => ['application/xml', 'text/xml'], 'param' => '_ext', 'value' => 'xml'],
163
    ];
164
165
    /**
166
     * Instance cache for results of is(something) calls
167
     *
168
     * @var array
169
     */
170
    protected $_detectorCache = [];
171
172
    /**
173
     * Request body stream. Contains php://input unless `input` constructor option is used.
174
     *
175
     * @var \Psr\Http\Message\StreamInterface
176
     */
177
    protected $stream;
178
179
    /**
180
     * Uri instance
181
     *
182
     * @var \Psr\Http\Message\UriInterface
183
     */
184
    protected $uri;
185
186
    /**
187
     * Instance of a Session object relative to this request
188
     *
189
     * @var \Cake\Http\Session
190
     */
191
    protected $session;
192
193
    /**
194
     * Store the additional attributes attached to the request.
195
     *
196
     * @var array
197
     */
198
    protected $attributes = [];
199
200
    /**
201
     * A list of propertes that emulated by the PSR7 attribute methods.
202
     *
203
     * @var array
204
     */
205
    protected $emulatedAttributes = ['session', 'webroot', 'base', 'params', 'here'];
206
207
    /**
208
     * Array of Psr\Http\Message\UploadedFileInterface objects.
209
     *
210
     * @var array
211
     */
212
    protected $uploadedFiles = [];
213
214
    /**
215
     * The HTTP protocol version used.
216
     *
217
     * @var string|null
218
     */
219
    protected $protocol;
220
221
    /**
222
     * The request target if overridden
223
     *
224
     * @var string|null
225
     */
226
    protected $requestTarget;
227
228
    /**
229
     * List of deprecated properties that have backwards
230
     * compatibility offered through magic methods.
231
     *
232
     * @var array
233
     */
234
    private $deprecatedProperties = [
235
        'data' => ['get' => 'getData()', 'set' => 'withData()'],
236
        'query' => ['get' => 'getQuery()', 'set' => 'withQueryParams()'],
237
        'params' => ['get' => 'getParam()', 'set' => 'withParam()'],
238
        'cookies' => ['get' => 'getCookie()', 'set' => 'withCookieParams()'],
239
        'url' => ['get' => 'getPath()', 'set' => 'withRequestTarget()'],
240
        'base' => ['get' => 'getAttribute("base")', 'set' => 'withAttribute("base")'],
241
        'webroot' => ['get' => 'getAttribute("webroot")', 'set' => 'withAttribute("webroot")'],
242
        'here' => ['get' => 'getAttribute("here")', 'set' => 'withAttribute("here")'],
243
    ];
244
245
    /**
246
     * Wrapper method to create a new request from PHP superglobals.
247
     *
248
     * Uses the $_GET, $_POST, $_FILES, $_COOKIE, $_SERVER, $_ENV and php://input data to construct
249
     * the request.
250
     *
251
     * @return self
252
     * @deprecated 3.4.0 Use `Cake\Http\ServerRequestFactory` instead.
253
     */
254
    public static function createFromGlobals()
255
    {
256
        deprecationWarning(
257
            'ServerRequest::createFromGlobals() is deprecated. ' .
258
            'Use `Cake\Http\ServerRequestFactory` instead.'
259
        );
260
261
        return ServerRequestFactory::fromGlobals();
262
    }
263
264
    /**
265
     * Create a new request object.
266
     *
267
     * You can supply the data as either an array or as a string. If you use
268
     * a string you can only supply the URL for the request. Using an array will
269
     * let you provide the following keys:
270
     *
271
     * - `post` POST data or non query string data
272
     * - `query` Additional data from the query string.
273
     * - `files` Uploaded file data formatted like $_FILES.
274
     * - `cookies` Cookies for this request.
275
     * - `environment` $_SERVER and $_ENV data.
276
     * - `url` The URL without the base path for the request.
277
     * - `uri` The PSR7 UriInterface object. If null, one will be created.
278
     * - `base` The base URL for the request.
279
     * - `webroot` The webroot directory for the request.
280
     * - `input` The data that would come from php://input this is useful for simulating
281
     *   requests with put, patch or delete data.
282
     * - `session` An instance of a Session object
283
     *
284
     * @param string|array $config An array of request data to create a request with.
285
     *   The string version of this argument is *deprecated* and will be removed in 4.0.0
286
     */
287
    public function __construct($config = [])
288
    {
289
        if (is_string($config)) {
290
            $config = ['url' => $config];
291
        }
292
        $config += [
293
            'params' => $this->params,
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
294
            'query' => [],
295
            'post' => [],
296
            'files' => [],
297
            'cookies' => [],
298
            'environment' => [],
299
            'url' => '',
300
            'uri' => null,
301
            'base' => '',
302
            'webroot' => '',
303
            'input' => null,
304
        ];
305
306
        $this->_setConfig($config);
307
    }
308
309
    /**
310
     * Process the config/settings data into properties.
311
     *
312
     * @param array $config The config data to use.
313
     * @return void
314
     */
315
    protected function _setConfig($config)
316
    {
317
        if (strlen($config['url']) > 1 && $config['url'][0] === '/') {
318
            $config['url'] = substr($config['url'], 1);
319
        }
320
321
        if (empty($config['session'])) {
322
            $config['session'] = new Session([
323
                'cookiePath' => $config['base'],
324
            ]);
325
        }
326
327
        $this->_environment = $config['environment'];
328
        $this->cookies = $config['cookies'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
329
330
        if (isset($config['uri']) && $config['uri'] instanceof UriInterface) {
331
            $uri = $config['uri'];
332
        } else {
333
            $uri = ServerRequestFactory::createUri($config['environment']);
334
        }
335
336
        // Extract a query string from config[url] if present.
337
        // This is required for backwards compatibility and keeping
338
        // UriInterface implementations happy.
339
        $querystr = '';
340
        if (strpos($config['url'], '?') !== false) {
341
            list($config['url'], $querystr) = explode('?', $config['url']);
342
        }
343
        if (strlen($config['url'])) {
344
            $uri = $uri->withPath('/' . $config['url']);
345
        }
346
        if (strlen($querystr)) {
347
            $uri = $uri->withQuery($querystr);
348
        }
349
350
        $this->uri = $uri;
351
        $this->base = $config['base'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$base has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
352
        $this->webroot = $config['webroot'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$webroot has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('webroot') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
353
354
        $this->url = substr($uri->getPath(), 1);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$url has been deprecated with message: 3.6.0 This public property will be removed in 4.0.0. Use getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
355
        $this->here = $this->base . '/' . $this->url;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$here has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('here') or getUri()->getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$base has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$url has been deprecated with message: 3.6.0 This public property will be removed in 4.0.0. Use getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
356
357 View Code Duplication
        if (isset($config['input'])) {
358
            $stream = new Stream('php://memory', 'rw');
359
            $stream->write($config['input']);
360
            $stream->rewind();
361
        } else {
362
            $stream = new PhpInputStream();
363
        }
364
        $this->stream = $stream;
365
366
        $config['post'] = $this->_processPost($config['post']);
367
        $this->data = $this->_processFiles($config['post'], $config['files']);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
368
        $this->query = $this->_processGet($config['query'], $querystr);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
369
        $this->params = $config['params'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
370
        $this->session = $config['session'];
371
    }
372
373
    /**
374
     * Sets the REQUEST_METHOD environment variable based on the simulated _method
375
     * HTTP override value. The 'ORIGINAL_REQUEST_METHOD' is also preserved, if you
376
     * want the read the non-simulated HTTP method the client used.
377
     *
378
     * @param array $data Array of post data.
379
     * @return array
380
     */
381
    protected function _processPost($data)
382
    {
383
        $method = $this->getEnv('REQUEST_METHOD');
384
        $override = false;
385
386
        if (
387
            in_array($method, ['PUT', 'DELETE', 'PATCH'], true) &&
388
            strpos($this->contentType(), 'application/x-www-form-urlencoded') === 0
389
        ) {
390
            $data = $this->input();
391
            parse_str($data, $data);
392
        }
393
        if ($this->hasHeader('X-Http-Method-Override')) {
394
            $data['_method'] = $this->getHeaderLine('X-Http-Method-Override');
395
            $override = true;
396
        }
397
        $this->_environment['ORIGINAL_REQUEST_METHOD'] = $method;
398
        if (isset($data['_method'])) {
399
            $this->_environment['REQUEST_METHOD'] = $data['_method'];
400
            unset($data['_method']);
401
            $override = true;
402
        }
403
404
        if ($override && !in_array($this->_environment['REQUEST_METHOD'], ['PUT', 'POST', 'DELETE', 'PATCH'], true)) {
405
            $data = [];
406
        }
407
408
        return $data;
409
    }
410
411
    /**
412
     * Process the GET parameters and move things into the object.
413
     *
414
     * @param array $query The array to which the parsed keys/values are being added.
415
     * @param string $queryString A query string from the URL if provided
416
     * @return array An array containing the parsed query string as keys/values.
417
     */
418
    protected function _processGet($query, $queryString = '')
419
    {
420
        $unsetUrl = '/' . str_replace(['.', ' '], '_', urldecode($this->url));
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$url has been deprecated with message: 3.6.0 This public property will be removed in 4.0.0. Use getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
421
        unset($query[$unsetUrl], $query[$this->base . $unsetUrl]);
422
        if (strlen($queryString)) {
423
            parse_str($queryString, $queryArgs);
424
            $query += $queryArgs;
425
        }
426
427
        return $query;
428
    }
429
430
    /**
431
     * Process uploaded files and move things onto the post data.
432
     *
433
     * @param array $post Post data to merge files onto.
434
     * @param array $files Uploaded files to merge in.
435
     * @return array merged post + file data.
436
     */
437
    protected function _processFiles($post, $files)
438
    {
439
        if (!is_array($files)) {
440
            return $post;
441
        }
442
        $fileData = [];
443
        foreach ($files as $key => $value) {
444
            if ($value instanceof UploadedFileInterface) {
445
                $fileData[$key] = $value;
446
                continue;
447
            }
448
449
            if (is_array($value) && isset($value['tmp_name'])) {
450
                $fileData[$key] = $this->_createUploadedFile($value);
451
                continue;
452
            }
453
454
            throw new InvalidArgumentException(sprintf(
455
                'Invalid value in FILES "%s"',
456
                json_encode($value)
457
            ));
458
        }
459
        $this->uploadedFiles = $fileData;
460
461
        // Make a flat map that can be inserted into $post for BC.
462
        $fileMap = Hash::flatten($fileData);
463
        foreach ($fileMap as $key => $file) {
464
            $error = $file->getError();
465
            $tmpName = '';
466
            if ($error === UPLOAD_ERR_OK) {
467
                $tmpName = $file->getStream()->getMetadata('uri');
468
            }
469
            $post = Hash::insert($post, $key, [
470
                'tmp_name' => $tmpName,
471
                'error' => $error,
472
                'name' => $file->getClientFilename(),
473
                'type' => $file->getClientMediaType(),
474
                'size' => $file->getSize(),
475
            ]);
476
        }
477
478
        return $post;
479
    }
480
481
    /**
482
     * Create an UploadedFile instance from a $_FILES array.
483
     *
484
     * If the value represents an array of values, this method will
485
     * recursively process the data.
486
     *
487
     * @param array $value $_FILES struct
488
     * @return array|UploadedFileInterface
489
     */
490
    protected function _createUploadedFile(array $value)
491
    {
492
        if (is_array($value['tmp_name'])) {
493
            return $this->_normalizeNestedFiles($value);
494
        }
495
496
        return new UploadedFile(
497
            $value['tmp_name'],
498
            $value['size'],
499
            $value['error'],
500
            $value['name'],
501
            $value['type']
502
        );
503
    }
504
505
    /**
506
     * Normalize an array of file specifications.
507
     *
508
     * Loops through all nested files and returns a normalized array of
509
     * UploadedFileInterface instances.
510
     *
511
     * @param array $files The file data to normalize & convert.
512
     * @return array An array of UploadedFileInterface objects.
513
     */
514
    protected function _normalizeNestedFiles(array $files = [])
515
    {
516
        $normalizedFiles = [];
517
        foreach (array_keys($files['tmp_name']) as $key) {
518
            $spec = [
519
                'tmp_name' => $files['tmp_name'][$key],
520
                'size' => $files['size'][$key],
521
                'error' => $files['error'][$key],
522
                'name' => $files['name'][$key],
523
                'type' => $files['type'][$key],
524
            ];
525
            $normalizedFiles[$key] = $this->_createUploadedFile($spec);
526
        }
527
528
        return $normalizedFiles;
529
    }
530
531
    /**
532
     * Get the content type used in this request.
533
     *
534
     * @return string
535
     */
536
    public function contentType()
537
    {
538
        $type = $this->getEnv('CONTENT_TYPE');
539
        if ($type) {
540
            return $type;
541
        }
542
543
        return $this->getEnv('HTTP_CONTENT_TYPE');
544
    }
545
546
    /**
547
     * Returns the instance of the Session object for this request
548
     *
549
     * @return \Cake\Http\Session
550
     */
551
    public function getSession()
552
    {
553
        return $this->session;
554
    }
555
556
    /**
557
     * Returns the instance of the Session object for this request
558
     *
559
     * If a session object is passed as first argument it will be set as
560
     * the session to use for this request
561
     *
562
     * @deprecated 3.5.0 Use getSession() instead. The setter part will be removed.
563
     * @param \Cake\Http\Session|null $session the session object to use
564
     * @return \Cake\Http\Session
565
     */
566
    public function session(Session $session = null)
567
    {
568
        deprecationWarning(
569
            'ServerRequest::session() is deprecated. ' .
570
            'Use getSession() instead. The setter part will be removed.'
571
        );
572
573
        if ($session === null) {
574
            return $this->session;
575
        }
576
577
        return $this->session = $session;
578
    }
579
580
    /**
581
     * Get the IP the client is using, or says they are using.
582
     *
583
     * @return string The client IP.
584
     */
585
    public function clientIp()
586
    {
587
        if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_FOR')) {
588
            $addresses = array_map('trim', explode(',', $this->getEnv('HTTP_X_FORWARDED_FOR')));
589
            $trusted = (count($this->trustedProxies) > 0);
590
            $n = count($addresses);
591
592
            if ($trusted) {
593
                $trusted = array_diff($addresses, $this->trustedProxies);
594
                $trusted = (count($trusted) === 1);
595
            }
596
597
            if ($trusted) {
598
                return $addresses[0];
599
            }
600
601
            return $addresses[$n - 1];
602
        }
603
604
        if ($this->trustProxy && $this->getEnv('HTTP_X_REAL_IP')) {
605
            $ipaddr = $this->getEnv('HTTP_X_REAL_IP');
606
        } elseif ($this->trustProxy && $this->getEnv('HTTP_CLIENT_IP')) {
607
            $ipaddr = $this->getEnv('HTTP_CLIENT_IP');
608
        } else {
609
            $ipaddr = $this->getEnv('REMOTE_ADDR');
610
        }
611
612
        return trim($ipaddr);
613
    }
614
615
    /**
616
     * register trusted proxies
617
     *
618
     * @param string[] $proxies ips list of trusted proxies
619
     * @return void
620
     */
621
    public function setTrustedProxies(array $proxies)
622
    {
623
        $this->trustedProxies = $proxies;
624
        $this->trustProxy = true;
625
    }
626
627
    /**
628
     * Get trusted proxies
629
     *
630
     * @return string[]
631
     */
632
    public function getTrustedProxies()
633
    {
634
        return $this->trustedProxies;
635
    }
636
637
    /**
638
     * Returns the referer that referred this request.
639
     *
640
     * @param bool $local Attempt to return a local address.
641
     *   Local addresses do not contain hostnames.
642
     * @return string The referring address for this request.
643
     */
644
    public function referer($local = false)
645
    {
646
        $ref = $this->getEnv('HTTP_REFERER');
647
648
        $base = Configure::read('App.fullBaseUrl') . $this->webroot;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$webroot has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('webroot') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
649
        if (!empty($ref) && !empty($base)) {
650
            if ($local && strpos($ref, $base) === 0) {
651
                $ref = substr($ref, strlen($base));
652
                if (!strlen($ref) || strpos($ref, '//') === 0) {
653
                    $ref = '/';
654
                }
655
                if ($ref[0] !== '/') {
656
                    $ref = '/' . $ref;
657
                }
658
659
                return $ref;
660
            }
661
            if (!$local) {
662
                return $ref;
663
            }
664
        }
665
666
        return '/';
667
    }
668
669
    /**
670
     * Missing method handler, handles wrapping older style isAjax() type methods
671
     *
672
     * @param string $name The method called
673
     * @param array $params Array of parameters for the method call
674
     * @return mixed
675
     * @throws \BadMethodCallException when an invalid method is called.
676
     */
677
    public function __call($name, $params)
678
    {
679
        if (strpos($name, 'is') === 0) {
680
            $type = strtolower(substr($name, 2));
681
682
            array_unshift($params, $type);
683
684
            return $this->is(...$params);
685
        }
686
        throw new BadMethodCallException(sprintf('Method "%s()" does not exist', $name));
687
    }
688
689
    /**
690
     * Magic set method allows backward compatibility for former public properties
691
     *
692
     *
693
     * @param string $name The property being accessed.
694
     * @param mixed $value The property value.
695
     * @return mixed Either the value of the parameter or null.
696
     * @deprecated 3.6.0 Public properties will be removed in 4.0.0.
697
     *   Use appropriate setters instead.
698
     */
699
    public function __set($name, $value)
700
    {
701 View Code Duplication
        if (isset($this->deprecatedProperties[$name])) {
702
            $method = $this->deprecatedProperties[$name]['set'];
703
            deprecationWarning(
704
                "Setting {$name} as a property will be removed in 4.0.0. " .
705
                "Use {$method} instead."
706
            );
707
708
            return $this->{$name} = $value;
709
        }
710
        throw new BadMethodCallException("Cannot set {$name} it is not a known property.");
711
    }
712
713
    /**
714
     * Magic get method allows access to parsed routing parameters directly on the object.
715
     *
716
     * Allows access to `$this->params['controller']` via `$this->controller`
717
     *
718
     * @param string $name The property being accessed.
719
     * @return mixed Either the value of the parameter or null.
720
     * @deprecated 3.4.0 Accessing routing parameters through __get will removed in 4.0.0.
721
     *   Use getParam() instead.
722
     */
723
    public function &__get($name)
724
    {
725 View Code Duplication
        if (isset($this->deprecatedProperties[$name])) {
726
            $method = $this->deprecatedProperties[$name]['get'];
727
            deprecationWarning(
728
                "Accessing `{$name}` as a property will be removed in 4.0.0. " .
729
                "Use request->{$method} instead."
730
            );
731
732
            return $this->{$name};
733
        }
734
735
        deprecationWarning(sprintf(
736
            'Accessing routing parameters through `%s` will removed in 4.0.0. ' .
737
            'Use `getParam()` instead.',
738
            $name
739
        ));
740
741
        if (isset($this->params[$name])) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
742
            return $this->params[$name];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
743
        }
744
        $value = null;
745
746
        return $value;
747
    }
748
749
    /**
750
     * Magic isset method allows isset/empty checks
751
     * on routing parameters.
752
     *
753
     * @param string $name The property being accessed.
754
     * @return bool Existence
755
     * @deprecated 3.4.0 Accessing routing parameters through __isset will removed in 4.0.0.
756
     *   Use getParam() instead.
757
     */
758
    public function __isset($name)
759
    {
760 View Code Duplication
        if (isset($this->deprecatedProperties[$name])) {
761
            $method = $this->deprecatedProperties[$name]['get'];
762
            deprecationWarning(
763
                "Accessing {$name} as a property will be removed in 4.0.0. " .
764
                "Use {$method} instead."
765
            );
766
767
            return isset($this->{$name});
768
        }
769
770
        deprecationWarning(
771
            'Accessing routing parameters through __isset will removed in 4.0.0. ' .
772
            'Use getParam() instead.'
773
        );
774
775
        return isset($this->params[$name]);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
776
    }
777
778
    /**
779
     * Check whether or not a Request is a certain type.
780
     *
781
     * Uses the built in detection rules as well as additional rules
782
     * defined with Cake\Http\ServerRequest::addDetector(). Any detector can be called
783
     * as `is($type)` or `is$Type()`.
784
     *
785
     * @param string|array $type The type of request you want to check. If an array
786
     *   this method will return true if the request matches any type.
787
     * @param array ...$args List of arguments
788
     * @return bool Whether or not the request is the type you are checking.
789
     */
790
    public function is($type, ...$args)
791
    {
792
        if (is_array($type)) {
793
            $result = array_map([$this, 'is'], $type);
794
795
            return count(array_filter($result)) > 0;
796
        }
797
798
        $type = strtolower($type);
799
        if (!isset(static::$_detectors[$type])) {
800
            return false;
801
        }
802
        if ($args) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $args of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
803
            return $this->_is($type, $args);
804
        }
805
        if (!isset($this->_detectorCache[$type])) {
806
            $this->_detectorCache[$type] = $this->_is($type, $args);
807
        }
808
809
        return $this->_detectorCache[$type];
810
    }
811
812
    /**
813
     * Clears the instance detector cache, used by the is() function
814
     *
815
     * @return void
816
     */
817
    public function clearDetectorCache()
818
    {
819
        $this->_detectorCache = [];
820
    }
821
822
    /**
823
     * Worker for the public is() function
824
     *
825
     * @param string $type The type of request you want to check.
826
     * @param array $args Array of custom detector arguments.
827
     * @return bool Whether or not the request is the type you are checking.
828
     */
829
    protected function _is($type, $args)
830
    {
831
        $detect = static::$_detectors[$type];
832
        if (is_callable($detect)) {
833
            array_unshift($args, $this);
834
835
            return $detect(...$args);
836
        }
837
        if (isset($detect['env']) && $this->_environmentDetector($detect)) {
838
            return true;
839
        }
840
        if (isset($detect['header']) && $this->_headerDetector($detect)) {
841
            return true;
842
        }
843
        if (isset($detect['accept']) && $this->_acceptHeaderDetector($detect)) {
844
            return true;
845
        }
846
        if (isset($detect['param']) && $this->_paramDetector($detect)) {
847
            return true;
848
        }
849
850
        return false;
851
    }
852
853
    /**
854
     * Detects if a specific accept header is present.
855
     *
856
     * @param array $detect Detector options array.
857
     * @return bool Whether or not the request is the type you are checking.
858
     */
859
    protected function _acceptHeaderDetector($detect)
860
    {
861
        $acceptHeaders = explode(',', $this->getEnv('HTTP_ACCEPT'));
862
        foreach ($detect['accept'] as $header) {
863
            if (in_array($header, $acceptHeaders)) {
864
                return true;
865
            }
866
        }
867
868
        return false;
869
    }
870
871
    /**
872
     * Detects if a specific header is present.
873
     *
874
     * @param array $detect Detector options array.
875
     * @return bool Whether or not the request is the type you are checking.
876
     */
877
    protected function _headerDetector($detect)
878
    {
879
        foreach ($detect['header'] as $header => $value) {
880
            $header = $this->getEnv('http_' . $header);
881
            if ($header !== null) {
882
                if (!is_string($value) && !is_bool($value) && is_callable($value)) {
883
                    return call_user_func($value, $header);
884
                }
885
886
                return ($header === $value);
887
            }
888
        }
889
890
        return false;
891
    }
892
893
    /**
894
     * Detects if a specific request parameter is present.
895
     *
896
     * @param array $detect Detector options array.
897
     * @return bool Whether or not the request is the type you are checking.
898
     */
899
    protected function _paramDetector($detect)
900
    {
901
        $key = $detect['param'];
902 View Code Duplication
        if (isset($detect['value'])) {
903
            $value = $detect['value'];
904
905
            return isset($this->params[$key]) ? $this->params[$key] == $value : false;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
906
        }
907 View Code Duplication
        if (isset($detect['options'])) {
908
            return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
909
        }
910
911
        return false;
912
    }
913
914
    /**
915
     * Detects if a specific environment variable is present.
916
     *
917
     * @param array $detect Detector options array.
918
     * @return bool Whether or not the request is the type you are checking.
919
     */
920
    protected function _environmentDetector($detect)
921
    {
922
        if (isset($detect['env'])) {
923
            if (isset($detect['value'])) {
924
                return $this->getEnv($detect['env']) == $detect['value'];
925
            }
926
            if (isset($detect['pattern'])) {
927
                return (bool)preg_match($detect['pattern'], $this->getEnv($detect['env']));
928
            }
929
            if (isset($detect['options'])) {
930
                $pattern = '/' . implode('|', $detect['options']) . '/i';
931
932
                return (bool)preg_match($pattern, $this->getEnv($detect['env']));
933
            }
934
        }
935
936
        return false;
937
    }
938
939
    /**
940
     * Check that a request matches all the given types.
941
     *
942
     * Allows you to test multiple types and union the results.
943
     * See Request::is() for how to add additional types and the
944
     * built-in types.
945
     *
946
     * @param string[] $types The types to check.
947
     * @return bool Success.
948
     * @see \Cake\Http\ServerRequest::is()
949
     */
950
    public function isAll(array $types)
951
    {
952
        $result = array_filter(array_map([$this, 'is'], $types));
953
954
        return count($result) === count($types);
955
    }
956
957
    /**
958
     * Add a new detector to the list of detectors that a request can use.
959
     * There are several different types of detectors that can be set.
960
     *
961
     * ### Callback comparison
962
     *
963
     * Callback detectors allow you to provide a callable to handle the check.
964
     * The callback will receive the request object as its only parameter.
965
     *
966
     * ```
967
     * addDetector('custom', function ($request) { //Return a boolean });
968
     * ```
969
     *
970
     * ### Environment value comparison
971
     *
972
     * An environment value comparison, compares a value fetched from `env()` to a known value
973
     * the environment value is equality checked against the provided value.
974
     *
975
     * ```
976
     * addDetector('post', ['env' => 'REQUEST_METHOD', 'value' => 'POST']);
977
     * ```
978
     *
979
     * ### Request parameter comparison
980
     *
981
     * Allows for custom detectors on the request parameters.
982
     *
983
     * ```
984
     * addDetector('requested', ['param' => 'requested', 'value' => 1]);
985
     * ```
986
     *
987
     * ### Accept comparison
988
     *
989
     * Allows for detector to compare against Accept header value.
990
     *
991
     * ```
992
     * addDetector('csv', ['accept' => 'text/csv']);
993
     * ```
994
     *
995
     * ### Header comparison
996
     *
997
     * Allows for one or more headers to be compared.
998
     *
999
     * ```
1000
     * addDetector('fancy', ['header' => ['X-Fancy' => 1]);
1001
     * ```
1002
     *
1003
     * The `param`, `env` and comparison types allow the following
1004
     * value comparison options:
1005
     *
1006
     * ### Pattern value comparison
1007
     *
1008
     * Pattern value comparison allows you to compare a value fetched from `env()` to a regular expression.
1009
     *
1010
     * ```
1011
     * addDetector('iphone', ['env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i']);
1012
     * ```
1013
     *
1014
     * ### Option based comparison
1015
     *
1016
     * Option based comparisons use a list of options to create a regular expression. Subsequent calls
1017
     * to add an already defined options detector will merge the options.
1018
     *
1019
     * ```
1020
     * addDetector('mobile', ['env' => 'HTTP_USER_AGENT', 'options' => ['Fennec']]);
1021
     * ```
1022
     *
1023
     * You can also make compare against multiple values
1024
     * using the `options` key. This is useful when you want to check
1025
     * if a request value is in a list of options.
1026
     *
1027
     * `addDetector('extension', ['param' => '_ext', 'options' => ['pdf', 'csv']]`
1028
     *
1029
     * @param string $name The name of the detector.
1030
     * @param callable|array $callable A callable or options array for the detector definition.
1031
     * @return void
1032
     */
1033
    public static function addDetector($name, $callable)
1034
    {
1035
        $name = strtolower($name);
1036
        if (is_callable($callable)) {
1037
            static::$_detectors[$name] = $callable;
1038
1039
            return;
1040
        }
1041
        if (isset(static::$_detectors[$name], $callable['options'])) {
1042
            $callable = Hash::merge(static::$_detectors[$name], $callable);
1043
        }
1044
        static::$_detectors[$name] = $callable;
1045
    }
1046
1047
    /**
1048
     * Add parameters to the request's parsed parameter set. This will overwrite any existing parameters.
1049
     * This modifies the parameters available through `$request->getParam()`.
1050
     *
1051
     * @param array $params Array of parameters to merge in
1052
     * @return $this The current object, you can chain this method.
1053
     * @deprecated 3.6.0 ServerRequest::addParams() is deprecated. Use `withParam()` or
1054
     *   `withAttribute('params')` instead.
1055
     */
1056
    public function addParams(array $params)
1057
    {
1058
        deprecationWarning(
1059
            'ServerRequest::addParams() is deprecated. ' .
1060
            'Use `withParam()` or `withAttribute("params", $params)` instead.'
1061
        );
1062
        $this->params = array_merge($this->params, $params);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1063
1064
        return $this;
1065
    }
1066
1067
    /**
1068
     * Add paths to the requests' paths vars. This will overwrite any existing paths.
1069
     * Provides an easy way to modify, here, webroot and base.
1070
     *
1071
     * @param array $paths Array of paths to merge in
1072
     * @return $this The current object, you can chain this method.
1073
     * @deprecated 3.6.0 Mutating a request in place is deprecated. Use `withAttribute()` to modify paths instead.
1074
     */
1075
    public function addPaths(array $paths)
1076
    {
1077
        deprecationWarning(
1078
            'ServerRequest::addPaths() is deprecated. ' .
1079
            'Use `withAttribute($key, $value)` instead.'
1080
        );
1081
        foreach (['webroot', 'here', 'base'] as $element) {
1082
            if (isset($paths[$element])) {
1083
                $this->{$element} = $paths[$element];
1084
            }
1085
        }
1086
1087
        return $this;
1088
    }
1089
1090
    /**
1091
     * Get the value of the current requests URL. Will include the query string arguments.
1092
     *
1093
     * @param bool $base Include the base path, set to false to trim the base path off.
1094
     * @return string The current request URL including query string args.
1095
     * @deprecated 3.4.0 This method will be removed in 4.0.0. You should use getRequestTarget() instead.
1096
     */
1097
    public function here($base = true)
1098
    {
1099
        deprecationWarning(
1100
            'ServerRequest::here() will be removed in 4.0.0. You should use getRequestTarget() instead.'
1101
        );
1102
1103
        $url = $this->here;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$here has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('here') or getUri()->getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1104
        if (!empty($this->query)) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1105
            $url .= '?' . http_build_query($this->query, null, '&');
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1106
        }
1107
        if (!$base) {
1108
            $url = preg_replace('/^' . preg_quote($this->base, '/') . '/', '', $url, 1);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$base has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1109
        }
1110
1111
        return $url;
1112
    }
1113
1114
    /**
1115
     * Normalize a header name into the SERVER version.
1116
     *
1117
     * @param string $name The header name.
1118
     * @return string The normalized header name.
1119
     */
1120
    protected function normalizeHeaderName($name)
1121
    {
1122
        $name = str_replace('-', '_', strtoupper($name));
1123
        if (!in_array($name, ['CONTENT_LENGTH', 'CONTENT_TYPE'], true)) {
1124
            $name = 'HTTP_' . $name;
1125
        }
1126
1127
        return $name;
1128
    }
1129
1130
    /**
1131
     * Read an HTTP header from the Request information.
1132
     *
1133
     * If the header is not defined in the request, this method
1134
     * will fallback to reading data from $_SERVER and $_ENV.
1135
     * This fallback behavior is deprecated, and will be removed in 4.0.0
1136
     *
1137
     * @param string $name Name of the header you want.
1138
     * @return string|null Either null on no header being set or the value of the header.
1139
     * @deprecated 4.0.0 The automatic fallback to env() will be removed in 4.0.0, see getHeader()
1140
     */
1141
    public function header($name)
1142
    {
1143
        deprecationWarning(
1144
            'ServerRequest::header() is deprecated. ' .
1145
            'The automatic fallback to env() will be removed in 4.0.0, see getHeader()'
1146
        );
1147
1148
        $name = $this->normalizeHeaderName($name);
1149
1150
        return $this->getEnv($name);
1151
    }
1152
1153
    /**
1154
     * Get all headers in the request.
1155
     *
1156
     * Returns an associative array where the header names are
1157
     * the keys and the values are a list of header values.
1158
     *
1159
     * While header names are not case-sensitive, getHeaders() will normalize
1160
     * the headers.
1161
     *
1162
     * @return array An associative array of headers and their values.
1163
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1164
     */
1165
    public function getHeaders()
1166
    {
1167
        $headers = [];
1168
        foreach ($this->_environment as $key => $value) {
1169
            $name = null;
1170
            if (strpos($key, 'HTTP_') === 0) {
1171
                $name = substr($key, 5);
1172
            }
1173
            if (strpos($key, 'CONTENT_') === 0) {
1174
                $name = $key;
1175
            }
1176
            if ($name !== null) {
1177
                $name = str_replace('_', ' ', strtolower($name));
1178
                $name = str_replace(' ', '-', ucwords($name));
1179
                $headers[$name] = (array)$value;
1180
            }
1181
        }
1182
1183
        return $headers;
1184
    }
1185
1186
    /**
1187
     * Check if a header is set in the request.
1188
     *
1189
     * @param string $name The header you want to get (case-insensitive)
1190
     * @return bool Whether or not the header is defined.
1191
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1192
     */
1193
    public function hasHeader($name)
1194
    {
1195
        $name = $this->normalizeHeaderName($name);
1196
1197
        return isset($this->_environment[$name]);
1198
    }
1199
1200
    /**
1201
     * Get a single header from the request.
1202
     *
1203
     * Return the header value as an array. If the header
1204
     * is not present an empty array will be returned.
1205
     *
1206
     * @param string $name The header you want to get (case-insensitive)
1207
     * @return array An associative array of headers and their values.
1208
     *   If the header doesn't exist, an empty array will be returned.
1209
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1210
     */
1211
    public function getHeader($name)
1212
    {
1213
        $name = $this->normalizeHeaderName($name);
1214
        if (isset($this->_environment[$name])) {
1215
            return (array)$this->_environment[$name];
1216
        }
1217
1218
        return [];
1219
    }
1220
1221
    /**
1222
     * Get a single header as a string from the request.
1223
     *
1224
     * @param string $name The header you want to get (case-insensitive)
1225
     * @return string Header values collapsed into a comma separated string.
1226
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1227
     */
1228
    public function getHeaderLine($name)
1229
    {
1230
        $value = $this->getHeader($name);
1231
1232
        return implode(', ', $value);
1233
    }
1234
1235
    /**
1236
     * Get a modified request with the provided header.
1237
     *
1238
     * @param string $name The header name.
1239
     * @param string|array $value The header value
1240
     * @return static
1241
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1242
     */
1243 View Code Duplication
    public function withHeader($name, $value)
1244
    {
1245
        $new = clone $this;
1246
        $name = $this->normalizeHeaderName($name);
1247
        $new->_environment[$name] = $value;
1248
1249
        return $new;
1250
    }
1251
1252
    /**
1253
     * Get a modified request with the provided header.
1254
     *
1255
     * Existing header values will be retained. The provided value
1256
     * will be appended into the existing values.
1257
     *
1258
     * @param string $name The header name.
1259
     * @param string|array $value The header value
1260
     * @return static
1261
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1262
     */
1263
    public function withAddedHeader($name, $value)
1264
    {
1265
        $new = clone $this;
1266
        $name = $this->normalizeHeaderName($name);
1267
        $existing = [];
1268
        if (isset($new->_environment[$name])) {
1269
            $existing = (array)$new->_environment[$name];
1270
        }
1271
        $existing = array_merge($existing, (array)$value);
1272
        $new->_environment[$name] = $existing;
1273
1274
        return $new;
1275
    }
1276
1277
    /**
1278
     * Get a modified request without a provided header.
1279
     *
1280
     * @param string $name The header name to remove.
1281
     * @return static
1282
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1283
     */
1284 View Code Duplication
    public function withoutHeader($name)
1285
    {
1286
        $new = clone $this;
1287
        $name = $this->normalizeHeaderName($name);
1288
        unset($new->_environment[$name]);
1289
1290
        return $new;
1291
    }
1292
1293
    /**
1294
     * Get the HTTP method used for this request.
1295
     *
1296
     * @return string The name of the HTTP method used.
1297
     * @deprecated 3.4.0 This method will be removed in 4.0.0. Use getMethod() instead.
1298
     */
1299
    public function method()
1300
    {
1301
        deprecationWarning(
1302
            'ServerRequest::method() is deprecated. ' .
1303
            'This method will be removed in 4.0.0. Use getMethod() instead.'
1304
        );
1305
1306
        return $this->getEnv('REQUEST_METHOD');
1307
    }
1308
1309
    /**
1310
     * Get the HTTP method used for this request.
1311
     * There are a few ways to specify a method.
1312
     *
1313
     * - If your client supports it you can use native HTTP methods.
1314
     * - You can set the HTTP-X-Method-Override header.
1315
     * - You can submit an input with the name `_method`
1316
     *
1317
     * Any of these 3 approaches can be used to set the HTTP method used
1318
     * by CakePHP internally, and will effect the result of this method.
1319
     *
1320
     * @return string The name of the HTTP method used.
1321
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1322
     */
1323
    public function getMethod()
1324
    {
1325
        return $this->getEnv('REQUEST_METHOD');
1326
    }
1327
1328
    /**
1329
     * Update the request method and get a new instance.
1330
     *
1331
     * @param string $method The HTTP method to use.
1332
     * @return static A new instance with the updated method.
1333
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1334
     */
1335
    public function withMethod($method)
1336
    {
1337
        $new = clone $this;
1338
1339
        if (
1340
            !is_string($method) ||
1341
            !preg_match('/^[!#$%&\'*+.^_`\|~0-9a-z-]+$/i', $method)
1342
        ) {
1343
            throw new InvalidArgumentException(sprintf(
1344
                'Unsupported HTTP method "%s" provided',
1345
                $method
1346
            ));
1347
        }
1348
        $new->_environment['REQUEST_METHOD'] = $method;
1349
1350
        return $new;
1351
    }
1352
1353
    /**
1354
     * Get all the server environment parameters.
1355
     *
1356
     * Read all of the 'environment' or 'server' data that was
1357
     * used to create this request.
1358
     *
1359
     * @return array
1360
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1361
     */
1362
    public function getServerParams()
1363
    {
1364
        return $this->_environment;
1365
    }
1366
1367
    /**
1368
     * Get all the query parameters in accordance to the PSR-7 specifications. To read specific query values
1369
     * use the alternative getQuery() method.
1370
     *
1371
     * @return array
1372
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1373
     */
1374
    public function getQueryParams()
1375
    {
1376
        return $this->query;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1377
    }
1378
1379
    /**
1380
     * Update the query string data and get a new instance.
1381
     *
1382
     * @param array $query The query string data to use
1383
     * @return static A new instance with the updated query string data.
1384
     * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface.
1385
     */
1386
    public function withQueryParams(array $query)
1387
    {
1388
        $new = clone $this;
1389
        $new->query = $query;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1390
1391
        return $new;
1392
    }
1393
1394
    /**
1395
     * Get the host that the request was handled on.
1396
     *
1397
     * @return string
1398
     */
1399
    public function host()
1400
    {
1401
        if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_HOST')) {
1402
            return $this->getEnv('HTTP_X_FORWARDED_HOST');
1403
        }
1404
1405
        return $this->getEnv('HTTP_HOST');
1406
    }
1407
1408
    /**
1409
     * Get the port the request was handled on.
1410
     *
1411
     * @return string
1412
     */
1413
    public function port()
1414
    {
1415
        if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_PORT')) {
1416
            return $this->getEnv('HTTP_X_FORWARDED_PORT');
1417
        }
1418
1419
        return $this->getEnv('SERVER_PORT');
1420
    }
1421
1422
    /**
1423
     * Get the current url scheme used for the request.
1424
     *
1425
     * e.g. 'http', or 'https'
1426
     *
1427
     * @return string The scheme used for the request.
1428
     */
1429
    public function scheme()
1430
    {
1431
        if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_PROTO')) {
1432
            return $this->getEnv('HTTP_X_FORWARDED_PROTO');
1433
        }
1434
1435
        return $this->getEnv('HTTPS') ? 'https' : 'http';
1436
    }
1437
1438
    /**
1439
     * Get the domain name and include $tldLength segments of the tld.
1440
     *
1441
     * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
1442
     *   While `example.co.uk` contains 2.
1443
     * @return string Domain name without subdomains.
1444
     */
1445
    public function domain($tldLength = 1)
1446
    {
1447
        $segments = explode('.', $this->host());
1448
        $domain = array_slice($segments, -1 * ($tldLength + 1));
1449
1450
        return implode('.', $domain);
1451
    }
1452
1453
    /**
1454
     * Get the subdomains for a host.
1455
     *
1456
     * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
1457
     *   While `example.co.uk` contains 2.
1458
     * @return array An array of subdomains.
1459
     */
1460
    public function subdomains($tldLength = 1)
1461
    {
1462
        $segments = explode('.', $this->host());
1463
1464
        return array_slice($segments, 0, -1 * ($tldLength + 1));
1465
    }
1466
1467
    /**
1468
     * Find out which content types the client accepts or check if they accept a
1469
     * particular type of content.
1470
     *
1471
     * #### Get all types:
1472
     *
1473
     * ```
1474
     * $this->request->accepts();
1475
     * ```
1476
     *
1477
     * #### Check for a single type:
1478
     *
1479
     * ```
1480
     * $this->request->accepts('application/json');
1481
     * ```
1482
     *
1483
     * This method will order the returned content types by the preference values indicated
1484
     * by the client.
1485
     *
1486
     * @param string|null $type The content type to check for. Leave null to get all types a client accepts.
1487
     * @return array|bool Either an array of all the types the client accepts or a boolean if they accept the
1488
     *   provided type.
1489
     */
1490
    public function accepts($type = null)
1491
    {
1492
        $raw = $this->parseAccept();
1493
        $accept = [];
1494
        foreach ($raw as $types) {
1495
            $accept = array_merge($accept, $types);
1496
        }
1497
        if ($type === null) {
1498
            return $accept;
1499
        }
1500
1501
        return in_array($type, $accept, true);
1502
    }
1503
1504
    /**
1505
     * Parse the HTTP_ACCEPT header and return a sorted array with content types
1506
     * as the keys, and pref values as the values.
1507
     *
1508
     * Generally you want to use Cake\Http\ServerRequest::accept() to get a simple list
1509
     * of the accepted content types.
1510
     *
1511
     * @return array An array of prefValue => [content/types]
1512
     */
1513
    public function parseAccept()
1514
    {
1515
        return $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept'));
1516
    }
1517
1518
    /**
1519
     * Get the languages accepted by the client, or check if a specific language is accepted.
1520
     *
1521
     * Get the list of accepted languages:
1522
     *
1523
     * ``` \Cake\Http\ServerRequest::acceptLanguage(); ```
1524
     *
1525
     * Check if a specific language is accepted:
1526
     *
1527
     * ``` \Cake\Http\ServerRequest::acceptLanguage('es-es'); ```
1528
     *
1529
     * @param string|null $language The language to test.
1530
     * @return array|bool If a $language is provided, a boolean. Otherwise the array of accepted languages.
1531
     */
1532
    public function acceptLanguage($language = null)
1533
    {
1534
        $raw = $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept-Language'));
1535
        $accept = [];
1536
        foreach ($raw as $languages) {
1537
            foreach ($languages as &$lang) {
1538
                if (strpos($lang, '_')) {
1539
                    $lang = str_replace('_', '-', $lang);
1540
                }
1541
                $lang = strtolower($lang);
1542
            }
1543
            $accept = array_merge($accept, $languages);
1544
        }
1545
        if ($language === null) {
1546
            return $accept;
1547
        }
1548
1549
        return in_array(strtolower($language), $accept, true);
1550
    }
1551
1552
    /**
1553
     * Parse Accept* headers with qualifier options.
1554
     *
1555
     * Only qualifiers will be extracted, any other accept extensions will be
1556
     * discarded as they are not frequently used.
1557
     *
1558
     * @param string $header Header to parse.
1559
     * @return array
1560
     */
1561
    protected function _parseAcceptWithQualifier($header)
1562
    {
1563
        $accept = [];
1564
        $headers = explode(',', $header);
1565
        foreach (array_filter($headers) as $value) {
1566
            $prefValue = '1.0';
1567
            $value = trim($value);
1568
1569
            $semiPos = strpos($value, ';');
1570
            if ($semiPos !== false) {
1571
                $params = explode(';', $value);
1572
                $value = trim($params[0]);
1573
                foreach ($params as $param) {
1574
                    $qPos = strpos($param, 'q=');
1575
                    if ($qPos !== false) {
1576
                        $prefValue = substr($param, $qPos + 2);
1577
                    }
1578
                }
1579
            }
1580
1581
            if (!isset($accept[$prefValue])) {
1582
                $accept[$prefValue] = [];
1583
            }
1584
            if ($prefValue) {
1585
                $accept[$prefValue][] = $value;
1586
            }
1587
        }
1588
        krsort($accept);
1589
1590
        return $accept;
1591
    }
1592
1593
    /**
1594
     * Provides a read accessor for `$this->query`.
1595
     * Allows you to use a `Hash::get()` compatible syntax for reading post data.
1596
     *
1597
     * @param string|null $name Query string variable name or null to read all.
1598
     * @return string|array|null The value being read
1599
     * @deprecated 3.4.0 Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead.
1600
     */
1601
    public function query($name = null)
1602
    {
1603
        deprecationWarning(
1604
            'ServerRequest::query() is deprecated. ' .
1605
            'Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead.'
1606
        );
1607
1608
        if ($name === null) {
1609
            return $this->query;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1610
        }
1611
1612
        return $this->getQuery($name);
1613
    }
1614
1615
    /**
1616
     * Read a specific query value or dotted path.
1617
     *
1618
     * Developers are encouraged to use getQueryParams() when possible as it is PSR-7 compliant, and this method
1619
     * is not.
1620
     *
1621
     * ### PSR-7 Alternative
1622
     *
1623
     * ```
1624
     * $value = Hash::get($request->getQueryParams(), 'Post.id', null);
1625
     * ```
1626
     *
1627
     * @param string|null $name The name or dotted path to the query param or null to read all.
1628
     * @param mixed $default The default value if the named parameter is not set, and $name is not null.
1629
     * @return array|string|null Query data.
1630
     * @see ServerRequest::getQueryParams()
1631
     */
1632
    public function getQuery($name = null, $default = null)
1633
    {
1634
        if ($name === null) {
1635
            return $this->query;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1636
        }
1637
1638
        return Hash::get($this->query, $name, $default);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1639
    }
1640
1641
    /**
1642
     * Provides a read/write accessor for `$this->data`.
1643
     * Allows you to use a `Hash::get()` compatible syntax for reading post data.
1644
     *
1645
     * ### Reading values.
1646
     *
1647
     * ```
1648
     * $request->data('Post.title');
1649
     * ```
1650
     *
1651
     * When reading values you will get `null` for keys/values that do not exist.
1652
     *
1653
     * ### Writing values
1654
     *
1655
     * ```
1656
     * $request->data('Post.title', 'New post!');
1657
     * ```
1658
     *
1659
     * You can write to any value, even paths/keys that do not exist, and the arrays
1660
     * will be created for you.
1661
     *
1662
     * @param string|null $name Dot separated name of the value to read/write
1663
     * @param mixed ...$args The data to set (deprecated)
1664
     * @return mixed|$this Either the value being read, or this so you can chain consecutive writes.
1665
     * @deprecated 3.4.0 Use withData() and getData() or getParsedBody() instead.
1666
     */
1667
    public function data($name = null, ...$args)
1668
    {
1669
        deprecationWarning(
1670
            'ServerRequest::data() is deprecated. ' .
1671
            'Use withData() and getData() or getParsedBody() instead.'
1672
        );
1673
1674 View Code Duplication
        if (count($args) === 1) {
1675
            $this->data = Hash::insert($this->data, $name, $args[0]);
0 ignored issues
show
Bug introduced by
It seems like $this->data can also be of type null or object; however, Cake\Utility\Hash::insert() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1676
1677
            return $this;
1678
        }
1679
        if ($name !== null) {
1680
            return Hash::get($this->data, $name);
0 ignored issues
show
Bug introduced by
It seems like $this->data can also be of type null or object; however, Cake\Utility\Hash::get() does only seem to accept array|object<ArrayAccess>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1681
        }
1682
1683
        return $this->data;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1684
    }
1685
1686
    /**
1687
     * Provides a safe accessor for request data. Allows
1688
     * you to use Hash::get() compatible paths.
1689
     *
1690
     * ### Reading values.
1691
     *
1692
     * ```
1693
     * // get all data
1694
     * $request->getData();
1695
     *
1696
     * // Read a specific field.
1697
     * $request->getData('Post.title');
1698
     *
1699
     * // With a default value.
1700
     * $request->getData('Post.not there', 'default value');
1701
     * ```
1702
     *
1703
     * When reading values you will get `null` for keys/values that do not exist.
1704
     *
1705
     * @param string|null $name Dot separated name of the value to read. Or null to read all data.
1706
     * @param mixed $default The default data.
1707
     * @return array|string|null The value being read.
1708
     */
1709
    public function getData($name = null, $default = null)
1710
    {
1711
        if ($name === null) {
1712
            return $this->data;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->data; of type array|object|null adds the type object to the return on line 1712 which is incompatible with the return type documented by Cake\Http\ServerRequest::getData of type array|string|null.
Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1713
        }
1714
        if (!is_array($this->data) && $name) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1715
            return $default;
1716
        }
1717
1718
        return Hash::get($this->data, $name, $default);
0 ignored issues
show
Bug introduced by
It seems like $this->data can also be of type null or object; however, Cake\Utility\Hash::get() does only seem to accept array|object<ArrayAccess>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1719
    }
1720
1721
    /**
1722
     * Safely access the values in $this->params.
1723
     *
1724
     * @param string $name The name of the parameter to get.
1725
     * @param mixed ...$args Value to set (deprecated).
1726
     * @return mixed|$this The value of the provided parameter. Will
1727
     *   return false if the parameter doesn't exist or is falsey.
1728
     * @deprecated 3.4.0 Use getParam() and withParam() instead.
1729
     */
1730
    public function param($name, ...$args)
1731
    {
1732
        deprecationWarning(
1733
            'ServerRequest::param() is deprecated. ' .
1734
            'Use getParam() and withParam() instead.'
1735
        );
1736
1737 View Code Duplication
        if (count($args) === 1) {
1738
            $this->params = Hash::insert($this->params, $name, $args[0]);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Cake\Utility\Hash::inse...arams, $name, $args[0]) can be null. However, the property $params is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1739
1740
            return $this;
1741
        }
1742
1743
        return $this->getParam($name);
1744
    }
1745
1746
    /**
1747
     * Read data from `php://input`. Useful when interacting with XML or JSON
1748
     * request body content.
1749
     *
1750
     * Getting input with a decoding function:
1751
     *
1752
     * ```
1753
     * $this->request->input('json_decode');
1754
     * ```
1755
     *
1756
     * Getting input using a decoding function, and additional params:
1757
     *
1758
     * ```
1759
     * $this->request->input('Xml::build', ['return' => 'DOMDocument']);
1760
     * ```
1761
     *
1762
     * Any additional parameters are applied to the callback in the order they are given.
1763
     *
1764
     * @param string|null $callback A decoding callback that will convert the string data to another
1765
     *     representation. Leave empty to access the raw input data. You can also
1766
     *     supply additional parameters for the decoding callback using var args, see above.
1767
     * @param array ...$args The additional arguments
1768
     * @return string The decoded/processed request data.
1769
     */
1770
    public function input($callback = null, ...$args)
1771
    {
1772
        $this->stream->rewind();
1773
        $input = $this->stream->getContents();
1774
        if ($callback) {
1775
            array_unshift($args, $input);
1776
1777
            return call_user_func_array($callback, $args);
1778
        }
1779
1780
        return $input;
1781
    }
1782
1783
    /**
1784
     * Read cookie data from the request's cookie data.
1785
     *
1786
     * @param string $key The key you want to read.
1787
     * @return string|null Either the cookie value, or null if the value doesn't exist.
1788
     * @deprecated 3.4.0 Use getCookie() instead.
1789
     */
1790
    public function cookie($key)
1791
    {
1792
        deprecationWarning(
1793
            'ServerRequest::cookie() is deprecated. ' .
1794
            'Use getCookie() instead.'
1795
        );
1796
1797
        if (isset($this->cookies[$key])) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1798
            return $this->cookies[$key];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1799
        }
1800
1801
        return null;
1802
    }
1803
1804
    /**
1805
     * Read cookie data from the request's cookie data.
1806
     *
1807
     * @param string $key The key or dotted path you want to read.
1808
     * @param string $default The default value if the cookie is not set.
1809
     * @return string|array|null Either the cookie value, or null if the value doesn't exist.
1810
     */
1811
    public function getCookie($key, $default = null)
1812
    {
1813
        return Hash::get($this->cookies, $key, $default);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1814
    }
1815
1816
    /**
1817
     * Get a cookie collection based on the request's cookies
1818
     *
1819
     * The CookieCollection lets you interact with request cookies using
1820
     * `\Cake\Http\Cookie\Cookie` objects and can make converting request cookies
1821
     * into response cookies easier.
1822
     *
1823
     * This method will create a new cookie collection each time it is called.
1824
     * This is an optimization that allows fewer objects to be allocated until
1825
     * the more complex CookieCollection is needed. In general you should prefer
1826
     * `getCookie()` and `getCookieParams()` over this method. Using a CookieCollection
1827
     * is ideal if your cookies contain complex JSON encoded data.
1828
     *
1829
     * @return \Cake\Http\Cookie\CookieCollection
1830
     */
1831
    public function getCookieCollection()
1832
    {
1833
        return CookieCollection::createFromServerRequest($this);
1834
    }
1835
1836
    /**
1837
     * Replace the cookies in the request with those contained in
1838
     * the provided CookieCollection.
1839
     *
1840
     * @param \Cake\Http\Cookie\CookieCollection $cookies The cookie collection
1841
     * @return static
1842
     */
1843
    public function withCookieCollection(CookieCollection $cookies)
1844
    {
1845
        $new = clone $this;
1846
        $values = [];
1847
        foreach ($cookies as $cookie) {
1848
            $values[$cookie->getName()] = $cookie->getValue();
1849
        }
1850
        $new->cookies = $values;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1851
1852
        return $new;
1853
    }
1854
1855
    /**
1856
     * Get all the cookie data from the request.
1857
     *
1858
     * @return array An array of cookie data.
1859
     */
1860
    public function getCookieParams()
1861
    {
1862
        return $this->cookies;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1863
    }
1864
1865
    /**
1866
     * Replace the cookies and get a new request instance.
1867
     *
1868
     * @param array $cookies The new cookie data to use.
1869
     * @return static
1870
     */
1871
    public function withCookieParams(array $cookies)
1872
    {
1873
        $new = clone $this;
1874
        $new->cookies = $cookies;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$cookies has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1875
1876
        return $new;
1877
    }
1878
1879
    /**
1880
     * Get the parsed request body data.
1881
     *
1882
     * If the request Content-Type is either application/x-www-form-urlencoded
1883
     * or multipart/form-data, and the request method is POST, this will be the
1884
     * post data. For other content types, it may be the deserialized request
1885
     * body.
1886
     *
1887
     * @return object|array|null The deserialized body parameters, if any.
1888
     *     These will typically be an array or object.
1889
     */
1890
    public function getParsedBody()
1891
    {
1892
        return $this->data;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1893
    }
1894
1895
    /**
1896
     * Update the parsed body and get a new instance.
1897
     *
1898
     * @param object|array|null $data The deserialized body data. This will
1899
     *     typically be in an array or object.
1900
     * @return static
1901
     */
1902
    public function withParsedBody($data)
1903
    {
1904
        $new = clone $this;
1905
        $new->data = $data;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1906
1907
        return $new;
1908
    }
1909
1910
    /**
1911
     * Retrieves the HTTP protocol version as a string.
1912
     *
1913
     * @return string HTTP protocol version.
1914
     */
1915
    public function getProtocolVersion()
1916
    {
1917
        if ($this->protocol) {
1918
            return $this->protocol;
1919
        }
1920
1921
        // Lazily populate this data as it is generally not used.
1922
        preg_match('/^HTTP\/([\d.]+)$/', $this->getEnv('SERVER_PROTOCOL'), $match);
1923
        $protocol = '1.1';
1924
        if (isset($match[1])) {
1925
            $protocol = $match[1];
1926
        }
1927
        $this->protocol = $protocol;
1928
1929
        return $this->protocol;
1930
    }
1931
1932
    /**
1933
     * Return an instance with the specified HTTP protocol version.
1934
     *
1935
     * The version string MUST contain only the HTTP version number (e.g.,
1936
     * "1.1", "1.0").
1937
     *
1938
     * @param string $version HTTP protocol version
1939
     * @return static
1940
     */
1941
    public function withProtocolVersion($version)
1942
    {
1943
        if (!preg_match('/^(1\.[01]|2)$/', $version)) {
1944
            throw new InvalidArgumentException("Unsupported protocol version '{$version}' provided");
1945
        }
1946
        $new = clone $this;
1947
        $new->protocol = $version;
1948
1949
        return $new;
1950
    }
1951
1952
    /**
1953
     * Get a value from the request's environment data.
1954
     * Fallback to using env() if the key is not set in the $environment property.
1955
     *
1956
     * @param string $key The key you want to read from.
1957
     * @param string|null $default Default value when trying to retrieve an environment
1958
     *   variable's value that does not exist.
1959
     * @return string|null Either the environment value, or null if the value doesn't exist.
1960
     */
1961
    public function getEnv($key, $default = null)
1962
    {
1963
        $key = strtoupper($key);
1964
        if (!array_key_exists($key, $this->_environment)) {
1965
            $this->_environment[$key] = env($key);
1966
        }
1967
1968
        return $this->_environment[$key] !== null ? $this->_environment[$key] : $default;
1969
    }
1970
1971
    /**
1972
     * Update the request with a new environment data element.
1973
     *
1974
     * Returns an updated request object. This method returns
1975
     * a *new* request object and does not mutate the request in-place.
1976
     *
1977
     * @param string $key The key you want to write to.
1978
     * @param string $value Value to set
1979
     * @return static
1980
     */
1981
    public function withEnv($key, $value)
1982
    {
1983
        $new = clone $this;
1984
        $new->_environment[$key] = $value;
1985
        $new->clearDetectorCache();
1986
1987
        return $new;
1988
    }
1989
1990
    /**
1991
     * Get/Set value from the request's environment data.
1992
     * Fallback to using env() if key not set in $environment property.
1993
     *
1994
     * @deprecated 3.5.0 Use getEnv()/withEnv() instead.
1995
     * @param string $key The key you want to read/write from/to.
1996
     * @param string|null $value Value to set. Default null.
1997
     * @param string|null $default Default value when trying to retrieve an environment
1998
     *   variable's value that does not exist. The value parameter must be null.
1999
     * @return $this|string|null This instance if used as setter,
2000
     *   if used as getter either the environment value, or null if the value doesn't exist.
2001
     */
2002
    public function env($key, $value = null, $default = null)
2003
    {
2004
        deprecationWarning(
2005
            'ServerRequest::env() is deprecated. ' .
2006
            'Use getEnv()/withEnv() instead.'
2007
        );
2008
2009
        if ($value !== null) {
2010
            $this->_environment[$key] = $value;
2011
            $this->clearDetectorCache();
2012
2013
            return $this;
2014
        }
2015
2016
        $key = strtoupper($key);
2017
        if (!array_key_exists($key, $this->_environment)) {
2018
            $this->_environment[$key] = env($key);
2019
        }
2020
2021
        return $this->_environment[$key] !== null ? $this->_environment[$key] : $default;
2022
    }
2023
2024
    /**
2025
     * Allow only certain HTTP request methods, if the request method does not match
2026
     * a 405 error will be shown and the required "Allow" response header will be set.
2027
     *
2028
     * Example:
2029
     *
2030
     * $this->request->allowMethod('post');
2031
     * or
2032
     * $this->request->allowMethod(['post', 'delete']);
2033
     *
2034
     * If the request would be GET, response header "Allow: POST, DELETE" will be set
2035
     * and a 405 error will be returned.
2036
     *
2037
     * @param string|array $methods Allowed HTTP request methods.
2038
     * @return bool true
2039
     * @throws \Cake\Http\Exception\MethodNotAllowedException
2040
     */
2041
    public function allowMethod($methods)
2042
    {
2043
        $methods = (array)$methods;
2044
        foreach ($methods as $method) {
2045
            if ($this->is($method)) {
2046
                return true;
2047
            }
2048
        }
2049
        $allowed = strtoupper(implode(', ', $methods));
2050
        $e = new MethodNotAllowedException();
2051
        $e->responseHeader('Allow', $allowed);
2052
        throw $e;
2053
    }
2054
2055
    /**
2056
     * Read data from php://input, mocked in tests.
2057
     *
2058
     * @return string contents of php://input
2059
     */
2060
    protected function _readInput()
2061
    {
2062
        if (empty($this->_input)) {
2063
            $fh = fopen('php://input', 'rb');
2064
            $content = stream_get_contents($fh);
2065
            fclose($fh);
2066
            $this->_input = $content;
2067
        }
2068
2069
        return $this->_input;
2070
    }
2071
2072
    /**
2073
     * Modify data originally from `php://input`. Useful for altering json/xml data
2074
     * in middleware or DispatcherFilters before it gets to RequestHandlerComponent
2075
     *
2076
     * @param string $input A string to replace original parsed data from input()
2077
     * @return void
2078
     * @deprecated 3.4.0 This method will be removed in 4.0.0. Use withBody() instead.
2079
     */
2080
    public function setInput($input)
2081
    {
2082
        deprecationWarning(
2083
            'This method will be removed in 4.0.0.' .
2084
            'Use withBody() instead.'
2085
        );
2086
2087
        $stream = new Stream('php://memory', 'rw');
2088
        $stream->write($input);
2089
        $stream->rewind();
2090
        $this->stream = $stream;
2091
    }
2092
2093
    /**
2094
     * Update the request with a new request data element.
2095
     *
2096
     * Returns an updated request object. This method returns
2097
     * a *new* request object and does not mutate the request in-place.
2098
     *
2099
     * Use `withParsedBody()` if you need to replace the all request data.
2100
     *
2101
     * @param string $name The dot separated path to insert $value at.
2102
     * @param mixed $value The value to insert into the request data.
2103
     * @return static
2104
     */
2105
    public function withData($name, $value)
2106
    {
2107
        $copy = clone $this;
2108
        $copy->data = Hash::insert($copy->data, $name, $value);
0 ignored issues
show
Bug introduced by
It seems like $copy->data can also be of type null or object; however, Cake\Utility\Hash::insert() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2109
2110
        return $copy;
2111
    }
2112
2113
    /**
2114
     * Update the request removing a data element.
2115
     *
2116
     * Returns an updated request object. This method returns
2117
     * a *new* request object and does not mutate the request in-place.
2118
     *
2119
     * @param string $name The dot separated path to remove.
2120
     * @return static
2121
     */
2122
    public function withoutData($name)
2123
    {
2124
        $copy = clone $this;
2125
        $copy->data = Hash::remove($copy->data, $name);
0 ignored issues
show
Bug introduced by
It seems like $copy->data can also be of type null or object; however, Cake\Utility\Hash::remove() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2126
2127
        return $copy;
2128
    }
2129
2130
    /**
2131
     * Update the request with a new routing parameter
2132
     *
2133
     * Returns an updated request object. This method returns
2134
     * a *new* request object and does not mutate the request in-place.
2135
     *
2136
     * @param string $name The dot separated path to insert $value at.
2137
     * @param mixed $value The value to insert into the the request parameters.
2138
     * @return static
2139
     */
2140
    public function withParam($name, $value)
2141
    {
2142
        $copy = clone $this;
2143
        $copy->params = Hash::insert($copy->params, $name, $value);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Cake\Utility\Hash::inse...>params, $name, $value) can be null. However, the property $params is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2144
2145
        return $copy;
2146
    }
2147
2148
    /**
2149
     * Safely access the values in $this->params.
2150
     *
2151
     * @param string $name The name or dotted path to parameter.
2152
     * @param mixed $default The default value if `$name` is not set. Default `false`.
2153
     * @return mixed
2154
     */
2155
    public function getParam($name, $default = false)
2156
    {
2157
        return Hash::get($this->params, $name, $default);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2158
    }
2159
2160
    /**
2161
     * Return an instance with the specified request attribute.
2162
     *
2163
     * @param string $name The attribute name.
2164
     * @param mixed $value The value of the attribute.
2165
     * @return static
2166
     */
2167
    public function withAttribute($name, $value)
2168
    {
2169
        $new = clone $this;
2170
        if (in_array($name, $this->emulatedAttributes, true)) {
2171
            $new->{$name} = $value;
2172
        } else {
2173
            $new->attributes[$name] = $value;
2174
        }
2175
2176
        return $new;
2177
    }
2178
2179
    /**
2180
     * Return an instance without the specified request attribute.
2181
     *
2182
     * @param string $name The attribute name.
2183
     * @return static
2184
     * @throws \InvalidArgumentException
2185
     */
2186
    public function withoutAttribute($name)
2187
    {
2188
        $new = clone $this;
2189
        if (in_array($name, $this->emulatedAttributes, true)) {
2190
            throw new InvalidArgumentException(
2191
                "You cannot unset '$name'. It is a required CakePHP attribute."
2192
            );
2193
        }
2194
        unset($new->attributes[$name]);
2195
2196
        return $new;
2197
    }
2198
2199
    /**
2200
     * Read an attribute from the request, or get the default
2201
     *
2202
     * @param string $name The attribute name.
2203
     * @param mixed|null $default The default value if the attribute has not been set.
2204
     * @return mixed
2205
     */
2206
    public function getAttribute($name, $default = null)
2207
    {
2208
        if (in_array($name, $this->emulatedAttributes, true)) {
2209
            return $this->{$name};
2210
        }
2211
        if (array_key_exists($name, $this->attributes)) {
2212
            return $this->attributes[$name];
2213
        }
2214
2215
        return $default;
2216
    }
2217
2218
    /**
2219
     * Get all the attributes in the request.
2220
     *
2221
     * This will include the params, webroot, base, and here attributes that CakePHP
2222
     * provides.
2223
     *
2224
     * @return array
2225
     */
2226
    public function getAttributes()
2227
    {
2228
        $emulated = [
2229
            'params' => $this->params,
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2230
            'webroot' => $this->webroot,
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$webroot has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('webroot') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2231
            'base' => $this->base,
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$base has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2232
            'here' => $this->here,
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$here has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('here') or getUri()->getPath() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2233
        ];
2234
2235
        return $this->attributes + $emulated;
2236
    }
2237
2238
    /**
2239
     * Get the uploaded file from a dotted path.
2240
     *
2241
     * @param string $path The dot separated path to the file you want.
2242
     * @return \Psr\Http\Message\UploadedFileInterface|null
2243
     */
2244
    public function getUploadedFile($path)
2245
    {
2246
        $file = Hash::get($this->uploadedFiles, $path);
2247
        if (!$file instanceof UploadedFile) {
2248
            return null;
2249
        }
2250
2251
        return $file;
2252
    }
2253
2254
    /**
2255
     * Get the array of uploaded files from the request.
2256
     *
2257
     * @return array
2258
     */
2259
    public function getUploadedFiles()
2260
    {
2261
        return $this->uploadedFiles;
2262
    }
2263
2264
    /**
2265
     * Update the request replacing the files, and creating a new instance.
2266
     *
2267
     * @param array $files An array of uploaded file objects.
2268
     * @return static
2269
     * @throws \InvalidArgumentException when $files contains an invalid object.
2270
     */
2271
    public function withUploadedFiles(array $files)
2272
    {
2273
        $this->validateUploadedFiles($files, '');
2274
        $new = clone $this;
2275
        $new->uploadedFiles = $files;
2276
2277
        return $new;
2278
    }
2279
2280
    /**
2281
     * Recursively validate uploaded file data.
2282
     *
2283
     * @param array $uploadedFiles The new files array to validate.
2284
     * @param string $path The path thus far.
2285
     * @return void
2286
     * @throws \InvalidArgumentException If any leaf elements are not valid files.
2287
     */
2288
    protected function validateUploadedFiles(array $uploadedFiles, $path)
2289
    {
2290
        foreach ($uploadedFiles as $key => $file) {
2291
            if (is_array($file)) {
2292
                $this->validateUploadedFiles($file, $key . '.');
2293
                continue;
2294
            }
2295
2296
            if (!$file instanceof UploadedFileInterface) {
2297
                throw new InvalidArgumentException("Invalid file at '{$path}{$key}'");
2298
            }
2299
        }
2300
    }
2301
2302
    /**
2303
     * Gets the body of the message.
2304
     *
2305
     * @return \Psr\Http\Message\StreamInterface Returns the body as a stream.
2306
     */
2307
    public function getBody()
2308
    {
2309
        return $this->stream;
2310
    }
2311
2312
    /**
2313
     * Return an instance with the specified message body.
2314
     *
2315
     * @param \Psr\Http\Message\StreamInterface $body The new request body
2316
     * @return static
2317
     */
2318
    public function withBody(StreamInterface $body)
2319
    {
2320
        $new = clone $this;
2321
        $new->stream = $body;
2322
2323
        return $new;
2324
    }
2325
2326
    /**
2327
     * Retrieves the URI instance.
2328
     *
2329
     * @return \Psr\Http\Message\UriInterface Returns a UriInterface instance
2330
     *   representing the URI of the request.
2331
     */
2332
    public function getUri()
2333
    {
2334
        return $this->uri;
2335
    }
2336
2337
    /**
2338
     * Return an instance with the specified uri
2339
     *
2340
     * *Warning* Replacing the Uri will not update the `base`, `webroot`,
2341
     * and `url` attributes.
2342
     *
2343
     * @param \Psr\Http\Message\UriInterface $uri The new request uri
2344
     * @param bool $preserveHost Whether or not the host should be retained.
2345
     * @return static
2346
     */
2347
    public function withUri(UriInterface $uri, $preserveHost = false)
2348
    {
2349
        $new = clone $this;
2350
        $new->uri = $uri;
2351
2352
        if ($preserveHost && $this->hasHeader('Host')) {
2353
            return $new;
2354
        }
2355
2356
        $host = $uri->getHost();
2357
        if (!$host) {
2358
            return $new;
2359
        }
2360
        if ($uri->getPort()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $uri->getPort() of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2361
            $host .= ':' . $uri->getPort();
2362
        }
2363
        $new->_environment['HTTP_HOST'] = $host;
2364
2365
        return $new;
2366
    }
2367
2368
    /**
2369
     * Create a new instance with a specific request-target.
2370
     *
2371
     * You can use this method to overwrite the request target that is
2372
     * inferred from the request's Uri. This also lets you change the request
2373
     * target's form to an absolute-form, authority-form or asterisk-form
2374
     *
2375
     * @link https://tools.ietf.org/html/rfc7230#section-2.7 (for the various
2376
     *   request-target forms allowed in request messages)
2377
     * @param string $target The request target.
2378
     * @return static
2379
     */
2380
    public function withRequestTarget($target)
2381
    {
2382
        $new = clone $this;
2383
        $new->requestTarget = $target;
2384
2385
        return $new;
2386
    }
2387
2388
    /**
2389
     * Retrieves the request's target.
2390
     *
2391
     * Retrieves the message's request-target either as it was requested,
2392
     * or as set with `withRequestTarget()`. By default this will return the
2393
     * application relative path without base directory, and the query string
2394
     * defined in the SERVER environment.
2395
     *
2396
     * @return string
2397
     */
2398
    public function getRequestTarget()
2399
    {
2400
        if ($this->requestTarget !== null) {
2401
            return $this->requestTarget;
2402
        }
2403
2404
        $target = $this->uri->getPath();
2405
        if ($this->uri->getQuery()) {
2406
            $target .= '?' . $this->uri->getQuery();
2407
        }
2408
2409
        if (empty($target)) {
2410
            $target = '/';
2411
        }
2412
2413
        return $target;
2414
    }
2415
2416
    /**
2417
     * Get the path of current request.
2418
     *
2419
     * @return string
2420
     * @since 3.6.1
2421
     */
2422
    public function getPath()
2423
    {
2424
        if ($this->requestTarget === null) {
2425
            return $this->uri->getPath();
2426
        }
2427
2428
        list($path) = explode('?', $this->requestTarget);
2429
2430
        return $path;
2431
    }
2432
2433
    /**
2434
     * Array access read implementation
2435
     *
2436
     * @param string $name Name of the key being accessed.
2437
     * @return mixed
2438
     * @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use getParam(), getData() and getQuery() instead.
2439
     */
2440
    public function offsetGet($name)
2441
    {
2442
        deprecationWarning(
2443
            'The ArrayAccess methods will be removed in 4.0.0.' .
2444
            'Use getParam(), getData() and getQuery() instead.'
2445
        );
2446
2447
        if (isset($this->params[$name])) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2448
            return $this->params[$name];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2449
        }
2450
        if ($name === 'url') {
2451
            return $this->query;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2452
        }
2453
        if ($name === 'data') {
2454
            return $this->data;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2455
        }
2456
2457
        return null;
2458
    }
2459
2460
    /**
2461
     * Array access write implementation
2462
     *
2463
     * @param string $name Name of the key being written
2464
     * @param mixed $value The value being written.
2465
     * @return void
2466
     * @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use withParam() instead.
2467
     */
2468
    public function offsetSet($name, $value)
2469
    {
2470
        deprecationWarning(
2471
            'The ArrayAccess methods will be removed in 4.0.0.' .
2472
            'Use withParam() instead.'
2473
        );
2474
2475
        $this->params[$name] = $value;
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2476
    }
2477
2478
    /**
2479
     * Array access isset() implementation
2480
     *
2481
     * @param string $name thing to check.
2482
     * @return bool
2483
     * @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use getParam() instead.
2484
     */
2485
    public function offsetExists($name)
2486
    {
2487
        deprecationWarning(
2488
            'The ArrayAccess methods will be removed in 4.0.0.' .
2489
            'Use getParam() instead.'
2490
        );
2491
2492
        if ($name === 'url' || $name === 'data') {
2493
            return true;
2494
        }
2495
2496
        return isset($this->params[$name]);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$params has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2497
    }
2498
2499
    /**
2500
     * Array access unset() implementation
2501
     *
2502
     * @param string $name Name to unset.
2503
     * @return void
2504
     * @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use withParam() instead.
2505
     */
2506
    public function offsetUnset($name)
2507
    {
2508
        deprecationWarning(
2509
            'The ArrayAccess methods will be removed in 4.0.0.' .
2510
            'Use withParam() instead.'
2511
        );
2512
2513
        unset($this->params[$name]);
2514
    }
2515
}
2516
2517
// @deprecated 3.4.0 Add backwards compat alias.
2518
class_alias('Cake\Http\ServerRequest', 'Cake\Network\Request');
2519