Mixing multiple values for the same key and file uploads using cURL and PHP

  1. Vote for PHP Bug #51634.
  2. Try @BeauSimensen's answer.
  3. Guzzle can do this. See an example below.
$client = new \GuzzleHttp\Client();
$client->request('POST', $url, [
  'multipart' => [
    [ 'name' => 'foo', 'contents' => 'bar' ],
    [ 'name' => 'foo', 'contents' => 'baz' ],
  ]
]);

If you use tag[] rather than tag for the name, PHP will generate an array for you, in other words, rather than

tag=foo&tag=bar&tag=baz

You need

tag[]=foo&tag[]=bar&tag[]=baz

Note that when urlencoded for transmission this should become

tag%5B%5D=foo&tag%5B%5D=bar&tag%5B%5D=baz

I ended up writing my own function to build a custom CURLOPT_POSTFIELDS string with multipart/form-data. What a pain.

function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    // $postfields is an assoc array.
    // Creates a boundary.
    // Reads each postfields, detects which are @files, and which values are arrays
    // and dumps them into a new array (not an assoc array) so each key can exist
    // multiple times.
    // Sets content-length, content-type and sets CURLOPT_POSTFIELDS with the
    // generated body.
}

I was able to use this method like this:

curl_setopt_custom_postfields($ch, array(
    'file' => '@/path/to/file',
    'tag' => array('a', 'b', 'c'),
));

I am not certain of CURLOPT_HTTPHEADER stacks, so since this method calls it, I made certain that the function would allow for the user to specify additonal headers if needed.

I have the full code available in this blog post.

Tags:

Php

Curl