CURLOPT_POSTFIELDS 的 curl POST 格式

Posted

技术标签:

【中文标题】CURLOPT_POSTFIELDS 的 curl POST 格式【英文标题】:curl POST format for CURLOPT_POSTFIELDS 【发布时间】:2011-07-10 15:13:57 【问题描述】:

当我通过POST 使用curl 并设置CURLOPT_POSTFIELD 时,我是否必须使用urlencode 或任何特殊格式?

例如:如果我想发布 2 个字段,第一个和最后一个:

first=John&last=Smith

curl 应该使用的确切代码/格式是什么?

$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$reply=curl_exec($ch);
curl_close($ch);

【问题讨论】:

【参考方案1】:

如果您要发送一个字符串,请对其进行 urlencode()。否则如果是数组,它应该是 key=>value 配对并且Content-type 标头自动设置为multipart/form-data

此外,您不必创建额外的函数来为您的数组构建查询,您已经拥有了:

$query = http_build_query($data, '', '&');

【讨论】:

您可以只使用http_build_query($data),因为& 是默认分隔符。 当然你可以跳过它们。这是为了说明您可能(或可能不会)更改的其他两个参数(例如默认分隔符)以满足您的特定需求。【参考方案2】:

编辑php5以上,推荐使用http_build_query

string http_build_query ( mixed $query_data [, string $numeric_prefix [, 
                          string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )

手册中的简单示例:

<?php
$data = array('foo'=>'bar',
              'baz'=>'boom',
              'cow'=>'milk',
              'php'=>'hypertext processor');

echo http_build_query($data) . "\n";

/* output:
foo=bar&baz=boom&cow=milk&php=hypertext+processor
*/

?>

php5 之前:

来自manual:

CURLOPT_POSTFIELDS

要在 HTTP“POST”操作中发布的完整数据。要发布文件,请在文件名前加上 @ 并使用完整路径。文件类型可以通过使用格式为“;type=mimetype”的文件名来明确指定。 此参数可以作为 urlencoded 字符串(如 'para1=val1&para2=val2&...')传递,也可以作为以字段名称为键、字段数据为值的数组传递。如果 value 是一个数组,则 Content-Type 标头将设置为 multipart/form-data。 从 PHP 5.2.0 开始,使用 @ 前缀传递给此选项的文件必须采用数组形式才能工作。

所以这样的事情应该可以完美地工作(在关联数组中传递参数):

function preparePostFields($array) 
  $params = array();

  foreach ($array as $key => $value) 
    $params[] = $key . '=' . urlencode($value);
  

  return implode('&', $params);

【讨论】:

如果可以传递数组,为什么还要传递字符串...? 我认为 $key 也应该被编码,以防万一你有它像“name&surname”等。特别是如果数据是由最终用户提供的 @barius,我同意你的看法。而且我认为 http_build_query() 实际上比上面定义的函数要好。 @skyfree 我同意!该功能是在 php5 中添加的,但在 2011 年还远未达到标准。 为什么只需要传递数组就需要http_build_query?【参考方案3】:

根本不要传递字符串!

你可以传递一个数组,让 php/curl 做编码等这些脏活。

【讨论】:

传递数组将是与字符串不同的内容类型,因此有充分的理由这样做。我花了一段时间才弄明白。 我不知道为什么,但我发现在我的 win dev pc 上传递一个数组大约需要一秒钟的时间(使用数组为 1.029 秒,而在同一个数组上使用 http_build_query() 为 0.016 秒) 嵌套数组不起作用。 cURL 将尝试将它们转换为字符串,然后 PHP 数组到字符串的转换 通知将跟随【参考方案4】:

此处尚未提及的另一个主要区别是CURLOPT_POSTFIELDS 无法处理嵌套数组。

如果我们采用嵌套数组['a' =&gt; 1, 'b' =&gt; [2, 3, 4]],那么它应该被参数化为a=1&amp;b[]=2&amp;b[]=3&amp;b[]=4[] 将/应该是 URL 编码的)。这将在另一端自动转换回嵌套数组(假设这里的另一端也是 PHP)。

这将起作用:

var_dump(http_build_query(['a' => 1, 'b' => [2, 3, 4]]));
// output: string(36) "a=1&b%5B0%5D=2&b%5B1%5D=3&b%5B2%5D=4"

这行不通:

curl_setopt($ch, CURLOPT_POSTFIELDS, ['a' => 1, 'b' => [2, 3, 4]]);

这会给你一个通知。代码执行将继续,您的端点将接收参数b 作为字符串"Array"

PHP注意事项:在线...中数组到字符串的转换...

【讨论】:

【参考方案5】:

这取决于content-type

url-encoded 或 multipart/form-data

要以标准方式发送数据,就像浏览器使用表单一样,只需传递一个关联数组。如PHP手册所述:

此参数可以作为 urlencoded 字符串(如“para1=val1&para2=val2&...”)传递,也可以作为以字段名称为键、字段数据为值的数组传递。如果 value 是一个数组,则 Content-Type 标头将设置为 multipart/form-data。

JSON 编码

尽管如此,在与 JSON API 通信时,必须对内容进行 JSON 编码,以便 API 理解我们的 POST 数据。

在这种情况下,内容必须明确编码为 JSON:

CURLOPT_POSTFIELDS => json_encode(['param1' => $param1, 'param2' => $param2]),

在使用 JSON 进行通信时,我们通常也会相应地设置 acceptcontent-type 标头:

CURLOPT_HTTPHEADER => [
    'accept: application/json',
    'content-type: application/json'
]

【讨论】:

【参考方案6】:

对于CURLOPT_POSTFIELDS,参数既可以作为像para1=val1&amp;para2=val2&amp;..这样的urlencoded字符串传递,也可以作为以字段名作为键、字段数据作为值的数组传递

试试下面的格式:

$data = json_encode(array(
"first"  => "John",
"last" => "Smith"
));

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);

【讨论】:

嗨 Shraddha,json_encode() 将为您提供与 first=John&amp;last=Smith 完全不同的有效参数字符串。 json_encode() 将输出:"first":"John","last":"Smith" 然后将成为您的 POST 请求的原始正文。 添加到@7ochem 的评论中:除非收件人期望包含一个json 编码字符串的单个参数,而不是json_encode(...)http_build_query(...)。这将创建包含由“&”分隔的参数的预期“url 编码字符串”。【参考方案7】:

根据 PHP 手册,作为字符串传递给 cURL 的数据应该是 URL 编码的。查看curl_setopt() 的页面并搜索CURLOPT_POSTFIELDS

【讨论】:

【参考方案8】:

当我们为 CMS Effcore 编写测试时,我们一直在寻找相同的解决方案。解决方案非常简单,如下所示:

$data = [
  'name[0]' => 'value 1',
  'name[1]' => 'value 2',
  'name[2]' => 'value 3',
  'id'      => 'value 4'
];

$data = array(
  'name[0]' => 'value 1',
  'name[1]' => 'value 2',
  'name[2]' => 'value 3',
  'id'      => 'value 4'
);

【讨论】:

【参考方案9】:

有趣的是,Postman POST 的方式是一个完整的 GET 操作,带有以下两个附加选项:

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, '');

只是另一种方式,而且效果很好。

【讨论】:

优秀,简单,也为我工作!谢谢 Klompenrunner!【参考方案10】:

这个答案也花了我很长时间才找到。我发现您所要做的就是将 URL(文件名和扩展名后的“?”)与 URL 编码的查询字符串连接起来。看起来您甚至不必设置 POST cURL 选项。请参阅下面的假示例:

//create URL
$exampleURL = 'http://www.example.com/example.php?';

// create curl resource
$ch = curl_init(); 

// build URL-encoded query string
$data = http_build_query(
    array('first' => 'John', 'last' => 'Smith', '&'); // set url
curl_setopt($ch, CURLOPT_URL, $exampleURL . $data); 

// return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

// $output contains the output string
$output = curl_exec($ch); 

// close curl resource to free up system resources <br/>
curl_close($ch);

你也可以使用file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);

【讨论】:

您似乎在做 GET 而不是 POST。

以上是关于CURLOPT_POSTFIELDS 的 curl POST 格式的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CURLOPT_POSTFIELDS 中包含数组数据? [复制]

post传递数据

cURL + 通过浏览器下载文件

php curl的隐藏BUG

PHP curl传 json字符串

PHP cURL 错误“安全库失败”。