Fix #17701: Throw BadRequetHttpException when request params can’t be bound to bool, int, and float controller action arguments

This commit is contained in:
Brandon Kelly
2019-12-03 01:40:56 -08:00
committed by Alexander Makarov
parent 3ef303968f
commit 40797c1139
4 changed files with 86 additions and 4 deletions

View File

@ -5,6 +5,7 @@ Yii Framework 2 Change Log
------------------------ ------------------------
- Bug #17865: Fix invalid db component in `m180523_151638_rbac_updates_indexes_without_prefix` (rvkulikov) - Bug #17865: Fix invalid db component in `m180523_151638_rbac_updates_indexes_without_prefix` (rvkulikov)
- Enh #17701: Throw `BadRequetHttpException` when request params cant be bound to `bool`, `int`, and `float` controller action arguments (brandonkelly)
2.0.30 November 19, 2019 2.0.30 November 19, 2019

View File

@ -128,15 +128,35 @@ class Controller extends \yii\base\Controller
foreach ($method->getParameters() as $param) { foreach ($method->getParameters() as $param) {
$name = $param->getName(); $name = $param->getName();
if (array_key_exists($name, $params)) { if (array_key_exists($name, $params)) {
$isValid = true;
if ($param->isArray()) { if ($param->isArray()) {
$args[] = $actionParams[$name] = (array) $params[$name]; $params[$name] = (array)$params[$name];
} elseif (!is_array($params[$name])) { } elseif (is_array($params[$name])) {
$args[] = $actionParams[$name] = $params[$name]; $isValid = false;
} else { } elseif (
PHP_VERSION_ID >= 70000 &&
($type = $param->getType()) !== null &&
$type->isBuiltin() &&
($params[$name] !== null || !$type->allowsNull())
) {
switch ((string)$type) {
case 'int':
$params[$name] = filter_var($params[$name], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
break;
case 'float':
$params[$name] = filter_var($params[$name], FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE);
break;
}
if ($params[$name] === null) {
$isValid = false;
}
}
if (!$isValid) {
throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [ throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [
'param' => $name, 'param' => $name,
])); ]));
} }
$args[] = $actionParams[$name] = $params[$name];
unset($params[$name]); unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) { } elseif ($param->isDefaultValueAvailable()) {
$args[] = $actionParams[$name] = $param->getDefaultValue(); $args[] = $actionParams[$name] = $param->getDefaultValue();

View File

@ -32,6 +32,44 @@ class ControllerTest extends TestCase
$this->assertEquals('avaliable', $other); $this->assertEquals('avaliable', $other);
} }
/**
* @see https://github.com/yiisoft/yii2/issues/17701
*/
public function testBindTypedActionParams()
{
if (PHP_VERSION_ID < 70000) {
$this->markTestSkipped('Can not be tested on PHP < 7.0');
return;
}
// Use the PHP7 controller for this test
$this->controller = new FakePhp7Controller('fake', new \yii\web\Application([
'id' => 'app',
'basePath' => __DIR__,
'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
],
],
]));
$this->mockWebApplication(['controller' => $this->controller]);
$aksi1 = new InlineAction('aksi1', $this->controller, 'actionAksi1');
$params = ['foo' => '100', 'bar' => null];
list($foo, $bar) = $this->controller->bindActionParams($aksi1, $params);
$this->assertSame(100, $foo);
$this->assertSame(null, $bar);
$params = ['foo' => 'oops', 'bar' => null];
$this->expectException('yii\web\BadRequestHttpException');
$this->expectExceptionMessage('Invalid data received for parameter "foo".');
$this->controller->bindActionParams($aksi1, $params);
}
public function testAsJson() public function testAsJson()
{ {
$data = [ $data = [

View File

@ -0,0 +1,23 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\web;
use yii\web\Controller;
/**
* @author Brandon Kelly <branodn@craftcms.com>
* @since 2.0.31
*/
class FakePhp7Controller extends Controller
{
public $enableCsrfValidation = false;
public function actionAksi1(int $foo, float $bar = null)
{
}
}