Reputation: 2959
When I use curl
via POST
and set CURLOPT_POSTFIELD
do I have to urlencode
or any special format?
for example: If I want to post 2 fields, first and last:
first=John&last=Smith
what is the exact code/format that should be used with curl?
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$reply=curl_exec($ch);
curl_close($ch);
Upvotes: 119
Views: 366858
Reputation: 157
We were looking for the same solution when we wrote a test for CMS Effcore. The solution turned out to be quite simple and it is shown below:
$data = [
'name[0]' => 'value 1',
'name[1]' => 'value 2',
'name[2]' => 'value 3',
'id' => 'value 4'
];
$data = array(
'name[0]' => 'value 1',
'name[1]' => 'value 2',
'name[2]' => 'value 3',
'id' => 'value 4'
);
Upvotes: 2
Reputation: 5153
content-type
To send data the standard way, as a browser would with a form, just pass an associative array. As stated by PHP's manual:
This parameter 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.
Neverthless, when communicating with JSON APIs, content must be JSON encoded for the API to understand our POST data.
In such cases, content must be explicitely encoded as JSON :
CURLOPT_POSTFIELDS => json_encode(['param1' => $param1, 'param2' => $param2]),
When communicating in JSON, we also usually set accept
and content-type
headers accordingly:
CURLOPT_HTTPHEADER => [
'accept: application/json',
'content-type: application/json'
]
Upvotes: 20
Reputation: 783
Interestingly the way Postman does POST is a complete GET operation with these 2 additional options:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
Just another way, and it works very well.
Upvotes: 2
Reputation: 2340
One other major difference that is not yet mentioned here is that CURLOPT_POSTFIELDS
can't handle nested arrays.
If we take the nested array ['a' => 1, 'b' => [2, 3, 4]]
then this should be be parameterized as a=1&b[]=2&b[]=3&b[]=4
(the [
and ]
will be/should be URL encoded). This will be converted back automatically into a nested array on the other end (assuming here the other end is also PHP).
This will work:
var_dump(http_build_query(['a' => 1, 'b' => [2, 3, 4]]));
// output: string(36) "a=1&b%5B0%5D=2&b%5B1%5D=3&b%5B2%5D=4"
This won't work:
curl_setopt($ch, CURLOPT_POSTFIELDS, ['a' => 1, 'b' => [2, 3, 4]]);
This will give you a notice. Code execution will continue and your endpoint will receive parameter b
as string "Array"
:
PHP Notice: Array to string conversion in ... on line ...
Upvotes: 9
Reputation: 171
For CURLOPT_POSTFIELDS
, the parameters 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
Try the following format :
$data = json_encode(array(
"first" => "John",
"last" => "Smith"
));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);
Upvotes: 10
Reputation: 14992
EDIT: From php5 upwards, usage of http_build_query
is recommended:
string http_build_query ( mixed $query_data [, string $numeric_prefix [,
string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )
Simple example from the manual:
<?php
$data = array('foo'=>'bar',
'baz'=>'boom',
'cow'=>'milk',
'php'=>'hypertext processor');
echo http_build_query($data) . "\n";
/* output:
foo=bar&baz=boom&cow=milk&php=hypertext+processor
*/
?>
before php5:
From the manual:
CURLOPT_POSTFIELDS
The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. The filetype can be explicitly specified by following the filename with the type in the format ';type=mimetype'. This parameter 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. As of PHP 5.2.0, files thats passed to this option with the @ prefix must be in array form to work.
So something like this should work perfectly (with parameters passed in a associative array):
function preparePostFields($array) {
$params = array();
foreach ($array as $key => $value) {
$params[] = $key . '=' . urlencode($value);
}
return implode('&', $params);
}
Upvotes: 70
Reputation: 53
This answer took me forever to find as well. I discovered that all you have to do is concatenate the URL ('?' after the file name and extension) with the URL-encoded query string. It doesn't even look like you have to set the POST cURL options. See the fake example below:
//create URL
$exampleURL = 'http://www.example.com/example.php?';
// create curl resource
$ch = curl_init();
// build URL-encoded query string
$data = http_build_query(
array('first' => 'John', 'last' => 'Smith', '&'); // set url
curl_setopt($ch, CURLOPT_URL, $exampleURL . $data);
// return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
// close curl resource to free up system resources <br/>
curl_close($ch);
You can also use file_get_contents()
:
// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);
Upvotes: -3
Reputation: 318498
You can pass an array and let php/curl do the dirty work of encoding etc.
Upvotes: 42
Reputation: 1903
In case you are sending a string, urlencode() it. Otherwise if array, it should be key=>value paired and the Content-type
header is automatically set to multipart/form-data
.
Also, you don't have to create extra functions to build the query for your arrays, you already have that:
$query = http_build_query($data, '', '&');
Upvotes: 107
Reputation: 26380
According to the PHP manual, data passed to cURL as a string should be URLencoded. See the page for curl_setopt() and search for CURLOPT_POSTFIELDS
.
Upvotes: 6