Skip to content

Support for multipart/form-data in non-POST requests using request_parse_body() (PHP 8.4) #59331

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
rottifant opened this issue Dec 30, 2024 · 4 comments · May be fixed by #59358
Open

Support for multipart/form-data in non-POST requests using request_parse_body() (PHP 8.4) #59331

rottifant opened this issue Dec 30, 2024 · 4 comments · May be fixed by #59358

Comments

@rottifant
Copy link

Description

Symfony's Request class currently does not natively handle multipart/form-data for non-POST (PUT/PATCH) requests. Developers are forced to rely on workarounds, such as method spoofing (_method=PUT, see the $httpMethodParameterOverride option in symfony/http-foundation/Request.php).

This limitation stems from PHP itself, which historically hasn't supported parsing multipart/form-data for methods other than POST. However, as of PHP 8.4, the new request_parse_body() function was introduced tackle this issue.

I found issue #9226, which was locked in 2023 and discussed this limitation. With the introduction of request_parse_body(), this could now be revisited.

References:
PHP Bug 55815
request_parse_body() on PHP.Watch

Example

A small example what request_parse_body() does. This is just a demo implementation in symfony/http-foundation/Request.php createFromGlobals() to demonstrate the effect with PUT and PATCH requests:

public static function createFromGlobals(): static
{
    $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);

    if (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded')
        && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'], true)
    ) {
        parse_str($request->getContent(), $data);
        $request->request = new InputBag($data);
    }
    
+   if (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'multipart/form-data')
+       && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'PATCH'], true)
+       && function_exists('request_parse_body')
+   ) {
+       [$post, $files] = request_parse_body();
+       $request->request = new InputBag($post);
+       $request->files = new FileBag($files);
+   }

    return $request;
}
@faizanakram99
Copy link
Contributor

@rottifant sounds like a good idea, and seems very little changes are needed to support it. I'd suggest to create a PR.

@fabpot
Copy link
Member

fabpot commented Dec 31, 2024

@rottifant Please go ahead and submit a PR. That would ease reviews.

@rottifant
Copy link
Author

rottifant commented Jan 3, 2025

I am going to open a new PR.

For reference:

@florian2peaches
Copy link

#58724 see this as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants