Array versus String in CURLOPT_POSTFIELDS

Posted on May 29th, 2009 in General,PHP,Programming by Brandon

The PHP Curl Documentation for CURLOPT_POSTFIELDS makes this note:

This can either be passed as a urlencoded string like ‘para1=val1&para2=val2&…’ or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data.

I’ve always discounted the importance of that, and in most cases it doesn’t generally matter. The destination server and application likely know how to deal with both multipart/form-data and application/x-www-form-urlencoded equally well. However, the data is passed in a much different way using these two different mechanisms.

application/x-www-form-urlencoded

application/x-www-form-urlencoded is what I generally think of when doing POST requests. It is the default when you submit most forms on the web. It works by appending a blank line and then your urlencoded data to the end of the POST request. It also sets the Content-Length header to the length of your data. A request submitted with application/x-www-form-urlencoded looks like this (somewhat simplified):

POST /some-form.php HTTP/1.1
Host: www.brandonchecketts.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded

name=value&name2=value2

multipart/form-data

multipart/form-data is much more complicated, but more flexible. Its flexibility is required when uploading files. It works in a manner similar to MIME types. The HTTP Request looks like this (simpified):

POST / HTTP/1.1
Host: www.brandonchecketts.com
Content-Length: 244
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------26bea3301273

And then subsequent packets are sent containing the actual data. In my simple case with two name/value pairs, it looks like this:

HTTP/1.1 100 Continue
------------------------------26bea3301273
Content-Disposition: form-data; name="name"

value
------------------------------26bea3301273
Content-Disposition: form-data; name="name2"

value2
------------------------------26bea3301273--

CURL usage

So, when sending POST requests in PHP/cURL, it is important to urlencode it as a string first.

This will generate the multipart/form-data version

$data = array('name' => 'value', 'name2' => 'value2');
curl_setopt($curl_object, CURLOPT_POSTFIELDS,  $data)

And this simple change will ensure that it uses the application/x-www-form-urlencoded version:

$data = array('name' => 'value', 'name2' => 'value2');
$encoded = '';
foreach($data as $name => $value){
    $encoded .= urlencode($name).'='.urlencode($value).'&';
}
// chop off the last ampersand
$encoded = substr($encoded, 0, strlen($encoded)-1);
curl_setopt($curl_object, CURLOPT_POSTFIELDS,  $encoded)

3 Responses to 'Array versus String in CURLOPT_POSTFIELDS'

Subscribe to comments with RSS or TrackBack to 'Array versus String in CURLOPT_POSTFIELDS'.

  1. dol said,

    on October 4th, 2010 at 3:30 am

    If you use the PHP5 function ‘http_build_query’ your code will be a few line shorter. http_build_query also do urlencoding for key and value.

  2. Kerr said,

    on October 20th, 2010 at 7:44 pm

    Thank you so much for posting this information! I was pulling my hair out with POSTing whilst developing a RESTful wrapper class with cURL.

  3. Podnikatel said,

    on November 21st, 2010 at 2:35 pm

    Great article!

    But for send urlencoded form, I recommend use this:

    curl_setopt($curl_object, CURLOPT_POSTFIELDS, http_build_query($data, ”, ‘&’));

    Function http_build_query make url encoding for us with very easy and simply way. Instead foreach cycle…

  4. Rich said,

    on May 11th, 2011 at 6:31 am

    Thanks for the post – works like a dream!

  5. Chuck Frankel said,

    on October 12th, 2011 at 6:29 pm

    What about execution times between the two?

  6. Piter said,

    on October 21st, 2011 at 3:58 pm

    If you want send a file using a post, you have to add ‘@’ before file location in value.

    Thx for good article.

Post a comment

Please copy the string y7rLe4 to the field below: