Related
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);
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);
im trying to send to my api site, the following Json with one record.
It works Ok, but I want to send more than one record, how can I do that?
Later i want to read a txt and make a json with all the records in it.
<?php
//API URL
$url = 'http://mysitexder.net/receiveJson.php';
//create a new cURL resource
$ch = curl_init($url);
//setup request to send json via POST
$data = array(
'cod' => '321',
'name' => 'Jane',
'address' => 'Route 123456'
);
$payload = json_encode(array("user" => $data));
//attach encoded JSON string to the POST fields
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
//set the content type to application/json
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
//return response instead of outputting
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//execute the POST request
$result = curl_exec($ch);
//close cURL resource
curl_close($ch);
Send a 2-dimensional array:
$data1 = array(
'cod' => '321',
'name' => 'Jane',
'address' => 'Route 123456'
);
$data2 = array(
'cod' => '555',
'name' => 'John',
'address' => '123 Main St'
);
$payload = json_encode(array('users' => array($data1, $data2)));
Later i want to read a txt and make a json with all the records in it.
It's hard to tell what you mean by this. But you should parse the text in whatever way you want (e.g. each line is a record), create a PHP array from that, and call json_encode().
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);
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);
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);
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);
I'm trying to do a simple post to a web service using CURL and their API but I'm getting a 422 response. My code looks like:
include 'CurlRequest.php';
$secret_key = 'mykeyhere';
$group_id = 'group_id';
$postData = array(
'group_id' => $group_id,
'key' => $secret_key,
'status' => 'test'
);
$curl = new CurlRequest('http://coopapp.com/statuses/update.json');
$curl->exec(array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($postData)
));
I'm using an existing Curl Library to handle the posts. I'm sure it has something to do with the way I'm formatting the POST url (I've tried a bunch of different ways) or the way I'm posting the data.
Their docs are here: http://coopapp.com/api/statuses
Thanks!
Here's a quote from the api page
POST
/statuses/update.xml?group_id=#{group_id}&status=An%20encoded%20status&key=#{secret_key}
its supposed to be key not secret_key
$postData = array(
'group_id' => $group_id,
'key' => $secret_key,
'status' => 'test'
);
The solution was a missing content-type of 'application/json'.
Here's the working code:
include 'CurlRequest.php';
$key = 'mykeyhere';
$group_id = '1234';
$status = 'Awesome status update';
$curl = new CurlRequest('http://coopapp.com/statuses/update.xml?group_id=' . $group_id . '&key=' . $key);
$curl->exec(array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(array('status' => $status)),
CURLOPT_HTTPHEADER => array("Content-Type: application/json")
));
The HTTP error seems odd for an API like this.
The Co-Op API doc is a bit... well.. confusing on the status update, as it talks about POSTing the data, but the example shows a query string. What you could do, is try putting the stuff in the query string, or not using CURL. PHP's file_get_contents is actually a usable HTTP client, if you pass it enough parameters. So try this:
$params = array(
'group_id' => $group_id,
'secret_key' => $secret_key,
'status' => 'test'
);
$context = stream_context_create(
array(
'http' => array(
'method' => 'POST'
))
);
file_get_contents("http://coopapp.com/statuses/update.json?" .
http_build_query($params), false, $context);
And if that doesn't work, rule out CURL errors, by doing the same thing without CURL:
$params = array(
'group_id' => $group_id,
'secret_key' => $secret_key,
'status' => 'test'
);
$context = stream_context_create(
array('http' => array(
'method' => 'POST',
'content' => http_build_query($params)
))
);
file_get_contents("http://coopapp.com/statuses/update.json", false, $context);
Note that I haven't tested the code, so some error-checking/fixes might be needed.
I don't think you should json_decode() the POSTFIELDS data, should you? The response will be JSON, but the input is expected as POST fields. According to the manual:
The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with # and use the full path. 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.
this should work:
$curl = new CurlRequest('http://coopapp.com/statuses/update.json');
$curl->exec(array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData
));