diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index 009e4a7..fa32ddc 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -4,6 +4,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UploadedFileInterface; /** * Representation of an incoming, server-side HTTP request. @@ -193,7 +194,7 @@ class ServerRequest extends Request implements ServerRequestInterface { if (!$this->isValidUploadedFilesTree($uploadedFiles)) { throw new \InvalidArgumentException( - "withUploadedFiles expects an array with string keys and UploadedFileInterface[] values"); + "withUploadedFiles expects an array tree with UploadedFileInterface leaves."); } $request = clone $this; @@ -475,36 +476,45 @@ class ServerRequest extends Request implements ServerRequestInterface return $headers; } + /** + * @param array $uploadedFiles + * @return bool + */ private function isValidUploadedFilesTree(array $uploadedFiles) { - // Ensure all keys are strings. + // Allow empty array. + if (count($uploadedFiles) === 0) { + return true; + } + + // All keys MUST be strings. $keys = array_keys($uploadedFiles); if (count($keys) !== count(array_filter($keys, "is_string"))) { return false; } - // All values must be UploadedFileInterface[]. + foreach ($uploadedFiles as $branch) { + if (!$this->isValidUploadedFilesBranch($branch)) { + return false; + } + } - // Ensure all values are arrays. - $values = array_values($uploadedFiles); - if (count($values) !== count(array_filter($values, "is_array"))) { + return true; + } + + private function isValidUploadedFilesBranch($branch) + { + if ($branch instanceof UploadedFileInterface) { + return true; + } + + if (!is_array($branch)) { return false; } - $isUploadedFileInterface = function ($object) { - return is_object($object) && in_array('Psr\Http\Message\UploadedFileInterface', class_implements($object)); - }; - - foreach ($values as $items) { - - // Ensure values are list arrays. - if (array_keys($items) !== range(0, count($items) - 1)) { - return false; - } - - // Ensure all items are UploadedFileInterfaces - $itemValues = array_values($items); - if (count($itemValues) !== count(array_filter($itemValues, $isUploadedFileInterface))) { + $values = array_values($branch); + foreach ($values as $value) { + if (!$this->isValidUploadedFilesBranch($value)) { return false; } } diff --git a/test/tests/unit/Message/ServerRequestTest.php b/test/tests/unit/Message/ServerRequestTest.php index 685d0b5..9653bc6 100644 --- a/test/tests/unit/Message/ServerRequestTest.php +++ b/test/tests/unit/Message/ServerRequestTest.php @@ -369,7 +369,7 @@ class ServerRequestTest extends \PHPUnit_Framework_TestCase public function testWithUploadedFilesCreatesNewInstance() { $uploadedFiles = [ - "file" => [new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)] + "file" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) ]; $request = new ServerRequest(); $request1 = $request->withUploadedFiles([]); @@ -380,17 +380,32 @@ class ServerRequestTest extends \PHPUnit_Framework_TestCase /** * @covers WellRESTed\Message\ServerRequest::withUploadedFiles * @covers WellRESTed\Message\ServerRequest::isValidUploadedFilesTree + * @dataProvider validUploadedFilesProvider */ - public function testWithUploadedFilesReturnsPassedUploadedFiles() + public function testWithUploadedFilesReturnsPassedUploadedFiles($uploadedFiles) { - $uploadedFiles = [ - "file" => [new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)] - ]; $request = new ServerRequest(); $request = $request->withUploadedFiles($uploadedFiles); $this->assertSame($uploadedFiles, $request->getUploadedFiles()); } + public function validUploadedFilesProvider() + { + return [ + [[]], + [["files" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], + [["nested" => [ + "level2" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) + ]]], + [["nestedList" => [ + "level2" => [ + new UploadedFile("file1.html", "text/html", 524, "/tmp/php9hNlHe", 0), + new UploadedFile("file2.html", "text/html", 524, "/tmp/php9hNshj", 0) + ] + ]]] + ]; + } + /** * @covers WellRESTed\Message\ServerRequest::withUploadedFiles * @covers WellRESTed\Message\ServerRequest::isValidUploadedFilesTree @@ -408,33 +423,54 @@ class ServerRequestTest extends \PHPUnit_Framework_TestCase return [ // All keys must be strings [[new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], - - // All values must be arrays. - [["file" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], - - // All values must be list arrays. [ - [ - "file" => - [ - "file1" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) - ] - ] + [new UploadedFile("index1.html", "text/html", 524, "/tmp/php9hNlHe", 0)], + [new UploadedFile("index2.html", "text/html", 524, "/tmp/php9hNlHe", 0)] ], [ - [ - "file" => [ - 0 => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0), - 2 => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) + "single" => [ + "name" => "single.txt", + "type" => "text/plain", + "tmp_name" => "/tmp/php9hNlHe", + "error" => UPLOAD_ERR_OK, + "size" => 524 + ], + "nested" => [ + "level2" => [ + "name" => "nested.json", + "type" => "application/json", + "tmp_name" => "/tmp/phpadhjk", + "error" => UPLOAD_ERR_OK, + "size" => 1024 ] - ] - ], - [ - [ - "file" => [ - new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0), - new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0), - "index.html" + ], + "nestedList" => [ + "level2" => [ + "name" => [ + 0 => "nestedList0.jpg", + 1 => "nestedList1.jpg", + 2 => "" + ], + "type" => [ + 0 => "image/jpeg", + 1 => "image/jpeg", + 2 => "" + ], + "tmp_name" => [ + 0 => "/tmp/phpjpg0", + 1 => "/tmp/phpjpg1", + 2 => "" + ], + "error" => [ + 0 => UPLOAD_ERR_OK, + 1 => UPLOAD_ERR_OK, + 2 => UPLOAD_ERR_NO_FILE + ], + "size" => [ + 0 => 256, + 1 => 4096, + 2 => 0 + ] ] ] ]