Skip to content

Commit

Permalink
Support malformed multipart body for uploaded files too
Browse files Browse the repository at this point in the history
  • Loading branch information
mnapoli committed Jan 31, 2024
1 parent 30a3e47 commit 56df95e
Showing 1 changed file with 14 additions and 46 deletions.
60 changes: 14 additions & 46 deletions src/Event/Http/Psr7Bridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,28 +114,24 @@ private static function parseBodyAndUploadedFiles(HttpRequestEvent $event): arra
if (! $document->isMultiPart()) {
return [[], null];
}
$parsedBody = null;
$files = [];
$queryString = '';
foreach ($document->getParts() as $part) {
if ($part->isFile()) {
$tmpPath = tempnam(sys_get_temp_dir(), self::UPLOADED_FILES_PREFIX);
$tmpPath = tempnam(sys_get_temp_dir(), self::UPLOADED_FILES_PREFIX);
if ($tmpPath === false) {
throw new RuntimeException('Unable to create a temporary directory');
}
file_put_contents($tmpPath, $part->getBody());
$file = new UploadedFile($tmpPath, filesize($tmpPath), UPLOAD_ERR_OK, $part->getFileName(), $part->getMimeType());
self::parseKeyAndInsertValueInArray($files, $part->getName(), $file);
} else {
// Temporarily store as a query string so that we can use PHP's native parse_str function to parse keys
$queryString .= urlencode($part->getName()) . '=' . urlencode($part->getBody()) . '&';
if ($parsedBody === null) {
$parsedBody = [];
}
self::parseKeyAndInsertValueInArray($parsedBody, $part->getName(), $part->getBody());
}
}
if ($queryString !== '') {
$parsedBody = [];
parse_str($queryString, $parsedBody);
} else {
$parsedBody = null;
}
return [$files, $parsedBody];
}

Expand All @@ -144,42 +140,14 @@ private static function parseBodyAndUploadedFiles(HttpRequestEvent $event): arra
*/
private static function parseKeyAndInsertValueInArray(array &$array, string $key, mixed $value): void
{
if (! str_contains($key, '[')) {
$array[$key] = $value;

return;
}

$parts = explode('[', $key); // files[id_cards][jpg][] => [ 'files', 'id_cards]', 'jpg]', ']' ]
$pointer = &$array;

foreach ($parts as $k => $part) {
if ($k === 0) {
$pointer = &$pointer[$part];

continue;
}

// Skip two special cases:
// [[ in the key produces empty string
// [test : starts with [ but does not end with ]
if ($part === '' || ! str_ends_with($part, ']')) {
// Malformed key, we use it "as is"
$array[$key] = $value;

return;
}

$part = substr($part, 0, -1); // The last char is a ] => remove it to have the real key

if ($part === '') { // [] case
$pointer = &$pointer[];
} else {
$pointer = &$pointer[$part];
}
}

$pointer = $value;
$parsed = [];
// We use parse_str to parse the key in the same way PHP does natively
// We use "=mock" because the value can be an object (in case of uploaded files)
parse_str(urlencode($key) . '=mock', $parsed);
// Replace `mock` with the actual value
array_walk_recursive($parsed, fn (&$v) => $v = $value);
// Merge recursively into the main array to avoid overwriting existing values
$array = array_merge_recursive($array, $parsed);
}

/**
Expand Down

0 comments on commit 56df95e

Please sign in to comment.