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 ( 3bd204...90bee5 )
by Rob
03:58
created

Request::getCookieParam()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 10
loc 10
rs 9.4285
cc 2
eloc 6
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
     * Attributes
854
     ******************************************************************************/
855
856
    /**
857
     * Retrieve attributes derived from the request.
858
     *
859
     * The request "attributes" may be used to allow injection of any
860
     * parameters derived from the request: e.g., the results of path
861
     * match operations; the results of decrypting cookies; the results of
862
     * deserializing non-form-encoded message bodies; etc. Attributes
863
     * will be application and request specific, and CAN be mutable.
864
     *
865
     * @return array Attributes derived from the request.
866
     */
867
    public function getAttributes()
868
    {
869
        return $this->attributes->all();
870
    }
871
872
    /**
873
     * Retrieve a single derived request attribute.
874
     *
875
     * Retrieves a single derived request attribute as described in
876
     * getAttributes(). If the attribute has not been previously set, returns
877
     * the default value as provided.
878
     *
879
     * This method obviates the need for a hasAttribute() method, as it allows
880
     * specifying a default value to return if the attribute is not found.
881
     *
882
     * @see getAttributes()
883
     * @param string $name The attribute name.
884
     * @param mixed $default Default value to return if the attribute does not exist.
885
     * @return mixed
886
     */
887
    public function getAttribute($name, $default = null)
888
    {
889
        return $this->attributes->get($name, $default);
890
    }
891
892
    /**
893
     * Return an instance with the specified derived request attribute.
894
     *
895
     * This method allows setting a single derived request attribute as
896
     * described in getAttributes().
897
     *
898
     * This method MUST be implemented in such a way as to retain the
899
     * immutability of the message, and MUST return an instance that has the
900
     * updated attribute.
901
     *
902
     * @see getAttributes()
903
     * @param string $name The attribute name.
904
     * @param mixed $value The value of the attribute.
905
     * @return self
906
     */
907
    public function withAttribute($name, $value)
908
    {
909
        $clone = clone $this;
910
        $clone->attributes->set($name, $value);
911
912
        return $clone;
913
    }
914
915
    /**
916
     * Create a new instance with the specified derived request attributes.
917
     *
918
     * Note: This method is not part of the PSR-7 standard.
919
     *
920
     * This method allows setting all new derived request attributes as
921
     * described in getAttributes().
922
     *
923
     * This method MUST be implemented in such a way as to retain the
924
     * immutability of the message, and MUST return a new instance that has the
925
     * updated attributes.
926
     *
927
     * @param  array $attributes New attributes
928
     * @return self
929
     */
930
    public function withAttributes(array $attributes)
931
    {
932
        $clone = clone $this;
933
        $clone->attributes = new Collection($attributes);
934
935
        return $clone;
936
    }
937
938
    /**
939
     * Return an instance that removes the specified derived request attribute.
940
     *
941
     * This method allows removing a single derived request attribute as
942
     * described in getAttributes().
943
     *
944
     * This method MUST be implemented in such a way as to retain the
945
     * immutability of the message, and MUST return an instance that removes
946
     * the attribute.
947
     *
948
     * @see getAttributes()
949
     * @param string $name The attribute name.
950
     * @return self
951
     */
952
    public function withoutAttribute($name)
953
    {
954
        $clone = clone $this;
955
        $clone->attributes->remove($name);
956
957
        return $clone;
958
    }
959
960
    /*******************************************************************************
961
     * Body
962
     ******************************************************************************/
963
964
    /**
965
     * Retrieve any parameters provided in the request body.
966
     *
967
     * If the request Content-Type is either application/x-www-form-urlencoded
968
     * or multipart/form-data, and the request method is POST, this method MUST
969
     * return the contents of $_POST.
970
     *
971
     * Otherwise, this method may return any results of deserializing
972
     * the request body content; as parsing returns structured content, the
973
     * potential types MUST be arrays or objects only. A null value indicates
974
     * the absence of body content.
975
     *
976
     * @return null|array|object The deserialized body parameters, if any.
977
     *     These will typically be an array or object.
978
     * @throws RuntimeException if the request body media type parser returns an invalid value
979
     */
980
    public function getParsedBody()
981
    {
982
        if ($this->bodyParsed !== false) {
983
            return $this->bodyParsed;
984
        }
985
986
        if (!$this->body) {
987
            return null;
988
        }
989
990
        $mediaType = $this->getMediaType();
991
992
        // look for a media type with a structured syntax suffix (RFC 6839)
993
        $parts = explode('+', $mediaType);
994
        if (count($parts) >= 2) {
995
            $mediaType = 'application/' . $parts[count($parts)-1];
996
        }
997
998
        if (isset($this->bodyParsers[$mediaType]) === true) {
999
            $body = (string)$this->getBody();
1000
            $parsed = $this->bodyParsers[$mediaType]($body);
1001
1002
            if (!is_null($parsed) && !is_object($parsed) && !is_array($parsed)) {
1003
                throw new RuntimeException(
1004
                    'Request body media type parser return value must be an array, an object, or null'
1005
                );
1006
            }
1007
            $this->bodyParsed = $parsed;
1008
            return $this->bodyParsed;
1009
        }
1010
1011
        return null;
1012
    }
1013
1014
    /**
1015
     * Return an instance with the specified body parameters.
1016
     *
1017
     * These MAY be injected during instantiation.
1018
     *
1019
     * If the request Content-Type is either application/x-www-form-urlencoded
1020
     * or multipart/form-data, and the request method is POST, use this method
1021
     * ONLY to inject the contents of $_POST.
1022
     *
1023
     * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
1024
     * deserializing the request body content. Deserialization/parsing returns
1025
     * structured data, and, as such, this method ONLY accepts arrays or objects,
1026
     * or a null value if nothing was available to parse.
1027
     *
1028
     * As an example, if content negotiation determines that the request data
1029
     * is a JSON payload, this method could be used to create a request
1030
     * instance with the deserialized parameters.
1031
     *
1032
     * This method MUST be implemented in such a way as to retain the
1033
     * immutability of the message, and MUST return an instance that has the
1034
     * updated body parameters.
1035
     *
1036
     * @param null|array|object $data The deserialized body data. This will
1037
     *     typically be in an array or object.
1038
     * @return self
1039
     * @throws \InvalidArgumentException if an unsupported argument type is
1040
     *     provided.
1041
     */
1042
    public function withParsedBody($data)
1043
    {
1044
        if (!is_null($data) && !is_object($data) && !is_array($data)) {
1045
            throw new InvalidArgumentException('Parsed body value must be an array, an object, or null');
1046
        }
1047
1048
        $clone = clone $this;
1049
        $clone->bodyParsed = $data;
1050
1051
        return $clone;
1052
    }
1053
1054
    /**
1055
     * Force Body to be parsed again.
1056
     *
1057
     * Note: This method is not part of the PSR-7 standard.
1058
     *
1059
     * @return self
1060
     */
1061
    public function reparseBody()
1062
    {
1063
        $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...
1064
1065
        return $this;
1066
    }
1067
1068
    /**
1069
     * Register media type parser.
1070
     *
1071
     * Note: This method is not part of the PSR-7 standard.
1072
     *
1073
     * @param string   $mediaType A HTTP media type (excluding content-type
1074
     *     params).
1075
     * @param callable $callable  A callable that returns parsed contents for
1076
     *     media type.
1077
     */
1078
    public function registerMediaTypeParser($mediaType, callable $callable)
1079
    {
1080
        if ($callable instanceof Closure) {
1081
            $callable = $callable->bindTo($this);
1082
        }
1083
        $this->bodyParsers[(string)$mediaType] = $callable;
1084
    }
1085
1086
    /*******************************************************************************
1087
     * Parameters (e.g., POST and GET data)
1088
     ******************************************************************************/
1089
1090
    /**
1091
     * Fetch request parameter value from body or query string (in that order).
1092
     *
1093
     * Note: This method is not part of the PSR-7 standard.
1094
     *
1095
     * @param  string $key The parameter key.
1096
     * @param  string $default The default value.
1097
     *
1098
     * @return mixed The parameter value.
1099
     */
1100
    public function getParam($key, $default = null)
1101
    {
1102
        $postParams = $this->getParsedBody();
1103
        $getParams = $this->getQueryParams();
1104
        $result = $default;
1105
        if (is_array($postParams) && isset($postParams[$key])) {
1106
            $result = $postParams[$key];
1107
        } elseif (is_object($postParams) && property_exists($postParams, $key)) {
1108
            $result = $postParams->$key;
1109
        } elseif (isset($getParams[$key])) {
1110
            $result = $getParams[$key];
1111
        }
1112
1113
        return $result;
1114
    }
1115
1116
    /**
1117
     * Fetch parameter value from request body.
1118
     *
1119
     * Note: This method is not part of the PSR-7 standard.
1120
     *
1121
     * @param      $key
1122
     * @param null $default
1123
     *
1124
     * @return null
1125
     */
1126
    public function getParsedBodyParam($key, $default = null)
1127
    {
1128
        $postParams = $this->getParsedBody();
1129
        $result = $default;
1130
        if (is_array($postParams) && isset($postParams[$key])) {
1131
            $result = $postParams[$key];
1132
        } elseif (is_object($postParams) && property_exists($postParams, $key)) {
1133
            $result = $postParams->$key;
1134
        }
1135
1136
        return $result;
1137
    }
1138
1139
    /**
1140
     * Fetch parameter value from query string.
1141
     *
1142
     * Note: This method is not part of the PSR-7 standard.
1143
     *
1144
     * @param      $key
1145
     * @param null $default
1146
     *
1147
     * @return null
1148
     */
1149 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...
1150
    {
1151
        $getParams = $this->getQueryParams();
1152
        $result = $default;
1153
        if (isset($getParams[$key])) {
1154
            $result = $getParams[$key];
1155
        }
1156
1157
        return $result;
1158
    }
1159
1160
    /**
1161
     * Fetch assocative array of body and query string parameters.
1162
     *
1163
     * Note: This method is not part of the PSR-7 standard.
1164
     *
1165
     * @return array
1166
     */
1167
    public function getParams()
1168
    {
1169
        $params = $this->getQueryParams();
1170
        $postParams = $this->getParsedBody();
1171
        if ($postParams) {
1172
            $params = array_merge($params, (array)$postParams);
1173
        }
1174
1175
        return $params;
1176
    }
1177
}
1178