Skip to content
Permalink
Browse files

Update Request file processing to use objects.

Internally we can use PSR7 UploadedFile objects so that uploaded request
files can be accessed in the PSR7 compliant way. We'll also need to
downsample into an array for backwards compatibility.
  • Loading branch information...
markstory committed Sep 4, 2016
1 parent 7910ce9 commit 07741a3ab896237e52d93e8b32f499215583bff6
Showing with 82 additions and 48 deletions.
  1. +69 −35 src/Network/Request.php
  2. +13 −13 tests/TestCase/Network/RequestTest.php
@@ -19,6 +19,8 @@
use Cake\Core\Configure;
use Cake\Network\Exception\MethodNotAllowedException;
use Cake\Utility\Hash;
use Psr\Http\Message\UploadedFileInterface;
use Zend\Diactoros\UploadedFile;
use InvalidArgumentException;
/**
@@ -463,59 +465,91 @@ protected function _processFiles($post, $files)
if (!is_array($files)) {
return $post;
}
$fileData = [];
foreach ($files as $key => $data) {
foreach ($files as $key => $data) {
if (isset($data['tmp_name']) && is_string($data['tmp_name'])) {
$fileData[$key] = $data;
} else {
$keyData = isset($post[$key]) ? $post[$key] : [];
$fileData[$key] = $this->_processFileData($keyData, $data);
}
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)
));
}
// Make a flat map that can be inserted into $post for BC.
$fileMap = Hash::flatten($fileData);
foreach ($fileMap as $key => $file) {
$post = Hash::insert($post, $key, $file);
$error = $file->getError();
$tmpName = '';
if ($error === UPLOAD_ERR_OK) {
$tmpName = $file->getStream()->getMetadata('uri');
}
$post = Hash::insert($post, $key, [
'tmp_name' => $tmpName,
'error' => $error,
'name' => $file->getClientFilename(),
'type' => $file->getClientMediaType(),
'size' => $file->getSize(),
]);
}
return $post;
}
/**
* Recursively walks the FILES array restructuring the data
* into something sane and usable.
* Create an UploadedFile instance from a $_FILES array.
*
* @param array $data The data being built
* @param array $post The post data being traversed
* @param string $path The dot separated path to insert $data into.
* @param string $field The terminal field in the path. This is one of the
* $_FILES properties e.g. name, tmp_name, size, error
* @return array The restructured FILES data
* If the value represents an array of values, this method will
* recursively process the data.
*
* @param array $value $_FILES struct
* @return array|UploadedFileInterface
*/
protected function _processFileData($data, $post, $path = '', $field = '')
protected function _createUploadedFile(array $value)
{
foreach ($post as $key => $fields) {
$newField = $field;
$newPath = $path;
if ($path === '' && $newField === '') {
$newField = $key;
}
if ($field === $newField) {
$newPath .= '.' . $key;
}
if (is_array($fields)) {
$data = $this->_processFileData($data, $fields, $newPath, $newField);
} else {
$newPath = trim($newPath . '.' . $field, '.');
$data = Hash::insert($data, $newPath, $fields);
}
if (is_array($value['tmp_name'])) {
return $this->_normalizeNestedFiles($value);
}
return $data;
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 = [])
{
$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;
}
/**
@@ -360,14 +360,14 @@ public function testProcessFilesNested()
'image_main' => [
'name' => ['file' => 'born on.txt'],
'type' => ['file' => 'text/plain'],
'tmp_name' => ['file' => '/private/var/tmp/php'],
'tmp_name' => ['file' => __FILE__],
'error' => ['file' => 0],
'size' => ['file' => 17178]
],
0 => [
'name' => ['image' => 'scratch.text'],
'type' => ['image' => 'text/plain'],
'tmp_name' => ['image' => '/private/var/tmp/phpChIZPb'],
'tmp_name' => ['image' => __FILE__],
'error' => ['image' => 0],
'size' => ['image' => 1490]
],
@@ -381,12 +381,12 @@ public function testProcessFilesNested()
1 => ['file' => 'image/jpg']
],
'tmp_name' => [
0 => ['file' => '/tmp/file123'],
1 => ['file' => '/tmp/file234']
0 => ['file' => __FILE__],
1 => ['file' => __FILE__]
],
'error' => [
0 => ['file' => '0'],
1 => ['file' => '0']
0 => ['file' => 0],
1 => ['file' => 0]
],
'size' => [
0 => ['file' => 17188],
@@ -409,7 +409,7 @@ public function testProcessFilesNested()
'file' => [
'name' => 'born on.txt',
'type' => 'text/plain',
'tmp_name' => '/private/var/tmp/php',
'tmp_name' => __FILE__,
'error' => 0,
'size' => 17178,
]
@@ -420,7 +420,7 @@ public function testProcessFilesNested()
'file' => [
'name' => 'a-file.png',
'type' => 'image/png',
'tmp_name' => '/tmp/file123',
'tmp_name' => __FILE__,
'error' => '0',
'size' => 17188,
]
@@ -430,7 +430,7 @@ public function testProcessFilesNested()
'file' => [
'name' => 'a-moose.png',
'type' => 'image/jpg',
'tmp_name' => '/tmp/file234',
'tmp_name' => __FILE__,
'error' => '0',
'size' => 2010,
]
@@ -441,7 +441,7 @@ public function testProcessFilesNested()
'image' => [
'name' => 'scratch.text',
'type' => 'text/plain',
'tmp_name' => '/private/var/tmp/phpChIZPb',
'tmp_name' => __FILE__,
'error' => 0,
'size' => 1490
]
@@ -461,7 +461,7 @@ public function testProcessFilesFlat()
'birth_cert' => [
'name' => 'born on.txt',
'type' => 'application/octet-stream',
'tmp_name' => '/private/var/tmp/phpbsUWfH',
'tmp_name' => __FILE__,
'error' => 0,
'size' => 123,
]
@@ -472,7 +472,7 @@ public function testProcessFilesFlat()
'birth_cert' => [
'name' => 'born on.txt',
'type' => 'application/octet-stream',
'tmp_name' => '/private/var/tmp/phpbsUWfH',
'tmp_name' => __FILE__,
'error' => 0,
'size' => 123
]
@@ -491,7 +491,7 @@ public function testFilesZeroithIndex()
0 => [
'name' => 'cake_sqlserver_patch.patch',
'type' => 'text/plain',
'tmp_name' => '/private/var/tmp/phpy05Ywj',
'tmp_name' => __FILE__,
'error' => 0,
'size' => 6271,
],

0 comments on commit 07741a3

Please sign in to comment.
You can’t perform that action at this time.