Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 63d920d

Browse files
committed
Merge branch 'hotfix/312-normalize-nested-uploaded-files'
Close #312 Fixes #311
2 parents 43c791e + 2bbccb7 commit 63d920d

File tree

3 files changed

+212
-16
lines changed

3 files changed

+212
-16
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
All notable changes to this project will be documented in this file, in reverse chronological order by release.
44

5-
## 1.8.1 - TBD
5+
## 1.8.1 - 2018-07-09
66

77
### Added
88

@@ -23,7 +23,8 @@ All notable changes to this project will be documented in this file, in reverse
2323

2424
### Fixed
2525

26-
- Nothing.
26+
- [#312](https://github.com/zendframework/zend-diactoros/pull/312) fixes how the `normalizeUploadedFiles()` utility function handles nested trees of
27+
uploaded files, ensuring it detects them properly.
2728

2829
## 1.8.0 - 2018-06-27
2930

src/functions/normalize_uploaded_files.php

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,47 @@
2424
*/
2525
function normalizeUploadedFiles(array $files)
2626
{
27+
/**
28+
* Traverse a nested tree of uploaded file specifications.
29+
*
30+
* @param string[]|array[] $tmpNameTree
31+
* @param int[]|array[] $sizeTree
32+
* @param int[]|array[] $errorTree
33+
* @param string[]|array[]|null $nameTree
34+
* @param string[]|array[]|null $typeTree
35+
* @return UploadedFile[]|array[]
36+
*/
37+
$recursiveNormalize = function (
38+
array $tmpNameTree,
39+
array $sizeTree,
40+
array $errorTree,
41+
array $nameTree = null,
42+
array $typeTree = null
43+
) use (&$recursiveNormalize) {
44+
$normalized = [];
45+
foreach ($tmpNameTree as $key => $value) {
46+
if (is_array($value)) {
47+
// Traverse
48+
$normalized[$key] = $recursiveNormalize(
49+
$tmpNameTree[$key],
50+
$sizeTree[$key],
51+
$errorTree[$key],
52+
isset($nameTree[$key]) ? $nameTree[$key] : null,
53+
isset($typeTree[$key]) ? $typeTree[$key] : null
54+
);
55+
continue;
56+
}
57+
$normalized[$key] = createUploadedFile([
58+
'tmp_name' => $tmpNameTree[$key],
59+
'size' => $sizeTree[$key],
60+
'error' => $errorTree[$key],
61+
'name' => isset($nameTree[$key]) ? $nameTree[$key] : null,
62+
'type' => isset($typeTree[$key]) ? $typeTree[$key] : null
63+
]);
64+
}
65+
return $normalized;
66+
};
67+
2768
/**
2869
* Normalize an array of file specifications.
2970
*
@@ -38,7 +79,7 @@ function normalizeUploadedFiles(array $files)
3879
* @param array $files
3980
* @return UploadedFile[]
4081
*/
41-
$normalizeUploadedFileSpecification = function (array $files = []) {
82+
$normalizeUploadedFileSpecification = function (array $files = []) use (&$recursiveNormalize) {
4283
if (! isset($files['tmp_name']) || ! is_array($files['tmp_name'])
4384
|| ! isset($files['size']) || ! is_array($files['size'])
4485
|| ! isset($files['error']) || ! is_array($files['error'])
@@ -51,19 +92,13 @@ function normalizeUploadedFiles(array $files)
5192
));
5293
}
5394

54-
55-
$normalized = [];
56-
foreach (array_keys($files['tmp_name']) as $key) {
57-
$spec = [
58-
'tmp_name' => $files['tmp_name'][$key],
59-
'size' => $files['size'][$key],
60-
'error' => $files['error'][$key],
61-
'name' => isset($files['name'][$key]) ? $files['name'][$key] : null,
62-
'type' => isset($files['type'][$key]) ? $files['type'][$key] : null,
63-
];
64-
$normalized[$key] = createUploadedFile($spec);
65-
}
66-
return $normalized;
95+
return $recursiveNormalize(
96+
$files['tmp_name'],
97+
$files['size'],
98+
$files['error'],
99+
isset($files['name']) ? $files['name'] : null,
100+
isset($files['type']) ? $files['type'] : null
101+
);
67102
};
68103

69104
$normalized = [];
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
4+
* @copyright Copyright (c) 2018 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
namespace ZendTest\Diactoros;
9+
10+
use PHPUnit\Framework\TestCase;
11+
use Psr\Http\Message\UploadedFileInterface;
12+
13+
use function Zend\Diactoros\normalizeUploadedFiles;
14+
15+
class NormalizeUploadedFilesTest extends TestCase
16+
{
17+
public function testCreatesUploadedFileFromFlatFileSpecification()
18+
{
19+
$files = [
20+
'avatar' => [
21+
'tmp_name' => 'phpUxcOty',
22+
'name' => 'my-avatar.png',
23+
'size' => 90996,
24+
'type' => 'image/png',
25+
'error' => 0,
26+
],
27+
];
28+
29+
$normalised = normalizeUploadedFiles($files);
30+
31+
$this->assertCount(1, $normalised);
32+
$this->assertInstanceOf(UploadedFileInterface::class, $normalised['avatar']);
33+
$this->assertEquals('my-avatar.png', $normalised['avatar']->getClientFilename());
34+
}
35+
36+
public function testTraversesNestedFileSpecificationToExtractUploadedFile()
37+
{
38+
$files = [
39+
'my-form' => [
40+
'details' => [
41+
'avatar' => [
42+
'tmp_name' => 'phpUxcOty',
43+
'name' => 'my-avatar.png',
44+
'size' => 90996,
45+
'type' => 'image/png',
46+
'error' => 0,
47+
],
48+
],
49+
],
50+
];
51+
52+
$normalised = normalizeUploadedFiles($files);
53+
54+
$this->assertCount(1, $normalised);
55+
$this->assertEquals('my-avatar.png', $normalised['my-form']['details']['avatar']->getClientFilename());
56+
}
57+
58+
public function testTraversesNestedFileSpecificationContainingNumericIndicesToExtractUploadedFiles()
59+
{
60+
$files = [
61+
'my-form' => [
62+
'details' => [
63+
'avatars' => [
64+
'tmp_name' => [
65+
0 => 'abc123',
66+
1 => 'duck123',
67+
2 => 'goose123',
68+
],
69+
'name' => [
70+
0 => 'file1.txt',
71+
1 => 'file2.txt',
72+
2 => 'file3.txt',
73+
],
74+
'size' => [
75+
0 => 100,
76+
1 => 240,
77+
2 => 750,
78+
],
79+
'type' => [
80+
0 => 'plain/txt',
81+
1 => 'image/jpg',
82+
2 => 'image/png',
83+
],
84+
'error' => [
85+
0 => 0,
86+
1 => 0,
87+
2 => 0,
88+
],
89+
],
90+
],
91+
],
92+
];
93+
94+
$normalised = normalizeUploadedFiles($files);
95+
96+
$this->assertCount(3, $normalised['my-form']['details']['avatars']);
97+
$this->assertEquals('file1.txt', $normalised['my-form']['details']['avatars'][0]->getClientFilename());
98+
$this->assertEquals('file2.txt', $normalised['my-form']['details']['avatars'][1]->getClientFilename());
99+
$this->assertEquals('file3.txt', $normalised['my-form']['details']['avatars'][2]->getClientFilename());
100+
}
101+
102+
/**
103+
* This case covers upfront numeric index which moves the tmp_name/size/etc
104+
* fields further up the array tree
105+
*/
106+
public function testTraversesDenormalizedNestedTreeOfIndicesToExtractUploadedFiles()
107+
{
108+
$files = [
109+
'slide-shows' => [
110+
'tmp_name' => [
111+
// Note: Nesting *under* tmp_name/etc
112+
0 => [
113+
'slides' => [
114+
0 => '/tmp/phpYzdqkD',
115+
1 => '/tmp/phpYzdfgh',
116+
],
117+
],
118+
],
119+
'error' => [
120+
0 => [
121+
'slides' => [
122+
0 => 0,
123+
1 => 0,
124+
],
125+
],
126+
],
127+
'name' => [
128+
0 => [
129+
'slides' => [
130+
0 => 'foo.txt',
131+
1 => 'bar.txt',
132+
],
133+
],
134+
],
135+
'size' => [
136+
0 => [
137+
'slides' => [
138+
0 => 123,
139+
1 => 200,
140+
],
141+
],
142+
],
143+
'type' => [
144+
0 => [
145+
'slides' => [
146+
0 => 'text/plain',
147+
1 => 'text/plain',
148+
],
149+
],
150+
],
151+
],
152+
];
153+
154+
$normalised = normalizeUploadedFiles($files);
155+
156+
$this->assertCount(2, $normalised['slide-shows'][0]['slides']);
157+
$this->assertEquals('foo.txt', $normalised['slide-shows'][0]['slides'][0]->getClientFilename());
158+
$this->assertEquals('bar.txt', $normalised['slide-shows'][0]['slides'][1]->getClientFilename());
159+
}
160+
}

0 commit comments

Comments
 (0)