Passed
Pull Request — master (#23)
by
unknown
01:58
created

HttpRequest::setQueryParam()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.0.0
13
 */
14
15
namespace Quantum\Http;
16
17
use Quantum\Exceptions\ExceptionMessages;
18
use Quantum\Exceptions\RequestException;
19
use Quantum\Environment\Server;
20
use Quantum\Bootstrap;
21
22
/**
23
 * Class HttpRequest
24
 * @package Quantum\Http
25
 */
26
abstract class HttpRequest
27
{
28
29
    /**
30
     * Request headers
31
     * @var array
32
     */
33
    private static $__headers = [];
34
35
    /**
36
     * Request body
37
     * @var array
38
     */
39
    private static $__request = [];
40
41
    /**
42
     * Files
43
     * @var array 
44
     */
45
    private static $__files = [];
46
47
    /**
48
     * Request method
49
     * @var string
50
     */
51
    private static $__method = null;
52
53
    /**
54
     * Scheme
55
     * @var string 
56
     */
57
    private static $__protocol = null;
58
59
    /**
60
     * Host name
61
     * @var string 
62
     */
63
    private static $__host = null;
64
65
    /**
66
     * Server port
67
     * @var string 
68
     */
69
    private static $__port = null;
70
71
    /**
72
     * Request URI
73
     * @var string
74
     */
75
    private static $__uri = null;
76
77
    /**
78
     * Query string
79
     * @var string
80
     */
81
    private static $__query = null;
82
83
    /**
84
     * Available methods
85
     * @var array 
86
     */
87
    private static $availableMetods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
88
89
    /**
90
     * Server
91
     * @var \Quantum\Environment\Server 
92
     */
93
    private static $server;
94
95
    /**
96
     * Initialize the Request
97
     * @throws RequestException When called outside of Bootstrap
98
     */
99
    public static function init(Server $server)
100
    {
101
        if (get_caller_class() !== Bootstrap::class) {
102
            throw new RequestException(ExceptionMessages::UNEXPECTED_REQUEST_INITIALIZATION);
103
        }
104
105
        self::$server = $server;
106
107
        self::$__method = self::$server->method();
108
109
        self::$__protocol = self::$server->protocol();
110
111
        self::$__host = self::$server->host();
112
113
        self::$__port = self::$server->port();
114
115
        self::$__uri = self::$server->uri();
116
117
        self::$__query = self::$server->query();
118
119
        self::$__headers = array_change_key_case((array) getallheaders(), CASE_UPPER);
120
121
        self::$__request = array_merge(
122
                self::$__request,
123
                self::getParams(),
124
                self::postParams(),
125
                self::getRawInputs()
126
        );
127
128
        self::$__files = self::handleFiles($_FILES);
129
    }
130
131
    /**
132
     * Creates new request for internal use
133
     * @param string $method
134
     * @param string $url
135
     * @param array|null $file
136
     */
137
    public static function create(string $method, string $url, array $data = null, array $file = null)
138
    {
139
        $parsed = parse_url($url);
140
141
        self::setMethod($method);
142
143
        if (isset($parsed['scheme'])) {
144
            self::setProtocol($parsed['scheme']);
145
        }
146
147
        if (isset($parsed['host'])) {
148
            self::setHost($parsed['host']);
149
        }
150
151
        if (isset($parsed['port'])) {
152
            self::setPort($parsed['port']);
153
        }
154
        if (isset($parsed['path'])) {
155
            self::setUri($parsed['path']);
156
        }
157
        if (isset($parsed['query'])) {
158
            self::setQuery($parsed['query']);
159
        }
160
161
        if ($data) {
162
            self::$__request = $data;
163
        }
164
165
        if ($file) {
166
            self::$__files = self::handleFiles($file);
167
        }
168
    }
169
170
    /**
171
     * Flushes the request header , body and files
172
     */
173
    public static function flush()
174
    {
175
        self::$__headers = [];
176
        self::$__request = [];
177
        self::$__files = [];
178
        self::$__protocol = null;
179
        self::$__host = null;
180
        self::$__port = null;
181
        self::$__uri = null;
182
        self::$__query = null;
183
    }
184
185
    /**
186
     * Gets the request method
187
     * @return mixed
188
     */
189
    public static function getMethod()
190
    {
191
        return self::$__method;
192
    }
193
194
    /**
195
     * Sets the request method
196
     * @param string $method
197
     * @throws RequestException
198
     */
199
    public static function setMethod(string $method)
200
    {
201
        if (!in_array($method, self::$availableMetods)) {
202
            throw new RequestException();
203
        }
204
205
        self::$__method = $method;
206
    }
207
208
    /**
209
     * Gets the protocol
210
     * @return string
211
     */
212
    public static function getProtocol()
213
    {
214
        return self::$__protocol;
215
    }
216
217
    /**
218
     * Sets the protocol
219
     * @param string $protocol
220
     */
221
    public static function setProtocol(string $protocol)
222
    {
223
        self::$__protocol = $protocol;
224
    }
225
226
    /**
227
     * Gets the host name
228
     * @return string
229
     */
230
    public static function getHost()
231
    {
232
        return self::$__host;
233
    }
234
235
    /**
236
     * Sets the host name
237
     * @param string $host
238
     */
239
    public static function setHost(string $host)
240
    {   
241
        self::$__host = $host;
242
    }
243
244
    /**
245
     * Gets the port
246
     * @return string
247
     */
248
    public static function getPort()
249
    {
250
        return self::$__port;
251
    }
252
253
    /**
254
     * Sets the port
255
     * @param string $port
256
     */
257
    public static function setPort($port)
258
    {
259
        self::$__port = $port;
260
    }
261
262
    /**
263
     * Gets the URI
264
     * @return string|null
265
     */
266
    public static function getUri()
267
    {
268
        return self::$__uri;
269
    }
270
271
    /**
272
     * Sets the URI
273
     * @param string $uri
274
     */
275
    public static function setUri(string $uri)
276
    {
277
        self::$__uri = ltrim($uri, '/');
278
    }
279
280
    /**
281
     * Gets the query string
282
     * @return string
283
     */
284
    public static function getQuery()
285
    {
286
        return self::$__query;
287
    }
288
289
    /**
290
     * Sets the query string
291
     * @param string $query
292
     */
293
    public static function setQuery(string $query)
294
    {
295
        self::$__query = $query;
296
    }
297
298
    /**
299
     * Sets the query param
300
     * @param string $key
301
     * @param string $value
302
     * @return string
303
     */
304
    public static function setQueryParam(string $key, string $value)
305
    {
306
        $queryParams = self::$__query ? explode('&', self::$__query) : []; 
307
        array_push($queryParams, $key . '=' . $value);  
308
        self::$__query =  implode('&', $queryParams);   
309
    }
310
311
    /**
312
     * Gets the query param
313
     * @param string $key
314
     * @return string|null
315
     */
316
    public static function getQueryParam(string $key)
317
    {  
318
        $query = explode('&', self::$__query);    
319
320
        foreach($query as $items){
321
           $item = explode('=', $items); 
322
           if($item[0] == $key){
323
                return $item[1];
324
           }
325
        }
326
327
        return null;
328
    }
329
330
    /**
331
     * Sets new key/value pair into request
332
     * @param string $key
333
     * @param mixed $value
334
     */
335
    public static function set($key, $value)
336
    {
337
        self::$__request[$key] = $value;
338
    }
339
340
    /**
341
     * Checks if request contains a data by given key
342
     * @param string $key
343
     * @return bool
344
     */
345
    public static function has($key)
346
    {
347
        return isset(self::$__request[$key]);
348
    }
349
350
    /**
351
     * Retrieves data from request by given key
352
     * @param string $key
353
     * @param string $default
354
     * @param bool $raw
355
     * @return mixed
356
     */
357
    public static function get($key, $default = null, $raw = false)
358
    {
359
        $data = $default;
360
361
        if (self::has($key)) {
362
            if ($raw) {
363
                $data = self::$__request[$key];
364
            } else {
365
                $data = is_array(self::$__request[$key]) ?
366
                        filter_var_array(self::$__request[$key], FILTER_SANITIZE_STRING) :
367
                        filter_var(self::$__request[$key], FILTER_SANITIZE_STRING);
368
            }
369
        }
370
371
        return $data;
372
    }
373
374
    /**
375
     * Gets all request parameters
376
     * @return array
377
     */
378
    public static function all()
379
    {
380
        return array_merge(self::$__request, self::$__files);
381
    }
382
383
    /**
384
     * Deletes the element from request by given key
385
     * @param string $key
386
     */
387
    public static function delete($key)
388
    {
389
        if (self::has($key)) {
390
            unset(self::$__request[$key]);
391
        }
392
    }
393
394
    /**
395
     * Checks to see if request contains file
396
     * @return bool
397
     */
398
    public static function hasFile($key)
399
    {
400
        return isset(self::$__files[$key]);
401
    }
402
403
    /**
404
     * Gets the file info by given key
405
     * @param string $key
406
     * @return array
407
     * @throws \InvalidArgumentException
408
     */
409
    public static function getFile($key)
410
    {
411
        if (!self::hasFile($key)) {
412
            throw new \InvalidArgumentException(_message(ExceptionMessages::UPLOADED_FILE_NOT_FOUND, $key));
413
        }
414
415
        return self::$__files[$key];
416
    }
417
418
    /**
419
     * Sets the request header
420
     * @param string $key
421
     * @param mixed $value
422
     */
423
    public static function setHeader($key, $value)
424
    {
425
        self::$__headers[$key] = $value;
426
    }
427
428
    /**
429
     * Checks the request header existence by given key
430
     * @param string $key
431
     * @return bool
432
     */
433
    public static function hasHeader($key)
434
    {
435
        return isset(self::$__headers[$key]);
436
    }
437
438
    /**
439
     * Gets the request header by given key
440
     * @param $key
441
     * @return mixed|null
442
     */
443
    public static function getHeader($key)
444
    {
445
        return self::hasHeader($key) ? self::$__headers[$key] : null;
446
    }
447
448
    /**
449
     * Gets all request headers
450
     * @return array
451
     */
452
    public static function allHeaders()
453
    {
454
        return self::$__headers;
455
    }
456
457
    /**
458
     * Deletes the header by given key
459
     * @param string $key
460
     */
461
    public static function deleteHeader($key)
462
    {
463
        if (self::hasHeader($key)) {
464
            unset(self::$__headers[$key]);
465
        }
466
    }
467
468
    /**
469
     * Gets the nth segment
470
     * @param integer $number
471
     * @return string|null
472
     */
473
    public static function getSegment($number)
474
    {
475
        $segments = self::getAllSegments();
476
477
        if (isset($segments[$number])) {
478
            return $segments[$number];
479
        }
480
481
        return null;
482
    }
483
484
    /**
485
     * Gets the segments of current URI
486
     * @return array
487
     */
488
    public static function getAllSegments()
489
    {
490
        $segments = explode('/', trim(parse_url(self::$__uri)['path'], '/'));
491
        array_unshift($segments, 'zero_segment');
492
        return $segments;
493
    }
494
495
    /**
496
     * Gets Сross Site Request Forgery Token
497
     * @return string
498
     */
499
    public static function getCSRFToken()
500
    {
501
        $csrfToken = null;
502
503
        if (self::has('token')) {
504
            $csrfToken = self::get('token');
505
        } elseif (self::hasHeader('X-csrf-token')) {
506
            $csrfToken = self::getHeader('X-csrf-token');
507
        }
508
509
        return $csrfToken;
510
    }
511
512
    /**
513
     * Gets Authorization Bearer token
514
     * @return string
515
     */
516
    public static function getAuthorizationBearer()
517
    {
518
        $bearerToken = null;
519
520
        if (self::hasHeader('Authorization')) {
521
            if (preg_match('/Bearer\s(\S+)/', self::getHeader('Authorization'), $matches)) {
522
                $bearerToken = $matches[1];
523
            }
524
        }
525
526
        return $bearerToken;
527
    }
528
529
    /**
530
     * Checks to see if request was AJAX request
531
     * @return boolean
532
     */
533
    public static function isAjax()
534
    {
535
        if (self::hasHeader('X-REQUESTED-WITH') || self::$server->ajax()) {
536
            return true;
537
        }
538
539
        return false;
540
    }
541
542
    /**
543
     * Gets the referrer
544
     * @return string
545
     */
546
    public static function getReferrer()
547
    {
548
        return self::$server->referrer();
549
    }
550
551
    /**
552
     * Gets the GET params
553
     * @return array
554
     */
555
    private static function getParams(): array
556
    {
557
        $getParams = [];
558
559
        if (!empty($_GET)) {
560
            $getParams = filter_input_array(INPUT_GET, FILTER_DEFAULT);
561
        }
562
563
        return $getParams;
564
    }
565
566
    /**
567
     * Gets the POST params
568
     * @return array
569
     */
570
    private static function postParams(): array
571
    {
572
        $postParams = [];
573
574
        if (!empty($_POST)) {
575
            $postParams = filter_input_array(INPUT_POST, FILTER_DEFAULT);
576
        }
577
578
        return $postParams;
579
    }
580
581
    /**
582
     * Get Input parameters sent via PUT, PATCH or DELETE methods
583
     * @return array
584
     */
585
    private static function getRawInputs(): array
586
    {
587
        $inputParams = [];
588
589
        if (in_array(self::$__method, ['PUT', 'PATCH', 'DELETE'])) {
590
591
            $input = file_get_contents('php://input');
592
593
            if (self::$server->contentType()) {
594
                switch (self::$server->contentType()) {
595
                    case 'application/x-www-form-urlencoded':
596
                        parse_str($input, $inputParams);
597
                        break;
598
                    case 'application/json':
599
                        $inputParams = json_decode($input);
600
                        break;
601
                    default :
602
                        $inputParams = parse_raw_http_request($input);
603
                        break;
604
                }
605
            }
606
        }
607
608
        return (array) $inputParams;
609
    }
610
611
    /**
612
     * Handles uploaded files
613
     */
614
    private static function handleFiles($_files)
615
    {
616
        if (!count($_files)) {
617
            return [];
618
        }
619
620
        $key = key($_files);
621
622
        if ($key) {
623
            if (!is_array($_files[$key]['name'])) {
624
                return [$key => (object) $_files[$key]];
625
            } else {
626
                $formattedFiles = [];
627
628
                foreach ($_files[$key]['name'] as $index => $name) {
629
                    $formattedFiles[$key][$index] = (object) [
630
                                'name' => $name,
631
                                'type' => $_files[$key]['type'][$index],
632
                                'tmp_name' => $_files[$key]['tmp_name'][$index],
633
                                'error' => $_files[$key]['error'][$index],
634
                                'size' => $_files[$key]['size'][$index],
635
                    ];
636
                }
637
638
                return $formattedFiles;
639
            }
640
        }
641
    }
642
643
}
644