Browse Source

`Psr\Http\Message\ServerRequestInterface` applied for `yii\web\Request` (#15416)

`Psr\Http\Message\ServerRequestInterface` applied for `yii\web\Request`
tags/3.0.0-alpha1
Paul Klimov 7 years ago committed by GitHub
parent
commit
874fcaaecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      framework/UPGRADE.md
  2. 2
      framework/data/DataFilter.php
  3. 2
      framework/rest/CreateAction.php
  4. 2
      framework/rest/IndexAction.php
  5. 2
      framework/rest/UpdateAction.php
  6. 2
      framework/validators/FileValidator.php
  7. 2
      framework/web/MultipartFormDataParser.php
  8. 361
      framework/web/Request.php
  9. 53
      tests/framework/filters/AccessRuleTest.php
  10. 2
      tests/framework/helpers/HtmlTest.php
  11. 6
      tests/framework/validators/FileValidatorTest.php
  12. 4
      tests/framework/web/MultipartFormDataParserTest.php
  13. 69
      tests/framework/web/RequestTest.php

3
framework/UPGRADE.md

@ -82,11 +82,12 @@ Upgrade from Yii 2.0.x
* Profiling related functionality has been extracted into a separated component under `yii\profile\ProfilerInterface`.
Profiling messages should be collection using `yii\base\Application::$profiler`. In case you wish to
continue storing profiling messages along with the log ones, you may use `yii\profile\LogTarget` profiling target.
* Classes `yii\web\Request` and `yii\web\Response` have been updated to match interfaces `Psr\Http\Message\RequestInterface`
* Classes `yii\web\Request` and `yii\web\Response` have been updated to match interfaces `Psr\Http\Message\ServerRequestInterface`
and `Psr\Http\Message\ResponseInterface` accordingly. Make sure you use their methods and properties correctly.
In particular: method `getHeaders()` and corresponding virtual property `$headers` are no longer return `HeaderCollection`
instance, you can use `getHeaderCollection()` in order to use old headers setup syntax; `Request|Response::$version` renamed
to `Request|Response::$protocolVersion`; `Response::$statusText` renamed `Response::$reasonPhrase`;
`Request::$bodyParams` renamed to `Request::$parsedBody`; `Request::getBodyParam()` renamed to `Request::getParsedBodyParam()`;
* `yii\web\Response::$stream` is no longer available, use `yii\web\Response::withBody()` to setup stream response.
You can use `Response::$bodyRange` to setup stream content range.
* Classes `yii\web\CookieCollection`, `yii\web\HeaderCollection` and `yii\web\UploadedFile` have been moved under

2
framework/data/DataFilter.php

@ -64,7 +64,7 @@ use yii\validators\StringValidator;
* use yii\data\DataFilter;
*
* $dataFilter = new DataFilter();
* $dataFilter->load(Yii::$app->request->getBodyParams());
* $dataFilter->load(Yii::$app->request->getParsedBody());
* ```
*
* In order to function this class requires a search model specified via [[searchModel]]. This search model should declare

2
framework/rest/CreateAction.php

@ -48,7 +48,7 @@ class CreateAction extends Action
'scenario' => $this->scenario,
]);
$model->load(Yii::$app->getRequest()->getBodyParams(), '');
$model->load(Yii::$app->getRequest()->getParsedBody(), '');
if ($model->save()) {
$response = Yii::$app->getResponse();
$response->setStatusCode(201);

2
framework/rest/IndexAction.php

@ -88,7 +88,7 @@ class IndexAction extends Action
*/
protected function prepareDataProvider()
{
$requestParams = Yii::$app->getRequest()->getBodyParams();
$requestParams = Yii::$app->getRequest()->getParsedBody();
if (empty($requestParams)) {
$requestParams = Yii::$app->getRequest()->getQueryParams();
}

2
framework/rest/UpdateAction.php

@ -44,7 +44,7 @@ class UpdateAction extends Action
}
$model->scenario = $this->scenario;
$model->load(Yii::$app->getRequest()->getBodyParams(), '');
$model->load(Yii::$app->getRequest()->getParsedBody(), '');
if ($model->save() === false && !$model->hasErrors()) {
throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
}

2
framework/validators/FileValidator.php

@ -307,7 +307,7 @@ class FileValidator extends Validator
}
if (($request = Yii::$app->getRequest()) instanceof \yii\web\Request) {
$maxFileSize = Yii::$app->getRequest()->getBodyParam('MAX_FILE_SIZE', 0);
$maxFileSize = Yii::$app->getRequest()->getParsedBodyParam('MAX_FILE_SIZE', 0);
if ($maxFileSize > 0 && $maxFileSize < $limit) {
$limit = (int)$maxFileSize;
}

2
framework/web/MultipartFormDataParser.php

@ -41,7 +41,7 @@ use yii\http\ResourceStream;
* ```php
* use yii\http\UploadedFile;
*
* $restRequestData = Yii::$app->request->getBodyParams();
* $restRequestData = Yii::$app->request->getParsedBody();
* $uploadedFile = Yii::$app->request->getUploadedFileByName('photo');
*
* $model = new Item();

361
framework/web/Request.php

@ -7,7 +7,7 @@
namespace yii\web;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
@ -15,7 +15,6 @@ use Yii;
use yii\base\InvalidConfigException;
use yii\di\Instance;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\http\Cookie;
use yii\http\CookieCollection;
use yii\http\FileStream;
@ -48,7 +47,7 @@ use yii\validators\IpValidator;
* @property string|null $authUser The username sent via HTTP authentication, null if the username is not
* given. This property is read-only.
* @property string $baseUrl The relative URL for the application.
* @property array $bodyParams The request parameters given in the request body.
* @property array $parsedBody The request parameters given in the request body.
* @property string $contentType Request content-type. Null is returned if this information is not available.
* This property is read-only.
* @property CookieCollection $cookies The cookie collection. This property is read-only.
@ -102,7 +101,7 @@ use yii\validators\IpValidator;
* @since 2.0
* @SuppressWarnings(PHPMD.SuperGlobals)
*/
class Request extends \yii\base\Request implements RequestInterface
class Request extends \yii\base\Request implements ServerRequestInterface
{
use MessageTrait;
@ -161,7 +160,7 @@ class Request extends \yii\base\Request implements RequestInterface
* @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()
* @see getParsedBody()
*/
public $methodParam = '_method';
/**
@ -181,7 +180,7 @@ class Request extends \yii\base\Request implements RequestInterface
* 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()
* @see getParsedBody()
*/
public $parsers = [];
/**
@ -268,6 +267,21 @@ class Request extends \yii\base\Request implements RequestInterface
];
/**
* @var array attributes derived from the request.
* @since 2.1.0
*/
private $_attributes;
/**
* @var array server parameters.
* @since 2.1.0
*/
private $_serverParams;
/**
* @var array the cookies sent by the client to the server.
* @since 2.1.0
*/
private $_cookieParams;
/**
* @var CookieCollection Collection of request cookies.
*/
private $_cookies;
@ -434,10 +448,8 @@ class Request extends \yii\base\Request implements RequestInterface
$this->_method = $_POST[$this->methodParam];
} elseif ($this->hasHeader('x-http-method-override')) {
$this->_method = $this->getHeaderLine('x-http-method-override');
} elseif (isset($_SERVER['REQUEST_METHOD'])) {
$this->_method = $_SERVER['REQUEST_METHOD'];
} else {
$this->_method = 'GET';
$this->_method = $this->getServerParam('REQUEST_METHOD', 'GET');
}
}
return $this->_method;
@ -647,7 +659,7 @@ class Request extends \yii\base\Request implements RequestInterface
$this->setBody($body);
}
private $_bodyParams;
private $_parsedBody;
/**
* Returns the request parameters given in the request body.
@ -662,16 +674,16 @@ class Request extends \yii\base\Request implements RequestInterface
* @throws InvalidConfigException if a registered parser does not implement the [[RequestParserInterface]].
* @throws UnsupportedMediaTypeHttpException if unable to parse raw body.
* @see getMethod()
* @see getBodyParam()
* @see setBodyParams()
* @see getParsedBodyParam()
* @see setParsedBody()
*/
public function getBodyParams()
public function getParsedBody()
{
if ($this->_bodyParams === null) {
if ($this->_parsedBody === null) {
if (isset($_POST[$this->methodParam])) {
$this->_bodyParams = $_POST;
unset($this->_bodyParams[$this->methodParam]);
return $this->_bodyParams;
$this->_parsedBody = $_POST;
unset($this->_parsedBody[$this->methodParam]);
return $this->_parsedBody;
}
$contentType = $this->getContentType();
@ -685,44 +697,55 @@ class Request extends \yii\base\Request implements RequestInterface
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);
$this->_parsedBody = $parser->parse($this);
} 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);
$this->_parsedBody = $parser->parse($this);
} elseif ($this->getMethod() === 'POST') {
if ($contentType !== 'application/x-www-form-urlencoded' && $contentType !== 'multipart/form-data') {
throw new UnsupportedMediaTypeHttpException();
}
// PHP has already parsed the body so we have all params in $_POST
$this->_bodyParams = $_POST;
$this->_parsedBody = $_POST;
if ($contentType === 'multipart/form-data') {
$this->_bodyParams = ArrayHelper::merge($this->_bodyParams, $this->getUploadedFiles());
$this->_parsedBody = ArrayHelper::merge($this->_parsedBody, $this->getUploadedFiles());
}
} else {
if ($contentType !== 'application/x-www-form-urlencoded') {
throw new UnsupportedMediaTypeHttpException();
}
$this->_bodyParams = [];
mb_parse_str($this->getBody()->__toString(), $this->_bodyParams);
$this->_parsedBody = [];
mb_parse_str($this->getBody()->__toString(), $this->_parsedBody);
}
}
return $this->_bodyParams;
return $this->_parsedBody;
}
/**
* Sets the request body parameters.
* @param array $values the request body parameters (name-value pairs)
* @see getBodyParam()
* @see getBodyParams()
* @see getParsedBodyParam()
* @see getParsedBody()
*/
public function setBodyParams($values)
public function setParsedBody($values)
{
$this->_bodyParams = $values;
$this->_parsedBody = $values;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function withParsedBody($data)
{
$newInstance = clone $this;
$newInstance->setParsedBody($data);
return $newInstance;
}
/**
@ -731,12 +754,12 @@ class Request extends \yii\base\Request implements RequestInterface
* @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()
* @see getParsedBody()
* @see setParsedBody()
*/
public function getBodyParam($name, $defaultValue = null)
public function getParsedBodyParam($name, $defaultValue = null)
{
$params = $this->getBodyParams();
$params = $this->getParsedBody();
return isset($params[$name]) ? $params[$name] : $defaultValue;
}
@ -751,10 +774,10 @@ class Request extends \yii\base\Request implements RequestInterface
public function post($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getBodyParams();
return $this->getParsedBody();
}
return $this->getBodyParam($name, $defaultValue);
return $this->getParsedBodyParam($name, $defaultValue);
}
private $_queryParams;
@ -787,6 +810,20 @@ class Request extends \yii\base\Request implements RequestInterface
}
/**
* {@inheritdoc}
*/
public function withQueryParams(array $query)
{
if ($this->getQueryParams() === $query) {
return $this;
}
$newInstance = clone $this;
$newInstance->setQueryParams($query);
return $newInstance;
}
/**
* 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
@ -808,7 +845,7 @@ class Request extends \yii\base\Request implements RequestInterface
* @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()
* @see getParsedBodyParam()
*/
public function getQueryParam($name, $defaultValue = null)
{
@ -817,6 +854,82 @@ class Request extends \yii\base\Request implements RequestInterface
return isset($params[$name]) ? $params[$name] : $defaultValue;
}
/**
* Sets the data related to the incoming request environment.
* @param array $serverParams server parameters.
* @since 2.1.0
*/
public function setServerParams(array $serverParams)
{
$this->_serverParams = $serverParams;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function getServerParams()
{
if ($this->_serverParams === null) {
$this->_serverParams = $_SERVER;
}
return $this->_serverParams;
}
/**
* Return the server environment parameter by name.
* @param string $name parameter name.
* @param mixed $default default value to return if the parameter does not exist.
* @return mixed parameter value.
* @since 2.1.0
*/
public function getServerParam($name, $default = null)
{
$params = $this->getServerParams();
if (!isset($params[$name])) {
return $default;
}
return $params[$name];
}
/**
* Specifies cookies.
* @param array $cookies array of key/value pairs representing cookies.
* @since 2.1.0
*/
public function setCookieParams(array $cookies)
{
$this->_cookieParams = $cookies;
$this->_cookies = null;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function getCookieParams()
{
if ($this->_cookieParams === null) {
$this->_cookieParams = $_COOKIE;
}
return $this->_cookieParams;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function withCookieParams(array $cookies)
{
if ($this->getCookieParams() === $cookies) {
return $this;
}
$newInstance = clone $this;
$newInstance->setCookieParams($cookies);
return $newInstance;
}
private $_hostInfo;
private $_hostName;
@ -854,8 +967,8 @@ class Request extends \yii\base\Request implements RequestInterface
$http = $secure ? 'https' : 'http';
if ($this->hasHeader('Host')) {
$this->_hostInfo = $http . '://' . $this->getHeaderLine('Host');
} elseif (isset($_SERVER['SERVER_NAME'])) {
$this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME'];
} elseif (($serverName = $this->getServerParam('SERVER_NAME')) !== null) {
$this->_hostInfo = $http . '://' . $serverName;
$port = $secure ? $this->getSecurePort() : $this->getPort();
if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
$this->_hostInfo .= ':' . $port;
@ -941,16 +1054,17 @@ class Request extends \yii\base\Request implements RequestInterface
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('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $scriptFile));
$serverParams = $this->getServerParams();
if (isset($serverParams['SCRIPT_NAME']) && basename($serverParams['SCRIPT_NAME']) === $scriptName) {
$this->_scriptUrl = $serverParams['SCRIPT_NAME'];
} elseif (isset($serverParams['PHP_SELF']) && basename($serverParams['PHP_SELF']) === $scriptName) {
$this->_scriptUrl = $serverParams['PHP_SELF'];
} elseif (isset($serverParams['ORIG_SCRIPT_NAME']) && basename($serverParams['ORIG_SCRIPT_NAME']) === $scriptName) {
$this->_scriptUrl = $serverParams['ORIG_SCRIPT_NAME'];
} elseif (isset($serverParams['PHP_SELF']) && ($pos = strpos($serverParams['PHP_SELF'], '/' . $scriptName)) !== false) {
$this->_scriptUrl = substr($serverParams['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
} elseif (!empty($serverParams['DOCUMENT_ROOT']) && strpos($scriptFile, $serverParams['DOCUMENT_ROOT']) === 0) {
$this->_scriptUrl = str_replace('\\', '/', str_replace($serverParams['DOCUMENT_ROOT'], '', $scriptFile));
} else {
throw new InvalidConfigException('Unable to determine the entry script URL.');
}
@ -984,8 +1098,8 @@ class Request extends \yii\base\Request implements RequestInterface
return $this->_scriptFile;
}
if (isset($_SERVER['SCRIPT_FILENAME'])) {
return $_SERVER['SCRIPT_FILENAME'];
if (($scriptFilename = $this->getServerParam('SCRIPT_FILENAME')) !== null) {
return $scriptFilename;
}
throw new InvalidConfigException('Unable to determine the entry script file path.');
@ -1072,8 +1186,8 @@ class Request extends \yii\base\Request implements RequestInterface
$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));
} elseif (($phpSelf = $this->getServerParam('PHP_SELF')) !== null && strpos($phpSelf, $scriptUrl) === 0) {
$pathInfo = substr($phpSelf, strlen($scriptUrl));
} else {
throw new InvalidConfigException('Unable to determine the path info of the current request.');
}
@ -1134,17 +1248,19 @@ class Request extends \yii\base\Request implements RequestInterface
*/
protected function resolveRequestUri()
{
$serverParams = $this->getServerParams();
if ($this->hasHeader('x-rewrite-url')) { // IIS
$requestUri = $this->getHeaderLine('x-rewrite-url');
} elseif (isset($_SERVER['REQUEST_URI'])) {
$requestUri = $_SERVER['REQUEST_URI'];
} elseif (isset($serverParams['REQUEST_URI'])) {
$requestUri = $serverParams['REQUEST_URI'];
if ($requestUri !== '' && $requestUri[0] !== '/') {
$requestUri = preg_replace('/^(http|https):\/\/[^\/]+/i', '', $requestUri);
}
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 CGI
$requestUri = $_SERVER['ORIG_PATH_INFO'];
if (!empty($_SERVER['QUERY_STRING'])) {
$requestUri .= '?' . $_SERVER['QUERY_STRING'];
} elseif (isset($serverParams['ORIG_PATH_INFO'])) { // IIS 5.0 CGI
$requestUri = $serverParams['ORIG_PATH_INFO'];
if (!empty($serverParams['QUERY_STRING'])) {
$requestUri .= '?' . $serverParams['QUERY_STRING'];
}
} else {
throw new InvalidConfigException('Unable to determine the request URI.');
@ -1159,7 +1275,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getQueryString()
{
return isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
return $this->getServerParam('QUERY_STRING', '');
}
/**
@ -1168,7 +1284,8 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getIsSecureConnection()
{
if (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)) {
$https = $this->getServerParam('HTTPS');
if ($https !== null && (strcasecmp($https, 'on') === 0 || $https == 1)) {
return true;
}
foreach ($this->secureProtocolHeaders as $header => $values) {
@ -1190,7 +1307,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getServerName()
{
return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
return $this->getServerParam('SERVER_NAME');
}
/**
@ -1199,7 +1316,8 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getServerPort()
{
return isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : null;
$port = $this->getServerParam('SERVER_PORT');
return $port === null ? null : (int) $port;
}
/**
@ -1286,7 +1404,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getRemoteIP()
{
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
return $this->getServerParam('REMOTE_ADDR');
}
/**
@ -1299,7 +1417,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getRemoteHost()
{
return isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : null;
return $this->getServerParam('REMOTE_HOST');
}
/**
@ -1330,8 +1448,8 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getAuthCredentials()
{
$username = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : null;
$password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : null;
$username = $this->getServerParam('PHP_AUTH_USER');
$password = $this->getServerParam('PHP_AUTH_PW');
if ($username !== null || $password !== null) {
return [$username, $password];
}
@ -1370,7 +1488,8 @@ class Request extends \yii\base\Request implements RequestInterface
public function getPort()
{
if ($this->_port === null) {
$this->_port = !$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 80;
$serverPort = $this->getServerParam('SERVER_PORT');
$this->_port = !$this->getIsSecureConnection() && $serverPort === null ? (int) $serverPort : 80;
}
return $this->_port;
@ -1402,7 +1521,8 @@ class Request extends \yii\base\Request implements RequestInterface
public function getSecurePort()
{
if ($this->_securePort === null) {
$this->_securePort = $this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 443;
$serverPort = $this->getServerParam('SERVER_PORT');
$this->_securePort = $this->getIsSecureConnection() && $serverPort === null ? (int) $serverPort : 443;
}
return $this->_securePort;
@ -1682,7 +1802,7 @@ class Request extends \yii\base\Request implements RequestInterface
}
/**
* Converts `$_COOKIE` into an array of [[Cookie]].
* Converts [[cookieParams]] into an array of [[Cookie]].
* @return array the cookies obtained from request
* @throws InvalidConfigException if [[cookieValidationKey]] is not set when [[enableCookieValidation]] is true
*/
@ -1691,9 +1811,9 @@ class Request extends \yii\base\Request implements RequestInterface
$cookies = [];
if ($this->enableCookieValidation) {
if ($this->cookieValidationKey == '') {
throw new InvalidConfigException(get_class($this) . '::cookieValidationKey must be configured with a secret key.');
throw new InvalidConfigException(get_class($this) . '::$cookieValidationKey must be configured with a secret key.');
}
foreach ($_COOKIE as $name => $value) {
foreach ($this->getCookieParams() as $name => $value) {
if (!is_string($value)) {
continue;
}
@ -1712,7 +1832,7 @@ class Request extends \yii\base\Request implements RequestInterface
}
}
} else {
foreach ($_COOKIE as $name => $value) {
foreach ($this->getCookieParams() as $name => $value) {
$cookies[$name] = Yii::createObject([
'class' => \yii\http\Cookie::class,
'name' => $name,
@ -1726,15 +1846,13 @@ class Request extends \yii\base\Request implements RequestInterface
}
/**
* Returns uploaded files for this request.
* Uploaded files are returned in format according to [PSR-7 Uploaded Files specs](http://www.php-fig.org/psr/psr-7/#16-uploaded-files).
* @return array uploaded files.
* {@inheritdoc}
* @since 2.1.0
*/
public function getUploadedFiles()
{
if ($this->_uploadedFiles === null) {
$this->getBodyParams(); // uploaded files are the part of the body and may be set while its parsing
$this->getParsedBody(); // uploaded files are the part of the body and may be set while its parsing
if ($this->_uploadedFiles === null) {
$this->_uploadedFiles = $this->defaultUploadedFiles();
}
@ -1754,6 +1872,17 @@ class Request extends \yii\base\Request implements RequestInterface
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function withUploadedFiles(array $uploadedFiles)
{
$newInstance = clone $this;
$newInstance->setUploadedFiles($uploadedFiles);
return $newInstance;
}
/**
* Initializes default uploaded files data structure parsing super-global $_FILES.
* @see http://www.php-fig.org/psr/psr-7/#16-uploaded-files
* @return array uploaded files.
@ -1977,7 +2106,7 @@ class Request extends \yii\base\Request implements RequestInterface
return $this->validateCsrfTokenInternal($clientSuppliedToken, $trueToken);
}
return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
return $this->validateCsrfTokenInternal($this->getParsedBodyParam($this->csrfParam), $trueToken)
|| $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
}
@ -2001,6 +2130,86 @@ class Request extends \yii\base\Request implements RequestInterface
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function getAttributes()
{
if ($this->_attributes === null) {
$this->_attributes = $this->defaultAttributes();
}
return $this->_attributes;
}
/**
* @param array $attributes attributes derived from the request.
*/
public function setAttributes(array $attributes)
{
$this->_attributes = $attributes;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function getAttribute($name, $default = null)
{
$attributes = $this->getAttributes();
if (!array_key_exists($name, $attributes)) {
return $default;
}
return $attributes[$name];
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function withAttribute($name, $value)
{
$attributes = $this->getAttributes();
if (array_key_exists($name, $attributes) && $attributes[$name] === $value) {
return $this;
}
$attributes[$name] = $value;
$newInstance = clone $this;
$newInstance->setAttributes($attributes);
return $newInstance;
}
/**
* {@inheritdoc}
* @since 2.1.0
*/
public function withoutAttribute($name)
{
$attributes = $this->getAttributes();
if (!array_key_exists($name, $attributes)) {
return $this;
}
unset($attributes[$name]);
$newInstance = clone $this;
$newInstance->setAttributes($attributes);
return $newInstance;
}
/**
* Returns default server request attributes to be used in case they are not explicitly set.
* @return array attributes derived from the request.
* @since 2.1.0
*/
protected function defaultAttributes()
{
return [];
}
/**
* {@inheritdoc}
*/
public function __clone()
{

53
tests/framework/filters/AccessRuleTest.php

@ -416,7 +416,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertFalse($rule->allows($action, $user, $request));
// match, one IP
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.1'
]);
$rule->ips = ['127.0.0.1'];
$rule->allow = true;
$this->assertTrue($rule->allows($action, $user, $request));
@ -424,7 +426,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertFalse($rule->allows($action, $user, $request));
// no match, one IP
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.1'
]);
$rule->ips = ['192.168.0.1'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -432,13 +436,17 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertNull($rule->allows($action, $user, $request));
// no partial match, one IP
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.1'
]);
$rule->ips = ['127.0.0.10'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
$rule->allow = false;
$this->assertNull($rule->allows($action, $user, $request));
$_SERVER['REMOTE_ADDR'] = '127.0.0.10';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.10'
]);
$rule->ips = ['127.0.0.1'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -446,7 +454,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertNull($rule->allows($action, $user, $request));
// match, one IP IPv6
$_SERVER['REMOTE_ADDR'] = '::1';
$request->setServerParams([
'REMOTE_ADDR' => '::1'
]);
$rule->ips = ['::1'];
$rule->allow = true;
$this->assertTrue($rule->allows($action, $user, $request));
@ -454,7 +464,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertFalse($rule->allows($action, $user, $request));
// no match, one IP IPv6
$_SERVER['REMOTE_ADDR'] = '::1';
$request->setServerParams([
'REMOTE_ADDR' => '::1'
]);
$rule->ips = ['dead::beaf::1'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -462,13 +474,18 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertNull($rule->allows($action, $user, $request));
// no partial match, one IP IPv6
$_SERVER['REMOTE_ADDR'] = '::1';
$request->setServerParams([
'REMOTE_ADDR' => '::1'
]);
$rule->ips = ['::123'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
$rule->allow = false;
$this->assertNull($rule->allows($action, $user, $request));
$_SERVER['REMOTE_ADDR'] = '::123';
$request->setServerParams([
'REMOTE_ADDR' => '::123'
]);
$rule->ips = ['::1'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -476,7 +493,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertNull($rule->allows($action, $user, $request));
// undefined IP
$_SERVER['REMOTE_ADDR'] = null;
$request->setServerParams([
'REMOTE_ADDR' => null
]);
$rule->ips = ['192.168.*'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -493,7 +512,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$rule = new AccessRule();
// no match
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.1'
]);
$rule->ips = ['192.168.*'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));
@ -501,7 +522,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertNull($rule->allows($action, $user, $request));
// match
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$request->setServerParams([
'REMOTE_ADDR' => '127.0.0.1'
]);
$rule->ips = ['127.0.*'];
$rule->allow = true;
$this->assertTrue($rule->allows($action, $user, $request));
@ -509,7 +532,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertFalse($rule->allows($action, $user, $request));
// match, IPv6
$_SERVER['REMOTE_ADDR'] = '2a01:4f8:120:7202::2';
$request->setServerParams([
'REMOTE_ADDR' => '2a01:4f8:120:7202::2'
]);
$rule->ips = ['2a01:4f8:120:*'];
$rule->allow = true;
$this->assertTrue($rule->allows($action, $user, $request));
@ -517,7 +542,9 @@ class AccessRuleTest extends \yiiunit\TestCase
$this->assertFalse($rule->allows($action, $user, $request));
// no match, IPv6
$_SERVER['REMOTE_ADDR'] = '::1';
$request->setServerParams([
'REMOTE_ADDR' => '::1'
]);
$rule->ips = ['2a01:4f8:120:*'];
$rule->allow = true;
$this->assertNull($rule->allows($action, $user, $request));

2
tests/framework/helpers/HtmlTest.php

@ -149,7 +149,7 @@ class HtmlTest extends TestCase
],
]);
$this->expectException(\yii\base\InvalidConfigException::class);
$this->expectExceptionMessage('yii\web\Request::cookieValidationKey must be configured with a secret key.');
$this->expectExceptionMessage('yii\web\Request::$cookieValidationKey must be configured with a secret key.');
Html::csrfMetaTags();
}

6
tests/framework/validators/FileValidatorTest.php

@ -81,15 +81,15 @@ class FileValidatorTest extends TestCase
$size = min($this->sizeToBytes(ini_get('upload_max_filesize')), $this->sizeToBytes(ini_get('post_max_size')));
$val = new FileValidator();
Yii::$app->request->setBodyParams([]);
Yii::$app->request->setParsedBody([]);
$this->assertEquals($size, $val->getSizeLimit());
$val->maxSize = $size + 1; // set and test if value is overridden
$this->assertEquals($size, $val->getSizeLimit());
$val->maxSize = abs($size - 1);
$this->assertEquals($size - 1, $val->getSizeLimit());
Yii::$app->request->setBodyParams(['MAX_FILE_SIZE' => $size + 1]);
Yii::$app->request->setParsedBody(['MAX_FILE_SIZE' => $size + 1]);
$this->assertEquals($size - 1, $val->getSizeLimit());
Yii::$app->request->setBodyParams(['MAX_FILE_SIZE' => abs($size - 2)]);
Yii::$app->request->setParsedBody(['MAX_FILE_SIZE' => abs($size - 2)]);
$this->assertSame(abs($size - 2), $val->getSizeLimit());
}

4
tests/framework/web/MultipartFormDataParserTest.php

@ -84,7 +84,7 @@ class MultipartFormDataParserTest extends TestCase
'multipart/form-data' => MultipartFormDataParser::class
]
]);
$bodyParams = $request->getBodyParams();
$bodyParams = $request->getParsedBody();
$this->assertEquals($_POST, $bodyParams);
$this->assertEquals([], $request->getUploadedFiles());
}
@ -114,7 +114,7 @@ class MultipartFormDataParserTest extends TestCase
'multipart/form-data' => MultipartFormDataParser::class
]
]);
$bodyParams = $request->getBodyParams();
$bodyParams = $request->getParsedBody();
$this->assertEquals([], $bodyParams);
}

69
tests/framework/web/RequestTest.php

@ -162,9 +162,9 @@ class RequestTest extends TestCase
// only accept valid token on POST
foreach (['POST', 'PUT', 'DELETE'] as $method) {
$request->setMethod($method);
$request->setBodyParams([]);
$request->setParsedBody([]);
$this->assertFalse($request->validateCsrfToken());
$request->setBodyParams([$request->csrfParam => $token]);
$request->setParsedBody([$request->csrfParam => $token]);
$this->assertTrue($request->validateCsrfToken());
}
}
@ -190,7 +190,7 @@ class RequestTest extends TestCase
// only accept valid token on POST
foreach (['POST', 'PUT', 'DELETE'] as $method) {
$request->setMethod($method);
$request->setBodyParams([]);
$request->setParsedBody([]);
$this->assertFalse($request->withoutHeader(Request::CSRF_HEADER)->validateCsrfToken());
$this->assertTrue($request->withAddedHeader(Request::CSRF_HEADER, $token)->validateCsrfToken());
@ -292,10 +292,12 @@ class RequestTest extends TestCase
{
$request = new Request();
$_SERVER['SERVER_NAME'] = 'servername';
$request->setServerParams([
'SERVER_NAME' => 'servername'
]);
$this->assertEquals('servername', $request->getServerName());
unset($_SERVER['SERVER_NAME']);
$request->setServerParams([]);
$this->assertNull($request->getServerName());
}
@ -303,10 +305,12 @@ class RequestTest extends TestCase
{
$request = new Request();
$_SERVER['SERVER_PORT'] = 33;
$request->setServerParams([
'SERVER_PORT' => 33
]);
$this->assertEquals(33, $request->getServerPort());
unset($_SERVER['SERVER_PORT']);
$request->setServerParams([]);
$this->assertNull($request->getServerPort());
}
@ -607,17 +611,17 @@ class RequestTest extends TestCase
$request->setBody($body);
$_POST = ['name' => 'post'];
$this->assertSame(['name' => 'value'], $request->withHeader('Content-Type', 'application/x-www-form-urlencoded')->getBodyParams());
$this->assertSame(['name' => 'post'], $request->withHeader('Content-Type', 'application/x-www-form-urlencoded')->withMethod('POST')->getBodyParams());
$this->assertSame(['name' => 'post'], $request->withHeader('Content-Type', 'multipart/form-data')->withMethod('POST')->getBodyParams());
$this->assertSame(['name' => 'value'], $request->withHeader('Content-Type', 'application/x-www-form-urlencoded')->getParsedBody());
$this->assertSame(['name' => 'post'], $request->withHeader('Content-Type', 'application/x-www-form-urlencoded')->withMethod('POST')->getParsedBody());
$this->assertSame(['name' => 'post'], $request->withHeader('Content-Type', 'multipart/form-data')->withMethod('POST')->getParsedBody());
try {
$request->getBodyParams();
$request->getParsedBody();
} catch (UnsupportedMediaTypeHttpException $noContentTypeException) {}
$this->assertTrue(isset($noContentTypeException));
try {
$request->withMethod('POST')->getBodyParams();
$request->withMethod('POST')->getParsedBody();
} catch (UnsupportedMediaTypeHttpException $postWithoutContentTypeException) {}
$this->assertTrue(isset($postWithoutContentTypeException));
}
@ -838,4 +842,45 @@ class RequestTest extends TestCase
$this->assertCount(1, $uploadedFiles);
$this->assertTrue($uploadedFiles[0] instanceof UploadedFile);
}
public function testSetupAttributes()
{
$request = new Request();
$request->setAttributes(['some' => 'foo']);
$this->assertSame(['some' => 'foo'], $request->getAttributes());
}
/**
* @depends testSetupAttributes
*/
public function testGetAttribute()
{
$request = new Request();
$request->setAttributes(['some' => 'foo']);
$this->assertSame('foo', $request->getAttribute('some'));
$this->assertSame(null, $request->getAttribute('un-existing'));
$this->assertSame('default', $request->getAttribute('un-existing', 'default'));
}
/**
* @depends testSetupAttributes
*/
public function testModifyAttributes()
{
$request = new Request();
$request->setAttributes(['attr1' => '1']);
$newStorage = $request->withAttribute('attr2', '2');
$this->assertNotSame($newStorage, $request);
$this->assertSame(['attr1' => '1', 'attr2' => '2'], $newStorage->getAttributes());
$request = $newStorage;
$newStorage = $request->withoutAttribute('attr1');
$this->assertNotSame($newStorage, $request);
$this->assertSame(['attr2' => '2'], $newStorage->getAttributes());
}
}

Loading…
Cancel
Save