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¶2=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' => 1, 'b' => [2, 3, 4]]
,那么它应该被参数化为a=1&b[]=2&b[]=3&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¶2=val2&...”)传递,也可以作为以字段名称为键、字段数据为值的数组传递。如果 value 是一个数组,则 Content-Type 标头将设置为 multipart/form-data。
JSON 编码
尽管如此,在与 JSON API 通信时,必须对内容进行 JSON 编码,以便 API 理解我们的 POST 数据。
在这种情况下,内容必须明确编码为 JSON:
CURLOPT_POSTFIELDS => json_encode(['param1' => $param1, 'param2' => $param2]),
在使用 JSON 进行通信时,我们通常也会相应地设置 accept
和 content-type
标头:
CURLOPT_HTTPHEADER => [
'accept: application/json',
'content-type: application/json'
]
【讨论】:
【参考方案6】:对于CURLOPT_POSTFIELDS
,参数既可以作为像para1=val1&para2=val2&..
这样的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&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 格式的主要内容,如果未能解决你的问题,请参考以下文章