PHP + curl,HTTP POST示例代码?


489

谁能告诉我如何使用HTTP POST进行php curl?

我想这样发送数据:

username=user1, password=passuser1, gender=1

www.domain.com

我希望curl会返回类似的响应result=OK。有什么例子吗?

Answers:


838
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
            "postvar1=value1&postvar2=value2&postvar3=value3");

// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS, 
//          http_build_query(array('postvar1' => 'value1')));

// Receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$server_output = curl_exec($ch);

curl_close ($ch);

// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>

47
无需使用http_build_query()来处理参数;只需将数组传递给CURLOPT_POSTFIELDS就足够了。
猛禽

8
@Raptor直接将数组提供给CURLOPT_POSTFIELDS,实际上curl使POST的类型略有不同。(预期:100个继续)
Oleg Popov

22
同样,如果value为CURLOPT_POSTFIELDS数组,则Content-Type标头将设置为multipart/form-data而不是application/x-www-form-urlencodedphp.net/manual/en/function.curl-setopt.php
Chloe,

2
使用CURLOPT_RETURNTRANSFER意味着curl_exec将以字符串形式返回响应而不是将其输出。
bnp887 '16

2
我建议使用true代替1for CURLOPT_POST
FluorescentGreen17年

260

程序

// set post fields
$post = [
    'username' => 'user1',
    'password' => 'passuser1',
    'gender'   => 1,
];

$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

// execute!
$response = curl_exec($ch);

// close the connection, release resources used
curl_close($ch);

// do anything you want with your response
var_dump($response);

面向对象

<?php

// mutatis mutandis
namespace MyApp\Http;

class CurlPost
{
    private $url;
    private $options;

    /**
     * @param string $url     Request URL
     * @param array  $options cURL options
     */
    public function __construct($url, array $options = [])
    {
        $this->url = $url;
        $this->options = $options;
    }

    /**
     * Get the response
     * @return string
     * @throws \RuntimeException On cURL error
     */
    public function __invoke(array $post)
    {
        $ch = curl_init($this->url);

        foreach ($this->options as $key => $val) {
            curl_setopt($ch, $key, $val);
        }

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

        $response = curl_exec($ch);
        $error    = curl_error($ch);
        $errno    = curl_errno($ch);

        if (is_resource($ch)) {
            curl_close($ch);
        }

        if (0 !== $errno) {
            throw new \RuntimeException($error, $errno);
        }

        return $response;
    }
}

用法

// create curl object
$curl = new \MyApp\Http\CurlPost('http://www.example.com');

try {
    // execute the request
    echo $curl([
        'username' => 'user1',
        'password' => 'passuser1',
        'gender'   => 1,
    ]);
} catch (\RuntimeException $ex) {
    // catch errors
    die(sprintf('Http error %s with code %d', $ex->getMessage(), $ex->getCode()));
}

这里的边注:最好创建一个AdapterInterface例如使用getResponse()method 调用的接口,并让上面的类实现它。然后,您始终可以将这种实现与您喜欢的另一个适配器交换,而对您的应用程序没有任何副作用。

使用HTTPS /加密流量

通常,在Windows操作系统下,PHP中的cURL存在问题。尝试连接到受https保护的端点时,您会收到一条错误消息,告诉您certificate verify failed

大多数人在这里所做的是告诉cURL库简单地忽略证书错误并继续(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);)。由于这将使您的代码正常工作,因此会引入巨大的安全漏洞,并使恶意用户能够对您的应用执行各种攻击,例如“中间人攻击”等。

永远不要那样做。相反,您只需要修改您php.iniCA Certificate文件并告诉PHP您的文件在哪里,即可使其正确验证证书:

; modify the absolute path to the cacert.pem file
curl.cainfo=c:\php\cacert.pem

cacert.pem可以从Internet下载最新版本,也可以从喜欢的浏览器中提取最新版本。更改任何php.ini相关设置时,请记住重新启动Web服务器。


4
这实际上应该是公认的答案,因为最佳实践是让HTTP库处理变量的编码。
埃里克·海斯特兰德'16

4
这并非总是如此。我见过一些Web服务器,它们期望POST变量以某种方式进行编码,否则将导致它们失败。在我看来,http_build_query()实际上比cURL更可靠。
塞萨尔

4
关于POST参数的外观,HTTP规范非常简单。无论如何,网络服务器软件都应符合标准。
emix

1
通过这种方式,您将强制cURL使用稍有不同的POST类型。(预期:100-继续)。检查这篇文章:support.urbanairship.com/entries/...
奥列格波波夫

5
通过扩展@César的注释,PHP文档明确指出以下内容:“将数组传递给CURLOPT_POSTFIELDS会将数据编码为multipart / form-data,而传递URL编码的字符串会将数据编码为application / x-www-form -urlencoded。”。最近,我花了太多时间来解决为什么在第三方端点上进行cURL调用失败的原因,以便最终意识到他们不支持multipart / form-data。
杰克Z

31

一个使用php curl_exec进行HTTP发布的实时示例:

将其放在一个名为foobar.php的文件中:

<?php
  $ch = curl_init();
  $skipper = "luxury assault recreational vehicle";
  $fields = array( 'penguins'=>$skipper, 'bestpony'=>'rainbowdash');
  $postvars = '';
  foreach($fields as $key=>$value) {
    $postvars .= $key . "=" . $value . "&";
  }
  $url = "http://www.google.com";
  curl_setopt($ch,CURLOPT_URL,$url);
  curl_setopt($ch,CURLOPT_POST, 1);                //0 for a get request
  curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars);
  curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,3);
  curl_setopt($ch,CURLOPT_TIMEOUT, 20);
  $response = curl_exec($ch);
  print "curl response is:" . $response;
  curl_close ($ch);
?>

然后使用命令运行它php foobar.php,它将这种输出转储到屏幕上:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Title</title>

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<body>
  A mountain of content...
</body>
</html>

因此,您对www.google.com进行了PHP POST,并向其发送了一些数据。

如果对服务器进行了编程以读取post变量,则可以基于此决定执行其他操作。


$postvars .= $key . $value;应该$postvars .= $key . $value ."&";还是不应该?
Manwal 2014年

再次查看此答案,您还可以将自定义查询字符串转换器实现替换为http_build_query,只需为其提供$fields数组,它将输出查询字符串。

请注意,您应该对数据进行编码,以便安全地提交数据。
wtf8_decode 2015年

3
哦,不,不要尝试自己构建发布字符串!使用这个:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam

3
-1,因为您没有转义post var。OP的示例是发送用户提交的用户名和密码进行身份验证。使用您的解决方案,密码为&的用户将永远无法登录。oriadam的注释正确,但您可以忽略以下内容http_build_querycurl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand

26

可以很容易地达到它:

<?php

$post = [
    'username' => 'user1',
    'password' => 'passuser1',
    'gender'   => 1,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.domain.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
var_export($response);

13

卷曲发布+错误处理+设置标题[感谢@ mantas-d]:

function curlPost($url, $data=NULL, $headers = NULL) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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


curlPost('google.com', [
    'username' => 'admin',
    'password' => '12345',
]);

您的代码不会关闭句柄和释放资源,因为在引发异常后您会curl_close。您应该在finally块中使用curl_close。
emix

7
curlPost('google.com', [
    'username' => 'admin',
    'password' => '12345',
]);


function curlPost($url, $data) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $response = curl_exec($ch);
    $error = curl_error($ch);
    curl_close($ch);
    if ($error !== '') {
        throw new \Exception($error);
    }

    return $response;
}

1
您的代码不会关闭句柄和释放资源,因为在引发异常后您会curl_close。您应该curl_close在一个finally块内。
emix

6

如果表单使用重定向,身份验证,Cookie,SSL(https)或除需要POST变量的完全打开的脚本以外的其他任何内容,您将非常迅速地开始努力。看一下Snoopy,它确实满足您的想法,同时消除了设置大量开销的需求。


如果您想坚持使用股票库,只需尝试添加curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
MarkHu,2016年

唯一的缺点是您仍然必须设置cookie罐和其他潜在问题(例如是否遵循重定向,如何处理基于非HTTP的身份验证等)。6年后,我会建议使用更通用的“无头浏览器”概念,而不是该特定的库(或sourceforge上的任何内容,如何注明日期,对吗?)虽然我通常只直接处理curl选项,但我仍然建议看看一个与PSR-7兼容的无头浏览器库(我唯一知道的就是Guzzle)以避免头痛。
安东尼

3

如果要将信息传递到自己的网站,一个更简单的答案是使用SESSION变量。以以下内容开始php页面:

session_start();

如果某些时候您想在PHP中生成信息并传递到会话的下一页,而不是使用POST变量,则将其分配给SESSION变量。例:

$_SESSION['message']='www.'.$_GET['school'].'.edu was not found.  Please try again.'

然后在下一页上,您只需引用此SESSION变量。注意:使用后,请确保将其销毁,因此使用后它不会持续存在:

if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}

3

这是一些PHP + curl的样板代码 http://www.webbotsspidersscreenscrapers.com/DSP_download.php

这些库中包含将简化开发

<?php
# Initialization
include("LIB_http.php");
include("LIB_parse.php");
$product_array=array();
$product_count=0;

# Download the target (store) web page
$target = "http://www.tellmewhenitchanges.com/buyair";
$web_page = http_get($target, "");
    ...
?>

2

如果您尝试使用Cookie在网站上登录。

这段代码:

if ($server_output == "OK") { ... } else { ... }

如果您尝试登录,则可能无法工作,因为许多站点返回状态200,但是发布不成功。

检查登录是否成功的简单方法是检查是否再次设置cookie。如果在输出中具有Set-Cookies字符串,则意味着发布不成功,并且开始新的会话。

同样,发布可以成功,但状态可以重定向为200。

为确保发布成功,请尝试以下操作:

在帖子后关注位置,因此它将转到帖子重定向到的页面:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

然后检查请求中是否存在新的cookie:

if (!preg_match('/^Set-Cookie:\s*([^;]*)/mi', $server_output)) 

{echo 'post successful'; }

else { echo 'not successful'; }

1

发送表格原始数据的示例:

$curlHandler = curl_init();

curl_setopt_array($curlHandler, [
    CURLOPT_URL => 'https://postman-echo.com/post',
    CURLOPT_RETURNTRANSFER => true,

    /**
     * Specify POST method
     */
    CURLOPT_POST => true,

    /**
     * Specify array of form fields
     */
    CURLOPT_POSTFIELDS => [
        'foo' => 'bar',
        'baz' => 'biz',
    ],
]);

$response = curl_exec($curlHandler);

curl_close($curlHandler);

echo($response);
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.