Search code examples
curlssl-certificatepaypal-ipnphp-openssl

PayPal IPN in LIVE mode and [SSL_ERROR_SYSCALL, errno 60]


My problem is briefly indicated in the title of the question. I know that not only do I have the same problem and many people face it. Therefore, before asking my question, I used the search for all stackoverflow and read a lot of answers to such questions. I tried ALL of the solution options that were offered here, but none of them helped me solve this problem.

I use a simple php-script (ipnlistener) to receive IPN, as a result of which information about this transaction is entered into my database and sent mail to the buyer with a link to download the file. Everything works fine in the Sandbox test mode - data is entered into the database and the mail is sent to the buyer. I also checked in the IPN-simulator and also did not receive any errors - it gives out the message "IPN was sent and the handshake was verified."

But as soon as I switch to LIVE mode, I get the following entry in the log: "SSL_ERROR_SYSCALL, errno 60" and on this the script execution stops until the next attempts to send IPN, which also end with the same error.

Below is code of the ipnlistener.php that I use:

<?php
$raw_post_data  = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$paypal_post    = array();

foreach ($raw_post_array as $keyval) {
    $keyval = explode ('=', $keyval);
    if (count($keyval) == 2) {
        $paypal_post[$keyval[0]] = urldecode($keyval[1]);
    }
}

//extract vars
extract($paypal_post, EXTR_OVERWRITE);

// build request
$req = 'cmd=' . urlencode('_notify-validate');
$ipn_vars = 'cmd=' . urlencode('_notify-validate');
foreach ($paypal_post as $k => $v) {
    $v = urlencode($v);
    $req .= "&$k=$v";
}

// sort array keys (only after building $req var which will be used to send curl to paypal)
ksort($paypal_post);
foreach ($paypal_post as $k => $v) {
    $ipn_vars .= "\n$k=" . urldecode($v);
}

// paypal mode
$paypal_mode = 1;

// sandbox on/off
if($paypal_mode == 1) {
    $paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
    //for IPN-simulator:
    //$paypal_url = 'https://ipnpb.paypal.com/cgi-bin/webscr';  
}
// else is production site
else {
    $paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
    //for IPN-simulator:
    //$paypal_url = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $paypal_url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
$res = curl_exec($ch);

//Check if any error occured
if(curl_errno($ch)) {
    error_log("Got " . curl_error($ch); . " when processing IPN data");
}
else {
    if (strcmp (trim($res), "VERIFIED") == 0) {
        //here is the code for adding information to the database, downloading the link for downloading the file and sending the mail to the buyer.
    }
    else if (strcmp (trim($res), "INVALID") == 0) {
        //here is the code to send mail to the seller, if the transaction has not been verified
    }
}
?>

As you can see, in this code the certificate checking in the CURL options is DISABLED (false), but I still got the error "errno 60"!

OK. I downloaded the latest current certificate file from this link: https://curl.haxx.se/docs/caextract.html and set to ENABLED on the certificate check in the CURL options according to this tutorial: http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/, changing these lines:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

and adding the full path to the certificate file (of course, I indicated the real path to the file where it was put):

curl_setopt($ch, CURLOPT_CAINFO, getcwd() . '/cert/cacert.pem');

But I still keep getting the same error: SSL_ERROR_SYSCALL, errno 60!

Please tell me - what is wrong with my code? What is my error and how else can I solve my problem?

PS: Also, configuration of my server fully meets the requirements:TLS v1.2, OpenSSL 1.0.1k


Solution

  • Okay. For a while I had to get distracted from this question, because I was engaged in another project. But I found a solution. Everything turned out to be simple and it's not at all in the certificate and not in the cURL settings.

    It appears from recent time that PayPal has changed the links for checking IPN in LIVE mode, and now in the parameter $paypal_url = 'https://www.paypal.com/cgi-bin/webscr'; link does not begin with "www" but with "ipnpb". That is, completely this line in the code should be such: $paypal_url = 'https://ipnpb.paypal.com/cgi-bin/webscr'; Previously, this link was used only for the IPN-Simulator, but now it is used for the LIVE mode!

    For Sandbox, it is also desirable to use https://ipnpb.sandbox.paypal.com/cgi-bin/webscr instead of https://www.sandbox.paypal.com/cgi-bin/webscr, but for the time being it works in both versions.

    Also, it should be noted that in the form of the purchase button <form action ="https://www.paypal.com/cgi-bin/webscr" method ="post"/>, the link must still be used with "www" , and not with "ipnpb".

    When I corrected the link in the code ipn.php script - it all worked for me!

    More detailed information is available here: https://www.paypal-notice.com/en/IPN-Verification-Postback-to-HTTPS/