Issues (94)

src/Suricate/Request.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use InvalidArgumentException;
8
9
/**
10
 * Request class
11
 *
12
 * @SuppressWarnings("StaticAccess")
13
 */
14
class Request
15
{
16
    const HTTP_METHOD_GET = 'GET';
17
    const HTTP_METHOD_POST = 'POST';
18
    const HTTP_METHOD_PUT = 'PUT';
19
    const HTTP_METHOD_DELETE = 'DELETE';
20
    const HTTP_METHOD_HEAD = 'HEAD';
21
    const HTTP_METHOD_OPTIONS = 'OPTIONS';
22
23
    private $method = self::HTTP_METHOD_GET;
24
    private $methods = [
25
        self::HTTP_METHOD_GET => 'GET',
26
        self::HTTP_METHOD_POST => 'POST',
27
        self::HTTP_METHOD_PUT => 'PUT',
28
        self::HTTP_METHOD_DELETE => 'DELETE',
29
        self::HTTP_METHOD_HEAD => 'HEAD',
30
        self::HTTP_METHOD_OPTIONS => 'OPTIONS'
31
    ];
32
33
    private $httpCodeString = [
34
        100 => 'Continue',
35
        101 => 'Switching Protocols',
36
        102 => 'Processing',
37
        200 => 'OK',
38
        201 => 'Created',
39
        202 => 'Accepted',
40
        203 => 'Non-Authoritative Information',
41
        204 => 'No Content',
42
        205 => 'Reset Content',
43
        206 => 'Partial Content',
44
        207 => 'Multi-Status',
45
        208 => 'Already Reported',
46
        226 => 'IM Used',
47
        250 => 'Low on Storage Space',
48
        300 => 'Multiple Choices',
49
        301 => 'Moved Permanently',
50
        302 => 'Found',
51
        303 => 'See Other',
52
        304 => 'Not Modified',
53
        305 => 'Use Proxy',
54
        306 => '306 Switch Proxy',
55
        307 => 'Temporary Redirect',
56
        308 => 'Permanent Redirect',
57
        400 => 'Bad Request',
58
        401 => 'Unauthorized',
59
        402 => 'Payment Required',
60
        403 => 'Forbidden',
61
        404 => 'Not Found',
62
        405 => 'Method Not Allowed',
63
        406 => 'Not Acceptable',
64
        407 => 'Proxy Authentication Required',
65
        408 => 'Request Timeout',
66
        409 => 'Conflict',
67
        410 => 'Gone',
68
        411 => 'Length Required',
69
        412 => 'Precondition Failed',
70
        413 => 'Request Entity Too Large',
71
        414 => 'Request-URI Too Long',
72
        415 => 'Unsupported Media Type',
73
        416 => 'Requested Range Not Satisfiable',
74
        417 => 'Expectation Failed',
75
        422 => 'Unprocessable Entity',
76
        423 => 'Locked',
77
        424 => 'Failed Dependency',
78
        425 => 'Unordered Collection',
79
        426 => 'Upgrade Required',
80
        428 => 'Precondition Required',
81
        429 => 'Too Many Requests',
82
        431 => 'Request Header Fields Too Large',
83
        444 => 'No Response',
84
        449 => 'Retry With',
85
        450 => 'Blocked by Windows Parental Controls',
86
        494 => 'Request Header Too Large',
87
        495 => 'Cert Error',
88
        496 => 'No Cert',
89
        497 => 'HTTP to HTTPS',
90
        499 => 'Client Closed Request',
91
        500 => 'Internal Server Error',
92
        501 => 'Not Implemented',
93
        502 => 'Bad Gateway',
94
        503 => 'Service Unavailable',
95
        504 => 'Gateway Timeout',
96
        505 => 'HTTP Version Not Supported',
97
        506 => 'Variant Also Negotiates',
98
        507 => 'Insufficient Storage',
99
        508 => 'Loop Detected',
100
        509 => 'Bandwidth Limit Exceeded',
101
        510 => 'Not Extended',
102
        511 => 'Network Authentication Required'
103
    ];
104
105
    private $httpCode;
106
    private $headers = [];
107
    private $requestUri = '';
108
    private $remoteIp;
109
    private $url;
110
    private $body;
111
    private $path;
112
    private $query;
113
114
    /**
115
     * Request constructor
116
     */
117 18
    public function __construct()
118
    {
119 18
        $this->headers = [];
120 18
        $this->httpCode = 200;
121 18
    }
122
123
    /**
124
     * Parse server request
125
     *
126
     * @return void
127
     *
128
     * @SuppressWarnings(PHPMD).Superglobals
129
     */
130 9
    public function parse()
131
    {
132 9
        if (isset($_SERVER['REQUEST_URI'])) {
133 5
            $this->setRequestUri($_SERVER['REQUEST_URI']);
134 5
            $parseResult = parse_url($_SERVER['REQUEST_URI']);
135 5
            $this->path = dataGet($parseResult, 'path');
136 5
            $this->query = dataGet($parseResult, 'query');
137
        }
138
139 9
        if (isset($_SERVER['REQUEST_METHOD'])) {
140 1
            $this->setMethod($_SERVER['REQUEST_METHOD']);
141
        }
142 9
        if (isset($_POST['_method'])) {
143 5
            $this->setMethod($_POST['_method']);
144
        }
145
146 9
        $this->parseRemoteIp();
147 9
    }
148
149
    /**
150
     * Parse request and extract remote IP
151
     *
152
     * @return void
153
     *
154
     * @SuppressWarnings(PHPMD).Superglobals
155
     */
156 9
    private function parseRemoteIp()
157
    {
158
        // FIXME: check for trusted_proxy and void forged header
159
        if (
160 9
            array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) &&
161 9
            !empty($_SERVER['HTTP_X_FORWARDED_FOR'])
162
        ) {
163
            if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') > 0) {
164
                $addr = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);
165
                $this->remoteIp = trim($addr[0]);
166
                return;
167
            }
168
            $this->remoteIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
169
            return;
170
        }
171
172 9
        if (isset($_SERVER['REMOTE_ADDR'])) {
173
            $this->remoteIp = $_SERVER['REMOTE_ADDR'];
174
        }
175 9
        return;
176
    }
177
178
    /**
179
     * Set Request method
180
     *
181
     * @param string $method Request method
182
     * @return Request
183
     *
184
     * @throws InvalidArgumentException
185
     */
186 7
    public function setMethod($method): Request
187
    {
188 7
        if (!isset($this->methods[$method])) {
189 1
            throw new InvalidArgumentException(
190 1
                'Invalid HTTP Method ' . $method
191
            );
192
        }
193
194 7
        $this->method = $method;
195
196 7
        return $this;
197
    }
198
199
    /**
200
     * Get Request method
201
     *
202
     * @return string
203
     */
204 3
    public function getMethod(): string
205
    {
206 3
        return $this->method;
207
    }
208
209
    /**
210
     * Set Request URL
211
     *
212
     * @param string $url
213
     *
214
     * @return Request
215
     */
216 2
    public function setUrl($url): Request
217
    {
218 2
        $this->url = $url;
219
220 2
        return $this;
221
    }
222
223
    /**
224
     * Get Request URL
225
     *
226
     * @return string|null
227
     */
228 2
    public function getUrl(): ?string
229
    {
230 2
        return $this->url;
231
    }
232
233
    /**
234
     * Get Remote IP Address
235
     *
236
     * @return string|null
237
     */
238
    public function getRemoteIp(): ?string
239
    {
240
        return $this->remoteIp;
241
    }
242
243 10
    public function setRequestUri($uri)
244
    {
245 10
        $this->requestUri = $uri;
246
247 10
        return $this;
248
    }
249
250 11
    public function getRequestUri()
251
    {
252 11
        return $this->requestUri;
253
    }
254
255 1
    public function getPath()
256
    {
257 1
        return $this->path;
258
    }
259
260 1
    public function getQuery()
261
    {
262 1
        return $this->query;
263
    }
264
265
    /**
266
     * Get POST parameter
267
     *
268
     * @param string $variable     Parameter name
269
     * @param mixed  $defaultValue Fallback value when parameter not set
270
     *
271
     * @return mixed
272
     *
273
     * @SuppressWarnings(PHPMD).Superglobals
274
     */
275 1
    public static function getPostParam($variable, $defaultValue = null)
276
    {
277 1
        if (array_key_exists($variable, $_POST)) {
278 1
            return $_POST[$variable];
279
        }
280 1
        return $defaultValue;
281
    }
282
283
    /**
284
     * Get Request parameter, GET first, then POST
285
     *
286
     * @param string $variable     Parameter name
287
     * @param mixed  $defaultValue Fallback value when parameter not set
288
     *
289
     * @return mixed
290
     *
291
     * @SuppressWarnings(PHPMD).Superglobals
292
     */
293 1
    public static function getParam($variable, $defaultValue = null)
294
    {
295 1
        if (array_key_exists($variable, $_GET)) {
296 1
            return $_GET[$variable];
297
        }
298 1
        if (array_key_exists($variable, $_POST)) {
299 1
            return $_POST[$variable];
300
        }
301
302 1
        return $defaultValue;
303
    }
304
305
    /**
306
     * Check if parameter exists in Request
307
     *
308
     * @param string $variable parameter name
309
     *
310
     * @return boolean
311
     *
312
     * @SuppressWarnings(PHPMD).Superglobals
313
     */
314 1
    public static function hasParam($variable): bool
315
    {
316 1
        return array_key_exists($variable, $_GET) ||
317 1
            array_key_exists($variable, $_POST);
318
    }
319
320
    /**
321
     * Set request headers
322
     *
323
     * @param array $headers Headers to set key => $value
324
     *
325
     * @return Request
326
     */
327 1
    public function setHeaders(array $headers): Request
328
    {
329 1
        $this->headers = $headers;
330
331 1
        return $this;
332
    }
333
334
    /**
335
     * Add specific header
336
     *
337
     * @param string $header header name
338
     * @param string $value  header value
339
     * @return Request
340
     */
341 1
    public function addHeader($header, $value): Request
342
    {
343 1
        $this->headers[$header] = $value;
344
345 1
        return $this;
346
    }
347
348
    /**
349
     * Get request headers
350
     *
351
     * @return array
352
     */
353 1
    public function getHeaders(): array
354
    {
355 1
        return $this->headers;
356
    }
357
358 1
    public function setContentType(
359
        string $contentType,
360
        $encoding = null
361
    ): Request {
362 1
        if ($encoding !== null) {
363 1
            $contentType .= '; charset=' . $encoding;
364
        }
365 1
        $this->addHeader('Content-type', $contentType);
366
367 1
        return $this;
368
    }
369
370 1
    public function setBody(?string $body): Request
371
    {
372 1
        $this->body = $body;
373
374 1
        return $this;
375
    }
376
377 1
    public function getBody(): ?string
378
    {
379 1
        return $this->body;
380
    }
381
382
    public function write()
383
    {
384
        if (!headers_sent()) {
385
            if (substr(php_sapi_name(), 0, 3) == 'cgi') {
386
                $headerString = 'Status: ' . $this->getStringForHttpCode();
387
            } else {
388
                $headerString = 'HTTP/1.1 ' . $this->getStringForHttpCode();
389
            }
390
391
            header($headerString);
392
393
            // Send headers
394
            foreach ($this->headers as $headerName => $headerValue) {
395
                header($headerName . ':' . $headerValue);
396
            }
397
        }
398
399
        /**
400
         TODO HANDLE HTTP RESPONSE CODE
401
         */
402
        if ($this->httpCode !== null) {
403
        }
404
405
        // Send body
406
        echo $this->body;
407
    }
408
409
    //
410
    // HTTP Code
411
    //
412
413 1
    public function setHttpCode($code): Request
414
    {
415 1
        $this->httpCode = $code;
416
417 1
        return $this;
418
    }
419
420 1
    public function getHttpCode()
421
    {
422 1
        return $this->httpCode;
423
    }
424
425
    /**
426
     * Flash message
427
     *
428
     * @param string $type message type
429
     * @param array|string $data data to be flashed
430
     */
431
    public function flash(string $type, $data)
432
    {
433
        Flash::writeMessage($type, $data);
434
435
        return $this;
436
    }
437
438
    public function flashData($name, $value)
439
    {
440
        Flash::writeData($name, $value);
441
442
        return $this;
443
    }
444
445
    public function redirect($url, $httpCode = 302)
446
    {
447
        $this->setHttpCode($httpCode);
448
        $this->addHeader('Location', $url);
449
450
        $this->write();
451
        die();
0 ignored issues
show
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...
452
    }
453
454
    public function redirectWithSuccess($url, $message)
455
    {
456
        $this->flash('success', $message)->redirect($url);
457
    }
458
459
    public function redirectWithInfo($url, $message)
460
    {
461
        $this->flash('info', $message)->redirect($url);
462
    }
463
464
    public function redirectWithError($url, $message)
465
    {
466
        $this->flash('error', $message)->redirect($url);
467
    }
468
469
    public function redirectWithData($url, $key, $value)
470
    {
471
        $this->flashData($key, $value)->redirect($url);
472
    }
473
474
    /**
475
     * Check if request has a 200 OK Code
476
     *
477
     * @return boolean
478
     */
479 1
    public function isOK(): bool
480
    {
481 1
        return $this->httpCode == 200;
482
    }
483
484
    /**
485
     * Check if request has a 3XX HTTP code
486
     *
487
     * @return boolean
488
     */
489 1
    public function isRedirect(): bool
490
    {
491 1
        return $this->httpCode >= 300 && $this->httpCode < 400;
492
    }
493
494
    /**
495
     * Check is request has a 4XX HTTP code
496
     *
497
     * @return boolean
498
     */
499 1
    public function isClientError(): bool
500
    {
501 1
        return $this->httpCode >= 400 && $this->httpCode < 500;
502
    }
503
504
    /**
505
     * Check if request has a 5XX HTTP code
506
     *
507
     * @return boolean
508
     */
509 1
    public function isServerError(): bool
510
    {
511 1
        return $this->httpCode >= 500 && $this->httpCode < 600;
512
    }
513
514
    /**
515
     * Get string correspondig to HTTP code
516
     *
517
     * @return string|null
518
     */
519 1
    private function getStringForHttpCode(): ?string
520
    {
521 1
        if (isset($this->httpCodeString[$this->httpCode])) {
522 1
            return $this->httpCode .
523 1
                ' ' .
524 1
                $this->httpCodeString[$this->httpCode];
525
        }
526
527 1
        return null;
528
    }
529
}
530