From 798bad3dea47e0e91450ceb659e38bdb01b4fc84 Mon Sep 17 00:00:00 2001 From: Derek Date: Thu, 7 Jan 2021 20:39:58 -0700 Subject: [PATCH 1/3] Created a way to be able to access data in a JSON from an incoming request using getVar() or a new function getJsonVar(). --- system/HTTP/IncomingRequest.php | 41 ++++++++++- system/HTTP/Message.php | 2 +- tests/system/HTTP/IncomingRequestTest.php | 71 +++++++++++++++++++ .../source/incoming/incomingrequest.rst | 39 ++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 4e8bdf2dd75e..a7e2353565ec 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -288,7 +288,7 @@ public function isSecure(): bool //-------------------------------------------------------------------- /** - * Fetch an item from the $_REQUEST object. This is the simplest way + * Fetch an item from the $_REQUEST object or a JSON input stream. This is the simplest way * to grab data from the request object and can be used in lieu of the * other get* methods in most cases. * @@ -300,6 +300,26 @@ public function isSecure(): bool */ public function getVar($index = null, $filter = null, $flags = null) { + if ($this->isJSON()) + { + if (is_null($index)) + { + return $this->getJSON(); + } + + if (is_array($index)) + { + $output = []; + foreach ($index as $key) + { + $output[$key] = $this->getJsonVar($key); + } + return $output; + } + + return $this->getJsonVar($index); + } + return $this->fetchGlobal('request', $index, $filter, $flags); } @@ -325,6 +345,25 @@ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) return json_decode($this->body, $assoc, $depth, $options); } + /** + * Get a specific variable from a JSON input stream + * + * @param string $index The variable that you want which can use dot syntax for getting specific values. + * @param boolean $assoc If TRUE return the result as an associative array. + * @return array|mixed|null|object + */ + public function getJsonVar(string $index, bool $assoc = false) + { + helper('array'); + + $data = dot_array_search($index, $this->getJSON(true)); + if (is_array($data) && ! $assoc) + { + return json_decode(json_encode($data)); + } + return $data; + } + //-------------------------------------------------------------------- /** diff --git a/system/HTTP/Message.php b/system/HTTP/Message.php index 793ed5642c17..b1e8a741f86f 100644 --- a/system/HTTP/Message.php +++ b/system/HTTP/Message.php @@ -140,7 +140,7 @@ public function getProtocolVersion(): string * * @deprecated Use header calls directly */ - public function isJSON() + public function isJSON(): bool { if (! $this->hasHeader('Content-Type')) { diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 5ece3a30132c..8502a2a6c90b 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -298,6 +298,77 @@ public function testCanGrabGetRawJSON() $this->assertEquals($expected, $request->getJSON(true)); } + public function testCanGetAVariableFromJson() + { + $jsonObj = [ + 'foo' => 'bar', + 'baz' => [ + 'fizz' => 'buzz', + ], + ]; + $json = json_encode($jsonObj); + + $config = new App(); + $config->baseURL = 'http://example.com/'; + + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + + $this->assertEquals('bar', $request->getJsonVar('foo')); + $jsonVar = $request->getJsonVar('baz'); + $this->assertIsObject($jsonVar); + $this->assertEquals('buzz', $jsonVar->fizz); + $this->assertEquals('buzz', $request->getJsonVar('baz.fizz')); + } + + public function testGetJsonVarAsArray() + { + $jsonObj = [ + 'baz' => [ + 'fizz' => 'buzz', + 'foo' => 'bar', + ], + ]; + $json = json_encode($jsonObj); + + $config = new App(); + $config->baseURL = 'http://example.com/'; + + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + + $jsonVar = $request->getJsonVar('baz', true); + $this->assertIsArray($jsonVar); + $this->assertEquals('buzz', $jsonVar['fizz']); + $this->assertEquals('bar', $jsonVar['foo']); + } + + public function testGetVarWorksWithJson() + { + $jsonObj = [ + 'foo' => 'bar', + 'fizz' => 'buzz', + ]; + $json = json_encode($jsonObj); + + $config = new App(); + $config->baseURL = 'http://example.com/'; + + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request->setHeader('Content-Type', 'application/json'); + + $this->assertEquals('bar', $request->getVar('foo')); + $this->assertEquals('buzz', $request->getVar('fizz')); + + $multiple = $request->getVar(['foo', 'fizz']); + $this->assertIsArray($multiple); + $this->assertEquals('bar', $multiple['foo']); + $this->assertEquals('buzz', $multiple['fizz']); + + $all = $request->getVar(); + $this->assertIsObject($all); + $this->assertEquals('bar', $all->foo); + $this->assertEquals('buzz', $all->fizz); + } + public function testCanGrabGetRawInput() { $rawstring = 'username=admin001&role=administrator&usepass=0'; diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 9997c1011267..e70c83c3dee3 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -141,6 +141,45 @@ arrays, pass in ``true`` as the first parameter. The second and third parameters match up to the ``depth`` and ``options`` arguments of the `json_decode `_ PHP function. +If the incoming request has a ``CONTENT_TYPE`` header set to "application/json", you can also use ``getVar()`` to get +the JSON stream. Using ``getVar()`` in this way will always return an object. + +**Get Specific Data from JSON** + +You can get a specific piece of data from a JSON stream by passing a variable name into ``getVar()`` for the +data that you want or you can use "dot" notation to dig into the JSON to get data that is not on the root level. + +:: + + //With a request body of: + { + "foo": "bar", + "fizz": { + "buzz": "baz" + } + } + $data = $request->getVar('foo'); + //$data = "bar" + + $data = $request->getVar('fizz.buzz'); + //$data = "baz" + + +If you want the result to be an associative array instead of an object, you can use ``getJsonVar()`` instead and pass +true in the second parameter. This function can also be used if you can't guarantee that the incoming request will have the +correct ``CONTENT_TYPE`` header. + +:: + + //With the same request as above + $data = $request->getJsonVar('fizz'); + //$data->buzz = "baz" + + $data = $request->getJsonVar('fizz', true); + //$data = ["buzz" => "baz"] + +.. note:: See the documentation for ``dot_array_search()`` in the ``Array`` helper for more information on "dot" notation. + **Retrieving Raw data (PUT, PATCH, DELETE)** Finally, you can grab the contents of php://input as a raw stream with ``getRawInput()``:: From 392517d96d2b11961981bbca7aea60a7400f5d9c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 28 Jan 2021 03:41:17 +0700 Subject: [PATCH 2/3] doc comment Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/HTTP/IncomingRequest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index a7e2353565ec..1e339498b517 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -348,9 +348,10 @@ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) /** * Get a specific variable from a JSON input stream * - * @param string $index The variable that you want which can use dot syntax for getting specific values. - * @param boolean $assoc If TRUE return the result as an associative array. - * @return array|mixed|null|object + * @param string $index The variable that you want which can use dot syntax for getting specific values. + * @param boolean $assoc If true, return the result as an associative array. + * + * @return mixed */ public function getJsonVar(string $index, bool $assoc = false) { From 53a329dac874fe7f467c544ff99a2de7984492af Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 28 Jan 2021 03:51:19 +0700 Subject: [PATCH 3/3] revert isJSON return declaration --- system/HTTP/Message.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/Message.php b/system/HTTP/Message.php index b1e8a741f86f..d5bd9f24fc52 100644 --- a/system/HTTP/Message.php +++ b/system/HTTP/Message.php @@ -140,7 +140,7 @@ public function getProtocolVersion(): string * * @deprecated Use header calls directly */ - public function isJSON(): bool + public function isJSON() { if (! $this->hasHeader('Content-Type')) {