我无法通过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
,因为我通过同一个数组发送文件,因此我不能将数组转换为查询字符串或使用http_build_query()
。
此外,我无法访问接收主机上的代码,因此无法序列化和反序列化数组。
我假设作为数组的 name 键的值是导致此错误的原因,我还假设CURLOPT_POSTFIELDS
不支持多维数组。有没有其他方法可以解决这个问题,还是我注定要失败?
提前致谢!
答案 0 :(得分:32)
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);
答案 1 :(得分:27)
当涉及到HTTP请求时,数组的概念并不存在。 PHP(以及可能的其他服务器端语言)具有逻辑,可以将看起来像的请求数据(如果它)放在一起,并在填充$_GET
时将其作为数组放在一起, $_POST
等。
例如,当您从表单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知道如何处理这些数据(即构建一个数组),对HTML和HTTP,你有三个不相关的输入碰巧有类似(或相同,但这不是技术上有效的HTML)名称。
要对cURL请求执行相反操作,您需要将数组分解为键的字符串表示形式。因此,使用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。
答案 2 :(得分:23)
您必须手动构建POST字符串,而不是传递整个数组。然后,您可以使用以下命令覆盖curl的自动选择内容标题:
curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data"));
序列化/ json-ifying会更容易,但正如你所说,你无法控制接收端,所以你需要做一些额外的工作。
答案 3 :(得分:16)
最简单的解决方案是:
$array = urldecode(http_build_query($array));
以下是现实生活中使用的示例代码:
https://gist.github.com/gayanhewa/142c48162f72e68a4a23
当你在上面的要点中嵌套$ params部分时,它会相应地解析它并准备通过curl发布。
答案 4 :(得分:3)
首先,我要感谢 Daniel Vandersluis 的insightful reply。根据他的意见,我想出了解决原始问题的问题:
<?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'
)
答案 5 :(得分:0)
我认为您需要将选项作为字符串传递:
curl_setopt($this->ch, CURLOPT_POSTFIELDS, 'name[]=Jason&name[]=Mary&name[]=Lucy...');
然后您应该可以通过CURLOPT_HTTPHEADER手动设置标题。
答案 6 :(得分:0)
cURL选项CURLOPT_POSTFIELDS
将接受字符串或简单数组,但不接受嵌套数组。尝试这样做会产生Array to string conversion
错误。
但是http_build_query()
可以处理嵌套数组,因此使用它将$_POST
数组转换为字符串,然后发送该字符串。所以你在哪里;
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
改为使用它;
curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST)));
答案 7 :(得分:-1)
$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);