【问题标题】:Posting multidimensional array with PHP and CURL使用 PHP 和 CURL 发布多维数组
【发布时间】:2011-04-15 21:14:57
【问题描述】:

我无法通过 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 不支持多维数组。有没有其他方法可以解决这个问题,还是我注定要失败?

提前致谢!

【问题讨论】:

    标签: php arrays post curl


    【解决方案1】:

    首先,我要感谢 Daniel Vandersluisinsightful 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'
    )
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        最简单的解决办法是:

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

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

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

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

        【讨论】:

          【解决方案4】:
          $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);
          

          【讨论】:

            【解决方案5】:
            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);
            

            【讨论】:

            • 非常有帮助,谢谢!如果您有嵌套数组并需要上传文件,您将需要它
            • 我觉得这是更好的解决方案,因为它也可以轻松处理文件上传。谢谢!
            • 如果 $post 还没有定义,你可以简单地在函数末尾添加return $new;
            • 我(在我的代码上)更改它以返回 $new 数组。你有什么理由使用&amp;$new(通过引用)并返回void而不是仅仅返回$new
            【解决方案6】:

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

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

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

            【讨论】:

            • 谢谢!我真的不知道我能做到这一点。我添加了CURLOPT_HTTPHEADER 并将我的数组传递给http_build_query()。任务完成!
            • 感谢您提及http_build_query()。它对我来说就像一个魅力!
            • 在我的情况下这不起作用。错误是 Warning: Missing boundary in multipart/form-data POST data in Unknown on line 0。对我有用的是 Khristenko Yura 的this post
            【解决方案7】:

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

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

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

            【讨论】:

              【解决方案8】:

              当涉及到 HTTP 请求时,数组的概念并不真正存在。 PHP(以及可能的其他服务器端语言)具有内置逻辑,可以获取 看起来 像数组(对它而言)的请求数据,并在填充 $_GET、@987654322 时将其作为数组组合在一起@等

              例如,当您从表单 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 的需要表示。

              【讨论】:

              • 感谢您的回答,虽然没有完全回答问题,但很有见地!
              猜你喜欢
              • 2011-04-21
              • 2018-06-13
              • 2014-02-14
              • 2011-04-07
              • 2016-05-22
              • 1970-01-01
              • 2019-07-26
              • 1970-01-01
              相关资源
              最近更新 更多