ChatGPT解决这个技术问题 Extra ChatGPT

PHP、cURL 和 HTTP POST 示例?

谁能告诉我如何用 HTTP POST 做一个 PHP cURL?

我想发送这样的数据:

username=user1, password=passuser1, gender=1

www.example.com

我希望 cURL 返回类似 result=OK 的响应。有没有例子?


m
mimarcel
<?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 { ... }
?>

无需使用 http_build_query() 处理参数;只需将数组传递给 CURLOPT_POSTFIELDS 就足够了。
@Raptor 直接向 CURLOPT_POSTFIELDS 提供数组实际上 curl 使 POST 类型略有不同。 (预计:100-继续)
此外,如果 CURLOPT_POSTFIELDS 的值是一个数组,则 Content-Type 标头将设置为 multipart/form-data 而不是 application/x-www-form-urlencodedphp.net/manual/en/function.curl-setopt.php
使用 CURLOPT_RETURNTRANSFER 意味着 curl_exec 将以字符串的形式返回响应,而不是输出它。
我建议对 CURLOPT_POST 使用 true 而不是 1
e
emix

程序

// 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() 方法并让上面的类实现它。然后,您始终可以将此实现与您喜欢的另一个适配器交换,而不会对您的应用程序产生任何副作用。

使用 HTTPS / 加密流量

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

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

永远,永远不要那样做。相反,您只需修改您的 php.ini 并告诉 PHP 您的 CA Certificate 文件在哪里,让它正确验证证书:

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

最新的 cacert.pem 可以从 Internet 或 extracted from your favorite browser 下载。更改任何 php.ini 相关设置时,请记住重新启动您的网络服务器。


这确实应该是公认的答案,因为最佳实践是让 HTTP 库处理变量的编码。
这并非总是如此。我见过期望 POST 变量以某种方式编码的 Web 服务器,否则会导致它们失败。在我看来, http_build_query() 实际上比 cURL 更可靠。
HTTP 规范对 POST 参数的外观非常简单。无论如何,网络服务器软件都应该符合标准。
通过使用这种方式,您将强制 cURL 使用稍微不同类型的 POST。 (预期:100-继续)。查看这篇文章:support.urbanairship.com/entries/…
扩展@César 的评论,PHP documentation 明确指出以下内容:“将数组传递给 CURLOPT_POSTFIELDS 会将数据编码为 multipart/form-data,而传递 URL 编码的字符串将对数据进行编码作为 application/x-www-form-urlencoded."。我最近花费了大量时间来尝试解决为什么 cURL 调用在第三方端点上失败,最终才意识到他们不支持 multipart/form-data。
E
Eric Leschinski

使用 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 ."&"; 还是不应该?
再看一下这个答案,您还可以用 http_build_query 替换您的自定义查询字符串转换器实现,只需给它 $fields 数组,它就会输出一个查询字符串。
请注意,您应该对数据进行编码,以便安全地提交。
哦不,不要尝试自己构建帖子字符串!使用这个:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
-1 因为你没有逃避你的帖子变量。 OP 的示例是发送用户提交的用户名和密码以进行身份验证。使用您的解决方案,拥有 &在他们的密码中将永远无法登录。oriadam 的评论是正确的,但您可以省略 http_build_query,例如:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
c
cn007b

可以通过以下方式轻松实现:

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

M
MSS

Curl Post + 错误处理 + 设置标题 [感谢@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 。您应该 curl_close 在 finally 块内。
P
Pejman Kheyri

1.一步一步

初始化 cURL 会话:

$url = "www.domain.com";
$ch = curl_init($url);

如果您的请求具有不记名令牌之类的标头或定义 JSON 内容,您必须将 HTTPHEADER 选项设置为 cURL:

$token = "generated token code";
curl_setopt(
    $ch, 
    CURLOPT_HTTPHEADER, 
    array(
        'Content-Type: application/json', // for define content type that is json
        'bearer: '.$token, // send token in header request
        'Content-length: 100' // content length for example 100 characters (can add by strlen($fields))
    )
);

如果要在输出中包含标头,请将 CURLOPT_HEADER 设置为 true:

curl_setopt($ch, CURLOPT_HEADER, false);

将 RETURNTRANSFER 选项设置为 true 以将传输作为字符串返回,而不是直接输出:

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

要检查 SSL 对等证书中是否存在通用名称,可以将其设置为 0(不检查名称)、1(cURL 7.28.1 中不支持)、2(默认值和生产模式):

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

通过 cURL 将字段作为数组发布:

$fields = array(
    "username" => "user1",
    "password" => "passuser1",
    "gender" => 1
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

执行 cURL 并返回字符串。根据您的资源,这将返回结果 = OK 之类的输出:

$result = curl_exec($ch);

关闭 cURL 资源,释放系统资源:

curl_close($ch);

2.作为类使用

可以扩展的整个 call_cURL 类:

class class_name_for_call_cURL {
    protected function getUrl() {
        return "www.domain.com";
    }

    public function call_cURL() {
        $token = "generated token code";

        $fields = array(
            "username" => "user1",
            "password" => "passuser1",
            "gender" => 1
        );

        $url = $this->getUrl();
        $output = $this->_execute($fields, $url, $token);
        
        // if you want to get json data
        // $output = json_decode($output);
            
        if ($output == "OK") {
            return true;
        } else {
             return false;
        }
    }

    private function _execute($postData, $url, $token) {
        // for sending data as json type
        $fields = json_encode($postData);

        $ch = curl_init($url);
        curl_setopt(
            $ch, 
            CURLOPT_HTTPHEADER, 
            array(
                'Content-Type: application/json', // if the content type is json
                'bearer: '.$token // if you need token in header
            )
        );
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }
}

使用类并调用 cURL:

$class = new class_name_for_call_cURL();
var_dump($class->call_cURL()); // output is true/false

3.一个功能

在任何需要的地方使用的功能:

function get_cURL() {

        $url = "www.domain.com";
        $token = "generated token code";

        $postData = array(
            "username" => "user1",
            "password" => "passuser1",
            "gender" => 1
        );

        // for sending data as json type
        $fields = json_encode($postData);

        $ch = curl_init($url);
        curl_setopt(
            $ch, 
            CURLOPT_HTTPHEADER, 
            array(
                'Content-Type: application/json', // if the content type is json
                'bearer: '.$token // if you need token in header
            )
        );
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
}

此功能仅可通过以下方式使用:

var_dump(get_cURL());

你好@Pejman,你好吗?我看到你对这个很好..所以你能看看我的类似问题吗? stackoverflow.com/questions/72122223/…
P
Polluks

我很惊讶没有人建议 file_get_contents:

$url = "http://www.example.com";
$parameters = array('username' => 'user1', 'password' => 'passuser1', 'gender' => '1');
$options = array('http' => array(
    'header'  => 'Content-Type: application/x-www-form-urlencoded\r\n',
    'method'  => 'POST',
    'content' => http_build_query($parameters)
));

$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);

这很简单,它有效;我在我控制两端代码的环境中使用它。

更好的是,使用 json_decode (并设置您的代码以返回 JSON)

$result = json_decode(file_get_contents($url, false, $context), TRUE);

这种方法在幕后调用 curl,但您不会跳过那么多圈。

从 Stack Overflow 上其他地方的原始答案中提炼出来的答案:PHP sending variables to file_get_contents()


这是一个非常好的答案。但是,它仅在我删除内容类型标题部分时才对我有用。
@lukas,内容类型标头是由 SO 编辑器添加的,而不是我...
你好@cloudxix,你好吗?我看到你对这个很好..所以你能看看我的类似问题吗? stackoverflow.com/questions/72122223/…
M
Mantas D
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;
}

您的代码不会关闭句柄并释放资源,因为您在引发异常后 curl_close 。您应该在 finally 块内 curl_close
A
Anthony

如果表单使用重定向、身份验证、cookies、SSL (https) 或其他任何需要 POST 变量的完全开放脚本,那么您将很快开始咬牙切齿。看看 Snoopy,它完全符合您的想法,同时无需设置大量开销。


如果您想坚持使用股票库,只需尝试添加 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
唯一的缺点是您仍然需要处理设置 cookie jar 和其他潜在问题(例如是否遵循重定向、如何处理非基于 HTTP 的身份验证等)。 6 年后,我会推荐更通用的“无头浏览器”概念,而不是那个特定的库(或者 sourceforge 上的任何东西,过时了,对吧?)虽然我通常只是直接处理 curl 选项,但我仍然建议查看与 PSR-7 兼容的无头浏览器库(Guzzle 是我唯一知道的副手)以避免头痛。
a
andrewsi

如果您将信息传递到自己的网站,一个更简单的答案是使用 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']);}

A
AzizSM

以下是 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, "");
    ...
?>

S
Serhii Andriichuk

发送 formraw 数据的示例:

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

P
Pejman Kheyri

如果您尝试使用 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'; }

T
Tobias Ernst

最简单的是将数据作为 application/json 发送。这会将数组作为输入并将其正确编码为 json 字符串:

$data = array(
    'field1' => 'field1value',
    'field2' => 'field2value',
)

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type:application/json',
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultStr = curl_exec($ch);
return json_decode($resultStr, true);