From addc51f4195fa9727ffe4ccf2502eea440c58773 Mon Sep 17 00:00:00 2001 From: michalsn Date: Mon, 5 Dec 2022 17:16:24 +0100 Subject: [PATCH 1/3] feat: add IncomingRequest::getRawInputVar() method to work with raw stream data --- system/HTTP/IncomingRequest.php | 54 ++++++++++ tests/system/HTTP/IncomingRequestTest.php | 98 +++++++++++++++++++ user_guide_src/source/changelogs/v4.3.0.rst | 1 + .../source/incoming/incomingrequest.rst | 6 +- .../source/incoming/incomingrequest/039.php | 33 +++++++ 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 user_guide_src/source/incoming/incomingrequest/039.php diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 9e19563ab8b0..505ebcb3e433 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -608,6 +608,60 @@ public function getRawInput() return $output; } + /** + * Gets a specific variable from raw input stream (send method in PUT, PATCH, DELETE). + * + * @param array|string|null $index The variable that you want which can use dot syntax for getting specific values. + * @param int|null $filter Filter Constant + * @param array|int|null $flags Option + * + * @return mixed + */ + public function getRawInputVar($index = null, ?int $filter = null, $flags = null) + { + helper('array'); + + parse_str($this->body ?? '', $output); + + if (is_string($index)) { + $output = dot_array_search($index, $output); + } elseif (is_array($index)) { + $data = []; + + foreach ($index as $key) { + $data[$key] = dot_array_search($key, $output); + } + + [$output, $data] = [$data, null]; + } + + $filter ??= FILTER_DEFAULT; + $flags = is_array($flags) ? $flags : (is_numeric($flags) ? (int) $flags : 0); + + if (is_array($output) + && ( + $filter !== FILTER_DEFAULT + || ( + (is_numeric($flags) && $flags !== 0) + || is_array($flags) && $flags !== [] + ) + ) + ) { + // Iterate over array and append filter and flags + array_walk_recursive($output, static function (&$val) use ($filter, $flags) { + $val = filter_var($val, $filter, $flags); + }); + + return $output; + } + + if (is_string($output)) { + return filter_var($output, $filter, $flags); + } + + return $output; + } + /** * Fetch an item from GET data. * diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 2855fbf395fd..b6578a0969cf 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -442,6 +442,104 @@ public function testCanGrabGetRawInput() $this->assertSame($expected, $request->getRawInput()); } + public function provideRawInputVarChecks() + { + return [ + [ + 'username=admin001&role=administrator&usepass=0', + 'username', + 'admin001', + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0', + ['role', 'usepass'], + [ + 'role' => 'administrator', + 'usepass' => '0', + ], + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0', + 'not_exists', + null, + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0', + null, + [ + 'username' => 'admin001', + 'role' => 'administrator', + 'usepass' => '0', + ], + null, + null, + ], + [ + '', + null, + [], + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0&foo[]=one&foo[]=two', + ['username', 'foo'], + [ + 'username' => 'admin001', + 'foo' => ['one', 'two'], + ], + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0&foo[]=one&foo[]=two', + 'foo.0', + 'one', + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0&foo[]=one&foo[]=two&bar[baz]=hello', + 'bar.baz', + 'hello', + null, + null, + ], + [ + 'username=admin001&role=administrator&usepass=0&foo[]=one&foo[]=two&bar[baz]=hello6.5world', + 'bar.baz', + '6.5', + FILTER_SANITIZE_NUMBER_FLOAT, + FILTER_FLAG_ALLOW_FRACTION, + ], + ]; + } + + /** + * @dataProvider provideRawInputVarChecks + * + * @param string $rawstring + * @param mixed $var + * @param mixed $expected + * @param mixed $filter + * @param mixed $flag + */ + public function testCanGrabGetRawInputVar($rawstring, $var, $expected, $filter, $flag) + { + $config = new App(); + $config->baseURL = 'http://example.com/'; + + $request = new IncomingRequest($config, new URI(), $rawstring, new UserAgent()); + + $this->assertSame($expected, $request->getRawInputVar($var, $filter, $flag)); + } + public function testIsCLI() { $this->assertFalse($this->request->isCLI()); diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 47c156120a2f..63805ac0e002 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -295,6 +295,7 @@ Others - **View:** Added ``Controlled Cells`` that provide more structure and flexibility to your View Cells. See :ref:`View Cells ` for details. - **Config:** Now you can specify Composer packages to auto-discover manually. See :ref:`Code Modules `. - **Debug:** Kint has been updated to 5.0.1. +- **Request:** Added new ``$request->getRawInputVar()`` method to return a specified variable from raw stream. See :ref:`Retrieving Raw data `. Message Changes *************** diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index d665167f824c..1e506289ba60 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -155,6 +155,10 @@ This will retrieve data and convert it to an array. Like this: .. literalinclude:: incomingrequest/013.php +You can also use ``getRawInputVar()``, to get the specified variable from raw stream and filter it. + +.. literalinclude:: incomingrequest/039.php + Filtering Input Data ==================== @@ -168,7 +172,7 @@ Filtering a POST variable would look like this: .. literalinclude:: incomingrequest/014.php All of the methods mentioned above support the filter type passed in as the second parameter, with the -exception of ``getJSON()``. +exception of ``getJSON()`` and ``getRawInput()``. Retrieving Headers ****************** diff --git a/user_guide_src/source/incoming/incomingrequest/039.php b/user_guide_src/source/incoming/incomingrequest/039.php new file mode 100644 index 000000000000..58b235175ca1 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/039.php @@ -0,0 +1,33 @@ +getRawInputVar('bar')); + +// Outputs: two + +// foo=one&bar=two&baz[]=10&baz[]=20 +var_dump($request->getRawInputVar(['foo', 'bar'])); + +/* + * Outputs: + * [ + * 'foo' => 'one', + * 'bar' => 'two' + * ] + */ + +// foo=one&bar=two&baz[]=10&baz[]=20 +var_dump($request->getRawInputVar('baz')); + +/* + * Outputs: + * [ + * 10, + * 20 + * ] + */ + +// foo=one&bar=two&baz[]=10&baz[]=20 +var_dump($request->getRawInputVar('baz.0')); + +// Outputs: 10 From 5ed9f5ae9a59174c4767c5da65f8638ebb47822b Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Tue, 6 Dec 2022 08:01:08 +0100 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: kenjis --- user_guide_src/source/incoming/incomingrequest/039.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest/039.php b/user_guide_src/source/incoming/incomingrequest/039.php index 58b235175ca1..f1f8956fc31c 100644 --- a/user_guide_src/source/incoming/incomingrequest/039.php +++ b/user_guide_src/source/incoming/incomingrequest/039.php @@ -1,6 +1,6 @@ getRawInputVar('bar')); // Outputs: two @@ -22,8 +22,8 @@ /* * Outputs: * [ - * 10, - * 20 + * '10', + * '20' * ] */ From d1bcbd80519018abc7267aebe4acbfbc6e9481d3 Mon Sep 17 00:00:00 2001 From: michalsn Date: Tue, 6 Dec 2022 08:04:24 +0100 Subject: [PATCH 3/3] apply code suggestions for docs examples --- user_guide_src/source/incoming/incomingrequest/039.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest/039.php b/user_guide_src/source/incoming/incomingrequest/039.php index f1f8956fc31c..84e603fd80bc 100644 --- a/user_guide_src/source/incoming/incomingrequest/039.php +++ b/user_guide_src/source/incoming/incomingrequest/039.php @@ -2,12 +2,10 @@ // When the request body is 'foo=one&bar=two&baz[]=10&baz[]=20' var_dump($request->getRawInputVar('bar')); - // Outputs: two // foo=one&bar=two&baz[]=10&baz[]=20 var_dump($request->getRawInputVar(['foo', 'bar'])); - /* * Outputs: * [ @@ -18,7 +16,6 @@ // foo=one&bar=two&baz[]=10&baz[]=20 var_dump($request->getRawInputVar('baz')); - /* * Outputs: * [ @@ -29,5 +26,4 @@ // foo=one&bar=two&baz[]=10&baz[]=20 var_dump($request->getRawInputVar('baz.0')); - // Outputs: 10