From 578b2caf424417215309a827a127dac1394e53ac Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Mon, 24 Jul 2017 15:28:22 +0300 Subject: [PATCH] Added `yii\web\MultipartFormDataParser::$force` option allowing to enforce parsing even on 'POST' request --- framework/CHANGELOG.md | 1 + framework/web/MultipartFormDataParser.php | 19 ++++++++++-- .../framework/web/MultipartFormDataParserTest.php | 35 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 6971ca5..359b526 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -3,6 +3,7 @@ Yii Framework 2 Change Log 2.0.13 under development ------------------------ +- Bug #14523: Added `yii\web\MultipartFormDataParser::$force` option allowing to enforce parsing even on 'POST' request (klimov-paul) - Bug #14449: Fix PHP 7.2 compatibility bugs and add explicit closure support in `yii\base\Application` (dynasource) - Bug #7890: Allow `migrate/mark` to mark history at the point of the base migration (cebe) - Bug #14206: `MySqlMutex`, `PgsqlMutex` and `OracleMutex` now use `useMaster()` to ensure lock is aquired on the same DB server (cebe, ryusoft) diff --git a/framework/web/MultipartFormDataParser.php b/framework/web/MultipartFormDataParser.php index cddc32f..4351763 100644 --- a/framework/web/MultipartFormDataParser.php +++ b/framework/web/MultipartFormDataParser.php @@ -66,6 +66,15 @@ use yii\helpers\StringHelper; class MultipartFormDataParser extends BaseObject implements RequestParserInterface { /** + * @var bool whether to parse raw body even for 'POST' request and `$_FILES` already populated. + * By default this option is disabled saving performance for 'POST' requests, which are already + * processed by PHP automatically. + * > Note: if this option is enabled, value of `$_FILES` will be reset on each parse. + * @since 2.0.13 + */ + public $force = false; + + /** * @var int upload file max size in bytes. */ private $_uploadFileMaxSize; @@ -118,9 +127,13 @@ class MultipartFormDataParser extends BaseObject implements RequestParserInterfa */ public function parse($rawBody, $contentType) { - if (!empty($_POST) || !empty($_FILES)) { - // normal POST request is parsed by PHP automatically - return $_POST; + if (!$this->force) { + if (!empty($_POST) || !empty($_FILES)) { + // normal POST request is parsed by PHP automatically + return $_POST; + } + } else { + $_FILES = []; } if (empty($rawBody)) { diff --git a/tests/framework/web/MultipartFormDataParserTest.php b/tests/framework/web/MultipartFormDataParserTest.php index 68375eb..cf3888f 100644 --- a/tests/framework/web/MultipartFormDataParserTest.php +++ b/tests/framework/web/MultipartFormDataParserTest.php @@ -128,4 +128,39 @@ class MultipartFormDataParserTest extends TestCase $this->assertCount(3, $_FILES); $this->assertEquals(UPLOAD_ERR_INI_SIZE, $_FILES['thirdFile']['error']); } + + /** + * @depends testNotEmptyPost + * @depends testNotEmptyFiles + */ + public function testForce() + { + $parser = new MultipartFormDataParser(); + $parser->force = true; + + $_POST = [ + 'existingName' => 'value', + ]; + $_FILES = [ + 'existingFile' => [ + 'name' => 'file.txt', + 'type' => 'text/plain', + ], + ]; + + $boundary = '---------------------------22472926011618'; + $contentType = 'multipart/form-data; boundary=' . $boundary; + $rawBody = "--{$boundary}\nContent-Disposition: form-data; name=\"title\"\r\n\r\ntest-title"; + $rawBody .= "\r\n--{$boundary}\nContent-Disposition: form-data; name=\"someFile\"; filename=\"some-file.txt\"\nContent-Type: text/plain\r\n\r\nsome file content"; + $rawBody .= "\r\n--{$boundary}--"; + + $bodyParams = $parser->parse($rawBody, $contentType); + + $expectedBodyParams = [ + 'title' => 'test-title', + ]; + $this->assertEquals($expectedBodyParams, $bodyParams); + $this->assertNotEmpty($_FILES['someFile']); + $this->assertFalse(isset($_FILES['existingFile'])); + } }