Response::withStatus()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * This file is part of the alphaz Framework.
5
 *
6
 * @author Muhammad Umer Farooq (Malik) <[email protected]>
7
 *
8
 * @link https://github.com/alphazframework/framework
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 *  file that was distributed with this source code.
12
 * @since 1.0.0
13
 *
14
 * @license MIT
15
 */
16
17
namespace alphaz\http;
18
19
class Response extends Message
20
{
21
    /**
22
     * __construct.
23
     *
24
     * Instantiate the response object
25
     *
26
     * @param (array) $config
27
     *
28
     * @since 1.0.0
29
     */
30
    public function __construct(array $config = [])
31
    {
32
        parent::__construct();
33
        // Check for config values and set defaults
34
        if (!isset($config['version'])) {
35
            $config['version'] = '1.1';
36
        }
37
        if (!isset($config['code'])) {
38
            $config['code'] = 200;
39
        }
40
41
        $this->setVersion($config['version'])
42
             ->withStatus($config['code']);
43
44
        if (!isset($config['reasonPhrase'])) {
45
            $config['reasonPhrase'] = self::$responseCodes[$config['code']];
46
        }
47
        if (!isset($config['headers']) || (isset($config['headers']) && !is_array($config['headers']))) {
48
            $config['headers'] = ['Content-Type' => 'text/html'];
49
        }
50
        if (!isset($config['body'])) {
51
            $config['body'] = null;
52
        }
53
54
        $this->setReasonPhrase($config['reasonPhrase'])
55
             ->setHeaders($config['headers'])
56
             ->setBody($config['body']);
57
    }
58
59
    /**
60
     * Get response message from code.
61
     *
62
     * @param (int) $code
63
     *
64
     * @since 1.0.0
65
     *
66
     * @return string
67
     */
68
    public static function getMessageFromCode($code)
69
    {
70
        if (!array_key_exists($code, self::$responseCodes)) {
71
            throw new \Exception('The header code '.$code.' is not valid.');
72
        }
73
74
        return self::$responseCodes[$code];
75
    }
76
77
    /**
78
     * Encode the body data.
79
     *
80
     * @param (mixed)  $body
81
     * @param (string) $encode
82
     *
83
     * @since 1.0.0
84
     *
85
     * @return string
86
     */
87
    public static function encodeBody($body, $encode = 'gzip')
88
    {
89
        switch ($encode) {
90
            // GZIP compression
91
            case 'gzip':
92
                if (!function_exists('gzencode')) {
93
                    throw new \Exception('Gzip compression is not available.');
94
                }
95
                $encodedBody = gzencode($body);
96
                break;
97
98
                // Deflate compression
99
            case 'deflate':
100
                if (!function_exists('gzdeflate')) {
101
                    throw new \Exception('Deflate compression is not available.');
102
                }
103
                $encodedBody = gzdeflate($body);
104
                break;
105
106
                // Unknown compression
107
            default:
108
                $encodedBody = $body;
109
        }
110
111
        return $encodedBody;
112
    }
113
114
    /**
115
     * Decode the body data.
116
     *
117
     * @param (mixed)  $body
118
     * @param (string) $encode
119
     *
120
     * @since 1.0.0
121
     *
122
     * @return string
123
     */
124
    public static function decodeBody($body, $decode = 'gzip')
125
    {
126
        switch ($decode) {
127
            // GZIP compression
128
            case 'gzip':
129
                if (!function_exists('gzinflate')) {
130
                    throw new \Exception('Gzip compression is not available.');
131
                }
132
                $decodedBody = gzinflate(substr($body, 10));
133
                break;
134
135
                // Deflate compression
136
            case 'deflate':
137
                if (!function_exists('gzinflate')) {
138
                    throw new \Exception('Deflate compression is not available.');
139
                }
140
                $zlibHeader = unpack('n', substr($body, 0, 2));
141
                $decodedBody = ($zlibHeader[1] % 31 == 0) ? gzuncompress($body) : gzinflate($body);
142
                break;
143
144
                // Unknown compression
145
            default:
146
                $decodedBody = $body;
147
        }
148
149
        return $decodedBody;
150
    }
151
152
    /**
153
     * Is this response empty?.
154
     *
155
     * @since 1.0.0
156
     *
157
     * @return bool
158
     */
159
    public function isEmpty()
160
    {
161
        return in_array($this->getStatusCode(), [204, 205, 304]);
162
    }
163
164
    /**
165
     * Is this response ok?.
166
     *
167
     * @since 1.0.0
168
     *
169
     * @return bool
170
     */
171
    public function isOk()
172
    {
173
        return $this->getStatusCode() === 200;
174
    }
175
176
    /**
177
     * Is this response successful?.
178
     *
179
     * @since 1.0.0
180
     *
181
     * @return bool
182
     */
183
    public function isSuccessful()
184
    {
185
        return $this->getStatusCode() >= 200 && $this->getStatusCode() < 300;
186
    }
187
188
    /**
189
     * Is this response redirect.
190
     *
191
     * @since 1.0.0
192
     *
193
     * @return bool
194
     */
195
    public function isRedirect()
196
    {
197
        return in_array($this->getStatusCode(), [301, 302, 303, 307, 308]);
198
    }
199
200
    /**
201
     * Is this response Forbidden?.
202
     *
203
     * @since 1.0.0
204
     *
205
     * @return bool
206
     */
207
    public function isForbidden()
208
    {
209
        return $this->getStatusCode() === 403;
210
    }
211
212
    /**
213
     * Is this response not found?.
214
     *
215
     * @since 1.0.0
216
     *
217
     * @return bool
218
     */
219
    public function isNotFound()
220
    {
221
        return $this->getStatusCode() === 404;
222
    }
223
224
    /**
225
     * Is this response Client error?.
226
     *
227
     * @since 1.0.0
228
     *
229
     * @return bool
230
     */
231
    public function isClientError()
232
    {
233
        return $this->getStatusCode() >= 400 && $this->getStatusCode() < 500;
234
    }
235
236
    /**
237
     * Is this response Server error?.
238
     *
239
     * @since 1.0.0
240
     *
241
     * @return bool
242
     */
243
    public function isServertusCode()
244
    {
245
        return $this->getStatusCode() >= 500 && $this->getStatusCode() < 600;
246
    }
247
248
    /**
249
     * Get the response headers as a string.
250
     *
251
     * @param (bool) $status
252
     *                       (string) $eol
253
     *
254
     * @since 1.0.0
255
     *
256
     * @return string
257
     */
258
    public function getHeadersAsString($status = true, $eol = "\n")
259
    {
260
        $headers = '';
261
262
        if ($status) {
263
            $headers = "HTTP/{$this->version} {$this->code} {$this->reasonPhrase}{$eol}";
264
        }
265
266
        foreach ($this->headers as $name => $value) {
267
            $headers .= "{$name}: {$value}{$eol}";
268
        }
269
270
        return $headers;
271
    }
272
273
    /**
274
     * Set the reasonPhrase.
275
     *
276
     * @param (float) $version
277
     *
278
     * @since 1.0.0
279
     *
280
     * @return object
281
     */
282
    public function setReasonPhrase($reasonPhrase = '')
283
    {
284
        $this->reasonPhrase = $reasonPhrase;
285
286
        return $this;
287
    }
288
289
    /**
290
     * Set the protocol version.
291
     *
292
     * @param (float) $version
293
     *
294
     * @since 1.0.0
295
     *
296
     * @return object
297
     */
298
    public function setVersion($version = 1.1)
299
    {
300
        $this->withProtocolVersion($version);
301
302
        return $this;
303
    }
304
305
    /**
306
     * Get the status code.
307
     *
308
     * @since 1.0.0
309
     *
310
     * @return int
311
     */
312
    public function getStatusCode()
313
    {
314
        return $this->code;
315
    }
316
317
    /**
318
     * Set the status code.
319
     *
320
     * @param (int) $code
321
     *
322
     * @since 1.0.0
323
     *
324
     * @return object
325
     */
326
    public function withStatus($code = 200)
327
    {
328
        if (!array_key_exists($code, self::$responseCodes)) {
329
            throw new \Exception('That header code '.$code.' is not allowed.');
330
        }
331
332
        $this->code = $code;
333
        $this->reasonPhrase = self::$responseCodes[$code];
334
335
        return $this;
336
    }
337
338
    /**
339
     * Set the response body.
340
     *
341
     * @param (mixed) $body
342
     *
343
     * @since 1.0.0
344
     *
345
     * @return object
346
     */
347
    public function setBody($body = null)
348
    {
349
        $this->withBody($body);
350
351
        return $this;
352
    }
353
354
    /**
355
     * Set SSL headers to fix file cache issues over SSL in certain browsers.
356
     *
357
     * @since 1.0.0
358
     *
359
     * @return object
360
     */
361
    public function setSslHeaders()
362
    {
363
        $this->setHeader('Expires', 0);
364
        $this->setHeader('Cache-Control', 'private, must-revalidate');
365
        $this->setHeader('Pragma', 'cache');
366
367
        return $this;
368
    }
369
370
    /**
371
     * Send response and exit.
372
     *
373
     * @param (int) $code
374
     *                    (array) $headers
375
     *
376
     * @since 1.0.0
377
     *
378
     * @return void
379
     */
380
    public function sendAndExit($code = null, array $headers = null)
381
    {
382
        $this->send($code, $headers);
383
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
384
    }
385
386
    /**
387
     * Return entire response as a string.
388
     *
389
     * @return string
390
     */
391
    public function __toString()
392
    {
393
        $body = $this->body;
394
395
        if (array_key_exists('Content-Encoding', $this->headers)) {
396
            $body = self::encodeBody($body, $this->headers['Content-Encoding']);
397
            $this->headers['Content-Length'] = strlen($body);
398
        }
399
400
        return $this->getHeadersAsString()."\n".$body;
401
    }
402
}
403