The PHP Curl Documentation for CURLOPT_POSTFIELDS makes this note:
This can either be passed as a urlencoded string like ‘para1=val1¶2=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)