如何使用 PHP 发送 POST 请求?
Posted
技术标签:
【中文标题】如何使用 PHP 发送 POST 请求?【英文标题】:How do I send a POST request with PHP? 【发布时间】:2011-08-04 14:00:59 【问题描述】:实际上,我想在完成后阅读搜索查询之后的内容。问题是URL只接受POST
方法,对GET
方法没有任何动作...
我必须在domdocument
或file_get_contents()
的帮助下阅读所有内容。有没有什么方法可以让我用POST
方法发送参数,然后通过php
读取内容?
【问题讨论】:
【参考方案1】:使用 PHP5 的无 CURL 方法:
$url = 'http://server.com/path';
$data = array('key1' => 'value1', 'key2' => 'value2');
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) /* Handle error */
var_dump($result);
有关该方法以及如何添加标头的更多信息,请参阅 PHP 手册,例如:
stream_context_create:http://php.net/manual/en/function.stream-context-create.php【讨论】:
值得注意的是,如果您决定使用数组作为标题,请不要以“\r\n”结束键或值。 stream_context_create() 只会将文本带到第一个 '\r\n' 只有在启用了 fopen 包装器的情况下,才能将 URL 用作带有file_get_contents()
的文件名。见php.net/manual/en/…
不使用 CURL 是否有特定原因?
@jvannistelrooy PHP 的 CURL 是一个扩展,可能并不存在于所有环境中,而 file_get_contents()
是 PHP 核心的一部分。此外,不必要地使用扩展程序可能会扩大应用程序的攻击面。例如。谷歌php curl cve
bool(false) 我明白了吗??【参考方案2】:
你可以使用cURL:
<?php
//The url you wish to send the POST request to
$url = $file_name;
//The data you want to send via POST
$fields = [
'__VIEWSTATE ' => $state,
'__EVENTVALIDATION' => $valid,
'btnSubmit' => 'Submit'
];
//url-ify the data for the POST
$fields_string = http_build_query($fields);
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
//So that curl_exec returns the contents of the cURL; rather than echoing it
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
//execute post
$result = curl_exec($ch);
echo $result;
?>
【讨论】:
这个对我有用,因为我发送的页面没有内容,所以 file_get_contents 版本不起作用。 file_get_contents 解决方案不适用于 allow_url_fopen 关闭的 PHP 配置(如在共享主机中)。这个版本使用 curl 库,我认为是最“通用”的,所以我给你投票 您没有从以下站点复制此代码示例:davidwalsh.name/curl-post 虽然不是很重要,但是CURLOPT_POSTFIELDS参数数据其实不需要转换成字符串(“urlified”)。引用:“此参数可以作为 urlencoded 字符串传递,例如 'para1=val1¶2=val2&...'标头将设置为 multipart/form-data。”链接:php.net/manual/en/function.curl-setopt.php. 另外,以不同的方式编写它并没有冒犯,但我不知道为什么 CURLOPT_POST 参数在此处指定为数字,因为它说在手册页上将其设置为布尔值。 Quote: "CURLOPT_POST: TRUE 做一个常规的 HTTP POST。"链接:php.net/manual/en/function.curl-setopt.php.【参考方案3】:我使用以下函数使用 curl 发布数据。 $data 是要发布的字段数组(将使用 http_build_query 正确编码)。数据使用 application/x-www-form-urlencoded 进行编码。
function httpPost($url, $data)
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
curl_close($curl);
return $response;
@Edward 提到 http_build_query 可能会被省略,因为 curl 将正确编码传递给 CURLOPT_POSTFIELDS 参数的数组,但请注意,在这种情况下,数据将使用 multipart/form-data 进行编码。
我将此函数与期望数据使用 application/x-www-form-urlencoded 编码的 API 一起使用。这就是我使用 http_build_query() 的原因。
【讨论】:
将数组传递给 CURLOPT_POSTFIELDS 会导致数据使用 multipart/form-data 进行编码,这可能是不可取的。 用户确实请求了 file_get_contents,所以他需要一个解决方案来更改 default_stream_context 澄清一下:我认为@DimaL。正在回复已删除的评论;http_build_query
将 $data
数组转换为字符串,避免输出为 multipart/form-data。
@Radon8472 - ... CURLOPT_RETURNTRANSFER, true
导致 $response
包含内容。
@ToolmakerSteve 正如我所说,问题是针对file_get_contents
的,您的解决方案需要很多人没有的 CURL。所以您的解决方案可能有效,但它没有回答如何使用本机内置文件/流函数执行此操作的问题。【参考方案4】:
我建议您使用开源包guzzle,它经过全面单元测试并使用最新的编码实践。
安装 Guzzle
转到项目文件夹中的命令行并输入以下命令(假设您已经安装了包管理器composer)。如果您需要帮助如何安装 Composer,you should have a look here。
php composer.phar require guzzlehttp/guzzle
使用 Guzzle 发送 POST 请求
Guzzle 的使用非常简单,因为它使用轻量级的面向对象 API:
// Initialize Guzzle client
$client = new GuzzleHttp\Client();
// Create a POST request
$response = $client->request(
'POST',
'http://example.org/',
[
'form_params' => [
'key1' => 'value1',
'key2' => 'value2'
]
]
);
// Parse the response object, e.g. read the headers, body, etc.
$headers = $response->getHeaders();
$body = $response->getBody();
// Output headers and body for debugging purposes
var_dump($headers, $body);
【讨论】:
了解这与已经发布的原生 PHP 解决方案以及 cURL 相比有什么优势会很有用。 @artfulrobot:原生 PHP 解决方案有很多问题(例如连接 https、证书验证等),这就是几乎每个 PHP 开发人员都使用 cURL 的原因。在这种情况下为什么不使用 cURL 呢?很简单:Guzzle 有一个直接、简单、轻量级的界面,可以抽象出所有那些“低级 cURL 处理问题”。几乎每个开发现代 PHP 的人都使用 Composer,所以使用 Guzzle 非常简单。 谢谢,我知道 guzzle 很受欢迎,但是有些用例会导致作曲家导致悲伤(例如,为可能已经使用(不同版本)guzzle 或其他依赖项的更大软件项目开发插件),所以很高兴知道这些信息以决定哪种解决方案最强大 @Andreas 虽然你是对的,但这是一个很好的例子,越来越多的抽象导致对低级技术的理解越来越少,从而导致越来越多的开发人员不知道他们在那里做什么无论如何,即使是一个简单的请求也无法调试。 @clockw0rk 不幸的是,你是对的。但是抽象(在某种程度上)仍然是有用的,并且可以节省大量时间和错误/潜在的错误。显然,每个使用 Guzzle 的人都应该能够调试请求,并且对网络和 HTTP 的工作原理有基本的了解。【参考方案5】:我想就 Fred Tanrikut 的基于 curl 的答案添加一些想法。我知道他们中的大多数已经写在上面的答案中,但我认为显示一个包含所有这些答案的答案是个好主意。
这是我编写的基于 curl 发出 HTTP-GET/POST/PUT/DELETE 请求的类,仅涉及响应正文:
class HTTPRequester
/**
* @description Make HTTP-GET call
* @param $url
* @param array $params
* @return HTTP-Response body or an empty string if the request fails or is empty
*/
public static function HTTPGet($url, array $params)
$query = http_build_query($params);
$ch = curl_init($url.'?'.$query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
/**
* @description Make HTTP-POST call
* @param $url
* @param array $params
* @return HTTP-Response body or an empty string if the request fails or is empty
*/
public static function HTTPPost($url, array $params)
$query = http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
$response = curl_exec($ch);
curl_close($ch);
return $response;
/**
* @description Make HTTP-PUT call
* @param $url
* @param array $params
* @return HTTP-Response body or an empty string if the request fails or is empty
*/
public static function HTTPPut($url, array $params)
$query = \http_build_query($params);
$ch = \curl_init();
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, \CURLOPT_HEADER, false);
\curl_setopt($ch, \CURLOPT_URL, $url);
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
\curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
$response = \curl_exec($ch);
\curl_close($ch);
return $response;
/**
* @category Make HTTP-DELETE call
* @param $url
* @param array $params
* @return HTTP-Response body or an empty string if the request fails or is empty
*/
public static function HTTPDelete($url, array $params)
$query = \http_build_query($params);
$ch = \curl_init();
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, \CURLOPT_HEADER, false);
\curl_setopt($ch, \CURLOPT_URL, $url);
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
\curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
$response = \curl_exec($ch);
\curl_close($ch);
return $response;
改进
使用 http_build_query 从请求数组中获取查询字符串。(您也可以使用数组本身,因此请参阅:http://php.net/manual/en/function.curl-setopt.php) 返回响应而不是回显它。顺便说一句,您可以通过删除 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 行来避免返回。之后返回值为布尔值(true = 请求成功,否则发生错误)并回显响应。 见:http://php.net/en/manual/function.curl-exec.php 使用 curl_close 清除会话关闭和 curl 处理程序的删除。见:http://php.net/manual/en/function.curl-close.php curl_setopt 函数使用布尔值而不是使用任何数字。(我知道任何不等于 0 的数字也被认为是 true,但使用 true 会生成更易读的代码,但是这只是我的看法) 能够进行 HTTP-PUT/DELETE 调用(用于 RESTful 服务测试)使用示例
获取
$response = HTTPRequester::HTTPGet("http://localhost/service/foobar.php", array("getParam" => "foobar"));
发布
$response = HTTPRequester::HTTPPost("http://localhost/service/foobar.php", array("postParam" => "foobar"));
放
$response = HTTPRequester::HTTPPut("http://localhost/service/foobar.php", array("putParam" => "foobar"));
删除
$response = HTTPRequester::HTTPDelete("http://localhost/service/foobar.php", array("deleteParam" => "foobar"));
测试
您还可以使用这个简单的类进行一些很酷的服务测试。
class HTTPRequesterCase extends TestCase
/**
* @description test static method HTTPGet
*/
public function testHTTPGet()
$requestArr = array("getLicenses" => 1);
$url = "http://localhost/project/req/licenseService.php";
$this->assertEquals(HTTPRequester::HTTPGet($url, $requestArr), '["error":false,"val":["NONE","AGPL","GPLv3"]]');
/**
* @description test static method HTTPPost
*/
public function testHTTPPost()
$requestArr = array("addPerson" => array("foo", "bar"));
$url = "http://localhost/project/req/personService.php";
$this->assertEquals(HTTPRequester::HTTPPost($url, $requestArr), '["error":false]');
/**
* @description test static method HTTPPut
*/
public function testHTTPPut()
$requestArr = array("updatePerson" => array("foo", "bar"));
$url = "http://localhost/project/req/personService.php";
$this->assertEquals(HTTPRequester::HTTPPut($url, $requestArr), '["error":false]');
/**
* @description test static method HTTPDelete
*/
public function testHTTPDelete()
$requestArr = array("deletePerson" => array("foo", "bar"));
$url = "http://localhost/project/req/personService.php";
$this->assertEquals(HTTPRequester::HTTPDelete($url, $requestArr), '["error":false]');
【讨论】:
对我来说,它说 “未捕获的错误:调用未定义的方法 HTTPRequester::HTTPost()”。我只是将您的课程粘贴到我的 .php 文件中。还有什么我需要做的吗? 你能发布你的代码吗?没有任何代码 sn-p 很难猜出问题所在。 正如我所说,我已经将你的复制到我的普通 php 文件中,它给了我这个错误。 好的,现在我看到了问题,.. 示例中的错误!您必须调用 HTTPRequester::HTTPPost() 而不是 HTTPRequester::HTTPost() 啊。那个很容易错过。在我发现额外的 P 之前,我必须像 5x 一样阅读您的评论。谢谢!【参考方案6】:如果你要这样做,还有另一种 CURL 方法。
一旦您了解了 PHP curl 扩展的工作方式,将各种标志与 setopt() 调用结合起来,这将非常简单。在这个例子中,我有一个变量 $xml,它保存着我准备发送的 XML - 我将把它的内容发布到例子的测试方法中。
$url = 'http://api.example.com/services/xmlrpc/';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
//process $response
首先我们初始化连接,然后我们使用 setopt() 设置一些选项。这些告诉 PHP 我们正在发出一个 post 请求,并且我们正在发送一些数据,提供数据。 CURLOPT_RETURNTRANSFER 标志告诉 curl 给我们输出作为 curl_exec 的返回值,而不是输出它。然后我们进行调用并关闭连接 - 结果在 $response 中。
【讨论】:
在第三次 curl_setopt() 调用中,第一个参数应该是$ch
而不是 $curl
,对吗?
你能用同样的代码来发布 JSON 数据吗?但是将 $xml 替换为 $json (其中 $json 可能是 JSON 字符串?)【参考方案7】:
如果您有机会使用 Wordpress 来开发您的应用程序(它实际上是一种获得授权、信息页面等非常简单的东西的便捷方式),您可以使用以下 sn-p:
$response = wp_remote_post( $url, array('body' => $parameters));
if ( is_wp_error( $response ) )
// $response->get_error_message()
else
// $response['body']
它使用不同的方式来发出实际的 HTTP 请求,具体取决于 Web 服务器上可用的内容。详情请见HTTP API documentation。
如果您不想开发自定义主题或插件来启动 Wordpress 引擎,您可以在 wordpress 根目录中的一个独立 PHP 文件中执行以下操作:
require_once( dirname(__FILE__) . '/wp-load.php' );
// ... your code
它不会显示任何主题或输出任何 html,只需使用 Wordpress API 破解即可!
【讨论】:
【参考方案8】:curl-less method above 的另一种选择是使用原生 stream 函数:
stream_context_create()
:
使用 options 预设中提供的任何选项创建并返回流上下文。
stream_get_contents()
:
与
file_get_contents()
相同,除了stream_get_contents()
对已打开的流 资源进行操作并以字符串形式返回剩余内容,最长为 maxlength 个字节并开始在指定的偏移量。
带有这些的 POST 函数可以简单地像这样:
<?php
function post_request($url, array $params)
$query_content = http_build_query($params);
$fp = fopen($url, 'r', FALSE, // do not use_include_path
stream_context_create([
'http' => [
'header' => [ // header array does not need '\r\n'
'Content-type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($query_content)
],
'method' => 'POST',
'content' => $query_content
]
]));
if ($fp === FALSE)
return json_encode(['error' => 'Failed to get contents...']);
$result = stream_get_contents($fp); // no maxlength/offset
fclose($fp);
return $result;
【讨论】:
这种无 CURL 的方法对我来说可以很好地验证来自 google 的 reCAPTCHA。这个答案与这个谷歌代码一致:github.com/google/recaptcha/blob/master/src/ReCaptcha/… 如果$fp
是false
,则不必使用fclose()
。因为fclose()
期望资源是参数。
@Floris 刚刚编辑它,确实fclose docs 提到“文件指针必须有效”。感谢您注意到这一点!
我试过了,但我无法解析我的 api 中的“发布”数据。我正在使用 json_decode(file_get_contents("php://input"))) 有什么想法吗? ;编辑:通过将内容类型标头更改为 application/json,它起作用了。谢谢!【参考方案9】:
这里只使用一个没有 cURL 的命令。超级简单。
echo file_get_contents('https://www.server.com', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded",
'content' => http_build_query([
'key1' => 'Hello world!', 'key2' => 'second value'
])
]
]));
【讨论】:
Key2 将如何工作?它们之间的分隔符是什么? @Sayedidrees 添加 key2 您可以将其作为第二个数组项输入。 'key1' => 'Hello world!', 'key2' => '第二个值' 效果很好【参考方案10】:使用PHP
发送GET
或POST
请求的更好方法如下:
<?php
$r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
$r->setOptions(array('cookies' => array('lang' => 'de')));
$r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
try
echo $r->send()->getBody();
catch (HttpException $ex)
echo $ex;
?>
代码取自官方文档http://docs.php.net/manual/da/httprequest.send.php
【讨论】:
@akinuri 感谢您的关注,我将分享新的。 在 PHP 5x 上怎么做? @YumYumYum 请查看上面 dbau 的回答 5x,它使用了这种技术 php.net/manual/en/function.stream-context-create.php 或者你总是可以回到标准 curl 解决方案。 这不是原生 PHP。这需要 pecl http。【参考方案11】:我一直在寻找类似的问题,并找到了一种更好的方法。就这样吧。
您可以简单地将以下行放在重定向页面上(比如 page1.php)。
header("Location: URL", TRUE, 307); // Replace URL with to be redirected URL, e.g. final.php
我需要这个来重定向 REST API 调用的 POST 请求。此解决方案能够使用发布数据以及自定义标头值进行重定向。
这里是the reference link。
【讨论】:
这回答了如何重定向页面请求而不是如何使用 PHP 发送 POST 请求? 当然这会转发任何 POST 参数,但根本不是一回事 @DelightedD0D,对不起,我没有得到redirect a page request with POST param
和 send POST request
之间的区别。对我来说,两者的目的是一样的,如果我错了,请纠正我。
有没有什么方法可以让我用 POST 方法发送参数,然后通过 PHP 读取内容? OP 希望他们的 php 脚本构造一组 POST 参数和将他们发送到另一个 php 页面并让他们的脚本接收来自该页面的输出。该解决方案将简单地接受一组已发布的值并将它们转发到另一个页面。它们完全不同。【参考方案12】:
根据主要答案,这是我使用的:
function do_post($url, $params)
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => $params
)
);
$result = file_get_contents($url, false, stream_context_create($options));
示例用法:
do_post('https://www.google-analytics.com/collect', 'v=1&t=pageview&tid=UA-xxxxxxx-xx&cid=abcdef...');
【讨论】:
嗨,巴斯基。我不明白。我试过你的例子,它对我不起作用。您能否展示一些 URL 的用法,例如https://jsonplaceholder.typicode.com/todos/1
?提前致谢【参考方案13】:
尝试使用 PEAR 的 HTTP_Request2 包轻松发送 POST 请求。或者,您可以使用 PHP 的 curl 函数或使用 PHP stream context。
HTTP_Request2 也使mock out the server 成为可能,因此您可以轻松地对代码进行单元测试
【讨论】:
如果可能的话,我想请你详细说明一下。【参考方案14】:[编辑]:请忽略,目前在php中不可用。
还有一个你可以使用
<?php
$fields = array(
'name' => 'mike',
'pass' => 'se_ret'
);
$files = array(
array(
'name' => 'uimg',
'type' => 'image/jpeg',
'file' => './profile.jpg',
)
);
$response = http_post_fields("http://www.example.com/", $fields, $files);
?>
Click here for details
【讨论】:
这依赖于大多数人不会安装的 PECL 扩展。甚至不确定它是否仍然可用,因为手册页已被删除。 点击这里查看详细链接无效【参考方案15】:我更喜欢这个:
function curlPost($url, $data = NULL, $headers = [])
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5); //timeout in seconds
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_ENCODING, 'identity');
if (!empty($data))
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
if (!empty($headers))
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
if (curl_error($ch))
trigger_error('Curl Error:' . curl_error($ch));
curl_close($ch);
return $response;
使用示例:
$response=curlPost("http://my.url.com", ["myField1"=>"myValue1"], ["myFitstHeaderName"=>"myFirstHeaderValue"]);
【讨论】:
【参考方案16】:我创建了一个使用 JSON 请求帖子的函数:
const FORMAT_CONTENT_LENGTH = 'Content-Length: %d';
const FORMAT_CONTENT_TYPE = 'Content-Type: %s';
const CONTENT_TYPE_JSON = 'application/json';
/**
* @description Make a HTTP-POST JSON call
* @param string $url
* @param array $params
* @return bool|string HTTP-Response body or an empty string if the request fails or is empty
*/
function HTTPJSONPost(string $url, array $params)
$content = json_encode($params);
$response = file_get_contents($url, false, // do not use_include_path
stream_context_create([
'http' => [
'method' => 'POST',
'header' => [ // header array does not need '\r\n'
sprintf(FORMAT_CONTENT_TYPE, CONTENT_TYPE_JSON),
sprintf(FORMAT_CONTENT_LENGTH, strlen($content)),
],
'content' => $content
]
])); // no maxlength/offset
if ($response === false)
return json_encode(['error' => 'Failed to get contents...']);
return $response;
【讨论】:
【参考方案17】:如果您来自以前的 POST/GET/... 您可以在实际的 php 表单中使用include('fileName.php')
或 require('fileName.php')
PHP 脚本。因此它将继续 POST/GET/... 请愿书将在范围内有效
【讨论】:
以上是关于如何使用 PHP 发送 POST 请求?的主要内容,如果未能解决你的问题,请参考以下文章