Request::getAccept()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Alpha\Util\Http;
4
5
use Alpha\Exception\IllegalArguementException;
6
use Alpha\Util\Config\ConfigProvider;
7
8
/**
9
 * A class to encapsulate a HTTP request.
10
 *
11
 * @since 2.0
12
 *
13
 * @author John Collins <[email protected]>
14
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
15
 * @copyright Copyright (c) 2018, John Collins (founder of Alpha Framework).
16
 * All rights reserved.
17
 *
18
 * <pre>
19
 * Redistribution and use in source and binary forms, with or
20
 * without modification, are permitted provided that the
21
 * following conditions are met:
22
 *
23
 * * Redistributions of source code must retain the above
24
 *   copyright notice, this list of conditions and the
25
 *   following disclaimer.
26
 * * Redistributions in binary form must reproduce the above
27
 *   copyright notice, this list of conditions and the
28
 *   following disclaimer in the documentation and/or other
29
 *   materials provided with the distribution.
30
 * * Neither the name of the Alpha Framework nor the names
31
 *   of its contributors may be used to endorse or promote
32
 *   products derived from this software without specific
33
 *   prior written permission.
34
 *
35
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
36
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
37
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
40
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
 * </pre>
49
 */
50
class Request
51
{
52
    /**
53
     * Array of supported HTTP methods.
54
     *
55
     * @var array
56
     *
57
     * @since 2.0
58
     */
59
    private $HTTPMethods = array('HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'TRACE');
60
61
    /**
62
     * The HTTP method of this request (must be in HTTPMethods array).
63
     *
64
     * @var string
65
     *
66
     * @since 2.0
67
     */
68
    private $method;
69
70
    /**
71
     * An associative array of HTTP headers on this request.
72
     *
73
     * @var array
74
     *
75
     * @since 2.0
76
     */
77
    private $headers;
78
79
    /**
80
     * An associative array of HTTP cookies on this request.
81
     *
82
     * @var array
83
     *
84
     * @since 2.0
85
     */
86
    private $cookies;
87
88
    /**
89
     * The HTTP params (form data and query string) on this request.
90
     *
91
     * @var array
92
     *
93
     * @since 2.0
94
     */
95
    private $params;
96
97
    /**
98
     * An associative 3D array of uploaded files.
99
     *
100
     * @var array
101
     *
102
     * @since 2.0
103
     */
104
    private $files;
105
106
    /**
107
     * The request body if one was provided.
108
     *
109
     * @var string
110
     *
111
     * @since 2.0
112
     */
113
    private $body;
114
115
    /**
116
     * The host header provided on the request.
117
     *
118
     * @var string
119
     *
120
     * @since 2.0
121
     */
122
    private $host;
123
124
    /**
125
     * The IP of the client making the request.
126
     *
127
     * @var string
128
     *
129
     * @since 2.0
130
     */
131
    private $IP;
132
133
    /**
134
     * The URI requested.
135
     *
136
     * @var string
137
     *
138
     * @since 2.0
139
     */
140
    private $URI;
141
142
    /**
143
     * The query string provided on the request (if any).
144
     *
145
     * @var string
146
     *
147
     * @since 2.0
148
     */
149
    private $queryString;
150
151
    /**
152
     * Builds up the request based on available PHP super globals, in addition to
153
     * any overrides provided (useful for testing).
154
     *
155
     * @param array $overrides Hash array of PHP super globals to override
156
     *
157
     * @throws \Alpha\Exception\IllegalArguementException
158
     *
159
     * @since 2.0
160
     */
161
    public function __construct($overrides = array())
162
    {
163
        // set HTTP headers
164
        if (isset($overrides['headers']) && is_array($overrides['headers'])) {
165
            $this->headers = $overrides['headers'];
166
        } else {
167
            $this->headers = $this->getGlobalHeaders();
168
        }
169
170
        // set HTTP method
171
        if (isset($overrides['method']) && in_array($overrides['method'], $this->HTTPMethods)) {
172
            $this->method = $overrides['method'];
173
        } else {
174
            $method = $this->getGlobalServerValue('REQUEST_METHOD');
175
            if (in_array($method, $this->HTTPMethods)) {
176
                $this->method = $method;
177
            }
178
        }
179
180
        // allow the POST param _METHOD to override the HTTP method
181
        if (isset($_POST['_METHOD']) && in_array($_POST['_METHOD'], $this->HTTPMethods)) {
182
            $this->method = $_POST['_METHOD'];
183
        }
184
185
        // allow the POST param X-HTTP-Method-Override to override the HTTP method
186
        if (isset($this->headers['X-HTTP-Method-Override']) && in_array($this->headers['X-HTTP-Method-Override'], $this->HTTPMethods)) {
187
            $this->method = $this->headers['X-HTTP-Method-Override'];
188
        }
189
190
        if ($this->method == '') {
191
            throw new IllegalArguementException('No valid HTTP method provided when creating new Request object');
192
        }
193
194
        // set HTTP cookies
195
        if (isset($overrides['cookies']) && is_array($overrides['cookies'])) {
196
            $this->cookies = $overrides['cookies'];
197
        } elseif (isset($_COOKIE)) {
198
            $this->cookies = $_COOKIE;
199
        } else {
200
            $this->cookies = array();
201
        }
202
203
        // set HTTP params
204
        if (isset($overrides['params']) && is_array($overrides['params'])) {
205
            $this->params = $overrides['params'];
206
        } else {
207
            $this->params = array();
208
209
            if (isset($_GET)) {
210
                $this->params = array_merge($this->params, $_GET);
211
            }
212
213
            if (isset($_POST)) {
214
                $this->params = array_merge($this->params, $_POST);
215
            }
216
        }
217
218
        // set HTTP body
219
        if (isset($overrides['body'])) {
220
            $this->body = $overrides['body'];
221
        } else {
222
            $this->body = $this->getGlobalBody();
223
        }
224
225
        // set HTTP host
226
        if (isset($overrides['host'])) {
227
            $this->host = $overrides['host'];
228
        } else {
229
            $this->host = $this->getGlobalServerValue('HTTP_HOST');
230
        }
231
232
        // set IP of the client
233
        if (isset($overrides['IP'])) {
234
            $this->IP = $overrides['IP'];
235
        } else {
236
            $this->IP = $this->getGlobalServerValue('REMOTE_ADDR');
237
        }
238
239
        // set requested URI
240
        if (isset($overrides['URI'])) {
241
            $this->URI = $overrides['URI'];
242
        } else {
243
            $this->URI = $this->getGlobalServerValue('REQUEST_URI');
244
        }
245
246
        // set uploaded files (if any)
247
        if (isset($overrides['files'])) {
248
            $this->files = $overrides['files'];
249
        } elseif (isset($_FILES)) {
250
            $this->files = $_FILES;
251
        }
252
    }
253
254
    /**
255
     * Tries to get the requested param from the $_SERVER super global, otherwise returns an
256
     * empty string.
257
     *
258
     * @param string $param
259
     * @return string
260
     *
261
     * @since 3.0
262
     */
263
    private function getGlobalServerValue($param)
264
    {
265
        $server = $_SERVER;
266
267
        if (isset($server[$param])) {
268
            return $server[$param];
269
        } else {
270
            return '';
271
        }
272
    }
273
274
    /**
275
     * Get the HTTP method of this request.
276
     *
277
     * @return string
278
     *
279
     * @since 2.0
280
     */
281
    public function getMethod()
282
    {
283
        return $this->method;
284
    }
285
286
    /**
287
     * Set the HTTP method of this request.
288
     *
289
     * @param string $method
290
     *
291
     * @throws \Alpha\Exception\IllegalArguementException
292
     *
293
     * @since 2.0
294
     */
295
    public function setMethod($method)
296
    {
297
        if (in_array($method, $this->HTTPMethods)) {
298
            $this->method = $method;
299
        } else {
300
            throw new IllegalArguementException('The method provided ['.$method.'] is not valid!');
301
        }
302
    }
303
304
    /**
305
     * Return all headers on this request.
306
     *
307
     * @return array
308
     *
309
     * @since 2.0
310
     */
311
    public function getHeaders()
312
    {
313
        return $this->headers;
314
    }
315
316
    /**
317
     * Get the header matching the key provided.
318
     *
319
     * @param string $key     The key to search for
320
     * @param mixed  $default If key is not found, return this instead
321
     *
322
     * @return string
323
     *
324
     * @since 2.0
325
     */
326
    public function getHeader($key, $default = null)
327
    {
328
        if (array_key_exists($key, $this->headers)) {
329
            return $this->headers[$key];
330
        } else {
331
            return $default;
332
        }
333
    }
334
335
    /**
336
     * Tries to get the current HTTP request headers from super globals.
337
     *
338
     * @return array
339
     *
340
     * @since 2.0
341
     */
342
    private function getGlobalHeaders()
343
    {
344
        if (!function_exists('getallheaders')) {
345
            $headers = array();
346
            foreach ($_SERVER as $name => $value) {
347
                if (substr($name, 0, 5) == 'HTTP_') {
348
                    $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
349
                }
350
                if ($name == 'CONTENT_TYPE') {
351
                    $headers['Content-Type'] = $value;
352
                }
353
                if ($name == 'CONTENT_LENGTH') {
354
                    $headers['Content-Length'] = $value;
355
                }
356
            }
357
358
            return $headers;
359
        } else {
360
            return getallheaders();
361
        }
362
    }
363
364
    /**
365
     * Return all cookies on this request.
366
     *
367
     * @return array
368
     *
369
     * @since 2.0
370
     */
371
    public function getCookies()
372
    {
373
        return $this->cookies;
374
    }
375
376
    /**
377
     * Get the cookie matching the key provided.
378
     *
379
     * @param string $key     The key to search for
380
     * @param mixed  $default If key is not found, return this instead
381
     *
382
     * @return mixed
383
     *
384
     * @since 2.0
385
     */
386
    public function getCookie($key, $default = null)
387
    {
388
        if (array_key_exists($key, $this->cookies)) {
389
            return $this->cookies[$key];
390
        } else {
391
            return $default;
392
        }
393
    }
394
395
    /**
396
     * Return all params on this request.
397
     *
398
     * @return array
399
     *
400
     * @since 2.0
401
     */
402
    public function getParams()
403
    {
404
        return $this->params;
405
    }
406
407
    /**
408
     * Get the param matching the key provided.
409
     *
410
     * @param string $key     The key to search for
411
     * @param mixed  $default If key is not found, return this instead
412
     *
413
     * @return string
414
     *
415
     * @since 2.0
416
     */
417
    public function getParam($key, $default = null)
418
    {
419
        if (array_key_exists($key, $this->params)) {
420
            return $this->params[$key];
421
        } else {
422
            return $default;
423
        }
424
    }
425
426
    /**
427
     * Append the hash array provided to the params for this request.
428
     *
429
     * @param array A hash array of values to add to the request params
430
     *
431
     * @since 2.0
432
     */
433
    public function addParams($params)
434
    {
435
        if (is_array($params)) {
436
            $this->params = array_merge($this->params, $params);
437
        }
438
    }
439
440
    /**
441
     * Set the params array.
442
     *
443
     * @param array A hash array of values to set as the request params
444
     *
445
     * @since 2.0
446
     */
447
    public function setParams($params)
448
    {
449
        if (is_array($params)) {
450
            $this->params = $params;
451
        }
452
    }
453
454
    /**
455
     * Return all files on this request.
456
     *
457
     * @return array
458
     *
459
     * @since 2.0
460
     */
461
    public function getFiles()
462
    {
463
        return $this->files;
464
    }
465
466
    /**
467
     * Get the file matching the key provided.
468
     *
469
     * @param string $key     The key to search for
470
     * @param mixed  $default If key is not found, return this instead
471
     *
472
     * @return mixed
473
     *
474
     * @since 2.0
475
     */
476
    public function getFile($key, $default = null)
477
    {
478
        if (array_key_exists($key, $this->files)) {
479
            return $this->files[$key];
480
        } else {
481
            return $default;
482
        }
483
    }
484
485
    /**
486
     * Get the request body if one was provided.
487
     *
488
     * @return string
489
     *
490
     * @since 2.0
491
     */
492
    public function getBody()
493
    {
494
        return $this->body;
495
    }
496
497
    /**
498
     * Attempts to get the raw body of the current request from super globals.
499
     *
500
     * @return string
501
     *
502
     * @since 2.0
503
     */
504
    private function getGlobalBody()
505
    {
506
        if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
507
            return $GLOBALS['HTTP_RAW_POST_DATA'];
508
        } else {
509
            return file_get_contents('php://input');
510
        }
511
    }
512
513
    /**
514
     * Get the Accept header of the request.
515
     *
516
     * @return string
517
     *
518
     * @since 2.0
519
     */
520
    public function getAccept()
521
    {
522
        return $this->getHeader('Accept');
523
    }
524
525
    /**
526
     * Get the Content-Type header of the request.
527
     *
528
     * @return string
529
     *
530
     * @since 2.0
531
     */
532
    public function getContentType()
533
    {
534
        return $this->getHeader('Content-Type');
535
    }
536
537
    /**
538
     * Get the Content-Length header of the request.
539
     *
540
     * @return string
541
     *
542
     * @since 2.0
543
     */
544
    public function getContentLength()
545
    {
546
        return $this->getHeader('Content-Length');
547
    }
548
549
    /**
550
     * Get the host name of the client that sent the request.
551
     *
552
     * @return string
553
     *
554
     * @since 2.0
555
     */
556
    public function getHost()
557
    {
558
        return $this->host;
559
    }
560
561
    /**
562
     * Get the URI that was requested.
563
     *
564
     * @return string
565
     *
566
     * @since 2.0
567
     */
568
    public function getURI()
569
    {
570
        return $this->URI;
571
    }
572
573
    /**
574
     * Get the URL that was requested.
575
     *
576
     * @return string
577
     *
578
     * @since 2.0
579
     */
580
    public function getURL()
581
    {
582
        $config = ConfigProvider::getInstance();
583
584
        return $config->get('app.url').$this->getURI();
585
    }
586
587
    /**
588
     * Get the IP address of the client that sent the request.
589
     *
590
     * @return string
591
     *
592
     * @since 2.0
593
     */
594
    public function getIP()
595
    {
596
        return $this->IP;
597
    }
598
599
    /**
600
     * Get the Referrer header of the request.
601
     *
602
     * @return string
603
     *
604
     * @since 2.0
605
     */
606
    public function getReferrer()
607
    {
608
        return $this->getHeader('Referrer');
609
    }
610
611
    /**
612
     * Get the User-Agent header of the request.
613
     *
614
     * @return string
615
     *
616
     * @since 2.0
617
     */
618
    public function getUserAgent()
619
    {
620
        return $this->getHeader('User-Agent');
621
    }
622
623
    /**
624
     * Get the query string provided on the request.
625
     *
626
     * @return string
627
     *
628
     * @since 2.0
629
     */
630
    public function getQueryString()
631
    {
632
        return $this->queryString;
633
    }
634
635
    /**
636
     * Parses the route provided to extract matching params of the route from this request's URI.
637
     *
638
     * @param string $route         The route with parameter names, e.g. /user/{username}
639
     * @param array  $defaultParams Optional hash array of default request param values to use if they are missing from URI
640
     *
641
     * @since 2.0
642
     */
643
    public function parseParamsFromRoute($route, $defaultParams = array())
644
    {
645
        // if the URI has a query-string, we will ignore it for now
646
        if (mb_strpos($this->URI, '?') !== false) {
647
            $URI = mb_substr($this->URI, 0, mb_strpos($this->URI, '?'));
648
649
            // let's take this opportunity to pass query string params to $this->params
650
            $queryString = mb_substr($this->URI, (mb_strpos($this->URI, '?')+1));
651
            $this->queryString = $queryString;
652
            parse_str($queryString, $this->params);
653
        } else {
654
            $URI = $this->URI;
655
        }
656
657
        $paramNames = explode('/', $route);
658
        $paramValues = explode('/', $URI);
659
660
        for ($i = 0; $i < count($paramNames); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
661
            $name = $paramNames[$i];
662
663
            if (!isset($this->params[trim($name, '{}')])) {
664
                if (isset($paramValues[$i]) && substr($name, 0, 1) == '{' && substr($name, strlen($name)-1, 1) == '}') {
665
                    $this->params[trim($name, '{}')] = $paramValues[$i];
666
                }
667
                if (!isset($paramValues[$i]) && isset($defaultParams[trim($name, '{}')])) {
668
                    $this->params[trim($name, '{}')] = $defaultParams[trim($name, '{}')];
669
                }
670
            }
671
        }
672
    }
673
674
    /**
675
     * Checks to see if the request contains a secure/encrypted token.
676
     *
677
     * @return bool
678
     *
679
     * @since 2.0
680
     */
681
    public function isSecureURI()
682
    {
683
        if (isset($this->params['act']) && mb_strpos($this->URI, '/tk/') !== false) {
684
            return true;
685
        } else {
686
            return false;
687
        }
688
    }
689
}
690