13

我在 PHP 的 cURL 绑定中遇到了限制。似乎没有简单的方法可以为 postfields 的相同键发送相同的多个值。我遇到的大多数解决方法都涉及通过手动 tag=foo&tag=bar&tag=baz) 创建 URL 编码的帖子字段,而不是使用 CURLOPT_POSTFIELDS 的关联数组版本。

需要支持似乎是一件很常见的事情,所以我觉得我一定错过了一些东西。这真的是为同一个键处理多个值的唯一方法吗?

虽然这种解决方法可能被认为是可行的(如果不是很烦人的话),但我的主要问题是我需要能够为同一个键执行多个值并且还支持文件上传。据我所知,文件上传或多或少需要使用 CURLOPT_POSTFIELDS 的关联 arravy 版本。所以我觉得我被困住了。

我已经在 cURL PHP 邮件列表上更详细地发布了这个问题,希望有人对此有一些想法。

非常感谢有关我可以在哪里查找更多信息的建议或提示!

4

10 回答 10

12

我最终编写了自己的函数来使用 multipart/form-data 构建自定义 CURLOPT_POSTFIELDS 字符串。多么痛苦。

function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    // $postfields is an assoc array.
    // Creates a boundary.
    // Reads each postfields, detects which are @files, and which values are arrays
    // and dumps them into a new array (not an assoc array) so each key can exist
    // multiple times.
    // Sets content-length, content-type and sets CURLOPT_POSTFIELDS with the
    // generated body.
}

我能够像这样使用这种方法:

curl_setopt_custom_postfields($ch, array(
    'file' => '@/path/to/file',
    'tag' => array('a', 'b', 'c'),
));

我不确定 CURLOPT_HTTPHEADER 堆栈,因此由于此方法调用它,因此我确定该函数将允许用户在需要时指定附加标头。

在这篇博文中有完整的代码。

于 2009-01-01T05:07:31.690 回答
3

如果您使用tag[]而不是tag名称,PHP 将为您生成一个数组,换句话说,而不是

tag=foo&tag=bar&tag=baz

你需要

tag[]=foo&tag[]=bar&tag[]=baz

请注意,当 urlencoded 传输时,这应该变成

tag%5B%5D=foo&tag%5B%5D=bar&tag%5B%5D=baz
于 2008-12-31T11:03:43.610 回答
3
  1. PHP 错误 #51634投票。
  2. 试试@BeauSimensen 的答案。
  3. Guzzle可以做到这一点。请参阅下面的示例。
$client = new \GuzzleHttp\Client();
$client->request('POST', $url, [
  'multipart' => [
    [ 'name' => 'foo', 'contents' => 'bar' ],
    [ 'name' => 'foo', 'contents' => 'baz' ],
  ]
]);
于 2019-09-27T03:26:14.463 回答
2

我让它工作使用:

curl_setopt($ch, CURLOPT_POSTFIELDS,array('tag[0]'=>'val0','tag[1]'=>'val1'));

然后$_POST导致:$_POST['tag'][0] = 'val0'$_POST['tag'][1] = 'val1'

于 2009-11-05T21:03:47.323 回答
2

我遇到了同样的问题。但我能够以这种方式解决它。

for($cnt = 0; $cnt < count($siteRows); $cnt++)
{
    $curlParams['site_ids['.$cnt.']'] = $siteRows[$cnt]->site_id; 
}

也适用于文件:

for($cnt = 0; $cnt < count($imageRows); $cnt++)
{
    $curlParams['product_images['.$cnt.']'] = '@'.$imageRows[$cnt]->full_path;
}
于 2010-01-10T00:14:48.380 回答
1

我认为一个键(或同一个键)中多个值的既定标准是将其与分隔符连接起来,例如在表单元素中选择多个选项列表。我相信这个分隔符是制表符 ( \t) 或管道符号 ( |)。

[]如果键名以(like )结尾tag[],PHP 会自动将值转换为数组以方便您使用。

于 2008-12-31T11:49:41.147 回答
1

lImbus 和保罗,感谢您的意见。

如果我可以控制我发布到的表单,我可能会找到解决此问题的替代解决方案。但是,我对表单没有任何控制权。而且我几乎可以肯定,阅读这篇文章的软件不是 PHP 并且不遵守 tag[] 标准。

即使这样做了,cURL 似乎也不遵守 tag[] 语法。基本上,我尝试了以下方法,但都没有奏效......

curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@/pathtofile', 'tag[]' => array('a', 'b', 'c'));

curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@/pathtofile', 'tag' => array('a', 'b', 'c'));

再说一次,我不认为传递标签 [] 无论如何都会起作用,因为我要发布的表单实际上是在寻找“标签”而不是“标签 []”。

我真的开始觉得 cURL PHP 绑定真的不支持这个。这对我来说似乎很令人惊讶。它似乎可以做任何其他事情,但它无法做这样简单的事情?

于 2008-12-31T21:36:42.270 回答
0

不要使用 GUZZLE

# at your command line start php interactive
user@group:~:php -a
php > $arr=array('var' => array(1,2,3,4)); 
php > echo http_build_query($arr);
var%5B0%5D=1&var%5B1%5D=2&var%5B2%5D=3&var%5B3%5D=4
php > echo urldecode(http_build_query($arr));
var[0]=1&var[1]=2&var[2]=3&var[3]=4

因此,您需要http_build_query在其中传递键值的哈希数组;您的(数组)变量作为键输入,其值为数组而不是标量值,如'var' => array(1,2,3,4). 现在,http_build_query可以格式化curl命令的帖子字段:

$fields = array('key1' => 'value1', 'var' => array(1,2,3,4));
$curlPost = \http_build_query($fields);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);

那是 3 行代码!Guzzle 中有多少 1000 行代码?(*)

到目前为止,我曾经curl

那是用大约 100 行替换了数百万行!

(*):结果http_build_query可以根据您的需要进一步格式化。

于 2020-07-25T17:18:38.610 回答
0

我遇到了同样的问题,我必须将一个必须是数组的参数从 PHP 服务器发送到另一个不使用 '[]' 来混合具有相同键的值和文件的服务器。在 Laravel 8 中,我可以使用Http 客户端实现这个目标(当然 Http 客户端使用 guzzle)。这是我的代码示例。

Illuminate\Support\Facades\Http::attach('file', $fileContents, 'file-name')
->post('https://destination' , [['name' => 'tag', 'content' => 'foo'], ['name' => 'tag', 'content' => 'bar']])
于 2021-04-28T07:30:56.417 回答
-1

我在网上找到了这个答案,想在它消失之前把它贴在这里:

http://yeehuichan.wordpress.com/2011/08/07/sending-multiple-values-with-the-same-namekey-in-curl-post/

function curl_setopt_custom_postfields($ch, $postfields, $headers = null) {
    $algos = hash_algos();
    $hashAlgo = null;
    foreach ( array('sha1', 'md5') as $preferred ) {
        if ( in_array($preferred, $algos) ) {
            $hashAlgo = $preferred;
            break;
        }
    }
    if ( $hashAlgo === null ) { list($hashAlgo) = $algos; }
    $boundary =
        '----------------------------' .
        substr(hash($hashAlgo, 'cURL-php-multiple-value-same-key-support' . microtime()), 0, 12);

    $body = array();
    $crlf = "\r\n";
    $fields = array();
    foreach ( $postfields as $key => $value ) {
        if ( is_array($value) ) {
            foreach ( $value as $v ) {
                $fields[] = array($key, $v);
            }
        } else {
            $fields[] = array($key, $value);
        }
    }
    foreach ( $fields as $field ) {
        list($key, $value) = $field;
        if ( strpos($value, '@') === 0 ) {
            preg_match('/^@(.*?)$/', $value, $matches);
            list($dummy, $filename) = $matches;
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"; filename="' . basename($filename) . '"';
            $body[] = 'Content-Type: application/octet-stream';
            $body[] = '';
            $body[] = file_get_contents($filename);
        } else {
            $body[] = '--' . $boundary;
            $body[] = 'Content-Disposition: form-data; name="' . $key . '"';
            $body[] = '';
            $body[] = $value;
        }
    }
    $body[] = '--' . $boundary . '--';
    $body[] = '';
    $contentType = 'multipart/form-data; boundary=' . $boundary;
    $content = join($crlf, $body);
    $contentLength = strlen($content);

    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Length: ' . $contentLength,
        'Expect: 100-continue',
        'Content-Type: ' . $contentType,
    ));

    curl_setopt($ch, CURLOPT_POSTFIELDS, $content);

}

并使用它:

curl_setopt_custom_postfields($ch, array(
    'file' => '@a.csv',
    'name' => array('James', 'Peter', 'Richard'),
));
于 2013-10-04T02:45:07.890 回答