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
Pull Request — 3.x (#2345)
by Rob
01:39
created

Response::withHeader()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 3
eloc 6
nc 2
nop 2
1
<?php
2
/**
3
 * Slim Framework (https://slimframework.com)
4
 *
5
 * @link      https://github.com/slimphp/Slim
6
 * @copyright Copyright (c) 2011-2017 Josh Lockhart
7
 * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
8
 */
9
namespace Slim\Http;
10
11
use InvalidArgumentException;
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\StreamInterface;
14
use Psr\Http\Message\UriInterface;
15
use Slim\Interfaces\Http\HeadersInterface;
16
17
/**
18
 * Response
19
 *
20
 * This class represents an HTTP response. It manages
21
 * the response status, headers, and body
22
 * according to the PSR-7 standard.
23
 *
24
 * @link https://github.com/php-fig/http-message/blob/master/src/MessageInterface.php
25
 * @link https://github.com/php-fig/http-message/blob/master/src/ResponseInterface.php
26
 */
27
class Response extends Message implements ResponseInterface
28
{
29
    /**
30
     * Status code
31
     *
32
     * @var int
33
     */
34
    protected $status = 200;
35
36
    /**
37
     * Reason phrase
38
     *
39
     * @var string
40
     */
41
    protected $reasonPhrase = '';
42
43
    /**
44
     * Status codes and reason phrases
45
     *
46
     * @var array
47
     */
48
    protected static $messages = [
49
        //Informational 1xx
50
        100 => 'Continue',
51
        101 => 'Switching Protocols',
52
        102 => 'Processing',
53
        //Successful 2xx
54
        200 => 'OK',
55
        201 => 'Created',
56
        202 => 'Accepted',
57
        203 => 'Non-Authoritative Information',
58
        204 => 'No Content',
59
        205 => 'Reset Content',
60
        206 => 'Partial Content',
61
        207 => 'Multi-Status',
62
        208 => 'Already Reported',
63
        226 => 'IM Used',
64
        //Redirection 3xx
65
        300 => 'Multiple Choices',
66
        301 => 'Moved Permanently',
67
        302 => 'Found',
68
        303 => 'See Other',
69
        304 => 'Not Modified',
70
        305 => 'Use Proxy',
71
        306 => '(Unused)',
72
        307 => 'Temporary Redirect',
73
        308 => 'Permanent Redirect',
74
        //Client Error 4xx
75
        400 => 'Bad Request',
76
        401 => 'Unauthorized',
77
        402 => 'Payment Required',
78
        403 => 'Forbidden',
79
        404 => 'Not Found',
80
        405 => 'Method Not Allowed',
81
        406 => 'Not Acceptable',
82
        407 => 'Proxy Authentication Required',
83
        408 => 'Request Timeout',
84
        409 => 'Conflict',
85
        410 => 'Gone',
86
        411 => 'Length Required',
87
        412 => 'Precondition Failed',
88
        413 => 'Request Entity Too Large',
89
        414 => 'Request-URI Too Long',
90
        415 => 'Unsupported Media Type',
91
        416 => 'Requested Range Not Satisfiable',
92
        417 => 'Expectation Failed',
93
        418 => 'I\'m a teapot',
94
        421 => 'Misdirected Request',
95
        422 => 'Unprocessable Entity',
96
        423 => 'Locked',
97
        424 => 'Failed Dependency',
98
        426 => 'Upgrade Required',
99
        428 => 'Precondition Required',
100
        429 => 'Too Many Requests',
101
        431 => 'Request Header Fields Too Large',
102
        444 => 'Connection Closed Without Response',
103
        451 => 'Unavailable For Legal Reasons',
104
        499 => 'Client Closed Request',
105
        //Server Error 5xx
106
        500 => 'Internal Server Error',
107
        501 => 'Not Implemented',
108
        502 => 'Bad Gateway',
109
        503 => 'Service Unavailable',
110
        504 => 'Gateway Timeout',
111
        505 => 'HTTP Version Not Supported',
112
        506 => 'Variant Also Negotiates',
113
        507 => 'Insufficient Storage',
114
        508 => 'Loop Detected',
115
        510 => 'Not Extended',
116
        511 => 'Network Authentication Required',
117
        599 => 'Network Connect Timeout Error',
118
    ];
119
120
    /**
121
     * EOL characters used for HTTP response.
122
     *
123
     * @var string
124
     */
125
     const EOL = "\r\n";
126
127
    /**
128
     * Create new HTTP response.
129
     *
130
     * @param int                   $status  The response status code.
131
     * @param HeadersInterface|null $headers The response headers.
132
     * @param StreamInterface|null  $body    The response body.
133
     */
134
    public function __construct($status = 200, HeadersInterface $headers = null, StreamInterface $body = null)
135
    {
136
        $this->status = $this->filterStatus($status);
137
        $this->headers = $headers ? $headers : new Headers();
138
        $this->body = $body ? $body : new Body(fopen('php://temp', 'r+'));
139
    }
140
141
    /**
142
     * This method is applied to the cloned object
143
     * after PHP performs an initial shallow-copy. This
144
     * method completes a deep-copy by creating new objects
145
     * for the cloned object's internal reference pointers.
146
     */
147
    public function __clone()
148
    {
149
        $this->headers = clone $this->headers;
150
    }
151
152
    /*******************************************************************************
153
     * Status
154
     ******************************************************************************/
155
156
    /**
157
     * Gets the response status code.
158
     *
159
     * The status code is a 3-digit integer result code of the server's attempt
160
     * to understand and satisfy the request.
161
     *
162
     * @return int Status code.
163
     */
164
    public function getStatusCode()
165
    {
166
        return $this->status;
167
    }
168
169
    /**
170
     * Return an instance with the specified status code and, optionally, reason phrase.
171
     *
172
     * If no reason phrase is specified, implementations MAY choose to default
173
     * to the RFC 7231 or IANA recommended reason phrase for the response's
174
     * status code.
175
     *
176
     * This method MUST be implemented in such a way as to retain the
177
     * immutability of the message, and MUST return an instance that has the
178
     * updated status and reason phrase.
179
     *
180
     * @link http://tools.ietf.org/html/rfc7231#section-6
181
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
182
     * @param int $code The 3-digit integer result code to set.
183
     * @param string $reasonPhrase The reason phrase to use with the
184
     *     provided status code; if none is provided, implementations MAY
185
     *     use the defaults as suggested in the HTTP specification.
186
     * @return static
187
     * @throws \InvalidArgumentException For invalid status code arguments.
188
     */
189
    public function withStatus($code, $reasonPhrase = '')
190
    {
191
        $code = $this->filterStatus($code);
192
193
        if (!is_string($reasonPhrase) && !method_exists($reasonPhrase, '__toString')) {
194
            throw new InvalidArgumentException('ReasonPhrase must be a string');
195
        }
196
197
        $clone = clone $this;
198
        $clone->status = $code;
199
        if ($reasonPhrase === '' && isset(static::$messages[$code])) {
200
            $reasonPhrase = static::$messages[$code];
201
        }
202
203
        if ($reasonPhrase === '') {
204
            throw new InvalidArgumentException('ReasonPhrase must be supplied for this code');
205
        }
206
207
        $clone->reasonPhrase = $reasonPhrase;
208
209
        return $clone;
210
    }
211
212
    /**
213
     * Filter HTTP status code.
214
     *
215
     * @param  int $status HTTP status code.
216
     * @return int
217
     * @throws \InvalidArgumentException If an invalid HTTP status code is provided.
218
     */
219
    protected function filterStatus($status)
220
    {
221
        if (!is_integer($status) || $status<100 || $status>599) {
222
            throw new InvalidArgumentException('Invalid HTTP status code');
223
        }
224
225
        return $status;
226
    }
227
228
    /**
229
     * Gets the response reason phrase associated with the status code.
230
     *
231
     * Because a reason phrase is not a required element in a response
232
     * status line, the reason phrase value MAY be null. Implementations MAY
233
     * choose to return the default RFC 7231 recommended reason phrase (or those
234
     * listed in the IANA HTTP Status Code Registry) for the response's
235
     * status code.
236
     *
237
     * @link http://tools.ietf.org/html/rfc7231#section-6
238
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
239
     * @return string Reason phrase; must return an empty string if none present.
240
     */
241
    public function getReasonPhrase()
242
    {
243
        if ($this->reasonPhrase) {
244
            return $this->reasonPhrase;
245
        }
246
        if (isset(static::$messages[$this->status])) {
247
            return static::$messages[$this->status];
248
        }
249
        return '';
250
    }
251
252
    /*******************************************************************************
253
     * Headers
254
     ******************************************************************************/
255
256
    /**
257
     * Return an instance with the provided value replacing the specified header.
258
     *
259
     * If a Location header is set and the status code is 200, then set the status
260
     * code to 302 to mimic what PHP does. See https://github.com/slimphp/Slim/issues/1730
261
     *
262
     * @param string $name Case-insensitive header field name.
263
     * @param string|string[] $value Header value(s).
264
     * @return static
265
     * @throws \InvalidArgumentException for invalid header names or values.
266
     */
267
    public function withHeader($name, $value)
268
    {
269
        $clone = clone $this;
270
        $clone->headers->set($name, $value);
271
272
        if (200 == $clone->getStatusCode() && 'location' == strtolower($name)) {
273
            $clone = $clone->withStatus(302);
274
        }
275
276
        return $clone;
277
    }
278
279
280
    /*******************************************************************************
281
     * Body
282
     ******************************************************************************/
283
284
    /**
285
     * Write data to the response body.
286
     *
287
     * Note: This method is not part of the PSR-7 standard.
288
     *
289
     * Proxies to the underlying stream and writes the provided data to it.
290
     *
291
     * @param string $data
292
     * @return $this
293
     */
294
    public function write($data)
295
    {
296
        $this->getBody()->write($data);
297
298
        return $this;
299
    }
300
301
    /*******************************************************************************
302
     * Response Helpers
303
     ******************************************************************************/
304
305
    /**
306
     * Redirect.
307
     *
308
     * Note: This method is not part of the PSR-7 standard.
309
     *
310
     * This method prepares the response object to return an HTTP Redirect
311
     * response to the client.
312
     *
313
     * @param  string|UriInterface $url    The redirect destination.
314
     * @param  int|null            $status The redirect HTTP status code.
315
     * @return static
316
     */
317
    public function withRedirect($url, $status = null)
318
    {
319
        $responseWithRedirect = $this->withHeader('Location', (string)$url);
320
321
        if (is_null($status) && $this->getStatusCode() === 200) {
322
            $status = 302;
323
        }
324
325
        if (!is_null($status)) {
326
            return $responseWithRedirect->withStatus($status);
327
        }
328
329
        return $responseWithRedirect;
330
    }
331
332
    /**
333
     * Json.
334
     *
335
     * Note: This method is not part of the PSR-7 standard.
336
     *
337
     * This method prepares the response object to return an HTTP Json
338
     * response to the client.
339
     *
340
     * @param  mixed  $data   The data
341
     * @param  int    $status The HTTP status code.
342
     * @param  int    $encodingOptions Json encoding options
343
     * @throws \RuntimeException
344
     * @return static
345
     */
346
    public function withJson($data, $status = null, $encodingOptions = 0)
347
    {
348
        $response = $this->withBody(new Body(fopen('php://temp', 'r+')));
349
        $response->body->write($json = json_encode($data, $encodingOptions));
350
351
        // Ensure that the json encoding passed successfully
352
        if ($json === false) {
353
            throw new \RuntimeException(json_last_error_msg(), json_last_error());
354
        }
355
356
        $responseWithJson = $response->withHeader('Content-Type', 'application/json;charset=utf-8');
357
        if (isset($status)) {
358
            return $responseWithJson->withStatus($status);
359
        }
360
        return $responseWithJson;
361
    }
362
363
    /**
364
     * Is this response empty?
365
     *
366
     * Note: This method is not part of the PSR-7 standard.
367
     *
368
     * @return bool
369
     */
370
    public function isEmpty()
371
    {
372
        return in_array($this->getStatusCode(), [204, 205, 304]);
373
    }
374
375
    /**
376
     * Is this response informational?
377
     *
378
     * Note: This method is not part of the PSR-7 standard.
379
     *
380
     * @return bool
381
     */
382
    public function isInformational()
383
    {
384
        return $this->getStatusCode() >= 100 && $this->getStatusCode() < 200;
385
    }
386
387
    /**
388
     * Is this response OK?
389
     *
390
     * Note: This method is not part of the PSR-7 standard.
391
     *
392
     * @return bool
393
     */
394
    public function isOk()
395
    {
396
        return $this->getStatusCode() === 200;
397
    }
398
399
    /**
400
     * Is this response successful?
401
     *
402
     * Note: This method is not part of the PSR-7 standard.
403
     *
404
     * @return bool
405
     */
406
    public function isSuccessful()
407
    {
408
        return $this->getStatusCode() >= 200 && $this->getStatusCode() < 300;
409
    }
410
411
    /**
412
     * Is this response a redirect?
413
     *
414
     * Note: This method is not part of the PSR-7 standard.
415
     *
416
     * @return bool
417
     */
418
    public function isRedirect()
419
    {
420
        return in_array($this->getStatusCode(), [301, 302, 303, 307]);
421
    }
422
423
    /**
424
     * Is this response a redirection?
425
     *
426
     * Note: This method is not part of the PSR-7 standard.
427
     *
428
     * @return bool
429
     */
430
    public function isRedirection()
431
    {
432
        return $this->getStatusCode() >= 300 && $this->getStatusCode() < 400;
433
    }
434
435
    /**
436
     * Is this response forbidden?
437
     *
438
     * Note: This method is not part of the PSR-7 standard.
439
     *
440
     * @return bool
441
     * @api
442
     */
443
    public function isForbidden()
444
    {
445
        return $this->getStatusCode() === 403;
446
    }
447
448
    /**
449
     * Is this response not Found?
450
     *
451
     * Note: This method is not part of the PSR-7 standard.
452
     *
453
     * @return bool
454
     */
455
    public function isNotFound()
456
    {
457
        return $this->getStatusCode() === 404;
458
    }
459
460
    /**
461
     * Is this response a client error?
462
     *
463
     * Note: This method is not part of the PSR-7 standard.
464
     *
465
     * @return bool
466
     */
467
    public function isClientError()
468
    {
469
        return $this->getStatusCode() >= 400 && $this->getStatusCode() < 500;
470
    }
471
472
    /**
473
     * Is this response a server error?
474
     *
475
     * Note: This method is not part of the PSR-7 standard.
476
     *
477
     * @return bool
478
     */
479
    public function isServerError()
480
    {
481
        return $this->getStatusCode() >= 500 && $this->getStatusCode() < 600;
482
    }
483
484
    /**
485
     * Convert response to string.
486
     *
487
     * Note: This method is not part of the PSR-7 standard.
488
     *
489
     * @return string
490
     */
491
    public function __toString()
492
    {
493
        $output = sprintf(
494
            'HTTP/%s %s %s',
495
            $this->getProtocolVersion(),
496
            $this->getStatusCode(),
497
            $this->getReasonPhrase()
498
        );
499
        $output .= Response::EOL;
500
        foreach ($this->getHeaders() as $name => $values) {
501
            $output .= sprintf('%s: %s', $name, $this->getHeaderLine($name)) . Response::EOL;
502
        }
503
        $output .= Response::EOL;
504
        $output .= (string)$this->getBody();
505
506
        return $output;
507
    }
508
}
509