-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
/
Request.php
2000 lines (1812 loc) · 72.2 KB
/
Request.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/
namespace yii\web;
use Yii;
use yii\base\InvalidConfigException;
use yii\validators\IpValidator;
/**
* The web Request class represents an HTTP request.
*
* It encapsulates the $_SERVER variable and resolves its inconsistency among different Web servers.
* Also it provides an interface to retrieve request parameters from $_POST, $_GET, $_COOKIES and REST
* parameters sent via other HTTP methods like PUT or DELETE.
*
* Request is configured as an application component in [[\yii\web\Application]] by default.
* You can access that instance via `Yii::$app->request`.
*
* For more details and usage information on Request, see the [guide article on requests](guide:runtime-requests).
*
* @property-read string $absoluteUrl The currently requested absolute URL.
* @property array $acceptableContentTypes The content types ordered by the quality score. Types with the
* highest scores will be returned first. The array keys are the content types, while the array values are the
* corresponding quality score and other parameters as given in the header.
* @property array $acceptableLanguages The languages ordered by the preference level. The first element
* represents the most preferred language.
* @property-read array $authCredentials That contains exactly two elements: - 0: the username sent via HTTP
* authentication, `null` if the username is not given - 1: the password sent via HTTP authentication, `null` if
* the password is not given.
* @property-read string|null $authPassword The password sent via HTTP authentication, `null` if the password
* is not given.
* @property-read string|null $authUser The username sent via HTTP authentication, `null` if the username is
* not given.
* @property string $baseUrl The relative URL for the application.
* @property array|object $bodyParams The request parameters given in the request body.
* @property-read string $contentType Request content-type. Empty string is returned if this information is
* not available.
* @property-read CookieCollection $cookies The cookie collection.
* @property-read string $csrfToken The token used to perform CSRF validation.
* @property-read string|null $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is
* returned if no such header is sent.
* @property-read array $eTags The entity tags.
* @property-read HeaderCollection $headers The header collection.
* @property string|null $hostInfo Schema and hostname part (with port number if needed) of the request URL
* (e.g. `https://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set. See
* [[getHostInfo()]] for security related notes on this property.
* @property-read string|null $hostName Hostname part of the request URL (e.g. `www.yiiframework.com`).
* @property-read bool $isAjax Whether this is an AJAX (XMLHttpRequest) request.
* @property-read bool $isDelete Whether this is a DELETE request.
* @property-read bool $isFlash Whether this is an Adobe Flash or Adobe Flex request.
* @property-read bool $isGet Whether this is a GET request.
* @property-read bool $isHead Whether this is a HEAD request.
* @property-read bool $isOptions Whether this is a OPTIONS request.
* @property-read bool $isPatch Whether this is a PATCH request.
* @property-read bool $isPjax Whether this is a PJAX request.
* @property-read bool $isPost Whether this is a POST request.
* @property-read bool $isPut Whether this is a PUT request.
* @property-read bool $isSecureConnection If the request is sent via secure channel (https).
* @property-read string $method Request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. The value
* returned is turned into upper case.
* @property-read string|null $origin URL origin of a CORS request, `null` if not available.
* @property string $pathInfo Part of the request URL that is after the entry script and before the question
* mark. Note, the returned path info is already URL-decoded.
* @property int $port Port number for insecure requests.
* @property array $queryParams The request GET parameter values.
* @property-read string $queryString Part of the request URL that is after the question mark.
* @property string $rawBody The request body.
* @property-read string|null $referrer URL referrer, null if not available.
* @property-read string|null $remoteHost Remote host name, `null` if not available.
* @property-read string|null $remoteIP Remote IP address, `null` if not available.
* @property string $scriptFile The entry script file path.
* @property string $scriptUrl The relative URL of the entry script.
* @property int $securePort Port number for secure requests.
* @property-read string|null $serverName Server name, null if not available.
* @property-read int|null $serverPort Server port number, null if not available.
* @property string $url The currently requested relative URL. Note that the URI returned may be URL-encoded
* depending on the client.
* @property-read string|null $userAgent User agent, null if not available.
* @property-read string|null $userHost User host name, null if not available.
* @property-read string|null $userIP User IP address, null if not available.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
* @SuppressWarnings(PHPMD.SuperGlobals)
*/
class Request extends \yii\base\Request
{
/**
* The name of the HTTP header for sending CSRF token.
*/
const CSRF_HEADER = 'X-CSRF-Token';
/**
* The length of the CSRF token mask.
* @deprecated since 2.0.12. The mask length is now equal to the token length.
*/
const CSRF_MASK_LENGTH = 8;
/**
* @var bool whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to true.
* When CSRF validation is enabled, forms submitted to an Yii Web application must be originated
* from the same application. If not, a 400 HTTP exception will be raised.
*
* Note, this feature requires that the user client accepts cookie. Also, to use this feature,
* forms submitted via POST method must contain a hidden input whose name is specified by [[csrfParam]].
* You may use [[\yii\helpers\Html::beginForm()]] to generate his hidden input.
*
* In JavaScript, you may get the values of [[csrfParam]] and [[csrfToken]] via `yii.getCsrfParam()` and
* `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered.
* You also need to include CSRF meta tags in your pages by using [[\yii\helpers\Html::csrfMetaTags()]].
*
* @see Controller::enableCsrfValidation
* @see https://en.wikipedia.org/wiki/Cross-site_request_forgery
*/
public $enableCsrfValidation = true;
/**
* @var string the name of the token used to prevent CSRF. Defaults to '_csrf'.
* This property is used only when [[enableCsrfValidation]] is true.
*/
public $csrfParam = '_csrf';
/**
* @var array the configuration for creating the CSRF [[Cookie|cookie]]. This property is used only when
* both [[enableCsrfValidation]] and [[enableCsrfCookie]] are true.
*/
public $csrfCookie = ['httpOnly' => true];
/**
* @var bool whether to use cookie to persist CSRF token. If false, CSRF token will be stored
* in session under the name of [[csrfParam]]. Note that while storing CSRF tokens in session increases
* security, it requires starting a session for every page, which will degrade your site performance.
*/
public $enableCsrfCookie = true;
/**
* @var bool whether cookies should be validated to ensure they are not tampered. Defaults to true.
*/
public $enableCookieValidation = true;
/**
* @var string a secret key used for cookie validation. This property must be set if [[enableCookieValidation]] is true.
*/
public $cookieValidationKey;
/**
* @var string the name of the POST parameter that is used to indicate if a request is a PUT, PATCH or DELETE
* request tunneled through POST. Defaults to '_method'.
* @see getMethod()
* @see getBodyParams()
*/
public $methodParam = '_method';
/**
* @var array the parsers for converting the raw HTTP request body into [[bodyParams]].
* The array keys are the request `Content-Types`, and the array values are the
* corresponding configurations for [[Yii::createObject|creating the parser objects]].
* A parser must implement the [[RequestParserInterface]].
*
* To enable parsing for JSON requests you can use the [[JsonParser]] class like in the following example:
*
* ```
* [
* 'application/json' => 'yii\web\JsonParser',
* ]
* ```
*
* To register a parser for parsing all request types you can use `'*'` as the array key.
* This one will be used as a fallback in case no other types match.
*
* @see getBodyParams()
*/
public $parsers = [];
/**
* @var array the configuration for trusted security related headers.
*
* An array key is an IPv4 or IPv6 IP address in CIDR notation for matching a client.
*
* An array value is a list of headers to trust. These will be matched against
* [[secureHeaders]] to determine which headers are allowed to be sent by a specified host.
* The case of the header names must be the same as specified in [[secureHeaders]].
*
* For example, to trust all headers listed in [[secureHeaders]] for IP addresses
* in range `192.168.0.0-192.168.0.254` write the following:
*
* ```php
* [
* '192.168.0.0/24',
* ]
* ```
*
* To trust just the `X-Forwarded-For` header from `10.0.0.1`, use:
*
* ```
* [
* '10.0.0.1' => ['X-Forwarded-For']
* ]
* ```
*
* Default is to trust all headers except those listed in [[secureHeaders]] from all hosts.
* Matches are tried in order and searching is stopped when IP matches.
*
* > Info: Matching is performed using [[IpValidator]].
* See [[IpValidator::::setRanges()|IpValidator::setRanges()]]
* and [[IpValidator::networks]] for advanced matching.
*
* @see secureHeaders
* @since 2.0.13
*/
public $trustedHosts = [];
/**
* @var array lists of headers that are, by default, subject to the trusted host configuration.
* These headers will be filtered unless explicitly allowed in [[trustedHosts]].
* If the list contains the `Forwarded` header, processing will be done according to RFC 7239.
* The match of header names is case-insensitive.
* @see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
* @see https://datatracker.ietf.org/doc/html/rfc7239
* @see trustedHosts
* @since 2.0.13
*/
public $secureHeaders = [
// Common:
'X-Forwarded-For',
'X-Forwarded-Host',
'X-Forwarded-Proto',
'X-Forwarded-Port',
// Microsoft:
'Front-End-Https',
'X-Rewrite-Url',
// ngrok:
'X-Original-Host',
];
/**
* @var string[] List of headers where proxies store the real client IP.
* It's not advisable to put insecure headers here.
* To use the `Forwarded` header according to RFC 7239, the header must be added to [[secureHeaders]] list.
* The match of header names is case-insensitive.
* @see trustedHosts
* @see secureHeaders
* @since 2.0.13
*/
public $ipHeaders = [
'X-Forwarded-For', // Common
];
/**
* @var string[] List of headers where proxies store the real request port.
* It's not advisable to put insecure headers here.
* To use the `Forwarded Port`, the header must be added to [[secureHeaders]] list.
* The match of header names is case-insensitive.
* @see trustedHosts
* @see secureHeaders
* @since 2.0.46
*/
public $portHeaders = [
'X-Forwarded-Port', // Common
];
/**
* @var array list of headers to check for determining whether the connection is made via HTTPS.
* The array keys are header names and the array value is a list of header values that indicate a secure connection.
* The match of header names and values is case-insensitive.
* It's not advisable to put insecure headers here.
* @see trustedHosts
* @see secureHeaders
* @since 2.0.13
*/
public $secureProtocolHeaders = [
'X-Forwarded-Proto' => ['https'], // Common
'Front-End-Https' => ['on'], // Microsoft
];
/**
* @var CookieCollection Collection of request cookies.
*/
private $_cookies;
/**
* @var HeaderCollection Collection of request headers.
*/
private $_headers;
/**
* Resolves the current request into a route and the associated parameters.
* @return array the first element is the route, and the second is the associated parameters.
* @throws NotFoundHttpException if the request cannot be resolved.
*/
public function resolve()
{
$result = Yii::$app->getUrlManager()->parseRequest($this);
if ($result !== false) {
list($route, $params) = $result;
if ($this->_queryParams === null) {
$_GET = $params + $_GET; // preserve numeric keys
} else {
$this->_queryParams = $params + $this->_queryParams;
}
return [$route, $this->getQueryParams()];
}
throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
}
/**
* Filters headers according to the [[trustedHosts]].
* @param HeaderCollection $headerCollection
* @since 2.0.13
*/
protected function filterHeaders(HeaderCollection $headerCollection)
{
$trustedHeaders = $this->getTrustedHeaders();
// remove all secure headers unless they are trusted
foreach ($this->secureHeaders as $secureHeader) {
if (!in_array($secureHeader, $trustedHeaders)) {
$headerCollection->remove($secureHeader);
}
}
}
/**
* Trusted headers according to the [[trustedHosts]].
* @return array
* @since 2.0.28
*/
protected function getTrustedHeaders()
{
// do not trust any of the [[secureHeaders]] by default
$trustedHeaders = [];
// check if the client is a trusted host
if (!empty($this->trustedHosts)) {
$validator = $this->getIpValidator();
$ip = $this->getRemoteIP();
foreach ($this->trustedHosts as $cidr => $headers) {
if (!is_array($headers)) {
$cidr = $headers;
$headers = $this->secureHeaders;
}
$validator->setRanges($cidr);
if ($validator->validate($ip)) {
$trustedHeaders = $headers;
break;
}
}
}
return $trustedHeaders;
}
/**
* Creates instance of [[IpValidator]].
* You can override this method to adjust validator or implement different matching strategy.
*
* @return IpValidator
* @since 2.0.13
*/
protected function getIpValidator()
{
return new IpValidator();
}
/**
* Returns the header collection.
* The header collection contains incoming HTTP headers.
* @return HeaderCollection the header collection
*/
public function getHeaders()
{
if ($this->_headers === null) {
$this->_headers = new HeaderCollection();
if (function_exists('getallheaders')) {
$headers = getallheaders();
foreach ($headers as $name => $value) {
$this->_headers->add($name, $value);
}
} elseif (function_exists('http_get_request_headers')) {
$headers = http_get_request_headers();
foreach ($headers as $name => $value) {
$this->_headers->add($name, $value);
}
} else {
// ['prefix' => length]
$headerPrefixes = ['HTTP_' => 5, 'REDIRECT_HTTP_' => 14];
foreach ($_SERVER as $name => $value) {
foreach ($headerPrefixes as $prefix => $length) {
if (strncmp($name, $prefix, $length) === 0) {
$name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, $length)))));
$this->_headers->add($name, $value);
continue 2;
}
}
}
}
$this->filterHeaders($this->_headers);
}
return $this->_headers;
}
/**
* Returns the method of the current request (e.g. GET, POST, HEAD, PUT, PATCH, DELETE).
* @return string request method, such as GET, POST, HEAD, PUT, PATCH, DELETE.
* The value returned is turned into upper case.
*/
public function getMethod()
{
if (
isset($_POST[$this->methodParam])
// Never allow to downgrade request from WRITE methods (POST, PATCH, DELETE, etc)
// to read methods (GET, HEAD, OPTIONS) for security reasons.
&& !in_array(strtoupper($_POST[$this->methodParam]), ['GET', 'HEAD', 'OPTIONS'], true)
) {
return strtoupper($_POST[$this->methodParam]);
}
if ($this->headers->has('X-Http-Method-Override')) {
return strtoupper($this->headers->get('X-Http-Method-Override'));
}
if (isset($_SERVER['REQUEST_METHOD'])) {
return strtoupper($_SERVER['REQUEST_METHOD']);
}
return 'GET';
}
/**
* Returns whether this is a GET request.
* @return bool whether this is a GET request.
*/
public function getIsGet()
{
return $this->getMethod() === 'GET';
}
/**
* Returns whether this is an OPTIONS request.
* @return bool whether this is a OPTIONS request.
*/
public function getIsOptions()
{
return $this->getMethod() === 'OPTIONS';
}
/**
* Returns whether this is a HEAD request.
* @return bool whether this is a HEAD request.
*/
public function getIsHead()
{
return $this->getMethod() === 'HEAD';
}
/**
* Returns whether this is a POST request.
* @return bool whether this is a POST request.
*/
public function getIsPost()
{
return $this->getMethod() === 'POST';
}
/**
* Returns whether this is a DELETE request.
* @return bool whether this is a DELETE request.
*/
public function getIsDelete()
{
return $this->getMethod() === 'DELETE';
}
/**
* Returns whether this is a PUT request.
* @return bool whether this is a PUT request.
*/
public function getIsPut()
{
return $this->getMethod() === 'PUT';
}
/**
* Returns whether this is a PATCH request.
* @return bool whether this is a PATCH request.
*/
public function getIsPatch()
{
return $this->getMethod() === 'PATCH';
}
/**
* Returns whether this is an AJAX (XMLHttpRequest) request.
*
* Note that in case of cross domain requests, browser doesn't set the X-Requested-With header by default:
* https://stackoverflow.com/questions/8163703/cross-domain-ajax-doesnt-send-x-requested-with-header
*
* In case you are using `fetch()`, pass header manually:
*
* ```
* fetch(url, {
* method: 'GET',
* headers: {'X-Requested-With': 'XMLHttpRequest'}
* })
* ```
*
* @return bool whether this is an AJAX (XMLHttpRequest) request.
*/
public function getIsAjax()
{
return $this->headers->get('X-Requested-With') === 'XMLHttpRequest';
}
/**
* Returns whether this is a PJAX request.
* @return bool whether this is a PJAX request
*/
public function getIsPjax()
{
return $this->getIsAjax() && $this->headers->has('X-Pjax');
}
/**
* Returns whether this is an Adobe Flash or Flex request.
* @return bool whether this is an Adobe Flash or Adobe Flex request.
*/
public function getIsFlash()
{
$userAgent = $this->headers->get('User-Agent', '');
return stripos($userAgent, 'Shockwave') !== false
|| stripos($userAgent, 'Flash') !== false;
}
private $_rawBody;
/**
* Returns the raw HTTP request body.
* @return string the request body
*/
public function getRawBody()
{
if ($this->_rawBody === null) {
$this->_rawBody = file_get_contents('php://input');
}
return $this->_rawBody;
}
/**
* Sets the raw HTTP request body, this method is mainly used by test scripts to simulate raw HTTP requests.
* @param string $rawBody the request body
*/
public function setRawBody($rawBody)
{
$this->_rawBody = $rawBody;
}
private $_bodyParams;
/**
* Returns the request parameters given in the request body.
*
* Request parameters are determined using the parsers configured in [[parsers]] property.
* If no parsers are configured for the current [[contentType]] it uses the PHP function `mb_parse_str()`
* to parse the [[rawBody|request body]].
* @return array|object the request parameters given in the request body.
* @throws \yii\base\InvalidConfigException if a registered parser does not implement the [[RequestParserInterface]].
* @see getMethod()
* @see getBodyParam()
* @see setBodyParams()
*/
public function getBodyParams()
{
if ($this->_bodyParams === null) {
if (isset($_POST[$this->methodParam])) {
$this->_bodyParams = $_POST;
unset($this->_bodyParams[$this->methodParam]);
return $this->_bodyParams;
}
$rawContentType = $this->getContentType();
if (($pos = strpos((string)$rawContentType, ';')) !== false) {
// e.g. text/html; charset=UTF-8
$contentType = substr($rawContentType, 0, $pos);
} else {
$contentType = $rawContentType;
}
if (isset($this->parsers[$contentType])) {
$parser = Yii::createObject($this->parsers[$contentType]);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
} elseif (isset($this->parsers['*'])) {
$parser = Yii::createObject($this->parsers['*']);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException('The fallback request parser is invalid. It must implement the yii\\web\\RequestParserInterface.');
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
} elseif ($this->getMethod() === 'POST') {
// PHP has already parsed the body so we have all params in $_POST
$this->_bodyParams = $_POST;
} else {
$this->_bodyParams = [];
mb_parse_str($this->getRawBody(), $this->_bodyParams);
}
}
return $this->_bodyParams;
}
/**
* Sets the request body parameters.
*
* @param array|object $values the request body parameters (name-value pairs)
* @see getBodyParams()
*/
public function setBodyParams($values)
{
$this->_bodyParams = $values;
}
/**
* Returns the named request body parameter value.
*
* If the parameter does not exist, the second parameter passed to this method will be returned.
*
* @param string $name the parameter name
* @param mixed $defaultValue the default parameter value if the parameter does not exist.
* @return mixed the parameter value
* @see getBodyParams()
* @see setBodyParams()
*/
public function getBodyParam($name, $defaultValue = null)
{
$params = $this->getBodyParams();
if (is_object($params)) {
// unable to use `ArrayHelper::getValue()` due to different dots in key logic and lack of exception handling
try {
return isset($params->{$name}) ? $params->{$name} : $defaultValue;
} catch (\Exception $e) {
return $defaultValue;
}
}
return isset($params[$name]) ? $params[$name] : $defaultValue;
}
/**
* Returns POST parameter with a given name. If name isn't specified, returns an array of all POST parameters.
*
* @param string $name the parameter name
* @param mixed $defaultValue the default parameter value if the parameter does not exist.
* @return array|mixed
*/
public function post($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getBodyParams();
}
return $this->getBodyParam($name, $defaultValue);
}
private $_queryParams;
/**
* Returns the request parameters given in the [[queryString]].
*
* This method will return the contents of `$_GET` if params where not explicitly set.
* @return array the request GET parameter values.
* @see setQueryParams()
*/
public function getQueryParams()
{
if ($this->_queryParams === null) {
return $_GET;
}
return $this->_queryParams;
}
/**
* Sets the request [[queryString]] parameters.
* @param array $values the request query parameters (name-value pairs)
* @see getQueryParam()
* @see getQueryParams()
*/
public function setQueryParams($values)
{
$this->_queryParams = $values;
}
/**
* Returns GET parameter with a given name. If name isn't specified, returns an array of all GET parameters.
*
* @param string $name the parameter name
* @param mixed $defaultValue the default parameter value if the parameter does not exist.
* @return array|mixed
*/
public function get($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getQueryParams();
}
return $this->getQueryParam($name, $defaultValue);
}
/**
* Returns the named GET parameter value.
* If the GET parameter does not exist, the second parameter passed to this method will be returned.
* @param string $name the GET parameter name.
* @param mixed $defaultValue the default parameter value if the GET parameter does not exist.
* @return mixed the GET parameter value
* @see getBodyParam()
*/
public function getQueryParam($name, $defaultValue = null)
{
$params = $this->getQueryParams();
return isset($params[$name]) ? $params[$name] : $defaultValue;
}
private $_hostInfo;
private $_hostName;
/**
* Returns the schema and host part of the current request URL.
*
* The returned URL does not have an ending slash.
*
* By default this value is based on the user request information. This method will
* return the value of `$_SERVER['HTTP_HOST']` if it is available or `$_SERVER['SERVER_NAME']` if not.
* You may want to check out the [PHP documentation](https://www.php.net/manual/en/reserved.variables.server.php)
* for more information on these variables.
*
* You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property.
*
* > Warning: Dependent on the server configuration this information may not be
* > reliable and [may be faked by the user sending the HTTP request](https://www.acunetix.com/vulnerabilities/web/host-header-attack).
* > If the webserver is configured to serve the same site independent of the value of
* > the `Host` header, this value is not reliable. In such situations you should either
* > fix your webserver configuration or explicitly set the value by setting the [[setHostInfo()|hostInfo]] property.
* > If you don't have access to the server configuration, you can setup [[\yii\filters\HostControl]] filter at
* > application level in order to protect against such kind of attack.
*
* @property string|null schema and hostname part (with port number if needed) of the request URL
* (e.g. `https://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
* See [[getHostInfo()]] for security related notes on this property.
* @return string|null schema and hostname part (with port number if needed) of the request URL
* (e.g. `https://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
* @see setHostInfo()
*/
public function getHostInfo()
{
if ($this->_hostInfo === null) {
$secure = $this->getIsSecureConnection();
$http = $secure ? 'https' : 'http';
if ($this->getSecureForwardedHeaderTrustedPart('host') !== null) {
$this->_hostInfo = $http . '://' . $this->getSecureForwardedHeaderTrustedPart('host');
} elseif ($this->headers->has('X-Forwarded-Host')) {
$this->_hostInfo = $http . '://' . trim(explode(',', $this->headers->get('X-Forwarded-Host'))[0]);
} elseif ($this->headers->has('X-Original-Host')) {
$this->_hostInfo = $http . '://' . trim(explode(',', $this->headers->get('X-Original-Host'))[0]);
} elseif ($this->headers->has('Host')) {
$this->_hostInfo = $http . '://' . $this->headers->get('Host');
} elseif (isset($_SERVER['SERVER_NAME'])) {
$this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME'];
$port = $secure ? $this->getSecurePort() : $this->getPort();
if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
$this->_hostInfo .= ':' . $port;
}
}
}
return $this->_hostInfo;
}
/**
* Sets the schema and host part of the application URL.
* This setter is provided in case the schema and hostname cannot be determined
* on certain Web servers.
* @param string|null $value the schema and host part of the application URL. The trailing slashes will be removed.
* @see getHostInfo() for security related notes on this property.
*/
public function setHostInfo($value)
{
$this->_hostName = null;
$this->_hostInfo = $value === null ? null : rtrim($value, '/');
}
/**
* Returns the host part of the current request URL.
* Value is calculated from current [[getHostInfo()|hostInfo]] property.
*
* > Warning: The content of this value may not be reliable, dependent on the server
* > configuration. Please refer to [[getHostInfo()]] for more information.
*
* @return string|null hostname part of the request URL (e.g. `www.yiiframework.com`)
* @see getHostInfo()
* @since 2.0.10
*/
public function getHostName()
{
if ($this->_hostName === null) {
$this->_hostName = parse_url((string)$this->getHostInfo(), PHP_URL_HOST);
}
return $this->_hostName;
}
private $_baseUrl;
/**
* Returns the relative URL for the application.
* This is similar to [[scriptUrl]] except that it does not include the script file name,
* and the ending slashes are removed.
* @return string the relative URL for the application
* @see setScriptUrl()
*/
public function getBaseUrl()
{
if ($this->_baseUrl === null) {
$this->_baseUrl = rtrim(dirname($this->getScriptUrl()), '\\/');
}
return $this->_baseUrl;
}
/**
* Sets the relative URL for the application.
* By default the URL is determined based on the entry script URL.
* This setter is provided in case you want to change this behavior.
* @param string $value the relative URL for the application
*/
public function setBaseUrl($value)
{
$this->_baseUrl = $value;
}
private $_scriptUrl;
/**
* Returns the relative URL of the entry script.
* The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
* @return string the relative URL of the entry script.
* @throws InvalidConfigException if unable to determine the entry script URL
*/
public function getScriptUrl()
{
if ($this->_scriptUrl === null) {
$scriptFile = $this->getScriptFile();
$scriptName = basename($scriptFile);
if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $scriptName) {
$this->_scriptUrl = $_SERVER['SCRIPT_NAME'];
} elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $scriptName) {
$this->_scriptUrl = $_SERVER['PHP_SELF'];
} elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) {
$this->_scriptUrl = $_SERVER['ORIG_SCRIPT_NAME'];
} elseif (isset($_SERVER['PHP_SELF']) && ($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) {
$this->_scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
} elseif (!empty($_SERVER['DOCUMENT_ROOT']) && strpos($scriptFile, $_SERVER['DOCUMENT_ROOT']) === 0) {
$this->_scriptUrl = str_replace([$_SERVER['DOCUMENT_ROOT'], '\\'], ['', '/'], $scriptFile);
} else {
throw new InvalidConfigException('Unable to determine the entry script URL.');
}
}
return $this->_scriptUrl;
}
/**
* Sets the relative URL for the application entry script.
* This setter is provided in case the entry script URL cannot be determined
* on certain Web servers.
* @param string $value the relative URL for the application entry script.
*/
public function setScriptUrl($value)
{
$this->_scriptUrl = $value === null ? null : '/' . trim($value, '/');
}
private $_scriptFile;
/**
* Returns the entry script file path.
* The default implementation will simply return `$_SERVER['SCRIPT_FILENAME']`.
* @return string the entry script file path
* @throws InvalidConfigException
*/
public function getScriptFile()
{
if (isset($this->_scriptFile)) {
return $this->_scriptFile;
}
if (isset($_SERVER['SCRIPT_FILENAME'])) {
return $_SERVER['SCRIPT_FILENAME'];
}
throw new InvalidConfigException('Unable to determine the entry script file path.');
}
/**
* Sets the entry script file path.
* The entry script file path normally can be obtained from `$_SERVER['SCRIPT_FILENAME']`.
* If your server configuration does not return the correct value, you may configure
* this property to make it right.
* @param string $value the entry script file path.
*/
public function setScriptFile($value)
{
$this->_scriptFile = $value;
}
private $_pathInfo;
/**
* Returns the path info of the currently requested URL.
* A path info refers to the part that is after the entry script and before the question mark (query string).
* The starting and ending slashes are both removed.
* @return string part of the request URL that is after the entry script and before the question mark.
* Note, the returned path info is already URL-decoded.
* @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration
*/
public function getPathInfo()
{
if ($this->_pathInfo === null) {
$this->_pathInfo = $this->resolvePathInfo();
}
return $this->_pathInfo;
}
/**
* Sets the path info of the current request.
* This method is mainly provided for testing purpose.
* @param string $value the path info of the current request
*/
public function setPathInfo($value)
{
$this->_pathInfo = $value === null ? null : ltrim($value, '/');
}
/**
* Resolves the path info part of the currently requested URL.
* A path info refers to the part that is after the entry script and before the question mark (query string).
* The starting slashes are both removed (ending slashes will be kept).
* @return string part of the request URL that is after the entry script and before the question mark.
* Note, the returned path info is decoded.
* @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration
*/
protected function resolvePathInfo()
{
$pathInfo = $this->getUrl();
if (($pos = strpos($pathInfo, '?')) !== false) {
$pathInfo = substr($pathInfo, 0, $pos);
}
$pathInfo = urldecode($pathInfo);
// try to encode in UTF8 if not so
// https://www.w3.org/International/questions/qa-forms-utf-8.en.html
if (
!preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $pathInfo)
) {
$pathInfo = $this->utf8Encode($pathInfo);
}
$scriptUrl = $this->getScriptUrl();
$baseUrl = $this->getBaseUrl();
if (strpos($pathInfo, $scriptUrl) === 0) {
$pathInfo = substr($pathInfo, strlen($scriptUrl));
} elseif ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) {
$pathInfo = substr($pathInfo, strlen($baseUrl));
} elseif (isset($_SERVER['PHP_SELF']) && strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) {
$pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl));
} else {
throw new InvalidConfigException('Unable to determine the path info of the current request.');
}
if (strncmp($pathInfo, '/', 1) === 0) {
$pathInfo = substr($pathInfo, 1);
}
return (string) $pathInfo;
}
/**