用PHP和CURL发布multidimensional array

我无法通过CURL将表单数据发送到位于不同主机上的接收PHP脚本。

我得到一个Array to string conversion错误

这是我发布的数组的print_r

 Array ( [name] => Array ( [0] => Jason [1] => Mary [2] => Lucy ) [id] => 12 [status] => local [file] => @/test.txt ) 

这是错误发生的行:

 curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post); 

第三个参数必须是一个数组,因为我需要将Content-Type头设置为multipart/form-data因为我通过同一个数组发送文件,所以我无法将数组转换为查询string或使用http_build_query()

另外我没有访问接收主机上的代码,所以我不能序列化和反序列化数组。

我假设名称键是一个数组的值是这个错误的原因,我还假设CURLOPT_POSTFIELDS不支持multidimensional array。 有没有其他解决办法或注定?

提前致谢!

您必须手动构buildPOSTstring,而不是传入整个数组。然后,您可以使用以下命令覆盖curl的自动select的内容标题:

 curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data")); 

序列化/ json-ifying会更容易,但正如你所说,你无法控制接收端,所以你有一些额外的工作要做。

当涉及到HTTP请求时,数组的概念并不存在。 PHP(也可能是其他服务器端语言)具有逻辑烘焙function,可以将请求数据看起来像一个数组(数据),并将其作为数组放在一起,同时填充$_GET$_POST等。

例如,当你从一个表单发布数组时,表单元素通常看起来像这样:

 <form ...> <input name="my_array[0]"> <input name="my_array[1]"> <input name="my_array[2]"> </form> 

甚至:

 <form ...> <input name="my_array[]"> <input name="my_array[]"> <input name="my_array[]"> </form> 

虽然PHP知道如何处理这些数据,当它接收到(即build立一个数组),到HTML和HTTP,你有三个不相关的input,只是碰巧有相似的(或相同的,虽然这不是技术上有效的HTML )名称。

为了对你的cURL请求做相反的处理,你需要把你的数组分解成键的string表示。 所以你的name数组,你可以做这样的事情:

 foreach ($post['name'] as $id => $name) { $post['name[' . $id . ']'] = $name; } unset($post['name']); 

这将导致你的$post数组看起来像:

 Array ( [name[0]] => Jason [name[1]] => Mary [name[2]] => Lucy [id] => 12 [status] => local [file] => @/test.txt ) 

然后,你发布的数组中的每个键将是一个量值,这是cURL期望的,并且该数组将被表示为您需要的HTTP。

 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); 

最简单的解决办法是做一个:

 $array = urldecode(http_build_query($array)); 

以下是在现实生活中使用的示例代码:

https://gist.github.com/gayanhewa/142c48162f72e68a4a23

当你在上面的要点中嵌套$ params部分时,它会相应地parsing它,并准备通过curl发布。

首先我要感谢Daniel Vandersluis的深刻回答 。 根据他的意见,我想出了这个问题来解决原来的问题:

 <?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; } 

用法应该如下所示:

 curl_setopt($this->ch, CURLOPT_POSTFIELDS, curl_postfields_flatten($post)); 

这个函数会像这样转换数组:

 array( 'a' => 'a', 'b' => array( 'c' => array( 'd' => 'd', 'e' => array( 'f' => 'f', ), ), ), ); 

进入这个:

 array( 'a' => 'a', 'b[c][d]' => 'd', 'b[c][e][f]' => 'f', ) 

如果发生像这样的重大冲突,它不会处理混合格式的案例:

 array( 'b[c]' => '1', 'b' => array( 'c' => '2', ), ); 

输出将只包含该键的第一个值

 array( 'b[c]' => '1' ) 

我想你需要将选项作为string传递:

 curl_setopt($this->ch, CURLOPT_POSTFIELDS, 'name[]=Jason&name[]=Mary&name[]=Lucy...'); 

然后您应该可以通过CURLOPT_HTTPHEADER手动设置标题。

cURL选项CURLOPT_POSTFIELDS将接受一个string或简单数组,但不能嵌套数组。 试图这样做会生成Array to string conversion错误。

但是http_build_query()可以处理一个嵌套的数组,所以用它来将$_POST数组转换为一个string,然后发送该string。 那么你在哪里;

 curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST); 

用这个来代替;

 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);