Skip to content

Commit ee888e1

Browse files
mfbnicolas-grekas
authored andcommitted
Fix handling requests with nested files
1 parent 1ce09e7 commit ee888e1

File tree

2 files changed

+64
-25
lines changed

2 files changed

+64
-25
lines changed

src/Psr17Factory.php

+45-24
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,15 @@ private function buildServerRequestFromGlobals(ServerRequestInterface $request,
184184
->withUploadedFiles($this->normalizeFiles($files));
185185

186186
$headers = [];
187-
foreach ($server as $key => $value) {
188-
if (0 === strpos($key, 'HTTP_')) {
189-
$key = substr($key, 5);
190-
} elseif (!\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
187+
foreach ($server as $k => $v) {
188+
if (0 === strpos($k, 'HTTP_')) {
189+
$k = substr($k, 5);
190+
} elseif (!\in_array($k, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
191191
continue;
192192
}
193-
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
193+
$k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
194194

195-
$headers[$key] = $value;
195+
$headers[$k] = $v;
196196
}
197197

198198
if (!isset($headers['Authorization'])) {
@@ -205,9 +205,9 @@ private function buildServerRequestFromGlobals(ServerRequestInterface $request,
205205
}
206206
}
207207

208-
foreach ($headers as $key => $value) {
208+
foreach ($headers as $k => $v) {
209209
try {
210-
$request = $request->withHeader($key, $value);
210+
$request = $request->withHeader($k, $v);
211211
} catch (\InvalidArgumentException $e) {
212212
// ignore invalid headers
213213
}
@@ -257,26 +257,47 @@ private function buildUriFromGlobals(UriInterface $uri, array $server): UriInter
257257

258258
private function normalizeFiles(array $files): array
259259
{
260-
$normalized = [];
261-
262-
foreach ($files as $key => $value) {
263-
if ($value instanceof UploadedFileInterface) {
264-
$normalized[$key] = $value;
265-
} elseif (!\is_array($value)) {
260+
foreach ($files as $k => $v) {
261+
if ($v instanceof UploadedFileInterface) {
266262
continue;
267-
} elseif (!isset($value['tmp_name'])) {
268-
$normalized[$key] = $this->normalizeFiles($value);
269-
} elseif (\is_array($value['tmp_name'])) {
270-
foreach ($value['tmp_name'] as $k => $v) {
271-
$file = $this->createStreamFromFile($value['tmp_name'][$k], 'r');
272-
$normalized[$key][$k] = $this->createUploadedFile($file, $value['size'][$k], $value['error'][$k], $value['name'][$k], $value['type'][$k]);
273-
}
263+
}
264+
if (!\is_array($v)) {
265+
unset($files[$k]);
266+
} elseif (!isset($v['tmp_name'])) {
267+
$files[$k] = $this->normalizeFiles($v);
274268
} else {
275-
$file = $this->createStreamFromFile($value['tmp_name'], 'r');
276-
$normalized[$key] = $this->createUploadedFile($file, $value['size'], $value['error'], $value['name'], $value['type']);
269+
$files[$k] = $this->createUploadedFileFromSpec($v);
277270
}
278271
}
279272

280-
return $normalized;
273+
return $files;
274+
}
275+
276+
/**
277+
* Create and return an UploadedFile instance from a $_FILES specification.
278+
*
279+
* @param array $value $_FILES struct
280+
*
281+
* @return UploadedFileInterface|UploadedFileInterface[]
282+
*/
283+
private function createUploadedFileFromSpec(array $value)
284+
{
285+
if (!is_array($tmpName = $value['tmp_name'])) {
286+
$file = $this->createStreamFromFile($tmpName, 'r');
287+
288+
return $this->createUploadedFile($file, $value['size'], $value['error'], $value['name'], $value['type']);
289+
}
290+
291+
foreach ($tmpName as $k => $v) {
292+
$tmpName[$k] = $this->createUploadedFileFromSpec([
293+
'tmp_name' => $v,
294+
'size' => $value['size'][$k] ?? null,
295+
'error' => $value['error'][$k] ?? null,
296+
'name' => $value['name'][$k] ?? null,
297+
'type' => $value['type'][$k] ?? null,
298+
]);
299+
}
300+
301+
return $tmpName;
281302
}
282303
}

tests/Psr17FactoryTest.php

+19-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,14 @@ public function testFromGlobals()
285285
'tmp_name' => 'php://memory',
286286
'error' => UPLOAD_ERR_OK,
287287
'size' => 123,
288-
]
288+
],
289+
'files' => [
290+
'name' => ['file_0' => ['NestedFile.txt']],
291+
'type' => ['file_0' => ['text/plain']],
292+
'tmp_name' => ['file_0' => ['php://memory']],
293+
'error' => ['file_0' => [UPLOAD_ERR_OK]],
294+
'size' => ['file_0' => [123]],
295+
],
289296
];
290297

291298
$factory = new Psr17Factory();
@@ -318,6 +325,17 @@ public function testFromGlobals()
318325
'MyFile.txt',
319326
'text/plain'
320327
),
328+
'files' => [
329+
'file_0' => [
330+
$factory->createUploadedFile(
331+
$server->getUploadedFiles()['files']['file_0'][0]->getStream(),
332+
123,
333+
UPLOAD_ERR_OK,
334+
'NestedFile.txt',
335+
'text/plain'
336+
),
337+
],
338+
],
321339
];
322340

323341
self::assertEquals($expectedFiles, $server->getUploadedFiles());

0 commit comments

Comments
 (0)