GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — 3.x ( a4373d...54a8bb )
by Rob
02:42
created

Request::getServerParam()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 2
1
<?php
2
/**
3
 * Slim Framework (http://slimframework.com)
4
 *
5
 * @link      https://github.com/slimphp/Slim
6
 * @copyright Copyright (c) 2011-2016 Josh Lockhart
7
 * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
8
 */
9
namespace Slim\Http;
10
11
use Closure;
12
use InvalidArgumentException;
13
use Psr\Http\Message\UploadedFileInterface;
14
use RuntimeException;
15
use Psr\Http\Message\ServerRequestInterface;
16
use Psr\Http\Message\UriInterface;
17
use Psr\Http\Message\StreamInterface;
18
use Slim\Collection;
19
use Slim\Interfaces\Http\HeadersInterface;
20
21
/**
22
 * Request
23
 *
24
 * This class represents an HTTP request. It manages
25
 * the request method, URI, headers, cookies, and body
26
 * according to the PSR-7 standard.
27
 *
28
 * @link https://github.com/php-fig/http-message/blob/master/src/MessageInterface.php
29
 * @link https://github.com/php-fig/http-message/blob/master/src/RequestInterface.php
30
 * @link https://github.com/php-fig/http-message/blob/master/src/ServerRequestInterface.php
31
 */
32
class Request extends Message implements ServerRequestInterface
33
{
34
    /**
35
     * The request method
36
     *
37
     * @var string
38
     */
39
    protected $method;
40
41
    /**
42
     * The original request method (ignoring override)
43
     *
44
     * @var string
45
     */
46
    protected $originalMethod;
47
48
    /**
49
     * The request URI object
50
     *
51
     * @var \Psr\Http\Message\UriInterface
52
     */
53
    protected $uri;
54
55
    /**
56
     * The request URI target (path + query string)
57
     *
58
     * @var string
59
     */
60
    protected $requestTarget;
61
62
    /**
63
     * The request query string params
64
     *
65
     * @var array
66
     */
67
    protected $queryParams;
68
69
    /**
70
     * The request cookies
71
     *
72
     * @var array
73
     */
74
    protected $cookies;
75
76
    /**
77
     * The server environment variables at the time the request was created.
78
     *
79
     * @var array
80
     */
81
    protected $serverParams;
82
83
    /**
84
     * The request attributes (route segment names and values)
85
     *
86
     * @var \Slim\Collection
87
     */
88
    protected $attributes;
89
90
    /**
91
     * The request body parsed (if possible) into a PHP array or object
92
     *
93
     * @var null|array|object
94
     */
95
    protected $bodyParsed = false;
96
97
    /**
98
     * List of request body parsers (e.g., url-encoded, JSON, XML, multipart)
99
     *
100
     * @var callable[]
101
     */
102
    protected $bodyParsers = [];
103
104
    /**
105
     * List of uploaded files
106
     *
107
     * @var UploadedFileInterface[]
108
     */
109
    protected $uploadedFiles;
110
111
    /**
112
     * Valid request methods
113
     *
114
     * @var string[]
115
     */
116
    protected $validMethods = [
117
        'CONNECT' => 1,
118
        'DELETE' => 1,
119
        'GET' => 1,
120
        'HEAD' => 1,
121
        'OPTIONS' => 1,
122
        'PATCH' => 1,
123
        'POST' => 1,
124
        'PUT' => 1,
125
        'TRACE' => 1,
126
    ];
127
128
    /**
129
     * Create new HTTP request with data extracted from the application
130
     * Environment object
131
     *
132
     * @param  Environment $environment The Slim application Environment
133
     *
134
     * @return self
135
     */
136
    public static function createFromEnvironment(Environment $environment)
0 ignored issues
show
Coding Style introduced by
createFromEnvironment uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
137
    {
138
        $method = $environment['REQUEST_METHOD'];
139
        $uri = Uri::createFromEnvironment($environment);
140
        $headers = Headers::createFromEnvironment($environment);
141
        $cookies = Cookies::parseHeader($headers->get('Cookie', []));
0 ignored issues
show
Documentation introduced by
$headers->get('Cookie', array()) is of type array<integer,string>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
142
        $serverParams = $environment->all();
143
        $body = new RequestBody();
144
        $uploadedFiles = UploadedFile::createFromEnvironment($environment);
145
146
        $request = new static($method, $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);
0 ignored issues
show
Bug introduced by
It seems like $uploadedFiles defined by \Slim\Http\UploadedFile:...vironment($environment) on line 144 can also be of type null; however, Slim\Http\Request::__construct() 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...
147
148
        if ($method === 'POST' &&
149
            in_array($request->getMediaType(), ['application/x-www-form-urlencoded', 'multipart/form-data'])
150
        ) {
151
            // parsed body must be $_POST
152
            $request = $request->withParsedBody($_POST);
153
        }
154
        return $request;
155
    }
156
157
    /**
158
     * Create new HTTP request.
159
     *
160
     * Adds a host header when none was provided and a host is defined in uri.
161
     *
162
     * @param string           $method        The request method
163
     * @param UriInterface     $uri           The request URI object
164
     * @param HeadersInterface $headers       The request headers collection
165
     * @param array            $cookies       The request cookies collection
166
     * @param array            $serverParams  The server environment variables
167
     * @param StreamInterface  $body          The request body object
168
     * @param array            $uploadedFiles The request uploadedFiles collection
169
     */
170
    public function __construct(
171
        $method,
172
        UriInterface $uri,
173
        HeadersInterface $headers,
174
        array $cookies,
175
        array $serverParams,
176
        StreamInterface $body,
177
        array $uploadedFiles = []
178
    ) {
179
        $this->originalMethod = $this->filterMethod($method);
180
        $this->uri = $uri;
181
        $this->headers = $headers;
182
        $this->cookies = $cookies;
183
        $this->serverParams = $serverParams;
184
        $this->attributes = new Collection();
185
        $this->body = $body;
186
        $this->uploadedFiles = $uploadedFiles;
187
188
        if (isset($serverParams['SERVER_PROTOCOL'])) {
189
            $this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']);
190
        }
191
192
        if (!$this->headers->has('Host') || $this->uri->getHost() !== '') {
193
            $this->headers->set('Host', $this->uri->getHost());
194
        }
195
196
        $this->registerMediaTypeParser('application/json', function ($input) {
197
            return json_decode($input, true);
198
        });
199
200 View Code Duplication
        $this->registerMediaTypeParser('application/xml', function ($input) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
            $backup = libxml_disable_entity_loader(true);
202
            $result = simplexml_load_string($input);
203
            libxml_disable_entity_loader($backup);
204
            return $result;
205
        });
206
207 View Code Duplication
        $this->registerMediaTypeParser('text/xml', function ($input) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
            $backup = libxml_disable_entity_loader(true);
209
            $result = simplexml_load_string($input);
210
            libxml_disable_entity_loader($backup);
211
            return $result;
212
        });
213
214
        $this->registerMediaTypeParser('application/x-www-form-urlencoded', function ($input) {
215
            parse_str($input, $data);
216
            return $data;
217
        });
218
    }
219
220
    /**
221
     * This method is applied to the cloned object
222
     * after PHP performs an initial shallow-copy. This
223
     * method completes a deep-copy by creating new objects
224
     * for the cloned object's internal reference pointers.
225
     */
226
    public function __clone()
227
    {
228
        $this->headers = clone $this->headers;
229
        $this->attributes = clone $this->attributes;
230
        $this->body = clone $this->body;
231
    }
232
233
    /*******************************************************************************
234
     * Method
235
     ******************************************************************************/
236
237
    /**
238
     * Retrieves the HTTP method of the request.
239
     *
240
     * @return string Returns the request method.
241
     */
242
    public function getMethod()
243
    {
244
        if ($this->method === null) {
245
            $this->method = $this->originalMethod;
246
            $customMethod = $this->getHeaderLine('X-Http-Method-Override');
247
248
            if ($customMethod) {
249
                $this->method = $this->filterMethod($customMethod);
250
            } elseif ($this->originalMethod === 'POST') {
251
                $body = $this->getParsedBody();
252
253
                if (is_object($body) && property_exists($body, '_METHOD')) {
254
                    $this->method = $this->filterMethod((string)$body->_METHOD);
255
                } elseif (is_array($body) && isset($body['_METHOD'])) {
256
                    $this->method = $this->filterMethod((string)$body['_METHOD']);
257
                }
258
259
                if ($this->getBody()->eof()) {
260
                    $this->getBody()->rewind();
261
                }
262
            }
263
        }
264
265
        return $this->method;
266
    }
267
268
    /**
269
     * Get the original HTTP method (ignore override).
270
     *
271
     * Note: This method is not part of the PSR-7 standard.
272
     *
273
     * @return string
274
     */
275
    public function getOriginalMethod()
276
    {
277
        return $this->originalMethod;
278
    }
279
280
    /**
281
     * Return an instance with the provided HTTP method.
282
     *
283
     * While HTTP method names are typically all uppercase characters, HTTP
284
     * method names are case-sensitive and thus implementations SHOULD NOT
285
     * modify the given string.
286
     *
287
     * This method MUST be implemented in such a way as to retain the
288
     * immutability of the message, and MUST return an instance that has the
289
     * changed request method.
290
     *
291
     * @param string $method Case-sensitive method.
292
     * @return self
293
     * @throws \InvalidArgumentException for invalid HTTP methods.
294
     */
295
    public function withMethod($method)
296
    {
297
        $method = $this->filterMethod($method);
298
        $clone = clone $this;
299
        $clone->originalMethod = $method;
300
        $clone->method = $method;
301
302
        return $clone;
303
    }
304
305
    /**
306
     * Validate the HTTP method
307
     *
308
     * @param  null|string $method
309
     * @return null|string
310
     * @throws \InvalidArgumentException on invalid HTTP method.
311
     */
312
    protected function filterMethod($method)
313
    {
314
        if ($method === null) {
315
            return $method;
316
        }
317
318
        if (!is_string($method)) {
319
            throw new InvalidArgumentException(sprintf(
320
                'Unsupported HTTP method; must be a string, received %s',
321
                (is_object($method) ? get_class($method) : gettype($method))
322
            ));
323
        }
324
325
        $method = strtoupper($method);
326
        if (!isset($this->validMethods[$method])) {
327
            throw new InvalidArgumentException(sprintf(
328
                'Unsupported HTTP method "%s" provided',
329
                $method
330
            ));
331
        }
332
333
        return $method;
334
    }
335
336
    /**
337
     * Does this request use a given method?
338
     *
339
     * Note: This method is not part of the PSR-7 standard.
340
     *
341
     * @param  string $method HTTP method
342
     * @return bool
343
     */
344
    public function isMethod($method)
345
    {
346
        return $this->getMethod() === $method;
347
    }
348
349
    /**
350
     * Is this a GET request?
351
     *
352
     * Note: This method is not part of the PSR-7 standard.
353
     *
354
     * @return bool
355
     */
356
    public function isGet()
357
    {
358
        return $this->isMethod('GET');
359
    }
360
361
    /**
362
     * Is this a POST request?
363
     *
364
     * Note: This method is not part of the PSR-7 standard.
365
     *
366
     * @return bool
367
     */
368
    public function isPost()
369
    {
370
        return $this->isMethod('POST');
371
    }
372
373
    /**
374
     * Is this a PUT request?
375
     *
376
     * Note: This method is not part of the PSR-7 standard.
377
     *
378
     * @return bool
379
     */
380
    public function isPut()
381
    {
382
        return $this->isMethod('PUT');
383
    }
384
385
    /**
386
     * Is this a PATCH request?
387
     *
388
     * Note: This method is not part of the PSR-7 standard.
389
     *
390
     * @return bool
391
     */
392
    public function isPatch()
393
    {
394
        return $this->isMethod('PATCH');
395
    }
396
397
    /**
398
     * Is this a DELETE request?
399
     *
400
     * Note: This method is not part of the PSR-7 standard.
401
     *
402
     * @return bool
403
     */
404
    public function isDelete()
405
    {
406
        return $this->isMethod('DELETE');
407
    }
408
409
    /**
410
     * Is this a HEAD request?
411
     *
412
     * Note: This method is not part of the PSR-7 standard.
413
     *
414
     * @return bool
415
     */
416
    public function isHead()
417
    {
418
        return $this->isMethod('HEAD');
419
    }
420
421
    /**
422
     * Is this a OPTIONS request?
423
     *
424
     * Note: This method is not part of the PSR-7 standard.
425
     *
426
     * @return bool
427
     */
428
    public function isOptions()
429
    {
430
        return $this->isMethod('OPTIONS');
431
    }
432
433
    /**
434
     * Is this an XHR request?
435
     *
436
     * Note: This method is not part of the PSR-7 standard.
437
     *
438
     * @return bool
439
     */
440
    public function isXhr()
441
    {
442
        return $this->getHeaderLine('X-Requested-With') === 'XMLHttpRequest';
443
    }
444
445
    /*******************************************************************************
446
     * URI
447
     ******************************************************************************/
448
449
    /**
450
     * Retrieves the message's request target.
451
     *
452
     * Retrieves the message's request-target either as it will appear (for
453
     * clients), as it appeared at request (for servers), or as it was
454
     * specified for the instance (see withRequestTarget()).
455
     *
456
     * In most cases, this will be the origin-form of the composed URI,
457
     * unless a value was provided to the concrete implementation (see
458
     * withRequestTarget() below).
459
     *
460
     * If no URI is available, and no request-target has been specifically
461
     * provided, this method MUST return the string "/".
462
     *
463
     * @return string
464
     */
465
    public function getRequestTarget()
466
    {
467
        if ($this->requestTarget) {
468
            return $this->requestTarget;
469
        }
470
471
        if ($this->uri === null) {
472
            return '/';
473
        }
474
475
        $basePath = $this->uri->getBasePath();
476
        $path = $this->uri->getPath();
477
        $path = $basePath . '/' . ltrim($path, '/');
478
479
        $query = $this->uri->getQuery();
480
        if ($query) {
481
            $path .= '?' . $query;
482
        }
483
        $this->requestTarget = $path;
484
485
        return $this->requestTarget;
486
    }
487
488
    /**
489
     * Return an instance with the specific request-target.
490
     *
491
     * If the request needs a non-origin-form request-target — e.g., for
492
     * specifying an absolute-form, authority-form, or asterisk-form —
493
     * this method may be used to create an instance with the specified
494
     * request-target, verbatim.
495
     *
496
     * This method MUST be implemented in such a way as to retain the
497
     * immutability of the message, and MUST return an instance that has the
498
     * changed request target.
499
     *
500
     * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various
501
     *     request-target forms allowed in request messages)
502
     * @param mixed $requestTarget
503
     * @return self
504
     * @throws InvalidArgumentException if the request target is invalid
505
     */
506
    public function withRequestTarget($requestTarget)
507
    {
508
        if (preg_match('#\s#', $requestTarget)) {
509
            throw new InvalidArgumentException(
510
                'Invalid request target provided; must be a string and cannot contain whitespace'
511
            );
512
        }
513
        $clone = clone $this;
514
        $clone->requestTarget = $requestTarget;
515
516
        return $clone;
517
    }
518
519
    /**
520
     * Retrieves the URI instance.
521
     *
522
     * This method MUST return a UriInterface instance.
523
     *
524
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
525
     * @return UriInterface Returns a UriInterface instance
526
     *     representing the URI of the request.
527
     */
528
    public function getUri()
529
    {
530
        return $this->uri;
531
    }
532
533
    /**
534
     * Returns an instance with the provided URI.
535
     *
536
     * This method MUST update the Host header of the returned request by
537
     * default if the URI contains a host component. If the URI does not
538
     * contain a host component, any pre-existing Host header MUST be carried
539
     * over to the returned request.
540
     *
541
     * You can opt-in to preserving the original state of the Host header by
542
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
543
     * `true`, this method interacts with the Host header in the following ways:
544
     *
545
     * - If the the Host header is missing or empty, and the new URI contains
546
     *   a host component, this method MUST update the Host header in the returned
547
     *   request.
548
     * - If the Host header is missing or empty, and the new URI does not contain a
549
     *   host component, this method MUST NOT update the Host header in the returned
550
     *   request.
551
     * - If a Host header is present and non-empty, this method MUST NOT update
552
     *   the Host header in the returned request.
553
     *
554
     * This method MUST be implemented in such a way as to retain the
555
     * immutability of the message, and MUST return an instance that has the
556
     * new UriInterface instance.
557
     *
558
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
559
     * @param UriInterface $uri New request URI to use.
560
     * @param bool $preserveHost Preserve the original state of the Host header.
561
     * @return self
562
     */
563
    public function withUri(UriInterface $uri, $preserveHost = false)
564
    {
565
        $clone = clone $this;
566
        $clone->uri = $uri;
567
568
        if (!$preserveHost) {
569
            if ($uri->getHost() !== '') {
570
                $clone->headers->set('Host', $uri->getHost());
571
            }
572
        } else {
573
            if ($this->uri->getHost() !== '' && (!$this->hasHeader('Host') || $this->getHeader('Host') === null)) {
574
                $clone->headers->set('Host', $uri->getHost());
575
            }
576
        }
577
578
        return $clone;
579
    }
580
581
    /**
582
     * Get request content type.
583
     *
584
     * Note: This method is not part of the PSR-7 standard.
585
     *
586
     * @return string|null The request content type, if known
587
     */
588
    public function getContentType()
589
    {
590
        $result = $this->getHeader('Content-Type');
591
592
        return $result ? $result[0] : null;
593
    }
594
595
    /**
596
     * Get request media type, if known.
597
     *
598
     * Note: This method is not part of the PSR-7 standard.
599
     *
600
     * @return string|null The request media type, minus content-type params
601
     */
602
    public function getMediaType()
603
    {
604
        $contentType = $this->getContentType();
605
        if ($contentType) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contentType of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
606
            $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
607
608
            return strtolower($contentTypeParts[0]);
609
        }
610
611
        return null;
612
    }
613
614
    /**
615
     * Get request media type params, if known.
616
     *
617
     * Note: This method is not part of the PSR-7 standard.
618
     *
619
     * @return array
620
     */
621
    public function getMediaTypeParams()
622
    {
623
        $contentType = $this->getContentType();
624
        $contentTypeParams = [];
625
        if ($contentType) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contentType of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
626
            $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
627
            $contentTypePartsLength = count($contentTypeParts);
628
            for ($i = 1; $i < $contentTypePartsLength; $i++) {
629
                $paramParts = explode('=', $contentTypeParts[$i]);
630
                $contentTypeParams[strtolower($paramParts[0])] = $paramParts[1];
631
            }
632
        }
633
634
        return $contentTypeParams;
635
    }
636
637
    /**
638
     * Get request content character set, if known.
639
     *
640
     * Note: This method is not part of the PSR-7 standard.
641
     *
642
     * @return string|null
643
     */
644
    public function getContentCharset()
645
    {
646
        $mediaTypeParams = $this->getMediaTypeParams();
647
        if (isset($mediaTypeParams['charset'])) {
648
            return $mediaTypeParams['charset'];
649
        }
650
651
        return null;
652
    }
653
654
    /**
655
     * Get request content length, if known.
656
     *
657
     * Note: This method is not part of the PSR-7 standard.
658
     *
659
     * @return int|null
660
     */
661
    public function getContentLength()
662
    {
663
        $result = $this->headers->get('Content-Length');
664
665
        return $result ? (int)$result[0] : null;
666
    }
667
668
    /*******************************************************************************
669
     * Cookies
670
     ******************************************************************************/
671
672
    /**
673
     * Retrieve cookies.
674
     *
675
     * Retrieves cookies sent by the client to the server.
676
     *
677
     * The data MUST be compatible with the structure of the $_COOKIE
678
     * superglobal.
679
     *
680
     * @return array
681
     */
682
    public function getCookieParams()
683
    {
684
        return $this->cookies;
685
    }
686
687
    /**
688
     * Fetch cookie value from cookies sent by the client to the server.
689
     *
690
     * Note: This method is not part of the PSR-7 standard.
691
     *
692
     * @param string $name    The attribute name.
0 ignored issues
show
Bug introduced by
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
693
     * @param mixed  $default Default value to return if the attribute does not exist.
694
     *
695
     * @return mixed
696
     */
697 View Code Duplication
    public function getCookieParam($key, $default = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
698
    {
699
        $cookies = $this->getCookieParams();
700
        $result = $default;
701
        if (isset($cookies[$key])) {
702
            $result = $cookies[$key];
703
        }
704
705
        return $result;
706
    }
707
708
    /**
709
     * Return an instance with the specified cookies.
710
     *
711
     * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
712
     * be compatible with the structure of $_COOKIE. Typically, this data will
713
     * be injected at instantiation.
714
     *
715
     * This method MUST NOT update the related Cookie header of the request
716
     * instance, nor related values in the server params.
717
     *
718
     * This method MUST be implemented in such a way as to retain the
719
     * immutability of the message, and MUST return an instance that has the
720
     * updated cookie values.
721
     *
722
     * @param array $cookies Array of key/value pairs representing cookies.
723
     * @return self
724
     */
725
    public function withCookieParams(array $cookies)
726
    {
727
        $clone = clone $this;
728
        $clone->cookies = $cookies;
729
730
        return $clone;
731
    }
732
733
    /*******************************************************************************
734
     * Query Params
735
     ******************************************************************************/
736
737
    /**
738
     * Retrieve query string arguments.
739
     *
740
     * Retrieves the deserialized query string arguments, if any.
741
     *
742
     * Note: the query params might not be in sync with the URI or server
743
     * params. If you need to ensure you are only getting the original
744
     * values, you may need to parse the query string from `getUri()->getQuery()`
745
     * or from the `QUERY_STRING` server param.
746
     *
747
     * @return array
748
     */
749
    public function getQueryParams()
750
    {
751
        if (is_array($this->queryParams)) {
752
            return $this->queryParams;
753
        }
754
755
        if ($this->uri === null) {
756
            return [];
757
        }
758
759
        parse_str($this->uri->getQuery(), $this->queryParams); // <-- URL decodes data
760
761
        return $this->queryParams;
762
    }
763
764
    /**
765
     * Return an instance with the specified query string arguments.
766
     *
767
     * These values SHOULD remain immutable over the course of the incoming
768
     * request. They MAY be injected during instantiation, such as from PHP's
769
     * $_GET superglobal, or MAY be derived from some other value such as the
770
     * URI. In cases where the arguments are parsed from the URI, the data
771
     * MUST be compatible with what PHP's parse_str() would return for
772
     * purposes of how duplicate query parameters are handled, and how nested
773
     * sets are handled.
774
     *
775
     * Setting query string arguments MUST NOT change the URI stored by the
776
     * request, nor the values in the server params.
777
     *
778
     * This method MUST be implemented in such a way as to retain the
779
     * immutability of the message, and MUST return an instance that has the
780
     * updated query string arguments.
781
     *
782
     * @param array $query Array of query string arguments, typically from
783
     *     $_GET.
784
     * @return self
785
     */
786
    public function withQueryParams(array $query)
787
    {
788
        $clone = clone $this;
789
        $clone->queryParams = $query;
790
791
        return $clone;
792
    }
793
794
    /*******************************************************************************
795
     * File Params
796
     ******************************************************************************/
797
798
    /**
799
     * Retrieve normalized file upload data.
800
     *
801
     * This method returns upload metadata in a normalized tree, with each leaf
802
     * an instance of Psr\Http\Message\UploadedFileInterface.
803
     *
804
     * These values MAY be prepared from $_FILES or the message body during
805
     * instantiation, or MAY be injected via withUploadedFiles().
806
     *
807
     * @return array An array tree of UploadedFileInterface instances; an empty
808
     *     array MUST be returned if no data is present.
809
     */
810
    public function getUploadedFiles()
811
    {
812
        return $this->uploadedFiles;
813
    }
814
815
    /**
816
     * Create a new instance with the specified uploaded files.
817
     *
818
     * This method MUST be implemented in such a way as to retain the
819
     * immutability of the message, and MUST return an instance that has the
820
     * updated body parameters.
821
     *
822
     * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
823
     * @return self
824
     * @throws \InvalidArgumentException if an invalid structure is provided.
825
     */
826
    public function withUploadedFiles(array $uploadedFiles)
827
    {
828
        $clone = clone $this;
829
        $clone->uploadedFiles = $uploadedFiles;
830
831
        return $clone;
832
    }
833
834
    /*******************************************************************************
835
     * Server Params
836
     ******************************************************************************/
837
838
    /**
839
     * Retrieve server parameters.
840
     *
841
     * Retrieves data related to the incoming request environment,
842
     * typically derived from PHP's $_SERVER superglobal. The data IS NOT
843
     * REQUIRED to originate from $_SERVER.
844
     *
845
     * @return array
846
     */
847
    public function getServerParams()
848
    {
849
        return $this->serverParams;
850
    }
851
852
    /**
853
     * Retrieve a server parameter.
854
     *
855
     * Note: This method is not part of the PSR-7 standard.
856
     *
857
     * @param  string $key
858
     * @param  mixed  $default
859
     * @return mixed
860
     */
861
    public function getServerParam($key, $default = null)
862
    {
863
        $serverParams = $this->getServerParams();
864
865
        return isset($serverParams[$key]) ? $serverParams[$key] : $default;
866
    }
867
868
    /*******************************************************************************
869
     * Attributes
870
     ******************************************************************************/
871
872
    /**
873
     * Retrieve attributes derived from the request.
874
     *
875
     * The request "attributes" may be used to allow injection of any
876
     * parameters derived from the request: e.g., the results of path
877
     * match operations; the results of decrypting cookies; the results of
878
     * deserializing non-form-encoded message bodies; etc. Attributes
879
     * will be application and request specific, and CAN be mutable.
880
     *
881
     * @return array Attributes derived from the request.
882
     */
883
    public function getAttributes()
884
    {
885
        return $this->attributes->all();
886
    }
887
888
    /**
889
     * Retrieve a single derived request attribute.
890
     *
891
     * Retrieves a single derived request attribute as described in
892
     * getAttributes(). If the attribute has not been previously set, returns
893
     * the default value as provided.
894
     *
895
     * This method obviates the need for a hasAttribute() method, as it allows
896
     * specifying a default value to return if the attribute is not found.
897
     *
898
     * @see getAttributes()
899
     * @param string $name The attribute name.
900
     * @param mixed $default Default value to return if the attribute does not exist.
901
     * @return mixed
902
     */
903
    public function getAttribute($name, $default = null)
904
    {
905
        return $this->attributes->get($name, $default);
906
    }
907
908
    /**
909
     * Return an instance with the specified derived request attribute.
910
     *
911
     * This method allows setting a single derived request attribute as
912
     * described in getAttributes().
913
     *
914
     * This method MUST be implemented in such a way as to retain the
915
     * immutability of the message, and MUST return an instance that has the
916
     * updated attribute.
917
     *
918
     * @see getAttributes()
919
     * @param string $name The attribute name.
920
     * @param mixed $value The value of the attribute.
921
     * @return self
922
     */
923
    public function withAttribute($name, $value)
924
    {
925
        $clone = clone $this;
926
        $clone->attributes->set($name, $value);
927
928
        return $clone;
929
    }
930
931
    /**
932
     * Create a new instance with the specified derived request attributes.
933
     *
934
     * Note: This method is not part of the PSR-7 standard.
935
     *
936
     * This method allows setting all new derived request attributes as
937
     * described in getAttributes().
938
     *
939
     * This method MUST be implemented in such a way as to retain the
940
     * immutability of the message, and MUST return a new instance that has the
941
     * updated attributes.
942
     *
943
     * @param  array $attributes New attributes
944
     * @return self
945
     */
946
    public function withAttributes(array $attributes)
947
    {
948
        $clone = clone $this;
949
        $clone->attributes = new Collection($attributes);
950
951
        return $clone;
952
    }
953
954
    /**
955
     * Return an instance that removes the specified derived request attribute.
956
     *
957
     * This method allows removing a single derived request attribute as
958
     * described in getAttributes().
959
     *
960
     * This method MUST be implemented in such a way as to retain the
961
     * immutability of the message, and MUST return an instance that removes
962
     * the attribute.
963
     *
964
     * @see getAttributes()
965
     * @param string $name The attribute name.
966
     * @return self
967
     */
968
    public function withoutAttribute($name)
969
    {
970
        $clone = clone $this;
971
        $clone->attributes->remove($name);
972
973
        return $clone;
974
    }
975
976
    /*******************************************************************************
977
     * Body
978
     ******************************************************************************/
979
980
    /**
981
     * Retrieve any parameters provided in the request body.
982
     *
983
     * If the request Content-Type is either application/x-www-form-urlencoded
984
     * or multipart/form-data, and the request method is POST, this method MUST
985
     * return the contents of $_POST.
986
     *
987
     * Otherwise, this method may return any results of deserializing
988
     * the request body content; as parsing returns structured content, the
989
     * potential types MUST be arrays or objects only. A null value indicates
990
     * the absence of body content.
991
     *
992
     * @return null|array|object The deserialized body parameters, if any.
993
     *     These will typically be an array or object.
994
     * @throws RuntimeException if the request body media type parser returns an invalid value
995
     */
996
    public function getParsedBody()
997
    {
998
        if ($this->bodyParsed !== false) {
999
            return $this->bodyParsed;
1000
        }
1001
1002
        if (!$this->body) {
1003
            return null;
1004
        }
1005
1006
        $mediaType = $this->getMediaType();
1007
1008
        // look for a media type with a structured syntax suffix (RFC 6839)
1009
        $parts = explode('+', $mediaType);
1010
        if (count($parts) >= 2) {
1011
            $mediaType = 'application/' . $parts[count($parts)-1];
1012
        }
1013
1014
        if (isset($this->bodyParsers[$mediaType]) === true) {
1015
            $body = (string)$this->getBody();
1016
            $parsed = $this->bodyParsers[$mediaType]($body);
1017
1018
            if (!is_null($parsed) && !is_object($parsed) && !is_array($parsed)) {
1019
                throw new RuntimeException(
1020
                    'Request body media type parser return value must be an array, an object, or null'
1021
                );
1022
            }
1023
            $this->bodyParsed = $parsed;
1024
            return $this->bodyParsed;
1025
        }
1026
1027
        return null;
1028
    }
1029
1030
    /**
1031
     * Return an instance with the specified body parameters.
1032
     *
1033
     * These MAY be injected during instantiation.
1034
     *
1035
     * If the request Content-Type is either application/x-www-form-urlencoded
1036
     * or multipart/form-data, and the request method is POST, use this method
1037
     * ONLY to inject the contents of $_POST.
1038
     *
1039
     * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
1040
     * deserializing the request body content. Deserialization/parsing returns
1041
     * structured data, and, as such, this method ONLY accepts arrays or objects,
1042
     * or a null value if nothing was available to parse.
1043
     *
1044
     * As an example, if content negotiation determines that the request data
1045
     * is a JSON payload, this method could be used to create a request
1046
     * instance with the deserialized parameters.
1047
     *
1048
     * This method MUST be implemented in such a way as to retain the
1049
     * immutability of the message, and MUST return an instance that has the
1050
     * updated body parameters.
1051
     *
1052
     * @param null|array|object $data The deserialized body data. This will
1053
     *     typically be in an array or object.
1054
     * @return self
1055
     * @throws \InvalidArgumentException if an unsupported argument type is
1056
     *     provided.
1057
     */
1058
    public function withParsedBody($data)
1059
    {
1060
        if (!is_null($data) && !is_object($data) && !is_array($data)) {
1061
            throw new InvalidArgumentException('Parsed body value must be an array, an object, or null');
1062
        }
1063
1064
        $clone = clone $this;
1065
        $clone->bodyParsed = $data;
1066
1067
        return $clone;
1068
    }
1069
1070
    /**
1071
     * Force Body to be parsed again.
1072
     *
1073
     * Note: This method is not part of the PSR-7 standard.
1074
     *
1075
     * @return self
1076
     */
1077
    public function reparseBody()
1078
    {
1079
        $this->bodyParsed = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type null|array|object of property $bodyParsed.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

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

Loading history...
1080
1081
        return $this;
1082
    }
1083
1084
    /**
1085
     * Register media type parser.
1086
     *
1087
     * Note: This method is not part of the PSR-7 standard.
1088
     *
1089
     * @param string   $mediaType A HTTP media type (excluding content-type
1090
     *     params).
1091
     * @param callable $callable  A callable that returns parsed contents for
1092
     *     media type.
1093
     */
1094
    public function registerMediaTypeParser($mediaType, callable $callable)
1095
    {
1096
        if ($callable instanceof Closure) {
1097
            $callable = $callable->bindTo($this);
1098
        }
1099
        $this->bodyParsers[(string)$mediaType] = $callable;
1100
    }
1101
1102
    /*******************************************************************************
1103
     * Parameters (e.g., POST and GET data)
1104
     ******************************************************************************/
1105
1106
    /**
1107
     * Fetch request parameter value from body or query string (in that order).
1108
     *
1109
     * Note: This method is not part of the PSR-7 standard.
1110
     *
1111
     * @param  string $key The parameter key.
1112
     * @param  string $default The default value.
1113
     *
1114
     * @return mixed The parameter value.
1115
     */
1116
    public function getParam($key, $default = null)
1117
    {
1118
        $postParams = $this->getParsedBody();
1119
        $getParams = $this->getQueryParams();
1120
        $result = $default;
1121
        if (is_array($postParams) && isset($postParams[$key])) {
1122
            $result = $postParams[$key];
1123
        } elseif (is_object($postParams) && property_exists($postParams, $key)) {
1124
            $result = $postParams->$key;
1125
        } elseif (isset($getParams[$key])) {
1126
            $result = $getParams[$key];
1127
        }
1128
1129
        return $result;
1130
    }
1131
1132
    /**
1133
     * Fetch parameter value from request body.
1134
     *
1135
     * Note: This method is not part of the PSR-7 standard.
1136
     *
1137
     * @param      $key
1138
     * @param null $default
1139
     *
1140
     * @return null
1141
     */
1142
    public function getParsedBodyParam($key, $default = null)
1143
    {
1144
        $postParams = $this->getParsedBody();
1145
        $result = $default;
1146
        if (is_array($postParams) && isset($postParams[$key])) {
1147
            $result = $postParams[$key];
1148
        } elseif (is_object($postParams) && property_exists($postParams, $key)) {
1149
            $result = $postParams->$key;
1150
        }
1151
1152
        return $result;
1153
    }
1154
1155
    /**
1156
     * Fetch parameter value from query string.
1157
     *
1158
     * Note: This method is not part of the PSR-7 standard.
1159
     *
1160
     * @param      $key
1161
     * @param null $default
1162
     *
1163
     * @return null
1164
     */
1165 View Code Duplication
    public function getQueryParam($key, $default = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1166
    {
1167
        $getParams = $this->getQueryParams();
1168
        $result = $default;
1169
        if (isset($getParams[$key])) {
1170
            $result = $getParams[$key];
1171
        }
1172
1173
        return $result;
1174
    }
1175
1176
    /**
1177
     * Fetch assocative array of body and query string parameters.
1178
     *
1179
     * Note: This method is not part of the PSR-7 standard.
1180
     *
1181
     * @return array
1182
     */
1183
    public function getParams()
1184
    {
1185
        $params = $this->getQueryParams();
1186
        $postParams = $this->getParsedBody();
1187
        if ($postParams) {
1188
            $params = array_merge($params, (array)$postParams);
1189
        }
1190
1191
        return $params;
1192
    }
1193
}
1194