19

I am trying to upload file and send post parameters at the same time like this:

$response = $client->post('http://example.com/api', [
    'form_params' => [
        'name' => 'Example name',
    ],
    'multipart' => [
        [
            'name'     => 'image',
            'contents' => fopen('/path/to/image', 'r')
        ]
    ]
]);

However my form_params fields are ignored and only the multipart fields are present in my post body. Can I send both at all with guzzle 6.0 ?

Ankh
  • 5,478
  • 3
  • 36
  • 40
Jordan Dobrev
  • 317
  • 1
  • 3
  • 10

5 Answers5

49

I ran into the same problem. You need to add your form_params to the multipart array. Where 'name' is the form element name and 'contents' is the value. The example code you supplied would become:

$response = $client->post('http://example.com/api', [
    'multipart' => [
        [
            'name'     => 'image',
            'contents' => fopen('/path/to/image', 'r')
        ],
        [
            'name'     => 'name',
            'contents' => 'Example name'
        ]
    ]
]);
Arda
  • 6,756
  • 3
  • 47
  • 67
Simon Crowfoot
  • 506
  • 5
  • 3
  • 1
    if the code using headers tag, so, headers are written inside the 'multipart' or before multipart? like ``` $response = $client->post('http://xyz', [ 'headers' => [] 'multipart' => [] ]; or 'multipart' => [ 'name' => 'a' 'contents' => 'b' 'headers => 'c' ] ] – jhon Jun 19 '20 at 03:24
7

I got there too, but unfortunately it does not work if you have multidimensional params array. The only way i got it to work is if you send the form_paramaters as query parameters in the array:

$response = $client->post('http://example.com/api', [
    'query' => [
        'name' => 'Example name',
    ],
    'multipart' => [
        [
            'name'     => 'image',
            'contents' => fopen('/path/to/image', 'r')
        ]
    ]
]);
Jordan Dobrev
  • 317
  • 1
  • 3
  • 10
  • Were you able to successfully use that mixture of RequestOptions? When I perform that request you have, my query items get sent but the multipart does not. – Brady Jan 29 '16 at 10:52
  • According to the maintainer of Guzzle, this cannot work. Multipart cannot be mixed with any other request option. https://github.com/guzzle/guzzle/issues/1386 – Brady Jan 31 '16 at 09:09
  • Correction. This should work because query is not a body related option. – Brady Jan 31 '16 at 11:30
  • You can have multiple multipart elements with the same name. – penyaskito Jun 16 '20 at 11:12
4

I googled similar problem and write here advice:

Do not set header "Content-Type" manually for multipart request.

Solo.dmitry
  • 690
  • 8
  • 15
1
    $body['query'] = $request->input();
        if($_FILES)
         {
            $filedata = [];
            foreach( $_FILES as $key => $file){               
                if(!($file['tmp_name'] == '')){
                    $file['filename'] = $file['name'];
                    $file['name']=$key;
                    $file['contents'] = fopen($file['tmp_name'], 'r');
                    $file['headers'] = array('Content-Type' => mime_content_type($file['tmp_name']));
                }
                else{
                    $file['contents'] = '';
                }
                array_push($filedata, $file);
            }
        $body['multipart'] = $filedata;
        }

        $header= ['headers'=>[
                    'User-Agent' => 'vendor/1.0',
                    'Content-Type' =>'multipart/form-data',
                    'Accept'     => 'application/json',
                    'Authorization' => "Authorization: Bearer ".$token,
                ]];
        $client = new Client($header);
        $response = $client->POST($url, $body);
        $response=json_decode($response->getBody());
0

You can send both data and files as in the following code:

$response = $client->post('http://example.com/api', [
    'query' => [
        'name' => 'Example name',
    ],
    'multipart' => [
        [
            'name'     => 'image',
            'contents' => fopen('/path/to/image', 'r')
        ],
        [
            'name'     => 'product',
            'contents' => $product_array
    ]
]);

The product would be in the post part of the request, the files in the files part.

Where it get's tricky is when the contents of the data you are trying to send along with the files are in an array - since you can't just send the array as json when also using multipart. The trick I found to get around this is to json_encode the $product_array and then base64_encode that. Reversing the process on the other end gives you the desired results. Hope that helps.

Marcus
  • 1
  • 2