Search code examples
phppaypalpaypal-ipn

Paypal IPN listener always returns INVALID, yet transaction is successful in live paypal


I'm working with the paypal adaptive payments and my IPN listener worked fine in the sandbox, but now that we're testing live transactions, it always returns "INVALID", but the actual money has been transferred.

Any help on why I always receive "INVALD" is appreciated.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Paypal_ipn extends CI_Controller {

    public function index() {

        log_message('error', '');
        log_message('error', '');
        log_message('error', '##################');
        log_message('error', '##################');

        // read the post from PayPal system and add 'cmd'
        $req = 'cmd=_notify-validate&'.file_get_contents("php://input");
        $header = null;

        // post back to PayPal system to validate

        $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
        $header .= "Host: www.sandbox.paypal.com\r\n";  // this line is needed for sandbox, but may not be needed for prod. 
        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
        $fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

        $raw_post = file_get_contents("php://input");
        $post_array = $this->decodePayPalIPN($raw_post);

        log_message('error', "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        $log1 = var_export($post_array, true);

        log_message('error', $log1);
        log_message('error', "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        log_message('error', "sender_email = ".$post_array['sender_email']);
        if(isset($post_array['sender_email'])) {

            $sender_email = $post_array['sender_email'];
        }
        if(isset($post_array['status'])) {
            $status = $post_array['status'];
        }
        if(isset($post_array['payment_request_date'])) {
            $payment_request_date = $post_array['payment_request_date'];
        }
        if(isset($post_array['transaction'][0]['receiver'])) {
            $receiver0 = $post_array['transaction'][0]['receiver'];
        }
        if(isset($post_array['transaction'][1]['receiver'])) {
            $receiver1 = $post_array['transaction'][1]['receiver'];
        }
        if(isset($post_array['transaction'][0]['id'])) {
            $id0 = $post_array['transaction'][0]['id'];
        }
        if(isset($post_array['transaction'][1]['id'])) {
            $id1 = $post_array['transaction'][1]['id'];
        }
        if(isset($post_array['transaction'][0]['invoiceId'])) {
            $invoiceId0 = $post_array['transaction'][0]['invoiceId'];
        }
        if(isset($post_array['transaction'][1]['invoiceId'])) {
            $invoiceId1 = $post_array['transaction'][1]['invoiceId'];
        }
        if(isset($post_array['transaction'][0]['amount'])) {
            $amount0 = $post_array['transaction'][0]['amount'];
        }
        if(isset($post_array['transaction'][1]['amount'])) {
            $amount1 = $post_array['transaction'][1]['amount'];
        }
        if(isset($post_array['transaction'][0]['status'])) {
            $status0 = $post_array['transaction'][0]['status'];
        }
        if(isset($post_array['transaction'][1]['status'])) {
            $status1 = $post_array['transaction'][1]['status'];
        }
        if(isset($post_array['transaction'][0]['id_for_sender_txn'])) {
            $id_for_sender_txn0 = $post_array['transaction'][0]['id_for_sender_txn'];
        }
        if(isset($post_array['transaction'][1]['id_for_sender_txn'])) {
            $id_for_sender_txn1 = $post_array['transaction'][1]['id_for_sender_txn'];
        }
        if(isset($post_array['transaction'][0]['status_for_sender_txn'])) {
            $status_for_sender_txn0 = $post_array['transaction'][0]['status_for_sender_txn'];
        }
        if(isset($post_array['transaction'][1]['status_for_sender_txn'])) {
            $status_for_sender_txn1 = $post_array['transaction'][1]['status_for_sender_txn'];
        }
        if(isset($post_array['transaction'][1]['pending_reason'])) {
            $pending_reason0 = $post_array['transaction'][1]['pending_reason'];
        }
        if(isset($post_array['transaction'][1]['pending_reason'])) {
            $pending_reason1 = $post_array['transaction'][1]['pending_reason'];
        }

        if (!$fp) {
            log_message('error', 'Problem with !$fp');
            // HTTP ERROR
        } else {
            $counter = 0;
            fputs ($fp, $header . $req);

            $res = '';

            while (!feof($fp)) {

                $res .= fgets ($fp, 1024);

                log_message('error', "res = $res");

                if (strcmp ($res, "VERIFIED") == 0) {

                    log_message('error', 'we verified');
                    if($status0 == "Completed") {
                        log_message('error', 'we completed');
                        $this->load->model('customer_model');
                        $results = $this->customer_model->get_invoice_info($invoiceId0);

                        if($results != false) {
                            log_message('error', 'results is NOT false');
                            foreach($results as $row) {
                                if($row->amount_verified != 1) {
                                    log_message('error', 'row->amount_verified is NOT equal to 1');
                                    log_message('error', "row->amount = ".$row->amount);

                                    if($row->amount == $amount0) {
                                        //log_message('error', 'row->amount is equal to amount0');
                                        if($this->customer_model->verify_amount($invoiceId0)) {
                                            $subject = 'Successful transaction';
                                            $message = 'There was a successful transaction. View the log for details /public_html/application/logs';
                                            $this->_send_email($subject, $message);
                                        }
                                    } else {
                                        //log_message('error', 'we in the else');
                                        //log_message('error', 'invoiceId0 = '.$invoiceId0);
                                        if($this->customer_model->update_amount_and_verify($invoiceId0, $row->amount)) {
                                            //log_message('error', 'we inside update_amount_and_verify');
                                            $subject = 'Successful transaction';
                                            $message = 'There was a successful transaction. View the log for details /public_html/application/logs';
                                            $this->_send_email($subject, $message);
                                        }
                                    }
                                }
                            }
                        } else {
                            $subject = 'Results Equal False';
                            $message = 'View the log for details /public_html/application/logs';
                            $this->_send_email($subject, $message);
                        }
                    } else {
                        $subject = 'Status NOT Complete!';
                        $message = 'View the log for details /public_html/application/logs';
                        $this->_send_email($subject, $message);
                    }

                    log_message('error', "sender_email = $sender_email");
                    log_message('error', "payment_request_date = $payment_request_date");
                    log_message('error', "status = $status");
                    log_message('error', "receiver0 = $receiver0");
                    log_message('error', "receiver1 = $receiver1");
                    log_message('error', "id0 = $id0");
                    log_message('error', "id1 = $id1");
                    log_message('error', "invoiceId0 = $invoiceId0");
                    log_message('error', "invoiceId1 = $invoiceId1");
                    log_message('error', "amount0 = $amount0");
                    log_message('error', "amount1 = $amount1");
                    log_message('error', "status0 = $status0");
                    log_message('error', "status1 = $status1");
                    log_message('error', "id_for_sender_txn0 = $id_for_sender_txn0");
                    log_message('error', "id_for_sender_txn1 = $id_for_sender_txn1");
                    log_message('error', "status_for_sender_txn0 = $status_for_sender_txn0");
                    log_message('error', "status_for_sender_txn1 = $status_for_sender_txn1");
                    log_message('error', "pending_reason0 = $pending_reason0");
                    log_message('error', "pending_reason1 = $pending_reason1");


                    // check 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
                    $counter++;
                }
                else if (strcmp ($res, "INVALID") == 0) {
                    log_message('error', 'WE INVALIDDDDDDDDDDDDDDDDDD');
                    $test = var_export($res, true);
                    $test = str_replace(array("\r","\n"), '', $test);

                    log_message('error', $test);
                    log_message('error', "Problem with IPN. res = $test");
                }

            }
            fclose ($fp);
        }

    }

    function decodePayPalIPN($raw_post)
    {
        //log_message('error', "testing");
        if (empty($raw_post)) {
            return array();
        } # else:
        $post = array();
        $pairs = explode('&', $raw_post);
        foreach ($pairs as $pair) {
            list($key, $value) = explode('=', $pair, 2);
            $key = urldecode($key);
            $value = urldecode($value);
            # This is look for a key as simple as 'return_url' or as complex as 'somekey[x].property'
            preg_match('/(\w+)(?:\[(\d+)\])?(?:\.(\w+))?/', $key, $key_parts);
            switch (count($key_parts)) {
                case 4:
                    # Original key format: somekey[x].property
                    # Converting to $post[somekey][x][property]
                    if (!isset($post[$key_parts[1]])) {
                        $post[$key_parts[1]] = array($key_parts[2] => array($key_parts[3] => $value));
                    } else if (!isset($post[$key_parts[1]][$key_parts[2]])) {
                        $post[$key_parts[1]][$key_parts[2]] = array($key_parts[3] => $value);
                    } else {
                        $post[$key_parts[1]][$key_parts[2]][$key_parts[3]] = $value;
                    }
                    break;
                case 3:
                    # Original key format: somekey[x]
                    # Converting to $post[somkey][x] 
                    if (!isset($post[$key_parts[1]])) {
                        $post[$key_parts[1]] = array();
                    }
                    $post[$key_parts[1]][$key_parts[2]] = $value;
                    break;
                default:
                    # No special format
                    $post[$key] = $value;
                    break;
            }#switch
        }#foreach

        return $post;
    }#decodePayPalIPN()

    private function _send_email($subject, $message) {
        //log_message('error', 'we in send_email');
        $this->load->library('email');

        $this->email->from('[email protected]', 'Title');
        $this->email->to('[email protected]'); 

        $this->email->subject($subject);
        $this->email->message($message);

        $this->email->send();
        //log_message('error', 'email error = '.$this->email->print_debugger());
    }
}

Solution

  • If you are now testing live transactions your code is still showing for sandbox -

    $header .= "Host: www.sandbox.paypal.com\r\n";  // this line is needed for sandbox, but may not be needed for prod. 
    ...
    $fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
    

    Make sure that you change to -

    // $header .= "Host: www.sandbox.paypal.com\r\n"; line removed, not needed
    ...
    $fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);