fgets(): SSL: An existing connection was forcibly

2019-09-03 01:13发布

问题:

I am testing with PayPals example IPN code which should return valid, or invalid for a transaction. I am testing with PayPals IPN simulator which should send some dummy data, and then validate it (returning "Valid").

I am testing with two separate web servers, both have OpenSSL installed and enabled.

On our local web server, we get this error message.

fgets(): SSL: An existing connection was forcibly closed by the remote host.

On our clients web server, with the same code, we get this:

fgets() [<a href='function.fgets'>function.fgets</a>]: SSL: Connection reset by peer in ...../paypal_ipn.php on line 43

PayPal doesn't seem to have a non-SSL version of this anymore.

paypal_ipn.php:

    <?php

    ini_set("log_errors", 1);
    ini_set("error_log", "error.log");

       // Send an empty HTTP 200 OK response to acknowledge receipt of the notification 
       header('HTTP/1.1 200 OK'); 

       // Assign payment notification values to local variables
       //$item_name        = $_POST['item_name'];
       //$item_number      = $_POST['item_number'];
       $payment_status   = $_POST['payment_status'];
       $payment_amount   = $_POST['mc_gross'];
       $payment_currency = $_POST['mc_currency'];
       $txn_id           = $_POST['txn_id'];
       $receiver_email   = $_POST['receiver_email'];
       $payer_email      = $_POST['payer_email'];

         // Build the required acknowledgement message out of the notification just received
      $req = 'cmd=_notify-validate';               // Add 'cmd=_notify-validate' to beginning of the acknowledgement

    $req .= '&'.http_build_query($_POST);


      // Set up the acknowledgement request headers
      $header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";                    // HTTP POST request
      $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
      $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

      // Open a socket for the acknowledgement request
  //$fp = fsockopen('www.sandbox.paypal.com', 80, $errno, $errstr, 30);
  //$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30); 
  $fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);   
    if ($fp === FALSE) {
        error_log("Could not open socket");
        exit("Could not open socket");
    }

      // Send the HTTP POST request back to PayPal for validation
      fputs($fp, $header . $req);

      while (!feof($fp)) {                     // While not EOF
        $res = fgets($fp, 1024);               // Get the acknowledgement response
        if (strcmp ($res, "VERIFIED") == 0) {  // Response contains VERIFIED - process notification

          // Send an email announcing the IPN message is VERIFIED
          $mail_From    = "IPN@example.com";
          $mail_To      = "Your-eMail-Address";
          $mail_Subject = "VERIFIED IPN";
          $mail_Body    = $req;
          file_put_contents("log.txt", "valid: " . $req, FILE_APPEND | LOCK_EX);


          // Authentication protocol is complete - OK to process notification contents

          // Possible processing steps for a payment include the following:

          // Check that the payment_status is Completed
          // Check that txn_id has not been previously processed
          // Check that receiver_email is your Primary PayPal email
          // Check that payment_amount/payment_currency are correct
          // Process payment

        } 
        else if (strcmp ($res, "INVALID") == 0) { //Response contains INVALID - reject notification

          // Authentication protocol is complete - begin error handling

          // Send an email announcing the IPN message is INVALID
          $mail_From    = "IPN@example.com";
          $mail_To      = "Your-eMail-Address";
          $mail_Subject = "INVALID IPN";
          $mail_Body    = $req;
            file_put_contents("log.txt", "invalid: " . $req, FILE_APPEND | LOCK_EX);

        }
      }

      fclose($fp);  // Close the file
    ?>

I am not going to be using CURL, as that is whole other lot of problems! Can anyone see what could be causing these two (separate) errors?

EDIT:

I've just tested on another server running XAMPP (nearly everything enabled), and I now get this 'error':

PHP Warning: fgets(): SSL: The operation completed successfully.

Yet, the transaction doesn't get validated at all.

回答1:

Right well after a day of struggling with this, I went home, and decided to tackle it this morning.

It looked like there was an issue with using fget / fputs. I could browse to the verification URL using the post data in my browser and could see that the URL I was using was working fine.

I couldn't use CURL due to some other issues and not enough time to solve them.

*Solution*:

Use file_get_contents() instead. This made things easier, and no need to send headers or anything else. This works flawlessly!

  $url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?' . $req;

  $res = file_get_contents($url);


回答2:

I've had the same exact problem today but after a couple hours I finally located the root cause. It's perfectly fine to use Paypal's original PHP code but unfortunately it's fairly outdated ever since they switched over to HTTPS. In order to use fgets, you'll need to include the HOST in the header. For a quick fix, here is the code sample I used:

    $parsed_url = parse_url('https://www.sandbox.paypal.com/cgi-bin/webscr'); // Development (sandbox) or production URL
    $header  = "POST $parsed_url[path] HTTP/1.1\r\n";
    $header .= "Host: $parsed_url[host]\r\n";

Hope it works for you.