如何使用PHP发送POST请求?


656

实际上,我想阅读搜索查询之后的内容,完成之后。问题是URL仅接受POST方法,并且对GET方法不采取任何操作...

我必须借助domdocument或阅读所有内容file_get_contents()。有什么方法可以让我使用POSTmethod 发送参数,然后通过读取内容PHP

Answers:


1260

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手册,例如:


64
值得注意的是,如果您决定对标题使用数组,请不要以'\ r \ n'结尾键或值。stream_context_create()仅将文本带到第一个'\ r \
n'–猛禽

11
file_get_contents()仅当启用了fopen包装器时,URL才能用作文件名。见php.net/manual/en/…–
皮诺

3
@我爱file_get_contents()
僵局

14
是否有不使用CURL的特定原因?
jvannistelrooy,2015年

37
@jvannistelrooy PHP的CURL是一个扩展,可能并非在所有环境中都存在,但file_get_contents()它是PHP核心的一部分。另外,不必要地使用扩展程序可以扩大应用程序的攻击范围。例如Google php curl cve
Pocketsand '16

139

您可以使用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;
?>

3
这对我有用,因为我要发送的页面到一个没有内容的页面,所以file_get_contents版本不起作用。

9
file_get_contents解决方案不适用于禁用allow_url_fopen的PHP配置(例如在共享托管中)。这个版本使用curl库,我认为这是最“通用的”,所以我投我一票
Dayron Gallardo 2014年

81
您没有从以下位置复制此代码示例的站点: davidwalsh.name/curl-post
efreed,2015年

4
尽管不是很重要,但实际上不需要将CURLOPT_POSTFIELDS参数数据转换为字符串(“ URLified”)。Quote:“此参数可以作为诸如'para1 = val1&para2 = val2&...'的urlencoded字符串或字段名称作为键且字段数据作为值的数组传递。如果value是数组,则为Content-Type标头将设置为multipart / form-data。” 链接:php.net/manual/en/function.curl-setopt.php
Edward

2
同样,以不同的方式编写它也没有冒犯性,但是我不知道为什么在这里将CURLOPT_POST参数指定为数字,因为它说在手册页上将其设置为布尔值。Quote:“ CURLOPT_POST:TRUE进行常规HTTP POST。” 链接:php.net/manual/en/function.curl-setopt.php
爱德华

68

我使用以下函数使用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会导致使用多部分/表单数据对数据进行编码,这可能是不希望的。
Dima L.

用户确实要求file_get_contents,所以他需要一个用于更改default_stream_context的解决方案
Radon8472 '18

澄清一下:我认为是@DimaL。正在回应已删除的评论;http_build_query$data数组转换为字符串,避免输出为multipart / form-data。
ToolmakerSteve

@ Radon8472- ... CURLOPT_RETURNTRANSFER, true结果$response包含其中的内容。
ToolmakerSteve19年

如我所说,@ ToolmakerSteve是个问题file_get_contents,您的解决方案需要CURL,而许多人还没有。因此您的解决方案可能正在工作,但未回答如何使用本机内置文件/流功能执行此操作的问题。
Radon8472

42

我建议你使用开源包狂饮即完全单元测试,并采用了最新的编码实践。

安装枪口

转到项目文件夹中的命令行,然后键入以下命令(假设您已经安装了程序包管理器作曲家)。如果您需要有关如何安装Composer的帮助,请在此处查看

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);

7
知道与已发布的本机PHP解决方案相比,cURL有什么优势将很有用。
artfulrobot

9
@artfulrobot:本地PHP解决方案存在很多问题(例如,与https连接,证书验证等)。这就是为什么几乎每个PHP开发人员都使用cURL的原因。在这种情况下为什么不使用cURL?很简单:Guzzle具有简单,轻便的界面,可以将所有这些“低级cURL处理问题”抽象化。几乎每个开发现代PHP的人都使用Composer,因此使用Guzzle非常简单。
Andreas

2
谢谢,我知道guzzle很流行,但是在某些情况下,作曲家会感到悲伤(例如,为可能已经使用(不同版本)guzzle或其他依赖项的大型软件项目开发插件),因此很高兴知道此信息决定哪种解决方案最可靠
artfulrobot

26

如果要那样的话,还有另一个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我们正在发出一个发布请求,并且我们正在发送一些数据,并提供数据。CURLOPT_RETURNTRANSFER标志告诉curl向我们提供输出作为curl_exec的返回值,而不是输出它。然后我们进行呼叫并关闭连接-结果在$ response中。


1
在第三个curl_setopt()调用中,第一个arg应该$ch不是$curl,对吗?
jcomeau_ictx

您可以使用相同的代码发布JSON数据吗?但是用$ json(其中$ json可能是JSON字符串?)替换$ xml
Neal Davis

24

如果您有机会使用Wordpress开发应用程序(即使是非常简单的东西,这实际上也是获得授权,信息页面等的便捷方法),则可以使用以下代码段:

$response = wp_remote_post( $url, array('body' => $parameters));

if ( is_wp_error( $response ) ) {
    // $response->get_error_message()
} else {
    // $response['body']
}

它使用不同的方式来发出实际的HTTP请求,具体取决于Web服务器上可用的内容。有关更多详细信息,请参见HTTP API文档

如果您不想开发自定义主题或插件来启动Wordpress引擎,则可以在wordpress根目录下的独立PHP文件中执行以下操作:

require_once( dirname(__FILE__) . '/wp-load.php' );

// ... your code

它不会显示任何主题或输出任何HTML,只需使用Wordpress API即可!


22

我想对Fred Tanrikut基于卷曲的答案添加一些想法。我知道大多数答案已经写在上面的答案中,但是我认为将所有答案都包含在内是一个好主意。

这是我编写的基于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);来避免返回。之后,返回值为boolean(true =请求成功,否则发生错误),并回显响应。请参阅:http//php.net/en/manual/function.curl-exec.php
  • 使用curl_close清理会话关闭和删除curl-handler 。请参阅:http//php.net/manual/en/function.curl-close.php
  • curl_setopt函数使用布尔值而不是使用任何数字。(我知道不等于零的任何数字也被视为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文件中。我还需要做什么?
LinusGeffarth

1
您能发布您的代码吗?没有任何代码片段,很难猜测出什么问题了。
mwatzer

就像我说的,我已经将您的字面意思复制到我的纯php文件中,这给了我这个错误。
LinusGeffarth '18

1
好的,现在我看到了问题,在示例中是错误的!您必须调用HTTPRequester :: HTTPPost()而不是HTTPRequester :: HTTPost()
mwatzer

1
啊。那个很容易错过。在发现多余的P之前,我必须阅读5倍的评论。谢谢!
LinusGeffarth '18

19

上面的无卷曲方法的另一种替代方法是使用本机函数:

  • stream_context_create()

    使用选项预设中提供的任何选项创建并返回流上下文。

  • stream_get_contents()

    与相同file_get_contents(),不同之处在于stream_get_contents() 它对已经打开的流资源进行操作,并以字符串形式返回剩余的内容,最大长度为maxlength个字节,并从指定的offset开始

具有这些功能的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;
}

1
这种无CURL的方法对我来说很好,可以从Google验证reCAPTCHA。这个答案汇聚与此谷歌代码:github.com/google/recaptcha/blob/master/src/ReCaptcha/...
哈维蒙特罗

1
fclose()如果$fp是,则不必使用false。因为fclose()期望资源是参数。
弗洛里斯

1
@Floris刚刚对其进行了编辑,实际上fclose文档提到“文件指针必须有效”。谢谢您的注意!
CPHPython

8

更好的发送GETPOST请求方式PHP如下:

<?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


1
@akinuri感谢您的重点介绍,我将分享新内容。
Imran Zahoor,

如何在PHP 5x上做到这一点?

@YumYumYum请结帐dbau的答案为以上5倍使用这种技术php.net/manual/en/function.stream-context-create.php 或者,你可以随时返回到标准卷曲的解决方案。
Imran Zahoor

5

还有更多可以使用的

<?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);
?>

点击这里了解详情


2
这依赖于PECL扩展,大多数扩展都不会安装。由于手册页已被删除,因此甚至不确定它是否仍然可用。
miken32 '16

5

我在寻找类似的问题,并且找到了一种更好的方法。所以就到这里。

您只需将以下行放在重定向页面上(例如page1.php)。

header("Location: URL", TRUE, 307); // Replace URL with to be redirected URL, e.g. final.php

我需要它来重定向REST API调用的POST请求。该解决方案能够使用发布数据以及自定义标头值进行重定向。

这是参考链接


1
这个答案如何重定向页面请求不是如何发送与PHP POST请求?当然,这可以转发任何POST参数,但这完全不一样
Wesley Smith

@ DelightedD0D,对不起,我没有得到redirect a page request with POST paramvs与之间的区别send POST request。对我来说,两者的目的是相同的,如果我错了,请纠正我。
阿林丹·纳亚克

1
有什么方法可以让我使用POST方法发送参数,然后通过PHP读取内容?OP希望他们的php脚本构造一组POST参数,并将其发送到另一个php页面,以使其脚本接收该页面的输出。该解决方案将仅接受一组已过帐的值并将其转发到另一页。他们是完全不同的。
韦斯利·史密斯

5

这里仅使用一个没有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将如何工作?它们之间的分隔符是什么?
穆罕默德·伊德雷斯(Muhammad Idrees)

@Sayedidrees要添加key2,可以将其作为第二个数组项输入。'KEY1'=> '世界,你好!', '键2'=> '第二值'
西甲

与zapier一起使用时,效果很好。
Moxet 1

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.