使用 PHP 和 CURL 发布多维数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3772096/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 11:02:53  来源:igfitidea点击:

Posting multidimensional array with PHP and CURL

phparrayspostcurl

提问by David Hancock

I'm having trouble posting form data via CURL to a receiving PHP script located on a different host.

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

I get an Array to string conversionerror

我收到一个Array to string conversion错误

This is print_rof the array I'm posting:

这是print_r我发布的数组:

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

This is the line the error occurs on:

这是发生错误的行:

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

The third argument mustbe an array because I need the Content-Typeheader to be set to multipart/form-dataas I am sending a file via this same array, therefore I cannot convert the array to a query string or use http_build_query().

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

Also I do not have access to the code on the receiving host so I cannot serialize and unserialize the array.

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

I'm assuming that the value of the namekey being an array is the cause for this error, I'm also assuming that CURLOPT_POSTFIELDSdoesn't support multidimensional arrays. Is there any other way around this or am I doomed?

我假设name键的值是数组是导致此错误的原因,我还假设它CURLOPT_POSTFIELDS不支持多维数组。有没有其他办法解决这个问题,或者我注定要失败?

Thanks in advance!

提前致谢!

采纳答案by Marc B

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:

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

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.

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

回答by Khristenko Yura

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

回答by Daniel Vandersluis

The concept of an array doesn't really exist when it comes to HTTP requests. PHP (and likely other server-side languages) has logic baked in that can take request data that lookslike an array (to it) and puts it together as an array while populating $_GET, $_POSTetc.

当涉及到 HTTP 请求时,数组的概念实际上并不存在。PHP(和可能的其他服务器端语言)具有在烘烤逻辑可以采取请求的数据看起来像一个阵列(它),并把它一起作为一个数组,同时填充$_GET$_POST等等

For instance, when you POST an array from a form, the form elements often look something like this:

例如,当您从表单 POST 一个数组时,表单元素通常如下所示:

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

or even:

甚至:

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

While PHP knows what to do with this data when it receives it (ie. build an array), to HTML and HTTP, you have three unrelated inputs that just happen to have similar (or the same, although this isn't technically valid HTML) names.

虽然 PHP 在收到数据时知道如何处理(即构建数组),但对于 HTML 和 HTTP,您有三个不相关的输入,它们恰好具有相似(或相同,尽管这在技术上不是有效的 HTML) ) 名称。

To do the reverse for your cURL request, you need to decompose your array into string representations of the keys. So with your namearray, you could do something like:

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

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

Which would result in your $postarray looking like:

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

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

And then each key in the array you are posting would be a scalarvalue, which cURL is expecting, and the array would be represented as you need to for HTTP.

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

回答by Gayan Hewa

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

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.

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

回答by Luxian

First I would like to thank Daniel Vandersluisfor his insightful reply. Based on his input I came up with this to fix the problem from the original question:

首先,我要感谢丹尼尔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;
}

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

回答by Nigel Alderton

The cURL option CURLOPT_POSTFIELDSwill accept either a string or simple array but not a nested array. Attempting to do so will generate the Array to string conversionerror.

cURL 选项CURLOPT_POSTFIELDS将接受字符串或简单数组,但不接受嵌套数组。尝试这样做会产生Array to string conversion错误。

However http_build_query()can handle a nested array so use it to convert the $_POSTarray to a string then send that string instead. So where you have;

但是http_build_query()可以处理嵌套数组,因此使用它将$_POST数组转换为字符串然后发送该字符串。所以你在哪里;

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);

use this instead;

改用这个;

curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST)));

回答by Alex Howansky

I think you'll need to pass the options as a string:

我认为您需要将选项作为字符串传递:

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

You should then be able to set the header manually via CURLOPT_HTTPHEADER.

然后,您应该能够通过 CURLOPT_HTTPHEADER 手动设置标头。

回答by Farzad

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