Completed
Branch dev (f8c12d)
by
unknown
87:36 queued 78:32
created

Request::requestUri()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 8
nop 2
dl 0
loc 31
rs 9.424
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\services\request;
4
5
use EventEspresso\core\domain\services\contexts\RequestTypeContextCheckerInterface;
6
use EventEspresso\core\interfaces\InterminableInterface;
7
use EventEspresso\core\interfaces\ReservedInstanceInterface;
8
9
/**
10
 * Class Request
11
 * Representation of an incoming, server-side HTTP request
12
 *
13
 * @package EventEspresso\core\services\request
14
 * @author  Brent Christensen
15
 * @since   4.9.53
16
 */
17
class Request implements InterminableInterface, RequestInterface, ReservedInstanceInterface
18
{
19
20
    /**
21
     * $_GET parameters
22
     *
23
     * @var array $get
24
     */
25
    private $get;
26
27
    /**
28
     * $_POST parameters
29
     *
30
     * @var array $post
31
     */
32
    private $post;
33
34
    /**
35
     * $_COOKIE parameters
36
     *
37
     * @var array $cookie
38
     */
39
    private $cookie;
40
41
    /**
42
     * $_SERVER parameters
43
     *
44
     * @var array $server
45
     */
46
    private $server;
47
48
    /**
49
     * $_FILES parameters
50
     *
51
     * @var array $files
52
     */
53
    private $files;
54
55
    /**
56
     * $_REQUEST parameters
57
     *
58
     * @var array $request
59
     */
60
    private $request;
61
62
    /**
63
     * @var RequestTypeContextCheckerInterface
64
     */
65
    private $request_type;
66
67
    /**
68
     * IP address for request
69
     *
70
     * @var string $ip_address
71
     */
72
    private $ip_address;
73
74
    /**
75
     * @var string $user_agent
76
     */
77
    private $user_agent;
78
79
    /**
80
     * true if current user appears to be some kind of bot
81
     *
82
     * @var bool $is_bot
83
     */
84
    private $is_bot;
85
86
87
    /**
88
     * @param array $get
89
     * @param array $post
90
     * @param array $cookie
91
     * @param array $server
92
     * @param array $files
93
     */
94
    public function __construct(array $get, array $post, array $cookie, array $server, array $files = array())
95
    {
96
        // grab request vars
97
        $this->get = $get;
98
        $this->post = $post;
99
        $this->cookie = $cookie;
100
        $this->server = $server;
101
        $this->files = $files;
102
        $this->request = array_merge($this->get, $this->post);
103
        $this->ip_address = $this->visitorIp();
104
    }
105
106
107
    /**
108
     * @param RequestTypeContextCheckerInterface $type
109
     */
110
    public function setRequestTypeContextChecker(RequestTypeContextCheckerInterface $type)
111
    {
112
        $this->request_type = $type;
113
    }
114
115
116
    /**
117
     * @return array
118
     */
119
    public function getParams()
120
    {
121
        return $this->get;
122
    }
123
124
125
    /**
126
     * @return array
127
     */
128
    public function postParams()
129
    {
130
        return $this->post;
131
    }
132
133
134
    /**
135
     * @return array
136
     */
137
    public function cookieParams()
138
    {
139
        return $this->cookie;
140
    }
141
142
143
    /**
144
     * @return array
145
     */
146
    public function serverParams()
147
    {
148
        return $this->server;
149
    }
150
151
152
    /**
153
     * @return array
154
     */
155
    public function filesParams()
156
    {
157
        return $this->files;
158
    }
159
160
161
    /**
162
     * returns contents of $_REQUEST
163
     *
164
     * @return array
165
     */
166
    public function requestParams()
167
    {
168
        return $this->request;
169
    }
170
171
172
    /**
173
     * @param      $key
174
     * @param      $value
175
     * @param bool $override_ee
176
     * @return    void
177
     */
178
    public function setRequestParam($key, $value, $override_ee = false)
179
    {
180
        // don't allow "ee" to be overwritten unless explicitly instructed to do so
181
        if ($key !== 'ee' || empty($this->request['ee']) || $override_ee) {
182
            $this->request[ $key ] = $value;
183
        }
184
    }
185
186
187
    /**
188
     * returns   the value for a request param if the given key exists
189
     *
190
     * @param       $key
191
     * @param null  $default
192
     * @return mixed
193
     */
194
    public function getRequestParam($key, $default = null)
195
    {
196
        return $this->requestParameterDrillDown($key, $default, 'get');
197
    }
198
199
200
    /**
201
     * check if param exists
202
     *
203
     * @param       $key
204
     * @return bool
205
     */
206
    public function requestParamIsSet($key)
207
    {
208
        return $this->requestParameterDrillDown($key);
209
    }
210
211
212
    /**
213
     * check if a request parameter exists whose key that matches the supplied wildcard pattern
214
     * and return the value for the first match found
215
     * wildcards can be either of the following:
216
     *      ? to represent a single character of any type
217
     *      * to represent one or more characters of any type
218
     *
219
     * @param string     $pattern
220
     * @param null|mixed $default
221
     * @return mixed
222
     */
223
    public function getMatch($pattern, $default = null)
224
    {
225
        return $this->requestParameterDrillDown($pattern, $default, 'match');
226
    }
227
228
229
    /**
230
     * check if a request parameter exists whose key matches the supplied wildcard pattern
231
     * wildcards can be either of the following:
232
     *      ? to represent a single character of any type
233
     *      * to represent one or more characters of any type
234
     * returns true if a match is found or false if not
235
     *
236
     * @param string $pattern
237
     * @return bool
238
     */
239
    public function matches($pattern)
240
    {
241
        return $this->requestParameterDrillDown($pattern, null, 'match') !== null;
242
    }
243
244
245
    /**
246
     * @see https://stackoverflow.com/questions/6163055/php-string-matching-with-wildcard
247
     * @param string $pattern               A string including wildcards to be converted to a regex pattern
248
     *                                      and used to search through the current request's parameter keys
249
     * @param array  $request_params        The array of request parameters to search through
250
     * @param mixed  $default               [optional] The value to be returned if no match is found.
251
     *                                      Default is null
252
     * @param string $return                [optional] Controls what kind of value is returned.
253
     *                                      Options are:
254
     *                                      'bool' will return true or false if match is found or not
255
     *                                      'key' will return the first key found that matches the supplied pattern
256
     *                                      'value' will return the value for the first request parameter
257
     *                                      whose key matches the supplied pattern
258
     *                                      Default is 'value'
259
     * @return boolean|string
260
     */
261
    private function match($pattern, array $request_params, $default = null, $return = 'value')
262
    {
263
        $return = in_array($return, array('bool', 'key', 'value'), true)
264
            ? $return
265
            : 'is_set';
266
        // replace wildcard chars with regex chars
267
        $pattern = str_replace(
268
            array("\*", "\?"),
269
            array('.*', '.'),
270
            preg_quote($pattern, '/')
271
        );
272
        foreach ($request_params as $key => $request_param) {
273
            if (preg_match('/^' . $pattern . '$/is', $key)) {
274
                // return value for request param
275
                if ($return === 'value') {
276
                    return $request_params[ $key ];
277
                }
278
                // or actual key or true just to indicate it was found
279
                return $return === 'key' ? $key : true;
280
            }
281
        }
282
        // match not found so return default value or false
283
        return $return === 'value' ? $default : false;
284
    }
285
286
287
    /**
288
     * the supplied key can be a simple string to represent a "top-level" request parameter
289
     * or represent a key for a request parameter that is nested deeper within the request parameter array,
290
     * by using square brackets to surround keys for deeper array elements.
291
     * For example :
292
     * if the supplied $key was: "first[second][third]"
293
     * then this will attempt to drill down into the request parameter array to find a value.
294
     * Given the following request parameters:
295
     *  array(
296
     *      'first' => array(
297
     *          'second' => array(
298
     *              'third' => 'has a value'
299
     *          )
300
     *      )
301
     *  )
302
     * would return true if default parameters were set
303
     *
304
     * @param string $callback
305
     * @param        $key
306
     * @param null   $default
307
     * @param array  $request_params
308
     * @return bool|mixed|null
309
     */
310
    private function requestParameterDrillDown(
311
        $key,
312
        $default = null,
313
        $callback = 'is_set',
314
        array $request_params = array()
315
    ) {
316
        $callback = in_array($callback, array('is_set', 'get', 'match'), true)
317
            ? $callback
318
            : 'is_set';
319
        $request_params = ! empty($request_params)
320
            ? $request_params
321
            : $this->request;
322
        // does incoming key represent an array like 'first[second][third]'  ?
323
        if (strpos($key, '[') !== false) {
324
            // turn it into an actual array
325
            $key = str_replace(']', '', $key);
326
            $keys = explode('[', $key);
327
            $key = array_shift($keys);
328
            if ($callback === 'match') {
329
                $real_key = $this->match($key, $request_params, $default, 'key');
330
                $key = $real_key ? $real_key : $key;
331
            }
332
            // check if top level key exists
333
            if (isset($request_params[ $key ])) {
334
                // build a new key to pass along like: 'second[third]'
335
                // or just 'second' depending on depth of keys
336
                $key_string = array_shift($keys);
337
                if (! empty($keys)) {
338
                    $key_string .= '[' . implode('][', $keys) . ']';
339
                }
340
                return $this->requestParameterDrillDown(
341
                    $key_string,
342
                    $default,
343
                    $callback,
344
                    $request_params[ $key ]
345
                );
346
            }
347
        }
348
        if ($callback === 'is_set') {
349
            return isset($request_params[ $key ]);
350
        }
351
        if ($callback === 'match') {
352
            return $this->match($key, $request_params, $default);
353
        }
354
        return isset($request_params[ $key ])
355
            ? $request_params[ $key ]
356
            : $default;
357
    }
358
359
360
    /**
361
     * remove param
362
     *
363
     * @param      $key
364
     * @param bool $unset_from_global_too
365
     */
366
    public function unSetRequestParam($key, $unset_from_global_too = false)
367
    {
368
        // because unset may not actually remove var
369
        $this->request[ $key ] = null;
370
        unset($this->request[ $key ]);
371
        if ($unset_from_global_too) {
372
            unset($_REQUEST[ $key ]);
373
        }
374
    }
375
376
377
    /**
378
     * remove params
379
     *
380
     * @param array $keys
381
     * @param bool  $unset_from_global_too
382
     */
383
    public function unSetRequestParams(array $keys, $unset_from_global_too = false)
384
    {
385
        foreach ($keys as $key) {
386
            $this->unSetRequestParam($key, $unset_from_global_too);
387
        }
388
    }
389
390
391
    /**
392
     * @return string
393
     */
394
    public function ipAddress()
395
    {
396
        return $this->ip_address;
397
    }
398
399
400
    /**
401
     * attempt to get IP address of current visitor from server
402
     * plz see: http://stackoverflow.com/a/2031935/1475279
403
     *
404
     * @access public
405
     * @return string
406
     */
407
    private function visitorIp()
408
    {
409
        $visitor_ip = '0.0.0.0';
410
        $server_keys = array(
411
            'HTTP_CLIENT_IP',
412
            'HTTP_X_FORWARDED_FOR',
413
            'HTTP_X_FORWARDED',
414
            'HTTP_X_CLUSTER_CLIENT_IP',
415
            'HTTP_FORWARDED_FOR',
416
            'HTTP_FORWARDED',
417
            'REMOTE_ADDR',
418
        );
419
        foreach ($server_keys as $key) {
420
            if (isset($this->server[ $key ])) {
421
                foreach (array_map('trim', explode(',', $this->server[ $key ])) as $ip) {
422
                    if ($ip === '127.0.0.1' || filter_var($ip, FILTER_VALIDATE_IP) !== false) {
423
                        $visitor_ip = $ip;
424
                    }
425
                }
426
            }
427
        }
428
        return $visitor_ip;
429
    }
430
431
432
    /**
433
     * Gets the request's literal URI. Related to `requestUriAfterSiteHomeUri`, see its description for a comparison.
434
     *
435
     * @param boolean $relativeToWpRoot    If home_url() is "http://mysite.com/wp/", and a request comes to
436
     *                                     "http://mysite.com/wp/wp-json", setting $relativeToWpRoot=true will return
437
     *                                     "/wp-json", whereas $relativeToWpRoot=false will return "/wp/wp-json/".
438
     * @param boolean $remove_query_params whether or not to return the uri with all query params removed.
439
     * @return string
440
     */
441
    public function requestUri($relativeToWpRoot = false, $remove_query_params = false)
442
    {
443
        $request_uri = filter_input(
444
            INPUT_SERVER,
445
            'REQUEST_URI',
446
            FILTER_SANITIZE_URL,
447
            FILTER_NULL_ON_FAILURE
448
        );
449
        if (empty($request_uri)) {
450
            // fallback sanitization if the above fails
451
            $request_uri = wp_sanitize_redirect($this->server['REQUEST_URI']);
452
        }
453
        if ($remove_query_params) {
454
            $request_uri_parts = explode('?', $request_uri);
455
            $request_uri = reset($request_uri_parts);
456
        }
457
        if ($relativeToWpRoot) {
458
            $home_path = untrailingslashit(
459
                parse_url(
460
                    home_url(),
461
                    PHP_URL_PATH
462
                )
463
            );
464
            $request_uri = str_replace(
465
                $home_path,
466
                '',
467
                $request_uri
468
            );
469
        }
470
        return $request_uri;
471
    }
472
473
    /**
474
     * @return string
475
     */
476
    public function userAgent()
477
    {
478
        return $this->user_agent;
479
    }
480
481
482
    /**
483
     * @param string $user_agent
484
     */
485
    public function setUserAgent($user_agent = '')
486
    {
487
        if ($user_agent === '' || ! is_string($user_agent)) {
488
            $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? (string) esc_attr($_SERVER['HTTP_USER_AGENT']) : '';
489
        }
490
        $this->user_agent = $user_agent;
491
    }
492
493
494
    /**
495
     * @return bool
496
     */
497
    public function isBot()
498
    {
499
        return $this->is_bot;
500
    }
501
502
503
    /**
504
     * @param bool $is_bot
505
     */
506
    public function setIsBot($is_bot)
507
    {
508
        $this->is_bot = filter_var($is_bot, FILTER_VALIDATE_BOOLEAN);
509
    }
510
511
512
    /**
513
     * @return bool
514
     */
515
    public function isActivation()
516
    {
517
        return $this->request_type->isActivation();
518
    }
519
520
521
    /**
522
     * @param $is_activation
523
     * @return bool
524
     */
525
    public function setIsActivation($is_activation)
526
    {
527
        return $this->request_type->setIsActivation($is_activation);
528
    }
529
530
531
    /**
532
     * @return bool
533
     */
534
    public function isAdmin()
535
    {
536
        return $this->request_type->isAdmin();
537
    }
538
539
540
    /**
541
     * @return bool
542
     */
543
    public function isAdminAjax()
544
    {
545
        return $this->request_type->isAdminAjax();
546
    }
547
548
549
    /**
550
     * @return bool
551
     */
552
    public function isAjax()
553
    {
554
        return $this->request_type->isAjax();
555
    }
556
557
558
    /**
559
     * @return bool
560
     */
561
    public function isEeAjax()
562
    {
563
        return $this->request_type->isEeAjax();
564
    }
565
566
567
    /**
568
     * @return bool
569
     */
570
    public function isOtherAjax()
571
    {
572
        return $this->request_type->isOtherAjax();
573
    }
574
575
576
    /**
577
     * @return bool
578
     */
579
    public function isApi()
580
    {
581
        return $this->request_type->isApi();
582
    }
583
584
585
    /**
586
     * @return bool
587
     */
588
    public function isCli()
589
    {
590
        return $this->request_type->isCli();
591
    }
592
593
594
    /**
595
     * @return bool
596
     */
597
    public function isCron()
598
    {
599
        return $this->request_type->isCron();
600
    }
601
602
603
    /**
604
     * @return bool
605
     */
606
    public function isFeed()
607
    {
608
        return $this->request_type->isFeed();
609
    }
610
611
612
    /**
613
     * @return bool
614
     */
615
    public function isFrontend()
616
    {
617
        return $this->request_type->isFrontend();
618
    }
619
620
621
    /**
622
     * @return bool
623
     */
624
    public function isFrontAjax()
625
    {
626
        return $this->request_type->isFrontAjax();
627
    }
628
629
630
    /**
631
     * @return bool
632
     */
633
    public function isGQL()
634
    {
635
        return $this->request_type->isGQL();
636
    }
637
638
639
    /**
640
     * @return bool
641
     */
642
    public function isIframe()
643
    {
644
        return $this->request_type->isIframe();
645
    }
646
647
648
649
    /**
650
     * @return bool
651
     */
652
    public function isUnitTesting()
653
    {
654
        return $this->request_type->isUnitTesting();
655
    }
656
657
658
    /**
659
     * @return bool
660
     */
661
    public function isWordPressApi()
662
    {
663
        return $this->request_type->isWordPressApi();
664
    }
665
666
667
668
    /**
669
     * @return bool
670
     */
671
    public function isWordPressHeartbeat()
672
    {
673
        return $this->request_type->isWordPressHeartbeat();
674
    }
675
676
677
678
    /**
679
     * @return bool
680
     */
681
    public function isWordPressScrape()
682
    {
683
        return $this->request_type->isWordPressScrape();
684
    }
685
686
687
    /**
688
     * @return string
689
     */
690
    public function slug()
691
    {
692
        return $this->request_type->slug();
693
    }
694
695
696
    /**
697
     * returns the path portion of the current request URI with both the WP Root (home_url()) and query params removed
698
     *
699
     * @return string
700
     * @since   $VID:$
701
     */
702
    public function requestPath()
703
    {
704
        return $this->requestUri(true, true);
705
    }
706
707
708
    /**
709
     * returns true if the last segment of the current request path (without params) matches the provided string
710
     *
711
     * @param string $uri_segment
712
     * @return bool
713
     * @since   $VID:$
714
     */
715
    public function currentPageIs($uri_segment)
716
    {
717
        $request_path = $this->requestPath();
718
        $current_page = explode('/', $request_path);
719
        return end($current_page) === $uri_segment;
720
    }
721
}
722