使用PHP和CURL发布多维数组

Dav*_*ock 43 php arrays post curl

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

我收到一个Array to string conversion错误

这是print_r我发布的数组:

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

这是错误发生的行:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
Run Code Online (Sandbox Code Playgroud)

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

此外,我无法访问接收主机上的代码,因此我无法序列化和反序列化数组.

我假设名称键的值是一个数组是导致此错误的原因,我也假设CURLOPT_POSTFIELDS不支持多维数组.有没有其他方法可以解决这个问题,还是我注定要失败?

提前致谢!

小智 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);
Run Code Online (Sandbox Code Playgroud)

  • 我觉得这是更好的解决方案,因为它也很容易处理文件上传.谢谢! (2认同)

Dan*_*uis 27

当涉及到HTTP请求时,数组的概念并不存在.PHP(以及可能的其他服务器端语言)具有逻辑,可以获取看起来像数组(到它)的请求数据,并在填充时将它们组合在一起$_GET,$_POST等等.

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

<form ...>
  <input name="my_array[0]">
  <input name="my_array[1]">
  <input name="my_array[2]">
</form>
Run Code Online (Sandbox Code Playgroud)

甚至:

<form ...>
  <input name="my_array[]">
  <input name="my_array[]">
  <input name="my_array[]">
</form>
Run Code Online (Sandbox Code Playgroud)

虽然PHP知道如何处理这些数据(即构建一个数组),HTML和HTTP,你有三个不相关的输入碰巧有类似(或相同,虽然这不是技术上有效的HTML )名字.

要对cURL请求执行相反操作,需要将数组分解为键的字符串表示形式.因此,使用您的name阵列,您可以执行以下操作:

foreach ($post['name'] as $id => $name)
{
  $post['name[' . $id . ']'] = $name;
}
unset($post['name']);
Run Code Online (Sandbox Code Playgroud)

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

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

然后,您发布的数组中的每个键都是量值,这是cURL所期望的,并且数组将表示为您需要的HTTP.

  • 谢谢你的回答,它没有完全回答这个问题,但它非常有见地! (2认同)

Mar*_*c B 24

您必须手动构建POST字符串,而不是传递整个数组.然后您可以使用以下命令覆盖curl的自动选择内容标题:

curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data"));
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢!我实际上并不知道我能做到这一点.我添加了`CURLOPT_HTTPHEADER`并将我的数组传递给`http_build_query()`.任务完成! (5认同)
  • 在我的情况下,这不起作用。错误是 **Warning: Missing boundary in multipart/form-data POST data in Unknown on line 0**。对我有用的是 Khristenko Yura 的 [这篇文章](http://stackoverflow.com/a/8224117/1057527) (2认同)

Gay*_*ewa 16

最简单的解决方案是做一个:

$array = urldecode(http_build_query($array));
Run Code Online (Sandbox Code Playgroud)

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

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

当您在上面的要点中嵌套$ params部分时,它将相应地解析它并准备通过curl发布.


Lux*_*ian 9

首先,我要感谢丹尼尔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;
}
Run Code Online (Sandbox Code Playgroud)

用法应如下所示:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, curl_postfields_flatten($post));
Run Code Online (Sandbox Code Playgroud)

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

array(
  'a' => 'a',
  'b' => array(
    'c' => array(
      'd' => 'd',
      'e' => array(
        'f' => 'f',
      ),
    ),
  ),
);
Run Code Online (Sandbox Code Playgroud)

进入这个:

array(
  'a' => 'a',
  'b[c][d]' => 'd',
  'b[c][e][f]' => 'f',
)
Run Code Online (Sandbox Code Playgroud)

当有这样的键冲突时,它不处理混合格式的情况:

array(
 'b[c]' => '1',
 'b' => array(
   'c' => '2', 
  ),
);
Run Code Online (Sandbox Code Playgroud)

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

array(
 'b[c]' => '1'
)
Run Code Online (Sandbox Code Playgroud)