【问题标题】:How to upload files (multipart/form-data) with multidimensional POSTFIELDS using PHP and CURL?如何使用 PHP 和 CURL 上传具有多维 POSTFIELDS 的文件(multipart/form-data)?
【发布时间】:2011-03-28 01:41:48
【问题描述】:

我在使用 PHP 和 CURL 发布包含文件上传的多维数组时遇到问题。

多维数组例如:

$post['question'] = 'Are you human?';
$post['answers'] = array('yes', 'no', 'maybe');
$post['file'] = '@/path/to/file';

// Output:

Array(
    'question' => Are you human?,
    'answers' => Array(
        '0' => yes,
        '1' => no,
        '2' => maybe
        ),
    'file' => @/path/to/file
)

如果您只是尝试像这样在 CURL 中使用 CURLOPT_POSTFIELDS 发布此内容,则有一些原因无法正常工作:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

$response = curl_exec($ch);

首先官方 PHP description 的 CURLOPT_POSTFIELDS 说:

要在 HTTP“POST”中发布的完整数据 手术。要发布文件,请在前面添加 带有@ 的文件名并使用完整路径。 这可以作为 urlencoded 字符串,例如 'para1=val1&para2=val2&...' 或作为 以字段名称为键的数组和 字段数据作为值。如果值是 数组,Content-Type 标头将是 设置为 multipart/form-data。

听起来您可以将任何类型的数组传递给 POSTFIELDS 对吧?错误的。 POSTFIELDS 只接受非标量值,并且在传递多维数组时会出现Array to string conversion 错误。因此,您唯一的其他选择是 http_build_query() 您的数组能够传递不会阻塞的多维数组。

但是.. 你可以在 PHP 页面的注释中看到:

注意:将数组传递给 CURLOPT_POSTFIELDS 将编码 数据作为多部分/表单数据,而 传递一个 URL 编码的字符串将 将数据编码为 应用程序/x-www-form-urlencoded。

如果您将 urlencoded 字符串传递给 POSTFIELDS,则帖子不会被 multipart/form-data 编码,从而导致文件上传失败。

因此,将两者与 CURL 结合起来似乎几乎是不可能的,但如果您使用常规的 HTML 表单,这将不是问题。

我的问题是:是否有可能绕过 CURL 的这种奇怪的怪癖来发布多维数组和文件上传?

【问题讨论】:

    标签: php post file-upload curl multidimensional-array


    【解决方案1】:

    multipart/form-data 不支持嵌套值。而且我也不相信 CURL 可以做到。

    我怀疑您的请求的接收端也是一个 PHP 脚本。如果,那么你可以提交一个嵌套数组作为值之一,如果你自己准备的话:

     $post['answers[0]'] = "yes";
     $post['answers[1]'] = "no";
     $post['answers[2]'] = "maybe";
    

    理论上你只需要'answers[]' 没有索引,但这会覆盖前面的值 - 因此只适用于 http_build_query。

    我不确定 PHP 中是否有任何 HTTP 库可以自动执行此操作。

    【讨论】:

      【解决方案2】:

      完成第一个答案的另一种方法:

      foreach( array("yes","no","maybe") as $key=>$value )
          $post["answers[$key]"] = $value;

      【讨论】:

        【解决方案3】:

        试试这个递归函数。

        https://gist.github.com/yisraeldov/ec29d520062575c204be7ab71d3ecd2f

        <?php
        function build_post_fields( $data,$existingKeys='',&$returnArray=[]){
            if(($data instanceof CURLFile) or !(is_array($data) or is_object($data))){
                $returnArray[$existingKeys]=$data;
                return $returnArray;
            }
            else{
                foreach ($data as $key => $item) {
                    build_post_fields($item,$existingKeys?$existingKeys."[$key]":$key,$returnArray);
                }
                return $returnArray;
            }
        }
        

        你可以这样使用它。

        curl_setopt($ch, CURLOPT_POSTFIELDS, build_post_fields($postfields));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-08
          • 1970-01-01
          • 1970-01-01
          • 2015-10-23
          • 1970-01-01
          • 2011-02-12
          • 1970-01-01
          相关资源
          最近更新 更多