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