Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[HttpKernel] Fatal Error when using #[MapUploadedFile] with non-array/non-variadic argument #57824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: 7.1
Choose a base branch
from

Conversation

melya
Copy link
Contributor

@melya melya commented Jul 25, 2024

Q A
Branch? 7.1
Bug fix? yes
New feature? no
Deprecations? no
License MIT

Having a simple controller with MapUploadedFile as non-array.
When the file is omitted in request, symfony throws ValueError because resolver returns an empty array and it doesn't match with UploadedFile $file.

In my opinion, the HttpException should be thrown in this case.
For array argument the behaviour stays the same.

#[AsController]
#[Route(path: "/upload", methods: ["post"])]
final class Upload
{
    public function __invoke(
        #[MapUploadedFile()]
        UploadedFile $file,
    ): Response {
        ...
    }
}

Example with omitted file - ValueError occurs here

POST /upload HTTP/1.1
Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__

Error example

App\Controller\Upload::__invoke(): 
Argument #2 ($file) must be of type Symfony\Component\HttpFoundation\File\UploadedFile, array given, 
called in /app/vendor/symfony/http-kernel/HttpKernel.php on line 183 (500 Internal Server Error)

@melya
Copy link
Contributor Author

melya commented Jul 25, 2024

#[MapUploadedFile] was introduced with #49978.

@renedelima Thanks for this feature 💪 .
Could you please check my fix to ensure I haven't missed any initial ideas?

@melya melya changed the title [HttpKernel] Fix resolving of MapUploadedFile for non-array/non-variadic arguments [HttpKernel] Fix resolving of MapUploadedFile for non-array/non-variadic arguments Jul 29, 2024
@melya melya changed the title [HttpKernel] Fix resolving of MapUploadedFile for non-array/non-variadic arguments [HttpKernel] Fix resolving of #[MapUploadedFile] for non-array/non-variadic arguments Jul 29, 2024
@melya melya changed the title [HttpKernel] Fix resolving of #[MapUploadedFile] for non-array/non-variadic arguments [HttpKernel] Fatal Error when using #[MapUploadedFile] as non-array/non-variadic argument Jul 29, 2024
@melya melya changed the title [HttpKernel] Fatal Error when using #[MapUploadedFile] as non-array/non-variadic argument [HttpKernel] Fatal Error when using #[MapUploadedFile] with non-array/non-variadic argument Jul 29, 2024
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I just have minor comments.

if (!(is_array($payload) && array_is_list($payload))) {
throw HttpException::fromStatusCode(422);
}
array_splice($arguments, $i, count($payload), $payload);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't array_merge be more appropriate?

Suggested change
array_splice($arguments, $i, count($payload), $payload);
array_splice($arguments, $i, \count($payload), $payload);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish it work, here I put more details #54901 (comment)

@@ -68,7 +68,7 @@ public function testEmpty(RequestPayloadValueResolver $resolver, Request $reques
$attribute = new MapUploadedFile();
$argument = new ArgumentMetadata(
'qux',
UploadedFile::class,
"array",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"array",
'array',

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be spotted by fabbot? 🤔

}
array_splice($arguments, $i, count($payload), $payload);
} else {
$arguments[$i] = $payload;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the situation when the argument is UploadedFile and the $payload is an array of files? I think this would still result in a 500?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting 🤔
Is it possible to have UploadedFile as part of #[MapRequestPayload] $payload? (#[MapQuery] we can exclude, I guess)
Could you please share an example of what you mean, so I can elaborate more on this ?

@@ -170,7 +170,14 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
};
}

$arguments[$i] = $payload;
if ($argument->metadata->isVariadic()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check if it is variadic as well as if the type is an array here, similar to the check in the mapUploadedFile method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically $arguments here are original arguments of an action.
In example below $arguments = [$request, $payload, $files];

public function action(
 Request $request,
 #[MapRequestPayload] Payload $payload,
 #[MapUploadedFile] UploadedFile ...$files]
) {
   ...
}

And the magic here is to expand variadic $files into several items of $arguments.
I hope PHP won't change mechanics of how variadic works and it will be always only 1 possible variadic argument in function signature 🤞

Also, there is already an ability to use #[MapUploadedFile] as bellow. And it works and covered by UploadedFileValueResolverTest::testMultipleFilesArray test case.

public function action(
 Request $request,
 #[MapRequestPayload] Payload $payload,
 /** @var UploadedFile[] */
 #[MapUploadedFile] array $files]
) {
   ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested variant

final class TestPayloadRequest
{
    public UploadedFile $file;
}

final class IndexController extends AbstractController
{
    #[Route(path: "/test-upload", methods: "POST")]
    public function testUpload(
        #[MapRequestPayload] TestPayloadRequest $file,
        #[MapUploadedFile] UploadedFile ...$files,
    ): Response {
        return new Response();
    }
}

with request like

POST /test-upload HTTP/1.1
Cookie: XDEBUG_SESSION=PHPSTORM;
Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__

--__X_PAW_BOUNDARY__
Content-Disposition: form-data; name="files[]"; filename="test.yaml"
Content-Type: application/x-yaml

info: test
--__X_PAW_BOUNDARY__
Content-Disposition: form-data; name="file"; filename="test.yaml"
Content-Type: application/x-yaml

info: test
--__X_PAW_BOUNDARY__
Content-Disposition: form-data; name="files[]"; filename="test.yaml"
Content-Type: application/x-yaml

info: test

Shortly: current implementation is not designed to work like this, because data for #[MapRequestPayload]
is fetched like this :

https://github.com/melya/symfony/blob/fix-map-uploaded-file-in-request-payload-resolver2/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php?plain=1#L212-L232

@melya
Copy link
Contributor Author

melya commented Aug 29, 2024

Seems like failed tests are unrelated to my changes

@melya
Copy link
Contributor Author

melya commented Sep 13, 2024

@nicolas-grekas @stetodd friendly reminder ;)

@melya melya force-pushed the fix-map-uploaded-file-in-request-payload-resolver2 branch from faa10b6 to 93d4190 Compare September 24, 2024 14:22
@melya
Copy link
Contributor Author

melya commented Nov 4, 2024

any updates?

@nicolas-grekas nicolas-grekas modified the milestones: 7.1, 7.2 Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants