Browse Source

Move files array processing into ServerRequestFactory.

Refs #14213
ADmad 6 years ago
parent
commit
85a86b7bcd

+ 3 - 120
src/Http/ServerRequest.php

@@ -195,13 +195,6 @@ class ServerRequest implements ServerRequestInterface
     protected $requestTarget;
 
     /**
-     * Whether to merge file uploads as objects (`true`) or arrays (`false`).
-     *
-     * @var bool
-     */
-    protected $mergeFilesAsObjects = true;
-
-    /**
      * Create a new request object.
      *
      * You can supply the data as either an array or as a string. If you use
@@ -210,7 +203,7 @@ class ServerRequest implements ServerRequestInterface
      *
      * - `post` POST data or non query string data
      * - `query` Additional data from the query string.
-     * - `files` Uploaded file data formatted like $_FILES.
+     * - `files` Uploaded files in a normalized structure, with each leaf an instance of UploadedFileInterface.
      * - `cookies` Cookies for this request.
      * - `environment` $_SERVER and $_ENV data.
      * - `url` The URL without the base path for the request.
@@ -220,7 +213,6 @@ class ServerRequest implements ServerRequestInterface
      * - `input` The data that would come from php://input this is useful for simulating
      *   requests with put, patch or delete data.
      * - `session` An instance of a Session object
-     * - `mergeFilesAsObjects` Whether to merge file uploads as objects (`true`) or arrays (`false`).
      *
      * @param array $config An array of request data to create a request with.
      */
@@ -238,7 +230,6 @@ class ServerRequest implements ServerRequestInterface
             'base' => '',
             'webroot' => '',
             'input' => null,
-            'mergeFilesAsObjects' => true,
         ];
 
         $this->_setConfig($config);
@@ -298,10 +289,8 @@ class ServerRequest implements ServerRequestInterface
         }
         $this->stream = $stream;
 
-        $this->mergeFilesAsObjects = $config['mergeFilesAsObjects'];
-
-        $config['post'] = $this->_processPost($config['post']);
-        $this->data = $this->_processFiles($config['post'], $config['files']);
+        $this->data = $this->_processPost($config['post']);
+        $this->uploadedFiles = $config['files'];
         $this->query = $this->_processGet($config['query'], $querystr);
         $this->params = $config['params'];
         $this->session = $config['session'];
@@ -365,112 +354,6 @@ class ServerRequest implements ServerRequestInterface
     }
 
     /**
-     * Process uploaded files and move things onto the post data.
-     *
-     * @param mixed $post Post data to merge files onto.
-     * @param mixed $files Uploaded files to merge in.
-     * @return array merged post + file data.
-     */
-    protected function _processFiles($post, $files)
-    {
-        if (!is_array($post) || !is_array($files) || empty($files)) {
-            return $post;
-        }
-
-        $fileData = [];
-        foreach ($files as $key => $value) {
-            if ($value instanceof UploadedFileInterface) {
-                $fileData[$key] = $value;
-                continue;
-            }
-
-            if (is_array($value) && isset($value['tmp_name'])) {
-                $fileData[$key] = $this->_createUploadedFile($value);
-                continue;
-            }
-
-            throw new InvalidArgumentException(sprintf(
-                'Invalid value in FILES "%s"',
-                json_encode($value)
-            ));
-        }
-        $this->uploadedFiles = $fileData;
-
-        if ($this->mergeFilesAsObjects) {
-            return Hash::merge($post, $fileData);
-        }
-
-        // Make a flat map that can be inserted into $post for BC.
-        $fileMap = Hash::flatten($fileData);
-        foreach ($fileMap as $key => $file) {
-            $error = $file->getError();
-            $tmpName = '';
-            if ($error === UPLOAD_ERR_OK) {
-                $tmpName = $file->getStream()->getMetadata('uri');
-            }
-            $post = Hash::insert($post, (string)$key, [
-                'tmp_name' => $tmpName,
-                'error' => $error,
-                'name' => $file->getClientFilename(),
-                'type' => $file->getClientMediaType(),
-                'size' => $file->getSize(),
-            ]);
-        }
-
-        return $post;
-    }
-
-    /**
-     * Create an UploadedFile instance from a $_FILES array.
-     *
-     * If the value represents an array of values, this method will
-     * recursively process the data.
-     *
-     * @param array $value $_FILES struct
-     * @return array|\Psr\Http\Message\UploadedFileInterface
-     */
-    protected function _createUploadedFile(array $value)
-    {
-        if (is_array($value['tmp_name'])) {
-            return $this->_normalizeNestedFiles($value);
-        }
-
-        return new UploadedFile(
-            $value['tmp_name'],
-            $value['size'],
-            $value['error'],
-            $value['name'],
-            $value['type']
-        );
-    }
-
-    /**
-     * Normalize an array of file specifications.
-     *
-     * Loops through all nested files and returns a normalized array of
-     * UploadedFileInterface instances.
-     *
-     * @param array $files The file data to normalize & convert.
-     * @return array An array of UploadedFileInterface objects.
-     */
-    protected function _normalizeNestedFiles(array $files = []): array
-    {
-        $normalizedFiles = [];
-        foreach (array_keys($files['tmp_name']) as $key) {
-            $spec = [
-                'tmp_name' => $files['tmp_name'][$key],
-                'size' => $files['size'][$key],
-                'error' => $files['error'][$key],
-                'name' => $files['name'][$key],
-                'type' => $files['type'][$key],
-            ];
-            $normalizedFiles[$key] = $this->_createUploadedFile($spec);
-        }
-
-        return $normalizedFiles;
-    }
-
-    /**
      * Get the content type used in this request.
      *
      * @return string|null

+ 46 - 5
src/Http/ServerRequestFactory.php

@@ -24,6 +24,7 @@ use Psr\Http\Message\UriInterface;
 use function Laminas\Diactoros\marshalHeadersFromSapi;
 use function Laminas\Diactoros\marshalUriFromSapi;
 use function Laminas\Diactoros\normalizeServer;
+use function Laminas\Diactoros\normalizeUploadedFiles;
 
 /**
  * Factory for making ServerRequest instances.
@@ -46,7 +47,7 @@ abstract class ServerRequestFactory implements ServerRequestFactoryInterface
      * @see fromServer()
      * @param array $server $_SERVER superglobal
      * @param array $query $_GET superglobal
-     * @param array $body $_POST superglobal
+     * @param array $post $_POST superglobal
      * @param array $cookies $_COOKIE superglobal
      * @param array $files $_FILES superglobal
      * @return \Cake\Http\ServerRequest
@@ -55,36 +56,76 @@ abstract class ServerRequestFactory implements ServerRequestFactoryInterface
     public static function fromGlobals(
         ?array $server = null,
         ?array $query = null,
-        ?array $body = null,
+        ?array $post = null,
         ?array $cookies = null,
         ?array $files = null
     ): ServerRequest {
         $server = normalizeServer($server ?: $_SERVER);
         $uri = static::createUri($server);
+        $data = static::processFiles($files ?: $_FILES, $post ?: $_POST);
+        $files = $data['files'];
+        $post = $data['post'];
+
         /** @psalm-suppress NoInterfaceProperties */
         $sessionConfig = (array)Configure::read('Session') + [
             'defaults' => 'php',
             'cookiePath' => $uri->webroot,
         ];
         $session = Session::create($sessionConfig);
+
         /** @psalm-suppress NoInterfaceProperties */
         $request = new ServerRequest([
             'environment' => $server,
             'uri' => $uri,
-            'files' => $files ?: $_FILES,
+            'files' => $files,
             'cookies' => $cookies ?: $_COOKIE,
             'query' => $query ?: $_GET,
-            'post' => $body ?: $_POST,
+            'post' => $post,
             'webroot' => $uri->webroot,
             'base' => $uri->base,
             'session' => $session,
-            'mergeFilesAsObjects' => Configure::read('App.uploadedFilesAsObjects', true),
         ]);
 
         return $request;
     }
 
     /**
+     * Process uploaded files and move things onto the post data.
+     *
+     * @param array $files Files array for normalization and merging in post body.
+     * @param array $post Post body to merge files onto.
+     * @return array
+     * @psalm-return array{files: array, post: array}
+     */
+    protected static function processFiles($files, $post)
+    {
+        $files = normalizeUploadedFiles($files ?: $_FILES);
+
+        if (Configure::read('App.uploadedFilesAsObjects', true)) {
+            $post = Hash::merge($post, $files);
+        } else {
+            // Make a flat map that can be inserted into body for BC.
+            $fileMap = Hash::flatten($files);
+            foreach ($fileMap as $key => $file) {
+                $error = $file->getError();
+                $tmpName = '';
+                if ($error === UPLOAD_ERR_OK) {
+                    $tmpName = $file->getStream()->getMetadata('uri');
+                }
+                $post = Hash::insert($post, (string)$key, [
+                    'tmp_name' => $tmpName,
+                    'error' => $error,
+                    'name' => $file->getClientFilename(),
+                    'type' => $file->getClientMediaType(),
+                    'size' => $file->getSize(),
+                ]);
+            }
+        }
+
+        return ['files' => $files, 'post' => $post];
+    }
+
+    /**
      * Create a new server request.
      *
      * Note that server-params are taken precisely as given - no parsing/processing

+ 337 - 0
tests/TestCase/Http/ServerRequestFactoryTest.php

@@ -20,6 +20,7 @@ use Cake\Core\Configure;
 use Cake\Http\ServerRequestFactory;
 use Cake\Http\Session;
 use Cake\TestSuite\TestCase;
+use Laminas\Diactoros\Exception\InvalidArgumentException;
 use Laminas\Diactoros\UploadedFile;
 use Psr\Http\Message\UploadedFileInterface;
 
@@ -383,4 +384,340 @@ class ServerRequestFactoryTest extends TestCase
         ];
         $this->assertEquals($expected, $request->getData());
     }
+
+    /**
+     * Test processing files with `file` field names.
+     *
+     * @return void
+     */
+    public function testFilesNested()
+    {
+        $files = [
+            'image_main' => [
+                'name' => ['file' => 'born on.txt'],
+                'type' => ['file' => 'text/plain'],
+                'tmp_name' => ['file' => __FILE__],
+                'error' => ['file' => 0],
+                'size' => ['file' => 17178],
+            ],
+            0 => [
+                'name' => ['image' => 'scratch.text'],
+                'type' => ['image' => 'text/plain'],
+                'tmp_name' => ['image' => __FILE__],
+                'error' => ['image' => 0],
+                'size' => ['image' => 1490],
+            ],
+            'pictures' => [
+                'name' => [
+                    0 => ['file' => 'a-file.png'],
+                    1 => ['file' => 'a-moose.png'],
+                ],
+                'type' => [
+                    0 => ['file' => 'image/png'],
+                    1 => ['file' => 'image/jpg'],
+                ],
+                'tmp_name' => [
+                    0 => ['file' => __FILE__],
+                    1 => ['file' => __FILE__],
+                ],
+                'error' => [
+                    0 => ['file' => 0],
+                    1 => ['file' => 0],
+                ],
+                'size' => [
+                    0 => ['file' => 17188],
+                    1 => ['file' => 2010],
+                ],
+            ],
+        ];
+
+        $post = [
+            'pictures' => [
+                0 => ['name' => 'A cat'],
+                1 => ['name' => 'A moose'],
+            ],
+            0 => [
+                'name' => 'A dog',
+            ],
+        ];
+
+        $request = ServerRequestFactory::fromGlobals(null, null, $post, null, $files);
+        $expected = [
+            'image_main' => [
+                'file' => new UploadedFile(
+                    __FILE__,
+                    17178,
+                    0,
+                    'born on.txt',
+                    'text/plain'
+                ),
+            ],
+            'pictures' => [
+                0 => [
+                    'name' => 'A cat',
+                    'file' => new UploadedFile(
+                        __FILE__,
+                        17188,
+                        0,
+                        'a-file.png',
+                        'image/png'
+                    ),
+                ],
+                1 => [
+                    'name' => 'A moose',
+                    'file' => new UploadedFile(
+                        __FILE__,
+                        2010,
+                        0,
+                        'a-moose.png',
+                        'image/jpg'
+                    ),
+                ],
+            ],
+            0 => [
+                'name' => 'A dog',
+                'image' => new UploadedFile(
+                    __FILE__,
+                    1490,
+                    0,
+                    'scratch.text',
+                    'text/plain'
+                ),
+            ],
+        ];
+        $this->assertEquals($expected, $request->getData());
+
+        $uploads = $request->getUploadedFiles();
+        $this->assertCount(3, $uploads);
+        $this->assertArrayHasKey(0, $uploads);
+        $this->assertSame('scratch.text', $uploads[0]['image']->getClientFilename());
+
+        $this->assertArrayHasKey('pictures', $uploads);
+        $this->assertSame('a-file.png', $uploads['pictures'][0]['file']->getClientFilename());
+        $this->assertSame('a-moose.png', $uploads['pictures'][1]['file']->getClientFilename());
+
+        $this->assertArrayHasKey('image_main', $uploads);
+        $this->assertSame('born on.txt', $uploads['image_main']['file']->getClientFilename());
+    }
+
+    /**
+     * Test processing a file input with no .'s in it.
+     *
+     * @return void
+     */
+    public function testFilesFlat()
+    {
+        $files = [
+            'birth_cert' => [
+                'name' => 'born on.txt',
+                'type' => 'application/octet-stream',
+                'tmp_name' => __FILE__,
+                'error' => 0,
+                'size' => 123,
+            ],
+        ];
+
+        Configure::write('App.uploadedFilesAsObjects', false);
+        $request = ServerRequestFactory::fromGlobals([], [], [], [], $files);
+        $this->assertEquals($files, $request->getData());
+        Configure::write('App.uploadedFilesAsObjects', true);
+
+        $uploads = $request->getUploadedFiles();
+        $this->assertCount(1, $uploads);
+        $this->assertArrayHasKey('birth_cert', $uploads);
+        $this->assertSame('born on.txt', $uploads['birth_cert']->getClientFilename());
+        $this->assertSame(0, $uploads['birth_cert']->getError());
+        $this->assertSame('application/octet-stream', $uploads['birth_cert']->getClientMediaType());
+        $this->assertEquals(123, $uploads['birth_cert']->getSize());
+    }
+
+    /**
+     * Test that files in the 0th index work.
+     *
+     * @return void
+     */
+    public function testFilesZeroithIndex()
+    {
+        $files = [
+            0 => [
+                'name' => 'cake_sqlserver_patch.patch',
+                'type' => 'text/plain',
+                'tmp_name' => __FILE__,
+                'error' => 0,
+                'size' => 6271,
+            ],
+        ];
+
+        Configure::write('App.uploadedFilesAsObjects', false);
+        $request = ServerRequestFactory::fromGlobals([], [], [], [], $files);
+        $this->assertEquals($files, $request->getData());
+        Configure::write('App.uploadedFilesAsObjects', true);
+
+        $uploads = $request->getUploadedFiles();
+        $this->assertCount(1, $uploads);
+        $this->assertEquals($files[0]['name'], $uploads[0]->getClientFilename());
+    }
+
+    /**
+     * Tests that file uploads are merged into the post data as objects instead of as arrays.
+     *
+     * @return void
+     */
+    public function testFilesAsObjectsInRequestData()
+    {
+        $files = [
+            'flat' => [
+                'name' => 'flat.txt',
+                'type' => 'text/plain',
+                'tmp_name' => __FILE__,
+                'error' => 0,
+                'size' => 1,
+            ],
+            'nested' => [
+                'name' => ['file' => 'nested.txt'],
+                'type' => ['file' => 'text/plain'],
+                'tmp_name' => ['file' => __FILE__],
+                'error' => ['file' => 0],
+                'size' => ['file' => 12],
+            ],
+            0 => [
+                'name' => 'numeric.txt',
+                'type' => 'text/plain',
+                'tmp_name' => __FILE__,
+                'error' => 0,
+                'size' => 123,
+            ],
+            1 => [
+                'name' => ['file' => 'numeric-nested.txt'],
+                'type' => ['file' => 'text/plain'],
+                'tmp_name' => ['file' => __FILE__],
+                'error' => ['file' => 0],
+                'size' => ['file' => 1234],
+            ],
+            'deep' => [
+                'name' => [
+                    0 => ['file' => 'deep-1.txt'],
+                    1 => ['file' => 'deep-2.txt'],
+                ],
+                'type' => [
+                    0 => ['file' => 'text/plain'],
+                    1 => ['file' => 'text/plain'],
+                ],
+                'tmp_name' => [
+                    0 => ['file' => __FILE__],
+                    1 => ['file' => __FILE__],
+                ],
+                'error' => [
+                    0 => ['file' => 0],
+                    1 => ['file' => 0],
+                ],
+                'size' => [
+                    0 => ['file' => 12345],
+                    1 => ['file' => 123456],
+                ],
+            ],
+        ];
+
+        $post = [
+            'flat' => ['existing'],
+            'nested' => [
+                'name' => 'nested',
+                'file' => ['existing'],
+            ],
+            'deep' => [
+                0 => [
+                    'name' => 'deep 1',
+                    'file' => ['existing'],
+                ],
+                1 => [
+                    'name' => 'deep 2',
+                ],
+            ],
+            1 => [
+                'name' => 'numeric nested',
+            ],
+        ];
+
+        $expected = [
+            'flat' => new UploadedFile(
+                __FILE__,
+                1,
+                0,
+                'flat.txt',
+                'text/plain'
+            ),
+            'nested' => [
+                'name' => 'nested',
+                'file' => new UploadedFile(
+                    __FILE__,
+                    12,
+                    0,
+                    'nested.txt',
+                    'text/plain'
+                ),
+            ],
+            'deep' => [
+                0 => [
+                    'name' => 'deep 1',
+                    'file' => new UploadedFile(
+                        __FILE__,
+                        12345,
+                        0,
+                        'deep-1.txt',
+                        'text/plain'
+                    ),
+                ],
+                1 => [
+                    'name' => 'deep 2',
+                    'file' => new UploadedFile(
+                        __FILE__,
+                        123456,
+                        0,
+                        'deep-2.txt',
+                        'text/plain'
+                    ),
+                ],
+            ],
+            0 => new UploadedFile(
+                __FILE__,
+                123,
+                0,
+                'numeric.txt',
+                'text/plain'
+            ),
+            1 => [
+                'name' => 'numeric nested',
+                'file' => new UploadedFile(
+                    __FILE__,
+                    1234,
+                    0,
+                    'numeric-nested.txt',
+                    'text/plain'
+                ),
+            ],
+        ];
+
+        $request = ServerRequestFactory::fromGlobals([], [], $post, [], $files);
+
+        $this->assertEquals($expected, $request->getData());
+    }
+
+    /**
+     * Test passing invalid files list structure.
+     *
+     * @return void
+     */
+    public function testFilesWithInvalidStructure()
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Invalid value in files specification');
+
+        ServerRequestFactory::fromGlobals([], [], [], [], [
+            [
+                'invalid' => [
+                    'data',
+                ],
+            ],
+        ]);
+    }
 }

+ 0 - 363
tests/TestCase/Http/ServerRequestTest.php

@@ -348,185 +348,6 @@ class ServerRequestTest extends TestCase
     }
 
     /**
-     * Test processing files with `file` field names.
-     *
-     * @return void
-     */
-    public function testFilesNested()
-    {
-        $files = [
-            'image_main' => [
-                'name' => ['file' => 'born on.txt'],
-                'type' => ['file' => 'text/plain'],
-                'tmp_name' => ['file' => __FILE__],
-                'error' => ['file' => 0],
-                'size' => ['file' => 17178],
-            ],
-            0 => [
-                'name' => ['image' => 'scratch.text'],
-                'type' => ['image' => 'text/plain'],
-                'tmp_name' => ['image' => __FILE__],
-                'error' => ['image' => 0],
-                'size' => ['image' => 1490],
-            ],
-            'pictures' => [
-                'name' => [
-                    0 => ['file' => 'a-file.png'],
-                    1 => ['file' => 'a-moose.png'],
-                ],
-                'type' => [
-                    0 => ['file' => 'image/png'],
-                    1 => ['file' => 'image/jpg'],
-                ],
-                'tmp_name' => [
-                    0 => ['file' => __FILE__],
-                    1 => ['file' => __FILE__],
-                ],
-                'error' => [
-                    0 => ['file' => 0],
-                    1 => ['file' => 0],
-                ],
-                'size' => [
-                    0 => ['file' => 17188],
-                    1 => ['file' => 2010],
-                ],
-            ],
-        ];
-        $post = [
-            'pictures' => [
-                0 => ['name' => 'A cat'],
-                1 => ['name' => 'A moose'],
-            ],
-            0 => [
-                'name' => 'A dog',
-            ],
-        ];
-        $request = new ServerRequest(compact('files', 'post') + ['mergeFilesAsObjects' => false]);
-        $expected = [
-            'image_main' => [
-                'file' => [
-                    'name' => 'born on.txt',
-                    'type' => 'text/plain',
-                    'tmp_name' => __FILE__,
-                    'error' => 0,
-                    'size' => 17178,
-                ],
-            ],
-            'pictures' => [
-                0 => [
-                    'name' => 'A cat',
-                    'file' => [
-                        'name' => 'a-file.png',
-                        'type' => 'image/png',
-                        'tmp_name' => __FILE__,
-                        'error' => '0',
-                        'size' => 17188,
-                    ],
-                ],
-                1 => [
-                    'name' => 'A moose',
-                    'file' => [
-                        'name' => 'a-moose.png',
-                        'type' => 'image/jpg',
-                        'tmp_name' => __FILE__,
-                        'error' => '0',
-                        'size' => 2010,
-                    ],
-                ],
-            ],
-            0 => [
-                'name' => 'A dog',
-                'image' => [
-                    'name' => 'scratch.text',
-                    'type' => 'text/plain',
-                    'tmp_name' => __FILE__,
-                    'error' => 0,
-                    'size' => 1490,
-                ],
-            ],
-        ];
-        $this->assertEquals($expected, $request->getData());
-
-        $uploads = $request->getUploadedFiles();
-        $this->assertCount(3, $uploads);
-        $this->assertArrayHasKey(0, $uploads);
-        $this->assertSame('scratch.text', $uploads[0]['image']->getClientFilename());
-
-        $this->assertArrayHasKey('pictures', $uploads);
-        $this->assertSame('a-file.png', $uploads['pictures'][0]['file']->getClientFilename());
-        $this->assertSame('a-moose.png', $uploads['pictures'][1]['file']->getClientFilename());
-
-        $this->assertArrayHasKey('image_main', $uploads);
-        $this->assertSame('born on.txt', $uploads['image_main']['file']->getClientFilename());
-    }
-
-    /**
-     * Test processing a file input with no .'s in it.
-     *
-     * @return void
-     */
-    public function testFilesFlat()
-    {
-        $files = [
-            'birth_cert' => [
-                'name' => 'born on.txt',
-                'type' => 'application/octet-stream',
-                'tmp_name' => __FILE__,
-                'error' => 0,
-                'size' => 123,
-            ],
-        ];
-
-        $request = new ServerRequest(['files' => $files, 'mergeFilesAsObjects' => false]);
-        $expected = [
-            'birth_cert' => [
-                'name' => 'born on.txt',
-                'type' => 'application/octet-stream',
-                'tmp_name' => __FILE__,
-                'error' => 0,
-                'size' => 123,
-            ],
-        ];
-        $this->assertEquals($expected, $request->getData());
-
-        $uploads = $request->getUploadedFiles();
-        $this->assertCount(1, $uploads);
-        $this->assertArrayHasKey('birth_cert', $uploads);
-        $this->assertSame('born on.txt', $uploads['birth_cert']->getClientFilename());
-        $this->assertSame(0, $uploads['birth_cert']->getError());
-        $this->assertSame('application/octet-stream', $uploads['birth_cert']->getClientMediaType());
-        $this->assertEquals(123, $uploads['birth_cert']->getSize());
-    }
-
-    /**
-     * Test that files in the 0th index work.
-     *
-     * @return void
-     */
-    public function testFilesZeroithIndex()
-    {
-        $files = [
-            0 => [
-                'name' => 'cake_sqlserver_patch.patch',
-                'type' => 'text/plain',
-                'tmp_name' => __FILE__,
-                'error' => 0,
-                'size' => 6271,
-            ],
-        ];
-
-        $request = new ServerRequest([
-            'files' => $files,
-            'mergeFilesAsObjects' => false,
-        ]);
-        $this->assertEquals($files, $request->getData());
-
-        $uploads = $request->getUploadedFiles();
-        $this->assertCount(1, $uploads);
-        $this->assertEquals($files[0]['name'], $uploads[0]->getClientFilename());
-    }
-
-    /**
      * Test that the constructor uses uploaded file objects
      * if they are present. This could happen in test scenarios.
      *
@@ -546,21 +367,6 @@ class ServerRequestTest extends TestCase
     }
 
     /**
-     * Test passing an invalid data type for the files list.
-     *
-     * @return void
-     */
-    public function testFilesWithInvalidDataType()
-    {
-        $request = new ServerRequest([
-            'files' => 'invalid',
-        ]);
-
-        $this->assertEmpty($request->getData());
-        $this->assertEmpty($request->getUploadedFiles());
-    }
-
-    /**
      * Test passing an empty files list.
      *
      * @return void
@@ -576,175 +382,6 @@ class ServerRequestTest extends TestCase
     }
 
     /**
-     * Test passing invalid files list structure.
-     *
-     * @return void
-     */
-    public function testFilesWithInvalidStructure()
-    {
-        $this->expectException(\InvalidArgumentException::class);
-        $this->expectExceptionMessage('Invalid value in FILES "{"invalid":["data"]}"');
-
-        new ServerRequest([
-            'files' => [
-                [
-                    'invalid' => [
-                        'data',
-                    ],
-                ],
-            ],
-        ]);
-    }
-
-    /**
-     * Tests that file uploads are merged into the post data as objects instead of as arrays.
-     *
-     * @return void
-     */
-    public function testFilesAsObjectsInRequestData()
-    {
-        $files = [
-            'flat' => [
-                'name' => 'flat.txt',
-                'type' => 'text/plain',
-                'tmp_name' => __FILE__,
-                'error' => 0,
-                'size' => 1,
-            ],
-            'nested' => [
-                'name' => ['file' => 'nested.txt'],
-                'type' => ['file' => 'text/plain'],
-                'tmp_name' => ['file' => __FILE__],
-                'error' => ['file' => 0],
-                'size' => ['file' => 12],
-            ],
-            0 => [
-                'name' => 'numeric.txt',
-                'type' => 'text/plain',
-                'tmp_name' => __FILE__,
-                'error' => 0,
-                'size' => 123,
-            ],
-            1 => [
-                'name' => ['file' => 'numeric-nested.txt'],
-                'type' => ['file' => 'text/plain'],
-                'tmp_name' => ['file' => __FILE__],
-                'error' => ['file' => 0],
-                'size' => ['file' => 1234],
-            ],
-            'deep' => [
-                'name' => [
-                    0 => ['file' => 'deep-1.txt'],
-                    1 => ['file' => 'deep-2.txt'],
-                ],
-                'type' => [
-                    0 => ['file' => 'text/plain'],
-                    1 => ['file' => 'text/plain'],
-                ],
-                'tmp_name' => [
-                    0 => ['file' => __FILE__],
-                    1 => ['file' => __FILE__],
-                ],
-                'error' => [
-                    0 => ['file' => 0],
-                    1 => ['file' => 0],
-                ],
-                'size' => [
-                    0 => ['file' => 12345],
-                    1 => ['file' => 123456],
-                ],
-            ],
-        ];
-
-        $post = [
-            'flat' => ['existing'],
-            'nested' => [
-                'name' => 'nested',
-                'file' => ['existing'],
-            ],
-            'deep' => [
-                0 => [
-                    'name' => 'deep 1',
-                    'file' => ['existing'],
-                ],
-                1 => [
-                    'name' => 'deep 2',
-                ],
-            ],
-            1 => [
-                'name' => 'numeric nested',
-            ],
-        ];
-
-        $expected = [
-            'flat' => new UploadedFile(
-                __FILE__,
-                1,
-                0,
-                'flat.txt',
-                'text/plain'
-            ),
-            'nested' => [
-                'name' => 'nested',
-                'file' => new UploadedFile(
-                    __FILE__,
-                    12,
-                    0,
-                    'nested.txt',
-                    'text/plain'
-                ),
-            ],
-            'deep' => [
-                0 => [
-                    'name' => 'deep 1',
-                    'file' => new UploadedFile(
-                        __FILE__,
-                        12345,
-                        0,
-                        'deep-1.txt',
-                        'text/plain'
-                    ),
-                ],
-                1 => [
-                    'name' => 'deep 2',
-                    'file' => new UploadedFile(
-                        __FILE__,
-                        123456,
-                        0,
-                        'deep-2.txt',
-                        'text/plain'
-                    ),
-                ],
-            ],
-            0 => new UploadedFile(
-                __FILE__,
-                123,
-                0,
-                'numeric.txt',
-                'text/plain'
-            ),
-            1 => [
-                'name' => 'numeric nested',
-                'file' => new UploadedFile(
-                    __FILE__,
-                    1234,
-                    0,
-                    'numeric-nested.txt',
-                    'text/plain'
-                ),
-            ],
-        ];
-
-        $request = new ServerRequest([
-            'files' => $files,
-            'post' => $post,
-            'mergeFilesAsObjects' => true,
-        ]);
-
-        $this->assertEquals($expected, $request->getData());
-    }
-
-    /**
      * Test replacing files.
      *
      * @return void