Search code examples
phpsslpaypalpaypal-ipntls1.2

Why does tlstest.paypal.com work from browser but not from my PHP code (useful for Paypal IPN)?


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

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\r\n";
$header .= "Host: tlstest.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$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);
}
?>

Note:


Solution

  • 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.

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

    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>
    

    but with $fp = fsockopen('ssl://tlstest.paypal.com', 443, $errno, $errstr, 30); I get:

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

    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.