Response::getStatusCode()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 3
cp 0.6667
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1.037
1
<?php
2
3
/**
4
 * This file is part of the Phalcon Framework.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 *
11
 * Implementation of this file has been influenced by Zend Diactoros
12
 *
13
 * @link    https://github.com/zendframework/zend-diactoros
14
 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md
15
 */
16
17
declare(strict_types=1);
18
19
namespace Phalcon\Http\Message;
20
21
use Phalcon\Helper\Number;
22
use Phalcon\Http\Message\Exception\InvalidArgumentException;
23
use Phalcon\Http\Message\Traits\CommonTrait;
24
use Phalcon\Http\Message\Traits\MessageTrait;
25
use Phalcon\Http\Message\Traits\ResponseTrait;
26
use Psr\Http\Message\ResponseInterface;
27
28
use function is_int;
29
use function is_string;
30
31
/**
32
 * PSR-7 Response
33
 *
34
 * @property string $reasonPhrase
35
 * @property int    $statusCode
36
 */
37
final class Response implements ResponseInterface
38
{
39
    use CommonTrait;
40
    use MessageTrait;
41
    use ResponseTrait;
42
43
    /**
44
     * Gets the response reason phrase associated with the status code.
45
     *
46
     * Because a reason phrase is not a required element in a response
47
     * status line, the reason phrase value MAY be empty. Implementations MAY
48
     * choose to return the default RFC 7231 recommended reason phrase (or
49
     * those
50
     * listed in the IANA HTTP Status Code Registry) for the response's
51
     * status code.
52
     *
53
     * @see http://tools.ietf.org/html/rfc7231#section-6
54
     * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
55
     *
56
     * @var string
57
     */
58
    private $reasonPhrase = '';
59
60
    /**
61
     * Gets the response status code.
62
     *
63
     * The status code is a 3-digit integer result code of the server's attempt
64
     * to understand and satisfy the request.
65
     *
66
     * @var int
67
     */
68
    private $statusCode = 200;
69
70
    /**
71
     * Response constructor.
72
     *
73
     * @param string $body
74
     * @param int    $code
75
     * @param array  $headers
76
     */
77 29
    public function __construct(
78
        $body = "php://memory",
79
        int $code = 200,
80
        array $headers = []
81
    ) {
82 29
        $this->processCode($code);
83
84 28
        $this->headers = $this->processHeaders($headers);
85 28
        $this->body    = $this->processBody($body, "w+b");
86 28
    }
87
88
    /**
89
     * Returns the reason phrase
90
     *
91
     * @return string
92
     */
93 3
    public function getReasonPhrase(): string
94
    {
95 3
        return $this->reasonPhrase;
96
    }
97
98
    /**
99
     * Returns the status code
100
     *
101
     * @return int
102
     */
103 3
    public function getStatusCode()
104
    {
105 3
        return $this->statusCode;
106
    }
107
108
    /**
109
     * Return an instance with the specified status code and, optionally,
110
     * reason phrase.
111
     *
112
     * If no reason phrase is specified, implementations MAY choose to default
113
     * to the RFC 7231 or IANA recommended reason phrase for the response's
114
     * status code.
115
     *
116
     * This method MUST be implemented in such a way as to retain the
117
     * immutability of the message, and MUST return an instance that has the
118
     * updated status and reason phrase.
119
     *
120
     * @see http://tools.ietf.org/html/rfc7231#section-6
121
     * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
122
     *
123
     * @param int    $code
124
     * @param string $reasonPhrase
125
     *
126
     * @return Response
127
     */
128 5
    public function withStatus($code, $reasonPhrase = ""): Response
129
    {
130 5
        $newInstance = clone $this;
131
132 5
        $newInstance->processCode($code, $reasonPhrase);
133
134 3
        return $newInstance;
135
    }
136
137
    /**
138
     * Checks if a code is integer or string
139
     *
140
     * @param mixed $code
141
     */
142 29
    private function checkCodeType($code): void
143
    {
144 29
        if (!is_int($code) && !is_string($code)) {
145 1
            throw new InvalidArgumentException(
146 1
                "Invalid status code; it must be an integer or string"
147
            );
148
        }
149 29
    }
150
151
    /**
152
     * Checks if a code is integer or string
153
     *
154
     * @param int $code
155
     */
156 29
    private function checkCodeValue(int $code): void
157
    {
158 29
        if (true !== Number::between($code, 100, 599)) {
159 1
            throw new InvalidArgumentException(
160 1
                "Invalid status code '" . $code . "', (allowed values 100-599)"
161
            );
162
        }
163 28
    }
164
165
    /**
166
     * Returns the list of status codes available
167
     */
168 29
    private function getPhrases(): array
169
    {
170
        return [
171 29
            100 => "Continue",                                         // Information - RFC 7231, 6.2.1
172
            101 => "Switching Protocols",                              // Information - RFC 7231, 6.2.2
173
            102 => "Processing",                                       // Information - RFC 2518, 10.1
174
            103 => "Early Hints",
175
            200 => "OK",                                               // Success - RFC 7231, 6.3.1
176
            201 => "Created",                                          // Success - RFC 7231, 6.3.2
177
            202 => "Accepted",                                         // Success - RFC 7231, 6.3.3
178
            203 => "Non-Authoritative Information",                    // Success - RFC 7231, 6.3.4
179
            204 => "No Content",                                       // Success - RFC 7231, 6.3.5
180
            205 => "Reset Content",                                    // Success - RFC 7231, 6.3.6
181
            206 => "Partial Content",                                  // Success - RFC 7233, 4.1
182
            207 => "Multi-status",                                     // Success - RFC 4918, 11.1
183
            208 => "Already Reported",                                 // Success - RFC 5842, 7.1
184
            218 => "This is fine",                                     // Unofficial - Apache Web Server
185
            419 => "Page Expired",                                     // Unofficial - Laravel Framework
186
            226 => "IM Used",                                          // Success - RFC 3229, 10.4.1
187
            300 => "Multiple Choices",                                 // Redirection - RFC 7231, 6.4.1
188
            301 => "Moved Permanently",                                // Redirection - RFC 7231, 6.4.2
189
            302 => "Found",                                            // Redirection - RFC 7231, 6.4.3
190
            303 => "See Other",                                        // Redirection - RFC 7231, 6.4.4
191
            304 => "Not Modified",                                     // Redirection - RFC 7232, 4.1
192
            305 => "Use Proxy",                                        // Redirection - RFC 7231, 6.4.5
193
            306 => "Switch Proxy",                                     // Redirection - RFC 7231, 6.4.6 (Deprecated)
194
            307 => "Temporary Redirect",                               // Redirection - RFC 7231, 6.4.7
195
            308 => "Permanent Redirect",                               // Redirection - RFC 7538, 3
196
            400 => "Bad Request",                                      // Client Error - RFC 7231, 6.5.1
197
            401 => "Unauthorized",                                     // Client Error - RFC 7235, 3.1
198
            402 => "Payment Required",                                 // Client Error - RFC 7231, 6.5.2
199
            403 => "Forbidden",                                        // Client Error - RFC 7231, 6.5.3
200
            404 => "Not Found",                                        // Client Error - RFC 7231, 6.5.4
201
            405 => "Method Not Allowed",                               // Client Error - RFC 7231, 6.5.5
202
            406 => "Not Acceptable",                                   // Client Error - RFC 7231, 6.5.6
203
            407 => "Proxy Authentication Required",                    // Client Error - RFC 7235, 3.2
204
            408 => "Request Time-out",                                 // Client Error - RFC 7231, 6.5.7
205
            409 => "Conflict",                                         // Client Error - RFC 7231, 6.5.8
206
            410 => "Gone",                                             // Client Error - RFC 7231, 6.5.9
207
            411 => "Length Required",                                  // Client Error - RFC 7231, 6.5.10
208
            412 => "Precondition Failed",                              // Client Error - RFC 7232, 4.2
209
            413 => "Request Entity Too Large",                         // Client Error - RFC 7231, 6.5.11
210
            414 => "Request-URI Too Large",                            // Client Error - RFC 7231, 6.5.12
211
            415 => "Unsupported Media Type",                           // Client Error - RFC 7231, 6.5.13
212
            416 => "Requested range not satisfiable",                  // Client Error - RFC 7233, 4.4
213
            417 => "Expectation Failed",                               // Client Error - RFC 7231, 6.5.14
214
            418 => "I'm a teapot",                                     // Client Error - RFC 7168, 2.3.3
215
            420 => "Method Failure",                                   // Unofficial - Spring Framework
216
            421 => "Misdirected Request",
217
            422 => "Unprocessable Entity",                             // Client Error - RFC 4918, 11.2
218
            423 => "Locked",                                           // Client Error - RFC 4918, 11.3
219
            424 => "Failed Dependency",                                // Client Error - RFC 4918, 11.4
220
            425 => "Unordered Collection",
221
            426 => "Upgrade Required",                                 // Client Error - RFC 7231, 6.5.15
222
            428 => "Precondition Required",                            // Client Error - RFC 6585, 3
223
            429 => "Too Many Requests",                                // Client Error - RFC 6585, 4
224
            431 => "Request Header Fields Too Large",                  // Client Error - RFC 6585, 5
225
            440 => "Login Time-out",                                   // Unofficial - IIS
226
            444 => "No Response",                                      // Unofficial - nginx
227
            449 => "Retry With",                                       // Unofficial - IIS
228
            494 => "Request header too large",                         // Unofficial - nginx
229
            495 => "SSL Certificate Error",                            // Unofficial - nginx
230
            496 => "SSL Certificate Required",                         // Unofficial - nginx
231
            497 => "HTTP Request Sent to HTTPS Port",                  // Unofficial - nginx
232
            499 => "Client Closed Request",                            // Unofficial - nginx
233
            450 => "Blocked by Windows Parental Controls (Microsoft)", // Unofficial - nginx
234
            451 => "Unavailable For Legal Reasons",                    // Client Error - RFC 7725, 3
235
            498 => "Invalid Token (Esri)",                             // Unofficial - ESRI
236
            500 => "Internal Server Error",                            // Server Error - RFC 7231, 6.6.1
237
            501 => "Not Implemented",                                  // Server Error - RFC 7231, 6.6.2
238
            502 => "Bad Gateway",                                      // Server Error - RFC 7231, 6.6.3
239
            503 => "Service Unavailable",                              // Server Error - RFC 7231, 6.6.4
240
            504 => "Gateway Time-out",                                 // Server Error - RFC 7231, 6.6.5
241
            505 => "HTTP Version not supported",                       // Server Error - RFC 7231, 6.6.6
242
            506 => "Variant Also Negotiates",                          // Server Error - RFC 2295, 8.1
243
            507 => "Insufficient Storage",                             // Server Error - RFC 4918, 11.5
244
            508 => "Loop Detected",                                    // Server Error - RFC 5842, 7.2
245
            509 => "Bandwidth Limit Exceeded",                         // Unofficial - Apache/cPanel
246
            510 => "Not Extended",                                     // Server Error - RFC 2774, 7
247
            511 => "Network Authentication Required",                  // Server Error - RFC 6585, 6
248
            520 => "Unknown Error",                                    // Unofficial - Cloudflare
249
            521 => "Web Server Is Down",                               // Unofficial - Cloudflare
250
            522 => "Connection Timed Out",                             // Unofficial - Cloudflare
251
            523 => "Origin Is Unreachable",                            // Unofficial - Cloudflare
252
            524 => "A Timeout Occurred",                               // Unofficial - Cloudflare
253
            525 => "SSL Handshake Failed",                             // Unofficial - Cloudflare
254
            526 => "Invalid SSL Certificate",                          // Unofficial - Cloudflare
255
            527 => "Railgun Error",                                    // Unofficial - Cloudflare
256
            530 => "Origin DNS Error",                                 // Unofficial - Cloudflare
257
            598 => "Network read timeout error",                       // Unofficial
258
            599 => "Network Connect Timeout Error"                     // Server Error - RFC 6585, 6
259
        ];
260
    }
261
262
    /**
263
     * Set a valid status code and phrase
264
     *
265
     * @param mixed $code
266
     * @param mixed $phrase
267
     */
268 29
    private function processCode($code, $phrase = ""): void
269
    {
270 29
        $phrases = $this->getPhrases();
271
272 29
        $this->checkCodeType($code);
273
274 29
        $code = (int) $code;
275 29
        $this->checkCodeValue($code);
276
277 28
        if (!is_string($phrase)) {
278 1
            throw new InvalidArgumentException("Invalid response reason");
279
        }
280
281 28
        if ("" === $phrase && isset($phrases[$code])) {
282 28
            $phrase = $phrases[$code];
283
        }
284
285 28
        $this->statusCode   = $code;
286 28
        $this->reasonPhrase = $phrase;
287 28
    }
288
}
289