When I use curl
via POST
and set CURLOPT_POSTFIELD
do I have to urlencode
or any special format?
for exam开发者_Python百科ple: 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);
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, '', '&');
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);
}
Do not pass a string at all!
You can pass an array and let php/curl do the dirty work of encoding etc.
It depends on the content-type
url-encoded or multipart/form-data
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.
JSON encoding
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'
]
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);
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 ...
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
.
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.
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'
);
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);
精彩评论