Skip to content

[Mime] FormDataPart and multidimensional arrays structure #34031

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

Closed
jvahldick opened this issue Oct 18, 2019 · 0 comments
Closed

[Mime] FormDataPart and multidimensional arrays structure #34031

jvahldick opened this issue Oct 18, 2019 · 0 comments

Comments

@jvahldick
Copy link
Contributor

Symfony version(s) affected: 4.3

Description
I have had some issues trying to send (POST) data collections using the HttpClient component together with the Mime component.
The problem itself, or what I believe is a problem, lives on the Mime component.

Let's say I want to send a collection of names to the backend. Usually, what I've done can be seen on the code below:

<input type="text" name="names[]" value="John" />
<input type="text" name="names[]" value="Doe" />

It generates the following results on the $_POST globals on php

[
    'names' => [
        'John', 'Doe'
    ]
]

This is actual the raw body of the request:

----------------------------466490401959219490193856
Content-Disposition: form-data; name="names[]"

John
----------------------------466490401959219490193856
Content-Disposition: form-data; name="names[]"

Doe
----------------------------466490401959219490193856--

So, I tried to do same using the Symfony HttpClient:

$httpClient = new CurlHttpClient([
    'headers' => [
        'Content-Type' => 'multipart/form-data'
    ]
]);

$formFields = [
    'names' => [
        'John',
        'Doe',
    ],
];

$formData = new FormDataPart($formFields);

$response = $httpClient->request('POST', 'https://eng9788fdqqri.x.pipedream.net/', [
    'headers' => $formData->getPreparedHeaders()->toArray(),
    'body' => $formData->bodyToIterable(),
]);

The raw body received on the server was:

--_=_symfony_1571410806_b9d8ed1979329f4173335201a24a9293_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data

John
--_=_symfony_1571410806_b9d8ed1979329f4173335201a24a9293_=_
Content-Type: text/plain; charset=utf-8; name=1
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=1

Doe
--_=_symfony_1571410806_b9d8ed1979329f4173335201a24a9293_=_--

Let's say I add more levels on the payload.

$formFields = [
    'people' => [
        [
            'forename' => 'John',
            'surname' => 'Doe',
            'visits' => [
                'Monday',
                'Tuesday',
            ]
        ],
        [
            'forename' => 'Foo',
            'surname' => 'Baz',
            'visits' => [
                'Monday',
                'Tuesday',
            ]
        ],
    ],
];

When building the form data, the fields are not well recognized as showing below

--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=forename
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=forename

John
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=surname
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=surname

Doe
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data

Monday
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=1
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=1

Tuesday
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=forename
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=forename

Foo
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=surname
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=surname

Baz
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data

Monday
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_
Content-Type: text/plain; charset=utf-8; name=1
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=1

Tuesday
--_=_symfony_1571411167_e78fb7990a9a6884b665462eb252cc74_=_--

As you can see, some names are repeated, and also, it is not actually well reconized by the server.
The result I got on this payload on Symfony ($request->request->all()) was:

{
    "request": {
        "forename": "John",
        "surname": "Doe"
    }
}

I created an example that can be checked at:
https://github.com/jvahldick/symfony-issue-mime-component/blob/master/src/Controller/MyController.php

There is a similar issue that can be found at #33063, which also has a PR (#33064).
I tested it, however, I didn't get what I believe is the desirable result.

What actually I expect to be the result is:

{
    "request": {
        "people": [
            {
                "forename": "John",
                "surname": "Doe",
                "visits": [
                    "Monday",
                    "Tuesday"
                ]
            },
            {
                "forename": "Foo",
                "surname": "Baz",
                "visits": [
                    "Monday",
                    "Tuesday"
                ]
            }
        ]
    }
}

Possible Solution
Will be creating the PR.

@fabpot fabpot closed this as completed Nov 30, 2019
fabpot added a commit that referenced this issue Nov 30, 2019
…taPart (jvahldick)

This PR was merged into the 4.4 branch.

Discussion
----------

[Mime] Fixing multidimensional array structure with FormDataPart

| Q             | A
| ------------- | ---
| Branch?       | 4.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #33063 #34031
| License       | MIT
| Doc PR        | -

The issue is pretty much described on #34031
The current structure of the raw body build on FormDataPart is not well recognized by the server. It considers all the fields as a root type, when actually it is possible to send arrays by html forms.

Lets the following structure on the html
```html
<input type="text" name="names[]" value="John" />
<input type="text" name="names[]" value="Doe" />
```

It creates the following raw body:
```
----------------------------466490401959219490193856
Content-Disposition: form-data; name="names[]"

John
----------------------------466490401959219490193856
Content-Disposition: form-data; name="names[]"

Doe
----------------------------466490401959219490193856--
```

Meanwhile, the FormDataPart on Mime component generates the following body:
```
--_=_symfony_1571410799_b7846b3b4e86d821cdec4379e62b4068_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data

John
--_=_symfony_1571410799_b7846b3b4e86d821cdec4379e62b4068_=_
Content-Type: text/plain; charset=utf-8; name=1
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=1

Doe
--_=_symfony_1571410799_b7846b3b4e86d821cdec4379e62b4068_=_--
```

For more complex structures, the $_POST doesn't even recognize properly the field names and values.

Commits
-------

ca630e5 Changing the multipart form-data behavior to use the form name as an array, which makes it recognizable as an array by PHP on the $_POST globals once it is coming from the HttpClient component
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants