为什么 tlstest.paypal.com 可以在浏览器中运行,但不能在我的 PHP 代码中运行(对 Paypal IPN 有用)?

2021-12-29 00:00:00 ssl tls1.2 php paypal paypal-ipn

2018 年 6 月 30 日之后,Paypal 赢了不再接受非 TLS 1.2 + HTTP 1.1 请求.
他们创建了 URL https://tlstest.paypal.com/ 来测试连接是否正常.如果我们在浏览器中打开这个 URL,我们会得到一个成功的:

After 2018 June 30th, Paypal won't accept non-TLS 1.2 + HTTP 1.1 requests anymore.
They created the URL https://tlstest.paypal.com/ to test if connections are OK. If we open this URL in a browser, we get a successful:

PayPal_Connection_OK

问题:为什么使用以下代码从 PHP 连接时会失败?(我根本没有得到任何响应,浏览器仍处于等待状态"像这样,所以它甚至没有到达 echo $errno; echo $errstr;)

Quesiton: why does it fail when connecting from PHP with the following code? (I get no response at all, the browser is still in waiting "state" like this, so it doesn't even arrive at echo $errno; echo $errstr;)

<?php
$req = '';    // usually I use $req = 'cmd=_notify-validate'; for IPN
$header .= "POST / HTTP/1.1
";
$header .= "Host: tlstest.paypal.com
";
$header .= "Content-Type: application/x-www-form-urlencoded
";
$header .= "Content-Length: " . strlen($req) . "

";
$fp = fsockopen('tls://tlstest.paypal.com', 443, $errno, $errstr, 30);

if (!$fp) {
    echo $errno;
    echo $errstr;
} else {
    fputs($fp, $header);
    while (!feof($fp))
    {
        $res = fgets($fp, 1024);
        echo $res;
    }
    fclose($fp);
}
?>

注意:

  • 这不是 Paypal IPN HTTP/1.1 的副本 - 根本不提供任何响应,它是一个空字符串,后者已经过时.

我有 PHP 5.6.33-0+deb8u1 (cli)(构建时间:2018 年 1 月 5 日 15:46:26)和 openssl 版本文本:OpenSSL 1.0.1t 2016 年 5 月 3 日

I have PHP 5.6.33-0+deb8u1 (cli) (built: Jan 5 2018 15:46:26) and openssl version text: OpenSSL 1.0.1t 3 May 2016

推荐答案

通过将 tls:// 更改为 ssl:// 可以在我这边工作,这使得绝对对我来说没有意义,但这也是为什么使用 fsockopen 是一个太低级的库,无法与它进行 HTTP 交换(您应该使用适当的 HTTP 客户端库),同时又不够可配置关于 TLS 的东西.

It works on my side by changing tls:// to ssl:// which makes absolutely no sense to me, but this is also why using fsockopen is a too low level library to just do HTTP exchanges with it (you should use a proper HTTP client library) and at the same time not configurable enough regarding TLS stuff.

$fp = fsockopen('tls://tlstest.paypal.com', 443, $errno, $errstr, 30);我明白了:

HTTP/1.1 426 Unknown
Server: AkamaiGHost
Mime-Version: 1.0
Content-Type: text/html
Content-Length: 267
Expires: Fri, 22 Jun 2018 19:49:46 GMT
Date: Fri, 22 Jun 2018 19:49:46 GMT
Connection: keep-alive
Upgrade: TLS/1.2

<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>

You don't have permission to access "http&#58;&#47;&#47;tlstest&#46;paypal&#46;com&#47;" on this server.<P>
Reference&#32;&#35;18&#46;8024a17&#46;1529696986&#46;1fc51318
</BODY>
</HTML>

但是使用 $fp = fsockopen('ssl://tlstest.paypal.com', 443, $errno, $errstr, 30);我得到:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Date: Fri, 22 Jun 2018 20:05:35 GMT
Connection: keep-alive

然后就挂了,可能是因为是keep-alive连接,缓冲区小于1024,所以没有得到下面的正文内容.这可能是PayPal_Connection_OK",因为它与 Content-Length 中显示的长度完全匹配.这再次表明您应该使用 HTTP 客户端库,而不是试图(糟糕地)在 fsockopen 之上重新实现 HTTP.

And then it hangs, probably because it is a keep-alive connection and the buffer is smaller than 1024 so that you do not get the following body content. Which is probably "PayPal_Connection_OK", as it exactly matches the length displayed in Content-Length. This again shows that you should use an HTTP client library instead of trying to (badly) reimplement HTTP on top of fsockopen.

相关文章