Completed
Push — 2.1 ( ee81a0...83fa82 )
by
unknown
14:49
created

Request::getServerName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 2
eloc 2
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\web;
9
10
use Psr\Http\Message\RequestInterface;
11
use Psr\Http\Message\StreamInterface;
12
use Psr\Http\Message\UploadedFileInterface;
13
use Psr\Http\Message\UriInterface;
14
use Yii;
15
use yii\base\InvalidConfigException;
16
use yii\di\Instance;
17
use yii\helpers\ArrayHelper;
18
use yii\helpers\Html;
19
use yii\http\Cookie;
20
use yii\http\CookieCollection;
21
use yii\http\FileStream;
22
use yii\http\MemoryStream;
23
use yii\http\MessageTrait;
24
use yii\http\UploadedFile;
25
use yii\http\Uri;
26
27
/**
28
 * The web Request class represents an HTTP request
29
 *
30
 * It encapsulates the $_SERVER variable and resolves its inconsistency among different Web servers.
31
 * Also it provides an interface to retrieve request parameters from $_POST, $_GET, $_COOKIES and REST
32
 * parameters sent via other HTTP methods like PUT or DELETE.
33
 *
34
 * Request is configured as an application component in [[\yii\web\Application]] by default.
35
 * You can access that instance via `Yii::$app->request`.
36
 *
37
 * For more details and usage information on Request, see the [guide article on requests](guide:runtime-requests).
38
 *
39
 * @property string $absoluteUrl The currently requested absolute URL. This property is read-only.
40
 * @property array $acceptableContentTypes The content types ordered by the quality score. Types with the
41
 * highest scores will be returned first. The array keys are the content types, while the array values are the
42
 * corresponding quality score and other parameters as given in the header.
43
 * @property array $acceptableLanguages The languages ordered by the preference level. The first element
44
 * represents the most preferred language.
45
 * @property string|null $authPassword The password sent via HTTP authentication, null if the password is not
46
 * given. This property is read-only.
47
 * @property string|null $authUser The username sent via HTTP authentication, null if the username is not
48
 * given. This property is read-only.
49
 * @property string $baseUrl The relative URL for the application.
50
 * @property array $bodyParams The request parameters given in the request body.
51
 * @property string $contentType Request content-type. Null is returned if this information is not available.
52
 * This property is read-only.
53
 * @property CookieCollection $cookies The cookie collection. This property is read-only.
54
 * @property string $csrfToken The token used to perform CSRF validation. This property is read-only.
55
 * @property string $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned
56
 * if no such header is sent. This property is read-only.
57
 * @property array $eTags The entity tags. This property is read-only.
58
 * @property string|null $hostInfo Schema and hostname part (with port number if needed) of the request URL
59
 * (e.g. `http://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set. See
60
 * [[getHostInfo()]] for security related notes on this property.
61
 * @property string|null $hostName Hostname part of the request URL (e.g. `www.yiiframework.com`). This
62
 * property is read-only.
63
 * @property bool $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only.
64
 * @property bool $isDelete Whether this is a DELETE request. This property is read-only.
65
 * @property bool $isFlash Whether this is an Adobe Flash or Adobe Flex request. This property is read-only.
66
 * @property bool $isGet Whether this is a GET request. This property is read-only.
67
 * @property bool $isHead Whether this is a HEAD request. This property is read-only.
68
 * @property bool $isOptions Whether this is a OPTIONS request. This property is read-only.
69
 * @property bool $isPatch Whether this is a PATCH request. This property is read-only.
70
 * @property bool $isPjax Whether this is a PJAX request. This property is read-only.
71
 * @property bool $isPost Whether this is a POST request. This property is read-only.
72
 * @property bool $isPut Whether this is a PUT request. This property is read-only.
73
 * @property bool $isSecureConnection If the request is sent via secure channel (https). This property is
74
 * read-only.
75
 * @property string $method Request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. The value returned is
76
 * turned into upper case.
77
 * @property UriInterface $uri the URI instance.
78
 * @property mixed $requestTarget the message's request target.
79
 * @property string $pathInfo Part of the request URL that is after the entry script and before the question
80
 * mark. Note, the returned path info is already URL-decoded.
81
 * @property int $port Port number for insecure requests.
82
 * @property array $queryParams The request GET parameter values.
83
 * @property string $queryString Part of the request URL that is after the question mark. This property is
84
 * read-only.
85
 * @property string $rawBody The request body.
86
 * @property string|null $referrer URL referrer, null if not available. This property is read-only.
87
 * @property string|null $origin URL origin, null if not available. This property is read-only.
88
 * @property string $scriptFile The entry script file path.
89
 * @property string $scriptUrl The relative URL of the entry script.
90
 * @property int $securePort Port number for secure requests.
91
 * @property string $serverName Server name, null if not available. This property is read-only.
92
 * @property int|null $serverPort Server port number, null if not available. This property is read-only.
93
 * @property string $url The currently requested relative URL. Note that the URI returned may be URL-encoded
94
 * depending on the client.
95
 * @property array $uploadedFiles Uploaded files for this request. See [[getUploadedFiles()]] for details.
96
 * @property string|null $userAgent User agent, null if not available. This property is read-only.
97
 * @property string|null $userHost User host name, null if not available. This property is read-only.
98
 * @property string|null $userIP User IP address, null if not available. This property is read-only.
99
 *
100
 * @author Qiang Xue <[email protected]>
101
 * @since 2.0
102
 */
103
class Request extends \yii\base\Request implements RequestInterface
104
{
105
    use MessageTrait;
106
107
    /**
108
     * The name of the HTTP header for sending CSRF token.
109
     */
110
    const CSRF_HEADER = 'X-CSRF-Token';
111
    /**
112
     * The length of the CSRF token mask.
113
     * @deprecated 2.0.12 The mask length is now equal to the token length.
114
     */
115
    const CSRF_MASK_LENGTH = 8;
116
117
    /**
118
     * @var bool whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to true.
119
     * When CSRF validation is enabled, forms submitted to an Yii Web application must be originated
120
     * from the same application. If not, a 400 HTTP exception will be raised.
121
     *
122
     * Note, this feature requires that the user client accepts cookie. Also, to use this feature,
123
     * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfParam]].
124
     * You may use [[\yii\helpers\Html::beginForm()]] to generate his hidden input.
125
     *
126
     * In JavaScript, you may get the values of [[csrfParam]] and [[csrfToken]] via `yii.getCsrfParam()` and
127
     * `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered.
128
     * You also need to include CSRF meta tags in your pages by using [[\yii\helpers\Html::csrfMetaTags()]].
129
     *
130
     * @see Controller::enableCsrfValidation
131
     * @see http://en.wikipedia.org/wiki/Cross-site_request_forgery
132
     */
133
    public $enableCsrfValidation = true;
134
    /**
135
     * @var string the name of the token used to prevent CSRF. Defaults to '_csrf'.
136
     * This property is used only when [[enableCsrfValidation]] is true.
137
     */
138
    public $csrfParam = '_csrf';
139
    /**
140
     * @var array the configuration for creating the CSRF [[Cookie|cookie]]. This property is used only when
141
     * both [[enableCsrfValidation]] and [[enableCsrfCookie]] are true.
142
     */
143
    public $csrfCookie = ['httpOnly' => true];
144
    /**
145
     * @var bool whether to use cookie to persist CSRF token. If false, CSRF token will be stored
146
     * in session under the name of [[csrfParam]]. Note that while storing CSRF tokens in session increases
147
     * security, it requires starting a session for every page, which will degrade your site performance.
148
     */
149
    public $enableCsrfCookie = true;
150
    /**
151
     * @var bool whether cookies should be validated to ensure they are not tampered. Defaults to true.
152
     */
153
    public $enableCookieValidation = true;
154
    /**
155
     * @var string a secret key used for cookie validation. This property must be set if [[enableCookieValidation]] is true.
156
     */
157
    public $cookieValidationKey;
158
    /**
159
     * @var string the name of the POST parameter that is used to indicate if a request is a PUT, PATCH or DELETE
160
     * request tunneled through POST. Defaults to '_method'.
161
     * @see getMethod()
162
     * @see getBodyParams()
163
     */
164
    public $methodParam = '_method';
165
    /**
166
     * @var array the parsers for converting the raw HTTP request body into [[bodyParams]].
167
     * The array keys are the request `Content-Types`, and the array values are the
168
     * corresponding configurations for [[Yii::createObject|creating the parser objects]].
169
     * A parser must implement the [[RequestParserInterface]].
170
     *
171
     * To enable parsing for JSON requests you can use the [[JsonParser]] class like in the following example:
172
     *
173
     * ```
174
     * [
175
     *     'application/json' => \yii\web\JsonParser::class,
176
     * ]
177
     * ```
178
     *
179
     * To register a parser for parsing all request types you can use `'*'` as the array key.
180
     * This one will be used as a fallback in case no other types match.
181
     *
182
     * @see getBodyParams()
183
     */
184
    public $parsers = [];
185
    /**
186
     * @var string name of the class to be used for uploaded file instantiation.
187
     * This class should implement [[UploadedFileInterface]].
188
     * @since 2.1.0
189
     */
190
    public $uploadedFileClass = UploadedFile::class;
191
192
    /**
193
     * @var CookieCollection Collection of request cookies.
194
     */
195
    private $_cookies;
196
    /**
197
     * @var string the HTTP method of the request.
198
     */
199
    private $_method;
200
    /**
201
     * @var UriInterface the URI instance associated with request.
202
     */
203
    private $_uri;
204
    /**
205
     * @var mixed the message's request target.
206
     */
207
    private $_requestTarget;
208
    /**
209
     * @var array uploaded files.
210
     * @since 2.1.0
211
     */
212
    private $_uploadedFiles;
213
214
215
    /**
216
     * Resolves the current request into a route and the associated parameters.
217
     * @return array the first element is the route, and the second is the associated parameters.
218
     * @throws NotFoundHttpException if the request cannot be resolved.
219
     */
220 1
    public function resolve()
221
    {
222 1
        $result = Yii::$app->getUrlManager()->parseRequest($this);
223 1
        if ($result !== false) {
224 1
            [$route, $params] = $result;
0 ignored issues
show
Bug introduced by
The variable $route does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $params does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
225 1
            if ($this->_queryParams === null) {
226 1
                $_GET = $params + $_GET; // preserve numeric keys
227
            } else {
228 1
                $this->_queryParams = $params + $this->_queryParams;
229
            }
230 1
            return [$route, $this->getQueryParams()];
231
        }
232
233
        throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
234
    }
235
236
    /**
237
     * Returns default message's headers, which should be present once [[headerCollection]] is instantiated.
238
     * @return string[][] an associative array of the message's headers.
239
     */
240 63
    protected function defaultHeaders()
241
    {
242 63
        if (function_exists('getallheaders')) {
243
            $headers = getallheaders();
244 63
        } elseif (function_exists('http_get_request_headers')) {
245
            $headers = http_get_request_headers();
246
        } else {
247 63
            $headers = [];
248 63
            foreach ($_SERVER as $name => $value) {
249 63
                if (strncmp($name, 'HTTP_', 5) === 0) {
250 11
                    $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
251 63
                    $headers[$name] = $value;
252
                }
253
            }
254
        }
255
256 63
        return $headers;
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     * @since 2.1.0
262
     */
263
    public function getRequestTarget()
264
    {
265
        if ($this->_requestTarget === null) {
266
            $this->_requestTarget = $this->getUri()->__toString();
267
        }
268
        return $this->_requestTarget;
269
    }
270
271
    /**
272
     * Specifies the message's request target
273
     * @param mixed $requestTarget the message's request target.
274
     * @since 2.1.0
275
     */
276
    public function setRequestTarget($requestTarget)
277
    {
278
        $this->_requestTarget = $requestTarget;
279
    }
280
281
    /**
282
     * {@inheritdoc}
283
     * @since 2.1.0
284
     */
285
    public function withRequestTarget($requestTarget)
286
    {
287
        if ($this->getRequestTarget() === $requestTarget) {
288
            return $this;
289
        }
290
291
        $newInstance = clone $this;
292
        $newInstance->setRequestTarget($requestTarget);
293
        return $newInstance;
294
    }
295
296
    /**
297
     * {@inheritdoc}
298
     */
299 26
    public function getMethod()
300
    {
301 26
        if ($this->_method === null) {
302 17
            if (isset($_POST[$this->methodParam])) {
303 1
                $this->_method = $_POST[$this->methodParam];
304 16
            } elseif ($this->hasHeader('x-http-method-override')) {
305
                $this->_method = $this->getHeaderLine('x-http-method-override');
306 16
            } elseif (isset($_SERVER['REQUEST_METHOD'])) {
307 1
                $this->_method = $_SERVER['REQUEST_METHOD'];
308
            } else {
309 16
                $this->_method = 'GET';
310
            }
311
        }
312 26
        return $this->_method;
313
    }
314
315
    /**
316
     * Specifies request HTTP method.
317
     * @param string $method case-sensitive HTTP method.
318
     * @since 2.1.0
319
     */
320 11
    public function setMethod($method)
321
    {
322 11
        $this->_method =  $method;
323 11
    }
324
325
    /**
326
     * {@inheritdoc}
327
     * @since 2.1.0
328
     */
329 1
    public function withMethod($method)
330
    {
331 1
        if ($this->getMethod() === $method) {
332
            return $this;
333
        }
334
335 1
        $newInstance = clone $this;
336 1
        $newInstance->setMethod($method);
337 1
        return $newInstance;
338
    }
339
340
    /**
341
     * {@inheritdoc}
342
     * @since 2.1.0
343
     */
344
    public function getUri()
345
    {
346
        if (!$this->_uri instanceof UriInterface) {
347
            if ($this->_uri === null) {
348
                $uri = new Uri(['string' => $this->getAbsoluteUrl()]);
349
            } elseif ($this->_uri instanceof \Closure) {
350
                $uri = call_user_func($this->_uri, $this);
351
            } else {
352
                $uri = $this->_uri;
353
            }
354
355
            $this->_uri = Instance::ensure($uri, UriInterface::class);
356
        }
357
        return $this->_uri;
358
    }
359
360
    /**
361
     * Specifies the URI instance.
362
     * @param UriInterface|\Closure|array $uri URI instance or its DI compatible configuration.
363
     * @since 2.1.0
364
     */
365
    public function setUri($uri)
366
    {
367
        $this->_uri = $uri;
0 ignored issues
show
Documentation Bug introduced by
It seems like $uri can also be of type object<Closure> or array. However, the property $_uri is declared as type object<Psr\Http\Message\UriInterface>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
368
    }
369
370
    /**
371
     * {@inheritdoc}
372
     * @since 2.1.0
373
     */
374
    public function withUri(UriInterface $uri, $preserveHost = false)
375
    {
376
        if ($this->getUri() === $uri) {
377
            return $this;
378
        }
379
380
        $newInstance = clone $this;
381
382
        $newInstance->setUri($uri);
383
        if (!$preserveHost) {
384
            return $newInstance->withHeader('host', $uri->getHost());
385
        }
386
        return $newInstance;
387
    }
388
389
    /**
390
     * Returns whether this is a GET request.
391
     * @return bool whether this is a GET request.
392
     */
393 2
    public function getIsGet()
394
    {
395 2
        return $this->getMethod() === 'GET';
396
    }
397
398
    /**
399
     * Returns whether this is an OPTIONS request.
400
     * @return bool whether this is a OPTIONS request.
401
     */
402
    public function getIsOptions()
403
    {
404
        return $this->getMethod() === 'OPTIONS';
405
    }
406
407
    /**
408
     * Returns whether this is a HEAD request.
409
     * @return bool whether this is a HEAD request.
410
     */
411 9
    public function getIsHead()
412
    {
413 9
        return $this->getMethod() === 'HEAD';
414
    }
415
416
    /**
417
     * Returns whether this is a POST request.
418
     * @return bool whether this is a POST request.
419
     */
420
    public function getIsPost()
421
    {
422
        return $this->getMethod() === 'POST';
423
    }
424
425
    /**
426
     * Returns whether this is a DELETE request.
427
     * @return bool whether this is a DELETE request.
428
     */
429
    public function getIsDelete()
430
    {
431
        return $this->getMethod() === 'DELETE';
432
    }
433
434
    /**
435
     * Returns whether this is a PUT request.
436
     * @return bool whether this is a PUT request.
437
     */
438
    public function getIsPut()
439
    {
440
        return $this->getMethod() === 'PUT';
441
    }
442
443
    /**
444
     * Returns whether this is a PATCH request.
445
     * @return bool whether this is a PATCH request.
446
     */
447
    public function getIsPatch()
448
    {
449
        return $this->getMethod() === 'PATCH';
450
    }
451
452
    /**
453
     * Returns whether this is an AJAX (XMLHttpRequest) request.
454
     *
455
     * Note that jQuery doesn't set the header in case of cross domain
456
     * requests: https://stackoverflow.com/questions/8163703/cross-domain-ajax-doesnt-send-x-requested-with-header
457
     *
458
     * @return bool whether this is an AJAX (XMLHttpRequest) request.
459
     */
460 10
    public function getIsAjax()
461
    {
462 10
        return $this->getHeaderLine('x-requested-with') === 'XMLHttpRequest';
463
    }
464
465
    /**
466
     * Returns whether this is a PJAX request
467
     * @return bool whether this is a PJAX request
468
     */
469 1
    public function getIsPjax()
470
    {
471 1
        return $this->getIsAjax() && $this->hasHeader('x-pjax');
472
    }
473
474
    /**
475
     * Returns whether this is an Adobe Flash or Flex request.
476
     * @return bool whether this is an Adobe Flash or Adobe Flex request.
477
     */
478
    public function getIsFlash()
479
    {
480
        $userAgent = $this->getUserAgent();
481
        if ($userAgent === null) {
482
            return false;
483
        }
484
        return (stripos($userAgent, 'Shockwave') !== false || stripos($userAgent, 'Flash') !== false);
485
    }
486
487
    /**
488
     * Returns default message body to be used in case it is not explicitly set.
489
     * @return StreamInterface default body instance.
490
     */
491
    protected function defaultBody()
492
    {
493
        return new FileStream([
494
            'filename' => 'php://input',
495
            'mode' => 'r',
496
        ]);
497
    }
498
499
    /**
500
     * Returns the raw HTTP request body.
501
     * @return string the request body
502
     */
503
    public function getRawBody()
504
    {
505
        return $this->getBody()->__toString();
506
    }
507
508
    /**
509
     * Sets the raw HTTP request body, this method is mainly used by test scripts to simulate raw HTTP requests.
510
     * @param string $rawBody the request body
511
     */
512 6
    public function setRawBody($rawBody)
513
    {
514 6
        $body = new MemoryStream();
515 6
        $body->write($rawBody);
516 6
        $this->setBody($body);
517 6
    }
518
519
    private $_bodyParams;
520
521
    /**
522
     * Returns the request parameters given in the request body.
523
     *
524
     * Request parameters are determined using the parsers configured in [[parsers]] property.
525
     * If no parsers are configured for the current [[contentType]] it uses the PHP function `mb_parse_str()`
526
     * to parse the [[rawBody|request body]].
527
     * @return array the request parameters given in the request body.
528
     * @throws InvalidConfigException if a registered parser does not implement the [[RequestParserInterface]].
529
     * @throws UnsupportedMediaTypeHttpException if unable to parse raw body.
530
     * @see getMethod()
531
     * @see getBodyParam()
532
     * @see setBodyParams()
533
     */
534 11
    public function getBodyParams()
535
    {
536 11
        if ($this->_bodyParams === null) {
537 8
            if (isset($_POST[$this->methodParam])) {
538
                $this->_bodyParams = $_POST;
539
                unset($this->_bodyParams[$this->methodParam]);
540
                return $this->_bodyParams;
541
            }
542
543 8
            $contentType = $this->getContentType();
544 8
            if (($pos = strpos($contentType, ';')) !== false) {
545
                // e.g. text/html; charset=UTF-8
546 2
                $contentType = trim(substr($contentType, 0, $pos));
547
            }
548
549 8
            if (isset($this->parsers[$contentType])) {
550 2
                $parser = Yii::createObject($this->parsers[$contentType]);
551 2
                if (!($parser instanceof RequestParserInterface)) {
552
                    throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
553
                }
554 2
                $this->_bodyParams = $parser->parse($this);
555 6
            } elseif (isset($this->parsers['*'])) {
556
                $parser = Yii::createObject($this->parsers['*']);
557
                if (!($parser instanceof RequestParserInterface)) {
558
                    throw new InvalidConfigException('The fallback request parser is invalid. It must implement the yii\\web\\RequestParserInterface.');
559
                }
560
                $this->_bodyParams = $parser->parse($this);
561 6
            } elseif ($this->getMethod() === 'POST') {
562 6
                if ($contentType !== 'application/x-www-form-urlencoded' && $contentType !== 'multipart/form-data') {
563 1
                    throw new UnsupportedMediaTypeHttpException();
564
                }
565
                // PHP has already parsed the body so we have all params in $_POST
566 6
                $this->_bodyParams = $_POST;
567
            } else {
568 1
                if ($contentType !== 'application/x-www-form-urlencoded') {
569 1
                    throw new UnsupportedMediaTypeHttpException();
570
                }
571 1
                $this->_bodyParams = [];
572 1
                mb_parse_str($this->getBody()->__toString(), $this->_bodyParams);
573
            }
574
        }
575
576 11
        return $this->_bodyParams;
577
    }
578
579
    /**
580
     * Sets the request body parameters.
581
     * @param array $values the request body parameters (name-value pairs)
582
     * @see getBodyParam()
583
     * @see getBodyParams()
584
     */
585 3
    public function setBodyParams($values)
586
    {
587 3
        $this->_bodyParams = $values;
588 3
    }
589
590
    /**
591
     * Returns the named request body parameter value.
592
     * If the parameter does not exist, the second parameter passed to this method will be returned.
593
     * @param string $name the parameter name
594
     * @param mixed $defaultValue the default parameter value if the parameter does not exist.
595
     * @return mixed the parameter value
596
     * @see getBodyParams()
597
     * @see setBodyParams()
598
     */
599 4
    public function getBodyParam($name, $defaultValue = null)
600
    {
601 4
        $params = $this->getBodyParams();
602
603 4
        return isset($params[$name]) ? $params[$name] : $defaultValue;
604
    }
605
606
    /**
607
     * Returns POST parameter with a given name. If name isn't specified, returns an array of all POST parameters.
608
     *
609
     * @param string $name the parameter name
610
     * @param mixed $defaultValue the default parameter value if the parameter does not exist.
611
     * @return array|mixed
612
     */
613
    public function post($name = null, $defaultValue = null)
614
    {
615
        if ($name === null) {
616
            return $this->getBodyParams();
617
        }
618
619
        return $this->getBodyParam($name, $defaultValue);
620
    }
621
622
    private $_queryParams;
623
624
    /**
625
     * Returns the request parameters given in the [[queryString]].
626
     *
627
     * This method will return the contents of `$_GET` if params where not explicitly set.
628
     * @return array the request GET parameter values.
629
     * @see setQueryParams()
630
     */
631 29
    public function getQueryParams()
632
    {
633 29
        if ($this->_queryParams === null) {
634 23
            return $_GET;
635
        }
636
637 8
        return $this->_queryParams;
638
    }
639
640
    /**
641
     * Sets the request [[queryString]] parameters.
642
     * @param array $values the request query parameters (name-value pairs)
643
     * @see getQueryParam()
644
     * @see getQueryParams()
645
     */
646 8
    public function setQueryParams($values)
647
    {
648 8
        $this->_queryParams = $values;
649 8
    }
650
651
    /**
652
     * Returns GET parameter with a given name. If name isn't specified, returns an array of all GET parameters.
653
     *
654
     * @param string $name the parameter name
655
     * @param mixed $defaultValue the default parameter value if the parameter does not exist.
656
     * @return array|mixed
657
     */
658 15
    public function get($name = null, $defaultValue = null)
659
    {
660 15
        if ($name === null) {
661
            return $this->getQueryParams();
662
        }
663
664 15
        return $this->getQueryParam($name, $defaultValue);
665
    }
666
667
    /**
668
     * Returns the named GET parameter value.
669
     * If the GET parameter does not exist, the second parameter passed to this method will be returned.
670
     * @param string $name the GET parameter name.
671
     * @param mixed $defaultValue the default parameter value if the GET parameter does not exist.
672
     * @return mixed the GET parameter value
673
     * @see getBodyParam()
674
     */
675 20
    public function getQueryParam($name, $defaultValue = null)
676
    {
677 20
        $params = $this->getQueryParams();
678
679 20
        return isset($params[$name]) ? $params[$name] : $defaultValue;
680
    }
681
682
    private $_hostInfo;
683
    private $_hostName;
684
685
    /**
686
     * Returns the schema and host part of the current request URL.
687
     *
688
     * The returned URL does not have an ending slash.
689
     *
690
     * By default this value is based on the user request information. This method will
691
     * return the value of `$_SERVER['HTTP_HOST']` if it is available or `$_SERVER['SERVER_NAME']` if not.
692
     * You may want to check out the [PHP documentation](http://php.net/manual/en/reserved.variables.server.php)
693
     * for more information on these variables.
694
     *
695
     * You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property.
696
     *
697
     * > Warning: Dependent on the server configuration this information may not be
698
     * > reliable and [may be faked by the user sending the HTTP request](https://www.acunetix.com/vulnerabilities/web/host-header-attack).
699
     * > If the webserver is configured to serve the same site independent of the value of
700
     * > the `Host` header, this value is not reliable. In such situations you should either
701
     * > fix your webserver configuration or explicitly set the value by setting the [[setHostInfo()|hostInfo]] property.
702
     * > If you don't have access to the server configuration, you can setup [[\yii\filters\HostControl]] filter at
703
     * > application level in order to protect against such kind of attack.
704
     *
705
     * @property string|null schema and hostname part (with port number if needed) of the request URL
706
     * (e.g. `http://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
707
     * See [[getHostInfo()]] for security related notes on this property.
708
     * @return string|null schema and hostname part (with port number if needed) of the request URL
709
     * (e.g. `http://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
710
     * @see setHostInfo()
711
     */
712 24
    public function getHostInfo()
713
    {
714 24
        if ($this->_hostInfo === null) {
715 20
            $secure = $this->getIsSecureConnection();
716 20
            $http = $secure ? 'https' : 'http';
717 20
            if ($this->hasHeader('Host')) {
718 7
                $this->_hostInfo = $http . '://' . $this->getHeaderLine('Host');
719 13
            } elseif (isset($_SERVER['SERVER_NAME'])) {
720
                $this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME'];
721
                $port = $secure ? $this->getSecurePort() : $this->getPort();
722
                if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
723
                    $this->_hostInfo .= ':' . $port;
724
                }
725
            }
726
        }
727
728 24
        return $this->_hostInfo;
729
    }
730
731
    /**
732
     * Sets the schema and host part of the application URL.
733
     * This setter is provided in case the schema and hostname cannot be determined
734
     * on certain Web servers.
735
     * @param string|null $value the schema and host part of the application URL. The trailing slashes will be removed.
736
     * @see getHostInfo() for security related notes on this property.
737
     */
738 57
    public function setHostInfo($value)
739
    {
740 57
        $this->_hostName = null;
741 57
        $this->_hostInfo = $value === null ? null : rtrim($value, '/');
742 57
    }
743
744
    /**
745
     * Returns the host part of the current request URL.
746
     * Value is calculated from current [[getHostInfo()|hostInfo]] property.
747
     *
748
     * > Warning: The content of this value may not be reliable, dependent on the server
749
     * > configuration. Please refer to [[getHostInfo()]] for more information.
750
     *
751
     * @return string|null hostname part of the request URL (e.g. `www.yiiframework.com`)
752
     * @see getHostInfo()
753
     * @since 2.0.10
754
     */
755 11
    public function getHostName()
756
    {
757 11
        if ($this->_hostName === null) {
758 11
            $this->_hostName = parse_url($this->getHostInfo(), PHP_URL_HOST);
759
        }
760
761 11
        return $this->_hostName;
762
    }
763
764
    private $_baseUrl;
765
766
    /**
767
     * Returns the relative URL for the application.
768
     * This is similar to [[scriptUrl]] except that it does not include the script file name,
769
     * and the ending slashes are removed.
770
     * @return string the relative URL for the application
771
     * @see setScriptUrl()
772
     */
773 254
    public function getBaseUrl()
774
    {
775 254
        if ($this->_baseUrl === null) {
776 253
            $this->_baseUrl = rtrim(dirname($this->getScriptUrl()), '\\/');
777
        }
778
779 254
        return $this->_baseUrl;
780
    }
781
782
    /**
783
     * Sets the relative URL for the application.
784
     * By default the URL is determined based on the entry script URL.
785
     * This setter is provided in case you want to change this behavior.
786
     * @param string $value the relative URL for the application
787
     */
788 1
    public function setBaseUrl($value)
789
    {
790 1
        $this->_baseUrl = $value;
791 1
    }
792
793
    private $_scriptUrl;
794
795
    /**
796
     * Returns the relative URL of the entry script.
797
     * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
798
     * @return string the relative URL of the entry script.
799
     * @throws InvalidConfigException if unable to determine the entry script URL
800
     */
801 255
    public function getScriptUrl()
802
    {
803 255
        if ($this->_scriptUrl === null) {
804 2
            $scriptFile = $this->getScriptFile();
805 1
            $scriptName = basename($scriptFile);
806 1
            if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $scriptName) {
807 1
                $this->_scriptUrl = $_SERVER['SCRIPT_NAME'];
808
            } elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $scriptName) {
809
                $this->_scriptUrl = $_SERVER['PHP_SELF'];
810
            } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) {
811
                $this->_scriptUrl = $_SERVER['ORIG_SCRIPT_NAME'];
812
            } elseif (isset($_SERVER['PHP_SELF']) && ($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) {
813
                $this->_scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
814
            } elseif (!empty($_SERVER['DOCUMENT_ROOT']) && strpos($scriptFile, $_SERVER['DOCUMENT_ROOT']) === 0) {
815
                $this->_scriptUrl = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $scriptFile));
816
            } else {
817
                throw new InvalidConfigException('Unable to determine the entry script URL.');
818
            }
819
        }
820
821 254
        return $this->_scriptUrl;
822
    }
823
824
    /**
825
     * Sets the relative URL for the application entry script.
826
     * This setter is provided in case the entry script URL cannot be determined
827
     * on certain Web servers.
828
     * @param string $value the relative URL for the application entry script.
829
     */
830 265
    public function setScriptUrl($value)
831
    {
832 265
        $this->_scriptUrl = $value === null ? null : '/' . trim($value, '/');
833 265
    }
834
835
    private $_scriptFile;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
836
837
    /**
838
     * Returns the entry script file path.
839
     * The default implementation will simply return `$_SERVER['SCRIPT_FILENAME']`.
840
     * @return string the entry script file path
841
     * @throws InvalidConfigException
842
     */
843 256
    public function getScriptFile()
844
    {
845 256
        if (isset($this->_scriptFile)) {
846 234
            return $this->_scriptFile;
847
        }
848
849 23
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
850 21
            return $_SERVER['SCRIPT_FILENAME'];
851
        }
852
853 2
        throw new InvalidConfigException('Unable to determine the entry script file path.');
854
    }
855
856
    /**
857
     * Sets the entry script file path.
858
     * The entry script file path normally can be obtained from `$_SERVER['SCRIPT_FILENAME']`.
859
     * If your server configuration does not return the correct value, you may configure
860
     * this property to make it right.
861
     * @param string $value the entry script file path.
862
     */
863 234
    public function setScriptFile($value)
864
    {
865 234
        $this->_scriptFile = $value;
866 234
    }
867
868
    private $_pathInfo;
869
870
    /**
871
     * Returns the path info of the currently requested URL.
872
     * A path info refers to the part that is after the entry script and before the question mark (query string).
873
     * The starting and ending slashes are both removed.
874
     * @return string part of the request URL that is after the entry script and before the question mark.
875
     * Note, the returned path info is already URL-decoded.
876
     * @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration
877
     */
878 18
    public function getPathInfo()
879
    {
880 18
        if ($this->_pathInfo === null) {
881
            $this->_pathInfo = $this->resolvePathInfo();
882
        }
883
884 18
        return $this->_pathInfo;
885
    }
886
887
    /**
888
     * Sets the path info of the current request.
889
     * This method is mainly provided for testing purpose.
890
     * @param string $value the path info of the current request
891
     */
892 19
    public function setPathInfo($value)
893
    {
894 19
        $this->_pathInfo = $value === null ? null : ltrim($value, '/');
895 19
    }
896
897
    /**
898
     * Resolves the path info part of the currently requested URL.
899
     * A path info refers to the part that is after the entry script and before the question mark (query string).
900
     * The starting slashes are both removed (ending slashes will be kept).
901
     * @return string part of the request URL that is after the entry script and before the question mark.
902
     * Note, the returned path info is decoded.
903
     * @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration
904
     */
905
    protected function resolvePathInfo()
906
    {
907
        $pathInfo = $this->getUrl();
908
909
        if (($pos = strpos($pathInfo, '?')) !== false) {
910
            $pathInfo = substr($pathInfo, 0, $pos);
911
        }
912
913
        $pathInfo = urldecode($pathInfo);
914
915
        // try to encode in UTF8 if not so
916
        // http://w3.org/International/questions/qa-forms-utf-8.html
917
        if (!preg_match('%^(?:
918
            [\x09\x0A\x0D\x20-\x7E]              # ASCII
919
            | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
920
            | \xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs
921
            | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
922
            | \xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates
923
            | \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
924
            | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
925
            | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
926
            )*$%xs', $pathInfo)
927
        ) {
928
            $pathInfo = utf8_encode($pathInfo);
929
        }
930
931
        $scriptUrl = $this->getScriptUrl();
932
        $baseUrl = $this->getBaseUrl();
933
        if (strpos($pathInfo, $scriptUrl) === 0) {
934
            $pathInfo = substr($pathInfo, strlen($scriptUrl));
935
        } elseif ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) {
936
            $pathInfo = substr($pathInfo, strlen($baseUrl));
937
        } elseif (isset($_SERVER['PHP_SELF']) && strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) {
938
            $pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl));
939
        } else {
940
            throw new InvalidConfigException('Unable to determine the path info of the current request.');
941
        }
942
943
        if (substr($pathInfo, 0, 1) === '/') {
944
            $pathInfo = substr($pathInfo, 1);
945
        }
946
947
        return (string) $pathInfo;
948
    }
949
950
    /**
951
     * Returns the currently requested absolute URL.
952
     * This is a shortcut to the concatenation of [[hostInfo]] and [[url]].
953
     * @return string the currently requested absolute URL.
954
     */
955
    public function getAbsoluteUrl()
956
    {
957
        return $this->getHostInfo() . $this->getUrl();
958
    }
959
960
    private $_url;
961
962
    /**
963
     * Returns the currently requested relative URL.
964
     * This refers to the portion of the URL that is after the [[hostInfo]] part.
965
     * It includes the [[queryString]] part if any.
966
     * @return string the currently requested relative URL. Note that the URI returned may be URL-encoded depending on the client.
967
     * @throws InvalidConfigException if the URL cannot be determined due to unusual server configuration
968
     */
969 11
    public function getUrl()
970
    {
971 11
        if ($this->_url === null) {
972 3
            $this->_url = $this->resolveRequestUri();
973
        }
974
975 11
        return $this->_url;
976
    }
977
978
    /**
979
     * Sets the currently requested relative URL.
980
     * The URI must refer to the portion that is after [[hostInfo]].
981
     * Note that the URI should be URL-encoded.
982
     * @param string $value the request URI to be set
983
     */
984 24
    public function setUrl($value)
985
    {
986 24
        $this->_url = $value;
987 24
    }
988
989
    /**
990
     * Resolves the request URI portion for the currently requested URL.
991
     * This refers to the portion that is after the [[hostInfo]] part. It includes the [[queryString]] part if any.
992
     * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
993
     * @return string|bool the request URI portion for the currently requested URL.
994
     * Note that the URI returned may be URL-encoded depending on the client.
995
     * @throws InvalidConfigException if the request URI cannot be determined due to unusual server configuration
996
     */
997 3
    protected function resolveRequestUri()
998
    {
999 3
        if ($this->hasHeader('x-rewrite-url')) { // IIS
1000
            $requestUri = $this->getHeaderLine('x-rewrite-url');
1001 3
        } elseif (isset($_SERVER['REQUEST_URI'])) {
1002 3
            $requestUri = $_SERVER['REQUEST_URI'];
1003 3
            if ($requestUri !== '' && $requestUri[0] !== '/') {
1004 3
                $requestUri = preg_replace('/^(http|https):\/\/[^\/]+/i', '', $requestUri);
1005
            }
1006
        } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 CGI
1007
            $requestUri = $_SERVER['ORIG_PATH_INFO'];
1008
            if (!empty($_SERVER['QUERY_STRING'])) {
1009
                $requestUri .= '?' . $_SERVER['QUERY_STRING'];
1010
            }
1011
        } else {
1012
            throw new InvalidConfigException('Unable to determine the request URI.');
1013
        }
1014
1015 3
        return $requestUri;
1016
    }
1017
1018
    /**
1019
     * Returns part of the request URL that is after the question mark.
1020
     * @return string part of the request URL that is after the question mark
1021
     */
1022
    public function getQueryString()
1023
    {
1024
        return isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
1025
    }
1026
1027
    /**
1028
     * Return if the request is sent via secure channel (https).
1029
     * @return bool if the request is sent via secure channel (https)
1030
     */
1031 20
    public function getIsSecureConnection()
1032
    {
1033 20
        return isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)
1034 20
            || strcasecmp($this->getHeaderLine('x-forwarded-proto'), 'https') === 0;
1035
    }
1036
1037
    /**
1038
     * Returns the server name.
1039
     * @return string server name, null if not available
1040
     */
1041 1
    public function getServerName()
1042
    {
1043 1
        return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
1044
    }
1045
1046
    /**
1047
     * Returns the server port number.
1048
     * @return int|null server port number, null if not available
1049
     */
1050 1
    public function getServerPort()
1051
    {
1052 1
        return isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : null;
1053
    }
1054
1055
    /**
1056
     * Returns the URL referrer.
1057
     * @return string|null URL referrer, null if not available
1058
     */
1059
    public function getReferrer()
1060
    {
1061
        if (!$this->hasHeader('Referer')) {
1062
            return null;
1063
        }
1064
        return $this->getHeaderLine('Referer');
1065
    }
1066
1067
    /**
1068
     * Returns the URL origin of a CORS request.
1069
     *
1070
     * The return value is taken from the `Origin` [[getHeaders()|header]] sent by the browser.
1071
     *
1072
     * Note that the origin request header indicates where a fetch originates from.
1073
     * It doesn't include any path information, but only the server name.
1074
     * It is sent with a CORS requests, as well as with POST requests.
1075
     * It is similar to the referer header, but, unlike this header, it doesn't disclose the whole path.
1076
     * Please refer to <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin> for more information.
1077
     *
1078
     * @return string|null URL origin of a CORS request, `null` if not available.
1079
     * @see getHeaders()
1080
     * @since 2.0.13
1081
     */
1082 1
    public function getOrigin()
1083
    {
1084 1
        return $this->getHeaderLine('origin');
1085
    }
1086
1087
    /**
1088
     * Returns the user agent.
1089
     * @return string|null user agent, null if not available
1090
     */
1091
    public function getUserAgent()
1092
    {
1093
        if (!$this->hasHeader('User-Agent')) {
1094
            return null;
1095
        }
1096
        return $this->getHeaderLine('User-Agent');
1097
    }
1098
1099
    /**
1100
     * Returns the user IP address.
1101
     * @return string|null user IP address, null if not available
1102
     */
1103 27
    public function getUserIP()
1104
    {
1105 27
        return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
1106
    }
1107
1108
    /**
1109
     * Returns the user host name.
1110
     * @return string|null user host name, null if not available
1111
     */
1112
    public function getUserHost()
1113
    {
1114
        return isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : null;
1115
    }
1116
1117
    /**
1118
     * @return string|null the username sent via HTTP authentication, null if the username is not given
1119
     */
1120 10
    public function getAuthUser()
1121
    {
1122 10
        return isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : null;
1123
    }
1124
1125
    /**
1126
     * @return string|null the password sent via HTTP authentication, null if the password is not given
1127
     */
1128 10
    public function getAuthPassword()
1129
    {
1130 10
        return isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : null;
1131
    }
1132
1133
    private $_port;
1134
1135
    /**
1136
     * Returns the port to use for insecure requests.
1137
     * Defaults to 80, or the port specified by the server if the current
1138
     * request is insecure.
1139
     * @return int port number for insecure requests.
1140
     * @see setPort()
1141
     */
1142
    public function getPort()
1143
    {
1144
        if ($this->_port === null) {
1145
            $this->_port = !$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 80;
1146
        }
1147
1148
        return $this->_port;
1149
    }
1150
1151
    /**
1152
     * Sets the port to use for insecure requests.
1153
     * This setter is provided in case a custom port is necessary for certain
1154
     * server configurations.
1155
     * @param int $value port number.
1156
     */
1157
    public function setPort($value)
1158
    {
1159
        if ($value != $this->_port) {
1160
            $this->_port = (int) $value;
1161
            $this->_hostInfo = null;
1162
        }
1163
    }
1164
1165
    private $_securePort;
1166
1167
    /**
1168
     * Returns the port to use for secure requests.
1169
     * Defaults to 443, or the port specified by the server if the current
1170
     * request is secure.
1171
     * @return int port number for secure requests.
1172
     * @see setSecurePort()
1173
     */
1174
    public function getSecurePort()
1175
    {
1176
        if ($this->_securePort === null) {
1177
            $this->_securePort = $this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 443;
1178
        }
1179
1180
        return $this->_securePort;
1181
    }
1182
1183
    /**
1184
     * Sets the port to use for secure requests.
1185
     * This setter is provided in case a custom port is necessary for certain
1186
     * server configurations.
1187
     * @param int $value port number.
1188
     */
1189
    public function setSecurePort($value)
1190
    {
1191
        if ($value != $this->_securePort) {
1192
            $this->_securePort = (int) $value;
1193
            $this->_hostInfo = null;
1194
        }
1195
    }
1196
1197
    private $_contentTypes;
1198
1199
    /**
1200
     * Returns the content types acceptable by the end user.
1201
     * This is determined by the `Accept` HTTP header. For example,
1202
     *
1203
     * ```php
1204
     * $_SERVER['HTTP_ACCEPT'] = 'text/plain; q=0.5, application/json; version=1.0, application/xml; version=2.0;';
1205
     * $types = $request->getAcceptableContentTypes();
1206
     * print_r($types);
1207
     * // displays:
1208
     * // [
1209
     * //     'application/json' => ['q' => 1, 'version' => '1.0'],
1210
     * //      'application/xml' => ['q' => 1, 'version' => '2.0'],
1211
     * //           'text/plain' => ['q' => 0.5],
1212
     * // ]
1213
     * ```
1214
     *
1215
     * @return array the content types ordered by the quality score. Types with the highest scores
1216
     * will be returned first. The array keys are the content types, while the array values
1217
     * are the corresponding quality score and other parameters as given in the header.
1218
     */
1219 3
    public function getAcceptableContentTypes()
1220
    {
1221 3
        if ($this->_contentTypes === null) {
1222 2
            if ($this->hasHeader('Accept')) {
1223 2
                $this->_contentTypes = $this->parseAcceptHeader($this->getHeaderLine('Accept'));
1224
            } else {
1225 1
                $this->_contentTypes = [];
1226
            }
1227
        }
1228
1229 3
        return $this->_contentTypes;
1230
    }
1231
1232
    /**
1233
     * Sets the acceptable content types.
1234
     * Please refer to [[getAcceptableContentTypes()]] on the format of the parameter.
1235
     * @param array $value the content types that are acceptable by the end user. They should
1236
     * be ordered by the preference level.
1237
     * @see getAcceptableContentTypes()
1238
     * @see parseAcceptHeader()
1239
     */
1240 1
    public function setAcceptableContentTypes($value)
1241
    {
1242 1
        $this->_contentTypes = $value;
1243 1
    }
1244
1245
    /**
1246
     * Returns request content-type
1247
     * The Content-Type header field indicates the MIME type of the data
1248
     * contained in [[getBody()]] or, in the case of the HEAD method, the
1249
     * media type that would have been sent had the request been a GET.
1250
     * For the MIME-types the user expects in response, see [[acceptableContentTypes]].
1251
     * @return string request content-type. Empty string is returned if this information is not available.
1252
     * @link https://tools.ietf.org/html/rfc2616#section-14.17
1253
     * HTTP 1.1 header field definitions
1254
     */
1255 12
    public function getContentType()
1256
    {
1257 12
        return $this->getHeaderLine('Content-Type');
1258
    }
1259
1260
    private $_languages;
1261
1262
    /**
1263
     * Returns the languages acceptable by the end user.
1264
     * This is determined by the `Accept-Language` HTTP header.
1265
     * @return array the languages ordered by the preference level. The first element
1266
     * represents the most preferred language.
1267
     */
1268 1
    public function getAcceptableLanguages()
1269
    {
1270 1
        if ($this->_languages === null) {
1271
            if ($this->hasHeader('Accept-Language')) {
1272
                $this->_languages = array_keys($this->parseAcceptHeader($this->getHeaderLine('Accept-Language')));
1273
            } else {
1274
                $this->_languages = [];
1275
            }
1276
        }
1277
1278 1
        return $this->_languages;
1279
    }
1280
1281
    /**
1282
     * @param array $value the languages that are acceptable by the end user. They should
1283
     * be ordered by the preference level.
1284
     */
1285 1
    public function setAcceptableLanguages($value)
1286
    {
1287 1
        $this->_languages = $value;
1288 1
    }
1289
1290
    /**
1291
     * Parses the given `Accept` (or `Accept-Language`) header.
1292
     *
1293
     * This method will return the acceptable values with their quality scores and the corresponding parameters
1294
     * as specified in the given `Accept` header. The array keys of the return value are the acceptable values,
1295
     * while the array values consisting of the corresponding quality scores and parameters. The acceptable
1296
     * values with the highest quality scores will be returned first. For example,
1297
     *
1298
     * ```php
1299
     * $header = 'text/plain; q=0.5, application/json; version=1.0, application/xml; version=2.0;';
1300
     * $accepts = $request->parseAcceptHeader($header);
1301
     * print_r($accepts);
1302
     * // displays:
1303
     * // [
1304
     * //     'application/json' => ['q' => 1, 'version' => '1.0'],
1305
     * //      'application/xml' => ['q' => 1, 'version' => '2.0'],
1306
     * //           'text/plain' => ['q' => 0.5],
1307
     * // ]
1308
     * ```
1309
     *
1310
     * @param string $header the header to be parsed
1311
     * @return array the acceptable values ordered by their quality score. The values with the highest scores
1312
     * will be returned first.
1313
     */
1314 3
    public function parseAcceptHeader($header)
1315
    {
1316 3
        $accepts = [];
1317 3
        foreach (explode(',', $header) as $i => $part) {
1318 3
            $params = preg_split('/\s*;\s*/', trim($part), -1, PREG_SPLIT_NO_EMPTY);
1319 3
            if (empty($params)) {
1320 1
                continue;
1321
            }
1322
            $values = [
1323 3
                'q' => [$i, array_shift($params), 1],
1324
            ];
1325 3
            foreach ($params as $param) {
1326 2
                if (strpos($param, '=') !== false) {
1327 2
                    [$key, $value] = explode('=', $param, 2);
0 ignored issues
show
Bug introduced by
The variable $key does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $value does not exist. Did you mean $values?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1328 2
                    if ($key === 'q') {
1329 2
                        $values['q'][2] = (float) $value;
0 ignored issues
show
Bug introduced by
The variable $value does not exist. Did you mean $values?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1330
                    } else {
1331 2
                        $values[$key] = $value;
0 ignored issues
show
Bug introduced by
The variable $value does not exist. Did you mean $values?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1332
                    }
1333
                } else {
1334 2
                    $values[] = $param;
1335
                }
1336
            }
1337 3
            $accepts[] = $values;
1338
        }
1339
1340 3
        usort($accepts, function ($a, $b) {
1341 3
            $a = $a['q']; // index, name, q
1342 3
            $b = $b['q'];
1343 3
            if ($a[2] > $b[2]) {
1344 2
                return -1;
1345
            }
1346
1347 2
            if ($a[2] < $b[2]) {
1348 1
                return 1;
1349
            }
1350
1351 2
            if ($a[1] === $b[1]) {
1352
                return $a[0] > $b[0] ? 1 : -1;
1353
            }
1354
1355 2
            if ($a[1] === '*/*') {
1356
                return 1;
1357
            }
1358
1359 2
            if ($b[1] === '*/*') {
1360
                return -1;
1361
            }
1362
1363 2
            $wa = $a[1][strlen($a[1]) - 1] === '*';
1364 2
            $wb = $b[1][strlen($b[1]) - 1] === '*';
1365 2
            if ($wa xor $wb) {
1366
                return $wa ? 1 : -1;
1367
            }
1368
1369 2
            return $a[0] > $b[0] ? 1 : -1;
1370 3
        });
1371
1372 3
        $result = [];
1373 3
        foreach ($accepts as $accept) {
1374 3
            $name = $accept['q'][1];
1375 3
            $accept['q'] = $accept['q'][2];
1376 3
            $result[$name] = $accept;
1377
        }
1378
1379 3
        return $result;
1380
    }
1381
1382
    /**
1383
     * Returns the user-preferred language that should be used by this application.
1384
     * The language resolution is based on the user preferred languages and the languages
1385
     * supported by the application. The method will try to find the best match.
1386
     * @param array $languages a list of the languages supported by the application. If this is empty, the current
1387
     * application language will be returned without further processing.
1388
     * @return string the language that the application should use.
1389
     */
1390 1
    public function getPreferredLanguage(array $languages = [])
1391
    {
1392 1
        if (empty($languages)) {
1393 1
            return Yii::$app->language;
1394
        }
1395 1
        foreach ($this->getAcceptableLanguages() as $acceptableLanguage) {
1396 1
            $acceptableLanguage = str_replace('_', '-', strtolower($acceptableLanguage));
1397 1
            foreach ($languages as $language) {
1398 1
                $normalizedLanguage = str_replace('_', '-', strtolower($language));
1399
1400
                if (
1401 1
                    $normalizedLanguage === $acceptableLanguage // en-us==en-us
1402 1
                    || strpos($acceptableLanguage, $normalizedLanguage . '-') === 0 // en==en-us
1403 1
                    || strpos($normalizedLanguage, $acceptableLanguage . '-') === 0 // en-us==en
1404
                ) {
1405 1
                    return $language;
1406
                }
1407
            }
1408
        }
1409
1410 1
        return reset($languages);
1411
    }
1412
1413
    /**
1414
     * Gets the Etags.
1415
     *
1416
     * @return array The entity tags
1417
     */
1418
    public function getETags()
1419
    {
1420
        if ($this->hasHeader('if-none-match')) {
1421
            return preg_split('/[\s,]+/', str_replace('-gzip', '', $this->getHeaderLine('if-none-match')), -1, PREG_SPLIT_NO_EMPTY);
1422
        }
1423
1424
        return [];
1425
    }
1426
1427
    /**
1428
     * Returns the cookie collection.
1429
     * Through the returned cookie collection, you may access a cookie using the following syntax:
1430
     *
1431
     * ```php
1432
     * $cookie = $request->cookies['name']
1433
     * if ($cookie !== null) {
1434
     *     $value = $cookie->value;
1435
     * }
1436
     *
1437
     * // alternatively
1438
     * $value = $request->cookies->getValue('name');
1439
     * ```
1440
     *
1441
     * @return CookieCollection the cookie collection.
1442
     */
1443 32
    public function getCookies()
1444
    {
1445 32
        if ($this->_cookies === null) {
1446 32
            $this->_cookies = new CookieCollection($this->loadCookies(), [
1447 32
                'readOnly' => true,
1448
            ]);
1449
        }
1450
1451 32
        return $this->_cookies;
1452
    }
1453
1454
    /**
1455
     * Converts `$_COOKIE` into an array of [[Cookie]].
1456
     * @return array the cookies obtained from request
1457
     * @throws InvalidConfigException if [[cookieValidationKey]] is not set when [[enableCookieValidation]] is true
1458
     */
1459 32
    protected function loadCookies()
1460
    {
1461 32
        $cookies = [];
1462 32
        if ($this->enableCookieValidation) {
1463 31
            if ($this->cookieValidationKey == '') {
1464
                throw new InvalidConfigException(get_class($this) . '::cookieValidationKey must be configured with a secret key.');
1465
            }
1466 31
            foreach ($_COOKIE as $name => $value) {
1467
                if (!is_string($value)) {
1468
                    continue;
1469
                }
1470
                $data = Yii::$app->getSecurity()->validateData($value, $this->cookieValidationKey);
1471
                if ($data === false) {
1472
                    continue;
1473
                }
1474
                $data = @unserialize($data);
1475
                if (is_array($data) && isset($data[0], $data[1]) && $data[0] === $name) {
1476
                    $cookies[$name] = new Cookie([
1477 31
                        'name' => $name,
1478
                        'value' => $data[1],
1479
                        'expire' => null,
1480
                    ]);
1481
                }
1482
            }
1483
        } else {
1484 1
            foreach ($_COOKIE as $name => $value) {
1485
                $cookies[$name] = new Cookie([
1486
                    'name' => $name,
1487
                    'value' => $value,
1488
                    'expire' => null,
1489
                ]);
1490
            }
1491
        }
1492
1493 32
        return $cookies;
1494
    }
1495
1496
    /**
1497
     * Returns uploaded files for this request.
1498
     * Uploaded files are returned in format according to [PSR-7 Uploaded Files specs](http://www.php-fig.org/psr/psr-7/#16-uploaded-files).
1499
     * @return array uploaded files.
1500
     * @since 2.1.0
1501
     */
1502 11
    public function getUploadedFiles()
1503
    {
1504 11
        if ($this->_uploadedFiles === null) {
1505 5
            $this->getBodyParams(); // uploaded files are the part of the body and may be set while its parsing
1506 5
            if ($this->_uploadedFiles === null) {
1507 5
                $this->_uploadedFiles = $this->defaultUploadedFiles();
1508
            }
1509
        }
1510 11
        return $this->_uploadedFiles;
1511
    }
1512
1513
    /**
1514
     * Sets uploaded files for this request.
1515
     * Data structure for the uploaded files should follow [PSR-7 Uploaded Files specs](http://www.php-fig.org/psr/psr-7/#16-uploaded-files).
1516
     * @param array|null $uploadedFiles uploaded files.
1517
     * @since 2.1.0
1518
     */
1519 6
    public function setUploadedFiles($uploadedFiles)
1520
    {
1521 6
        $this->_uploadedFiles = $uploadedFiles;
0 ignored issues
show
Documentation Bug introduced by
It seems like $uploadedFiles can be null. However, the property $_uploadedFiles is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
1522 6
    }
1523
1524
    /**
1525
     * Initializes default uploaded files data structure parsing super-global $_FILES.
1526
     * @see http://www.php-fig.org/psr/psr-7/#16-uploaded-files
1527
     * @return array uploaded files.
1528
     * @since 2.1.0
1529
     */
1530 5
    protected function defaultUploadedFiles()
1531
    {
1532 5
        $files = [];
1533 5
        foreach ($_FILES as $class => $info) {
1534 3
            $files[$class] = [];
1535 3
            $this->populateUploadedFileRecursive($files[$class], $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']);
1536
        }
1537
1538 5
        return $files;
1539
    }
1540
1541
    /**
1542
     * Populates uploaded files array from $_FILE data structure recursively.
1543
     * @param array $files uploaded files array to be populated.
1544
     * @param mixed $names file names provided by PHP
1545
     * @param mixed $tempNames temporary file names provided by PHP
1546
     * @param mixed $types file types provided by PHP
1547
     * @param mixed $sizes file sizes provided by PHP
1548
     * @param mixed $errors uploading issues provided by PHP
1549
     * @since 2.1.0
1550
     */
1551 3
    private function populateUploadedFileRecursive(&$files, $names, $tempNames, $types, $sizes, $errors)
1552
    {
1553 3
        if (is_array($names)) {
1554 2
            foreach ($names as $i => $name) {
1555 2
                $files[$i] = [];
1556 2
                $this->populateUploadedFileRecursive($files[$i], $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]);
1557
            }
1558
        } else {
1559 3
            $files = Yii::createObject([
1560 3
                'class' => $this->uploadedFileClass,
1561 3
                'clientFilename' => $names,
1562 3
                'tempFilename' => $tempNames,
1563 3
                'clientMediaType' => $types,
1564 3
                'size' => $sizes,
1565 3
                'error' => $errors,
1566
            ]);
1567
        }
1568 3
    }
1569
1570
    /**
1571
     * Returns an uploaded file according to the given name.
1572
     * Name can be either a string HTML form input name, e.g. 'Item[file]' or array path, e.g. `['Item', 'file']`.
1573
     * Note: this method returns `null` in case given name matches multiple files.
1574
     * @param string|array $name HTML form input name or array path.
1575
     * @return UploadedFileInterface|null uploaded file instance, `null` - if not found.
1576
     * @since 2.1.0
1577
     */
1578 1
    public function getUploadedFileByName($name)
1579
    {
1580 1
        $uploadedFile = $this->findUploadedFiles($name);
1581 1
        if ($uploadedFile instanceof UploadedFileInterface) {
1582 1
            return $uploadedFile;
1583
        }
1584 1
        return null;
1585
    }
1586
1587
    /**
1588
     * Returns the list of uploaded file instances according to the given name.
1589
     * Name can be either a string HTML form input name, e.g. 'Item[file]' or array path, e.g. `['Item', 'file']`.
1590
     * Note: this method does NOT preserve uploaded files structure - it returns instances in single-level array (list),
1591
     * even if they are set by nested keys.
1592
     * @param string|array $name HTML form input name or array path.
1593
     * @return UploadedFileInterface[] list of uploaded file instances.
1594
     * @since 2.1.0
1595
     */
1596 1
    public function getUploadedFilesByName($name)
1597
    {
1598 1
        $uploadedFiles = $this->findUploadedFiles($name);
1599 1
        if ($uploadedFiles === null) {
1600
            return [];
1601
        }
1602 1
        if ($uploadedFiles instanceof UploadedFileInterface) {
1603 1
            return [$uploadedFiles];
1604
        }
1605 1
        return $this->reduceUploadedFiles($uploadedFiles);
1606
    }
1607
1608
    /**
1609
     * Finds the uploaded file or set of uploaded files inside [[$uploadedFiles]] according to given name.
1610
     * Name can be either a string HTML form input name, e.g. 'Item[file]' or array path, e.g. `['Item', 'file']`.
1611
     * @param string|array $name HTML form input name or array path.
1612
     * @return UploadedFileInterface|array|null
1613
     * @since 2.1.0
1614
     */
1615 2
    private function findUploadedFiles($name)
1616
    {
1617 2
        if (!is_array($name)) {
1618 2
            $name = preg_split('/\\]\\[|\\[|\\]/s', $name, -1, PREG_SPLIT_NO_EMPTY);
1619
        }
1620 2
        return ArrayHelper::getValue($this->getUploadedFiles(), $name);
1621
    }
1622
1623
    /**
1624
     * Reduces complex uploaded files structure to the single-level array (list).
1625
     * @param array $uploadedFiles raw set of the uploaded files.
1626
     * @return UploadedFileInterface[] list of uploaded files.
1627
     * @since 2.1.0
1628
     */
1629
    private function reduceUploadedFiles($uploadedFiles)
1630
    {
1631 1
        return array_reduce($uploadedFiles, function ($carry, $item) {
1632 1
            if ($item instanceof UploadedFileInterface) {
1633 1
                $carry[] = $item;
1634
            } else {
1635 1
                $carry = array_merge($carry, $this->reduceUploadedFiles($item));
1636
            }
1637 1
            return $carry;
1638 1
        }, []);
1639
    }
1640
1641
    private $_csrfToken;
1642
1643
    /**
1644
     * Returns the token used to perform CSRF validation.
1645
     *
1646
     * This token is generated in a way to prevent [BREACH attacks](http://breachattack.com/). It may be passed
1647
     * along via a hidden field of an HTML form or an HTTP header value to support CSRF validation.
1648
     * @param bool $regenerate whether to regenerate CSRF token. When this parameter is true, each time
1649
     * this method is called, a new CSRF token will be generated and persisted (in session or cookie).
1650
     * @return string the token used to perform CSRF validation.
1651
     */
1652 35
    public function getCsrfToken($regenerate = false)
1653
    {
1654 35
        if ($this->_csrfToken === null || $regenerate) {
1655 35
            if ($regenerate || ($token = $this->loadCsrfToken()) === null) {
1656 34
                $token = $this->generateCsrfToken();
1657
            }
1658 35
            $this->_csrfToken = Yii::$app->security->maskToken($token);
1659
        }
1660
1661 35
        return $this->_csrfToken;
1662
    }
1663
1664
    /**
1665
     * Loads the CSRF token from cookie or session.
1666
     * @return string the CSRF token loaded from cookie or session. Null is returned if the cookie or session
1667
     * does not have CSRF token.
1668
     */
1669 35
    protected function loadCsrfToken()
1670
    {
1671 35
        if ($this->enableCsrfCookie) {
1672 32
            return $this->getCookies()->getValue($this->csrfParam);
1673
        }
1674 3
        return Yii::$app->getSession()->get($this->csrfParam);
0 ignored issues
show
Bug introduced by
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
1675
    }
1676
1677
    /**
1678
     * Generates an unmasked random token used to perform CSRF validation.
1679
     * @return string the random token for CSRF validation.
1680
     */
1681 34
    protected function generateCsrfToken()
1682
    {
1683 34
        $token = Yii::$app->getSecurity()->generateRandomKey();
1684 34
        if ($this->enableCsrfCookie) {
1685 32
            $cookie = $this->createCsrfCookie($token);
1686 32
            Yii::$app->getResponse()->getCookies()->add($cookie);
1687
        } else {
1688 2
            Yii::$app->getSession()->set($this->csrfParam, $token);
0 ignored issues
show
Bug introduced by
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
1689
        }
1690 34
        return $token;
1691
    }
1692
1693
    /**
1694
     * @return string the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent.
1695
     */
1696 3
    public function getCsrfTokenFromHeader()
1697
    {
1698 3
        return $this->getHeaderLine(static::CSRF_HEADER);
1699
    }
1700
1701
    /**
1702
     * Creates a cookie with a randomly generated CSRF token.
1703
     * Initial values specified in [[csrfCookie]] will be applied to the generated cookie.
1704
     * @param string $token the CSRF token
1705
     * @return Cookie the generated cookie
1706
     * @see enableCsrfValidation
1707
     */
1708 32
    protected function createCsrfCookie($token)
1709
    {
1710 32
        $options = $this->csrfCookie;
1711 32
        $options['name'] = $this->csrfParam;
1712 32
        $options['value'] = $token;
1713 32
        return new Cookie($options);
1714
    }
1715
1716
    /**
1717
     * Performs the CSRF validation.
1718
     *
1719
     * This method will validate the user-provided CSRF token by comparing it with the one stored in cookie or session.
1720
     * This method is mainly called in [[Controller::beforeAction()]].
1721
     *
1722
     * Note that the method will NOT perform CSRF validation if [[enableCsrfValidation]] is false or the HTTP method
1723
     * is among GET, HEAD or OPTIONS.
1724
     *
1725
     * @param string $clientSuppliedToken the user-provided CSRF token to be validated. If null, the token will be retrieved from
1726
     * the [[csrfParam]] POST field or HTTP header.
1727
     * This parameter is available since version 2.0.4.
1728
     * @return bool whether CSRF token is valid. If [[enableCsrfValidation]] is false, this method will return true.
1729
     */
1730 5
    public function validateCsrfToken($clientSuppliedToken = null)
1731
    {
1732 5
        $method = $this->getMethod();
1733
        // only validate CSRF token on non-"safe" methods https://tools.ietf.org/html/rfc2616#section-9.1.1
1734 5
        if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {
1735 5
            return true;
1736
        }
1737
1738
1739 3
        $trueToken = $this->getCsrfToken();
1740
1741 3
        if ($clientSuppliedToken !== null) {
1742 1
            return $this->validateCsrfTokenInternal($clientSuppliedToken, $trueToken);
1743
        }
1744
1745 3
        return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
1746 3
            || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
1747
    }
1748
1749
    /**
1750
     * Validates CSRF token
1751
     *
1752
     * @param string $clientSuppliedToken The masked client-supplied token.
1753
     * @param string $trueToken The masked true token.
1754
     * @return bool
1755
     */
1756 3
    private function validateCsrfTokenInternal($clientSuppliedToken, $trueToken)
1757
    {
1758 3
        if (!is_string($clientSuppliedToken)) {
1759 3
            return false;
1760
        }
1761
1762 3
        $security = Yii::$app->security;
1763
1764 3
        return $security->unmaskToken($clientSuppliedToken) === $security->unmaskToken($trueToken);
1765
    }
1766
1767
    /**
1768
     * {@inheritdoc}
1769
     */
1770 2
    public function __clone()
1771
    {
1772 2
        parent::__clone();
1773
1774 2
        $this->cloneHttpMessageInternals();
1775
1776 2
        if (is_object($this->_cookies)) {
1777
            $this->_cookies = clone $this->_cookies;
1778
        }
1779 2
    }
1780
}
1781