0

i took the example implementation of the IPN handler from paypals official website

now this worked very well in the beginning. But the answers got slower and slower. For a while they worked fine with 20 seconds delay. Now I am getting no traffic at all for minutes. What is going on? maybe is the sandbox ipn handler of paypal themselves close to be down? they have a bad setup?

I want to mention this post (it kinda shed some light)

note i get not even an initial log. Paypal seems to not call my side at all any longer.

The IPN is callable, i can call it from, say an incognito window, and it will write to the logfile.

for completeness, here my file:

<?php

    use ...;
    // CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
    // Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
    // Set this to 0 once you go live or don't require logging.
    define("DEBUG", 1);
    // Set to 0 once you're ready to go live
    define("USE_SANDBOX", 1);
    define("LOG_FILE", "./ipn.log");
    require_once(__DIR__ . "/../../bootstrap.php");



    //define("LOG_FILE", __DIR__ . "/../../../../../japi/logs/ipn.log");
    error_log(date('[Y-m-d H:i e] '). "Lukas: Initial call to log". PHP_EOL, 3, LOG_FILE);
    // Read POST data
    // reading posted data directly from $_POST causes serialization
    // issues with array data in POST. Reading raw POST data from input stream instead.
    $raw_post_data = file_get_contents('php://input');
    $raw_post_array = explode('&', $raw_post_data);
    $myPost = array();
    foreach ($raw_post_array as $keyval) {
      $keyval = explode ('=', $keyval);
      if (count($keyval) == 2)
        $myPost[$keyval[0]] = urldecode($keyval[1]);
    }
    //$mmessage ="hi lukas <br/>";
    //
    //    include_once JCR_KINT_CLASS;
    //$mmessage .= @\Kint::dump($myPost);
    //mail("lukas.meier@gmail.com", "IPN from paypal test", $mmessage);
    // read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    if(function_exists('get_magic_quotes_gpc')) {
      $get_magic_quotes_exists = true;
    }
    foreach ($myPost as $key => $value) {
      if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
        $value = urlencode(stripslashes($value));
      } else {
        $value = urlencode($value);
      }
      $req .= "&$key=$value";
    }
    // Post IPN data back to PayPal to validate the IPN data is genuine
    // Without this step anyone can fake IPN data
    if(USE_SANDBOX == true) {
      $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
    } else {
      $paypal_url = "https://www.paypal.com/cgi-bin/webscr";
    }
    $ch = curl_init($paypal_url);
    if ($ch == FALSE) {
      return FALSE;
    }
    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, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
    if(DEBUG == true) {
      curl_setopt($ch, CURLOPT_HEADER, 1);
      curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
    }
    // CONFIG: Optional proxy configuration
    //curl_setopt($ch, CURLOPT_PROXY, $proxy);
    //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
    // Set TCP timeout to 30 seconds
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
    // CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
    // of the certificate as shown below. Ensure the file is readable by the webserver.
    // This is mandatory for some environments.
    //$cert = __DIR__ . "./cacert.pem";
    //curl_setopt($ch, CURLOPT_CAINFO, $cert);
    $res = curl_exec($ch);
    if (curl_errno($ch) != 0) // cURL error
    {
      if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
      }
      curl_close($ch);
      exit;
    } else {
      // Log the entire HTTP response if debug is switched on.
      if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
        error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);
      }
      curl_close($ch);
    }
    // Inspect IPN validation result and act accordingly
    // Split response headers and payload, a better way for strcmp
    $tokens = explode("\r\n\r\n", trim($res));
    $res = trim(end($tokens));
    if (strcmp ($res, "VERIFIED") == 0) {
      // check whether the payment_status is Completed
      // check that txn_id has not been previously processed
      // check that receiver_email is your PayPal email
      // check that payment_amount/payment_currency are correct
      // process payment and mark item as paid.
      // assign posted variables 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'];


      $jppa = new JcrPayPalAnswer();
      $jppa->createFromPayPalIpnResponseArray($myPost);

      if($jppa->is_completed){
        //content of file: paykey => array($project_id, serialize($fd), $statisticsId);
        $r = parse_ini_file(JCR_PAYKEY_INIFILE);
        if($r){
          $pkArr = $r[$jppa->pay_key];
          $project_id = $pkArr[0];
          /** @var FundingDetails $fd */
          $fd = unserialize(base64_decode($pkArr[1]));
          $statisticsId = $pkArr[2];
          $jcrp = new JewcerProject($project_id);
          $jewcerFee = $jcrppa->amount_fee_account;
          $fundingAmount = $jcrppa->amount_funding_account_brutto;

          $x = null;
          $js = new JcrStatistic($x, $statisticsId);

          //fna [$amount, $paypalfee, $jewcerFeeAmount]
          $fnA = JcrPayPalService::getFeesAndAmount($fd->amount, $fd->coverfee, $jcrp->getFundingFee());
          $amount = $fnA[0];
          $paypalfee = $fnA[3];
          $jewcerFeeAmount = $fnA[2];

          $fd->wepayFee = $paypalfee;
          $fd->jcrFee = $jewcerFeeAmount;
          $amount_with_fee = $amount;
          if ($fd->coverfee) {
            $fd->amount_without_fees = $amount - $paypalfee - $jewcerFeeAmount;
          } else {
            $fd->amount_without_fees = $fd->amount;
          }
          $fd->amount = $amount_with_fee;
          $jcrf = new JcrFunder($project_id);
          $jcrf->setBasicFunderValues($fd);
          $jcrf->save();
          $js->add_stats_from_fundingdetails($fd, "jfp3");
          EmailService::sendDonationSuccessEmails($jcrp, $fd);

          unset($r[$jppa->pay_key]);
          UtilityService::write_ini_file($r, JCR_PAYKEY_INIFILE);
          UtilityService::write_ini_file(array('ok',  $jcrf->id ), JCR_PAYPAL_STATUS_FOLDER . $jppa->pay_key);
        }else{
          error_log(date('[Y-m-d H:i e] '). "JEWCER ERROR 3200: couldn't find entry for paykey in inifile, inifile val: " . var_export($r, true). PHP_EOL, 3, LOG_FILE);
        }
    //    mail("lukas.meier@gmail.com", "IPN COMPLETED", serialize($jppa));
    //    JcrPayPalKeyPool::$keys[$jppa->pay_key] = $jppa; //eventually verify emails
    //    JcrPayPalKeyPool::$keys[$jppa->pay_key] = $jppa; //eventually verify emails

      }

      if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
      }
    } else if (strcmp ($res, "INVALID") == 0) {
      // log for manual investigation
      // Add business logic here which deals with invalid IPN messages
      if(DEBUG == true) {
        error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
      }
    }
Community
  • 1
  • 1
Toskan
  • 13,911
  • 14
  • 95
  • 185
  • IPN is not real time (never has been) you cant code assuming you will get the response instantly. –  May 25 '16 at 01:22
  • bravo. So the IPN has a 10 days delay? maybe a year? did you even read my question? i am not getting any traffic at all. – Toskan May 25 '16 at 01:25
  • actually up to 4 days. –  May 25 '16 at 01:27
  • @Dagon so how do you do it? how do you code a working solution for paypal? I want to let the user choose some message after successful donation. Now I only know after 4 days if he paid? – Toskan May 25 '16 at 01:28
  • store the message, but wait for verification from PP –  May 25 '16 at 01:32
  • have your tried the PP provided IPN simulator ? –  May 25 '16 at 01:34
  • The sandbox is slow, but the IPN simulator is useful for anything other than recurring payments. For those, you're on your own. In my experience, developing for the Paypal API is painfully tedious, between the scattered and fragmented documentation, conflicting versions of documentation and API, old sample code everywhere that doesn't work, and the clunky developer tools. You'll launch with far less code test coverage than you care for, and you'll probably have to make adjustments post-launch. Once you get it down, it works well enough, but it can be a real trial to get there. – Chris Baker May 25 '16 at 01:39
  • to be fair with you dagon, the simulator _i think_ stopped working after we switched to https. But the payments still worked. – Toskan May 25 '16 at 01:40
  • Reading through the docs I think i need to change to PDT?! – Toskan May 25 '16 at 01:40

1 Answers1

0

I have been using IPN for many years with a wide variety of projects. In my experience, if everything is configured correctly and your IPN script has no problems then it will work very close to real-time without many hiccups.

What you can run into, though, is if your IPN script is failing for any reason, or simply sending PayPal a response code other than 200 when it gets hit, it will re-try, but each time it re-tries it delays the time in which it sends. So it might send one instantly, if that doesn't provide a 200 response it'll send another one in 5 seconds, 10 seconds, 20 seconds, 40 seconds, etc. (that's not the exact increment it uses but it's an example of what it does.)

If your script is not returning a 200 response at some point, or if this is happening a lot with the IPNs that are getting sent to your script, PayPal's system will move your IPNs to a slower queue than the others that are working well.

Eventually, if it still isn't fixed, they'll just disable it altogether on your account.

Check the IPN history in your PayPal account to see what response you're getting back there on the IPNs that are getting sent. Of course, this will allow you to verify that they are indeed getting sent as well.

You'll also want to check the PHP error logs on your server to see if anything is going on when the IPN script gets hit that causes it to fail for any reason. This could be happening with only certain IPN types or when particular characters are included in the data, for example.

Drew Angell
  • 25,968
  • 5
  • 32
  • 51
  • I checked. First i had to enable the IPN in my sandbox.paypal.com account of the account i use for the transfers. I checked each single entry of the first page. They all said this: `HTTP response code: 200, Delivery status: Sent, No. of retries: 0` still. It took over an hour for the confirmation to arrive. This is sandbox.paypal.com, not production. Can it be that if my script once was faulty for a couple of requests, they move me down to a slower queue and never move me back up again? – Toskan May 25 '16 at 18:39
  • Yes, it's possible that your script was causing issues so it was moved to the slow queue. If that was happening, though, you should be able to see that in the IPN History from previous attempts. – Drew Angell May 25 '16 at 22:07
  • well it could have happened some 40 or something calls ago. I only checked the first page. I did not enable IPN reporting before that neither, so i cannot really check the old entries from i don't know how long ago. Can I just create a new paypal account? i reckon? or change the IPN url? if i do both, it should reset the queue right – Toskan May 25 '16 at 22:18
  • I would create a new sandbox account and start fresh. – Drew Angell May 25 '16 at 22:41