【问题标题】:Guzzle 6: upload files with array dataGuzzle 6:上传带有数组数据的文件
【发布时间】:2016-04-04 16:38:50
【问题描述】:

我必须用文件发送数组数据。仅使用数据可以正常工作:

$client->post('http://xxx/', [
    'form_params' => [
        [
            'data' => ['id' => 1234, 'name' => 'nombre'],
            'valid' => true
        ]
    ]
]);

但由于我不能将“form_params”与“multipart”一起使用,如何发送带有数组和布尔数据的文件?

我试过了:

$client->post('http://xxx/', [
    'multipart' => [
        [
            'name'     => 'myfile',
            'contents' => fopen('my_file.txt', 'r'),
        ],
        [
            'name'     => 'data',
            'contents' => ['id' => 1234, 'name' => 'nombre'],
        ]
        [
            'name'     => 'valid',
            'contents' => true,
        ]
    ],
]);

但我收到一个错误,因为“内容”不接受布尔值或数组值。

我需要一些帮助。

谢谢

更新: 我无法解决问题,最后我不得不使用一个不太好的解决方案,包括作为查询字符串的表单字段参数并仅使用 Multipart。比如:

$client->post('http://xxx?id=1234&name=nombre', [
'multipart' => [
    [
        'name'     => 'myfile',
        'contents' => fopen('my_file.txt', 'r'),
    ],
],

]);

【问题讨论】:

  • 我自己也在解决这个问题。我通过设置 [headers] => [ [Content-Type] => application/x-www-form-urlencoded ] 获得了数组数据。但我无法让文件与这些数据一起传递。看到这个关于数组作为内容值的问题github.com/guzzle/guzzle/issues/1177

标签: php arrays guzzle6


【解决方案1】:

根据 Guzzle 文档:

multipart 的值是一个关联数组的数组,每个 包含以下键值对:

  • 名称:(字符串,必填)表单字段名称
  • contents:(StreamInterface/resource/string,必填)要在表单元素中使用的数据。
  • headers:(数组)与表单元素一起使用的自定义标题的可选关联数组。
  • 文件名:(字符串)作为文件名发送的可选字符串。

所以看起来它只接受内容的字符串(直接或作为流)。他们可能的理由是,由于它是一个多部分的表单,您将分别发送每个数据点,如下所示...

$client->post('http://xxx/', [
    'multipart' => [
        [
            'name'     => 'myfile',
            'contents' => fopen('my_file.txt', 'r'),
        ],
        [
            'name'     => 'id',
            'contents' => '1234',
        ],
        [
            'name'     => 'name',
            'contents' => 'nombre',
        ],
        [
            'name'     => 'valid',
            'contents' => 'true',
        ]
    ],
]);

在不知道如何解析数据的情况下,我不能确定这是一个可行的选择,但由于它接受自定义标头,您可以将其作为 JSON 数组(以字符串形式)发送,然后设置内容类型:

$client->post('http://xxx/', [
    'multipart' => [
        [
            'name'     => 'myfile',
            'contents' => fopen('my_file.txt', 'r'),
        ],
        [
            'name'     => 'data',
            'contents' => '{"id":1234, "name":"nombre"}',
            'headers'  => ['Content-Type' => 'text/x-json']
        ],
        [
            'name'     => 'valid',
            'contents' => 'true',
        ]
    ],
]);

另一种选择是直接使用 cURL,但我确定你想避免这种情况,因为你使用的是 Guzzle。

更新

这不是我亲自测试过的东西,但你可以尝试另外一个东西......(实际上我应该首先想到这个)。

$client->post('http://xxx/', [
    'multipart' => [
        [
            'name'     => 'myfile',
            'contents' => fopen('my_file.txt', 'r'),
        ],
        [
            'name'     => 'data',
            'contents' => 'id=1234&name=nombre',
            'headers'  => ['Content-Type' => 'text/plain; charset=ISO-8859-1']
        ],
        [
            'name'     => 'valid',
            'contents' => true,
        ]
    ],
]);

【讨论】:

  • 非常感谢@Jabari,你的第一个选项是不可能的,因为我需要发送一个带有“数据”键的数组,第二个我已经尝试过了,第三个不起作用。唯一的可能性是发送“form_param”选项......有没有办法在“form_params”选项中发送文件?再次感谢
  • @Averias 今天晚些时候我会做一些测试,我也有兴趣让它工作。
【解决方案2】:

有一个选项可以通过 Guzzle 一起发送上传文件和数组数据,但形式发生了变化:

$client->post('http://xxx/', [
    'multipart' => [
        [
            'name'     => 'myfile',
            'contents' => fopen('my_file.txt', 'r'),
        ],
        [
            'name'     => 'data[0][id]',
            'contents' => 1234,
        ],
        [
            'name'     => 'data[0][name]',
            'contents' => 'nombre',
        ],
        [
            'name'     => 'data[1][id]',
            'contents' => 2222,
        ],
        [
            'name'     => 'data[1][name]',
            'contents' => 'nombre2',
        ],
        [
            'name'     => 'valid',
            'contents' => true,
        ]
    ],
]);

另一方面,您可以使用$_POST['data'] 获取数据,然后执行 foreach:

foreach ($_POST['data'] as $data) {
    echo "Id: ".$data['id'];
    echo "Name: ".$data['name'];
}

【讨论】:

    【解决方案3】:

    您可以使用递归方法获取数据数组并准备多部分数组:

    private function prepareMultipartParams($params, $baseKey = null): array
    {
        $result = [RequestOptions::MULTIPART => []];
        foreach ($params as $key => $value) {
            $key = $baseKey == null ? $key : "{$baseKey}[{$key}]";
            if (is_array($value))
                foreach ($this->prepareMultipartParams($value, $key) as $array)
                    $result[RequestOptions::MULTIPART] = array_merge($result[RequestOptions::MULTIPART], $array);
            else
                $result[RequestOptions::MULTIPART][] = [
                    'name' => $key,
                    'contents' => $value instanceof UploadedFile ? fopen($value->path(), 'r+') : $value
                ];
        }
    
        return $result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      • 2016-08-10
      • 2011-07-28
      • 2017-07-24
      相关资源
      最近更新 更多