I\'m having trouble posting form data via CURL to a receiving PHP script located on a different host.
I get an Array to string conversion
error
First I would like to thank Daniel Vandersluis for his insightful reply. Based on his input I came up with this to fix the problem from the original question:
<?php
function curl_postfields_flatten($data, $prefix = '') {
if (!is_array($data)) {
return $data; // in case someone sends an url-encoded string by mistake
}
$output = array();
foreach($data as $key => $value) {
$final_key = $prefix ? "{$prefix}[{$key}]" : $key;
if (is_array($value)) {
// @todo: handle name collision here if needed
$output += curl_postfields_flatten($value, $final_key);
}
else {
$output[$final_key] = $value;
}
}
return $output;
}
Usage should look like this:
curl_setopt($this->ch, CURLOPT_POSTFIELDS, curl_postfields_flatten($post));
This function will convert arrays like this:
array(
'a' => 'a',
'b' => array(
'c' => array(
'd' => 'd',
'e' => array(
'f' => 'f',
),
),
),
);
Into this:
array(
'a' => 'a',
'b[c][d]' => 'd',
'b[c][e][f]' => 'f',
)
It doesn't handle cases with mixed format when there is a key collision like this:
array(
'b[c]' => '1',
'b' => array(
'c' => '2',
),
);
The output will contain only the first value for that key
array(
'b[c]' => '1'
)
You'd have to build the POST string manually, rather than passing the entire array in. You can then override curl's auto-chose content header with:
curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data"));
Serializing/json-ifying would be easier, but as you say, you have no control over the receiving end, so you've got a bit of extra work to do.
Simplest solution is to do a :
$array = urldecode(http_build_query($array));
Below is sample code where this is used in real life :
https://gist.github.com/gayanhewa/142c48162f72e68a4a23
When you have nested $params section in the above gist it will parse it accordingly and prepare it for posting via curl.
function http_build_query_for_curl( $arrays, &$new = array(), $prefix = null ) {
if ( is_object( $arrays ) ) {
$arrays = get_object_vars( $arrays );
}
foreach ( $arrays AS $key => $value ) {
$k = isset( $prefix ) ? $prefix . '[' . $key . ']' : $key;
if ( is_array( $value ) OR is_object( $value ) ) {
http_build_query_for_curl( $value, $new, $k );
} else {
$new[$k] = $value;
}
}
}
$arrays = array(
'name' => array(
'first' => array(
'Natali', 'Yura'
)
)
);
http_build_query_for_curl( $arrays, $post );
print_r($post);
The cURL option CURLOPT_POSTFIELDS
will accept either a string or simple array but not a nested array. Attempting to do so will generate the Array to string conversion
error.
However http_build_query()
can handle a nested array so use it to convert the $_POST
array to a string then send that string instead. So where you have;
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
use this instead;
curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST)));
$post = "ac=on&p=1&pr[]=0&pr[]=1&a[]=3&a[]=4&pl=on&sp[]=3&ct[]=3&s=1&o=0&pp=3&sortBy=date";
parse_str($post,$fields);
$url = 'http://example.com/';
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);