Skip to content

Commit

Permalink
Fix handling requests with nested files
Browse files Browse the repository at this point in the history
  • Loading branch information
mfb authored and nicolas-grekas committed Apr 26, 2023
1 parent 1ce09e7 commit ee888e1
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 25 deletions.
69 changes: 45 additions & 24 deletions src/Psr17Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,15 @@ private function buildServerRequestFromGlobals(ServerRequestInterface $request,
->withUploadedFiles($this->normalizeFiles($files));

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

$headers[$key] = $value;
$headers[$k] = $v;
}

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

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

private function normalizeFiles(array $files): array
{
$normalized = [];

foreach ($files as $key => $value) {
if ($value instanceof UploadedFileInterface) {
$normalized[$key] = $value;
} elseif (!\is_array($value)) {
foreach ($files as $k => $v) {
if ($v instanceof UploadedFileInterface) {
continue;
} elseif (!isset($value['tmp_name'])) {
$normalized[$key] = $this->normalizeFiles($value);
} elseif (\is_array($value['tmp_name'])) {
foreach ($value['tmp_name'] as $k => $v) {
$file = $this->createStreamFromFile($value['tmp_name'][$k], 'r');
$normalized[$key][$k] = $this->createUploadedFile($file, $value['size'][$k], $value['error'][$k], $value['name'][$k], $value['type'][$k]);
}
}
if (!\is_array($v)) {
unset($files[$k]);
} elseif (!isset($v['tmp_name'])) {
$files[$k] = $this->normalizeFiles($v);
} else {
$file = $this->createStreamFromFile($value['tmp_name'], 'r');
$normalized[$key] = $this->createUploadedFile($file, $value['size'], $value['error'], $value['name'], $value['type']);
$files[$k] = $this->createUploadedFileFromSpec($v);
}
}

return $normalized;
return $files;
}

/**
* Create and return an UploadedFile instance from a $_FILES specification.
*
* @param array $value $_FILES struct
*
* @return UploadedFileInterface|UploadedFileInterface[]
*/
private function createUploadedFileFromSpec(array $value)
{
if (!is_array($tmpName = $value['tmp_name'])) {
$file = $this->createStreamFromFile($tmpName, 'r');

return $this->createUploadedFile($file, $value['size'], $value['error'], $value['name'], $value['type']);
}

foreach ($tmpName as $k => $v) {
$tmpName[$k] = $this->createUploadedFileFromSpec([
'tmp_name' => $v,
'size' => $value['size'][$k] ?? null,
'error' => $value['error'][$k] ?? null,
'name' => $value['name'][$k] ?? null,
'type' => $value['type'][$k] ?? null,
]);
}

return $tmpName;
}
}
20 changes: 19 additions & 1 deletion tests/Psr17FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,14 @@ public function testFromGlobals()
'tmp_name' => 'php://memory',
'error' => UPLOAD_ERR_OK,
'size' => 123,
]
],
'files' => [
'name' => ['file_0' => ['NestedFile.txt']],
'type' => ['file_0' => ['text/plain']],
'tmp_name' => ['file_0' => ['php://memory']],
'error' => ['file_0' => [UPLOAD_ERR_OK]],
'size' => ['file_0' => [123]],
],
];

$factory = new Psr17Factory();
Expand Down Expand Up @@ -318,6 +325,17 @@ public function testFromGlobals()
'MyFile.txt',
'text/plain'
),
'files' => [
'file_0' => [
$factory->createUploadedFile(
$server->getUploadedFiles()['files']['file_0'][0]->getStream(),
123,
UPLOAD_ERR_OK,
'NestedFile.txt',
'text/plain'
),
],
],
];

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

0 comments on commit ee888e1

Please sign in to comment.