Why do my paypal ipn validations always return INVALID?

I am using the PHP class that I created based on the sample code from paypal. I also use this with CodeIgniter. I am testing an IPN listener using an IPN simulator. My letters are sent, so I know that they are being addressed. The problem is that I always get an INVALID response, and I have no idea why. This is my first PayPal integration on one of my sites. What can cause this problem?

Here is my class:

<?php class Paypal { public $sandbox = false; private $_url; public $verified = false; public $fields = array(); public $post_fields = array(); public $result; public function __construct($params = array()){ $this->sandbox = (isset($params['sandbox'])) ? $params['sandbox'] : false; $this->_url = ($this->sandbox) ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr'; } public function run(){ $this->verified = false; // STEP 1: read POST data // Reading POSTed data directly from $_POST causes serialization issues with array data in the POST. // Instead, read raw POST data from the input stream. $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); foreach ($raw_post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $this->post_fields[$keyval[0]] = urldecode($keyval[1]); } // read the IPN message sent from PayPal and prepend 'cmd=_notify-validate' $req = 'cmd=_notify-validate'; if (function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($this->post_fields 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"; } // Step 2: POST IPN data back to PayPal to validate $ch = curl_init($this->_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, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); // In wamp-like environments that do not come bundled with root authority certificates, // please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set // the directory path of the certificate as shown below: curl_setopt($ch, CURLOPT_CAINFO, FCPATH.'cacert.pem'); if ( !($res = curl_exec($ch)) ) { // error_log("Got " . curl_error($ch) . " when processing IPN data"); curl_close($ch); die('curl did not work<br>'.FCPATH.'cacert.pem'); } curl_close($ch); if (strcmp ($res, "VERIFIED") == 0) { $this->verified = true; } $this->result = $res; } 

Here is my CI controller:

 function paypalipn(){ $this->load->model('subscription'); $this->load->library('paypal', array('sandbox' => true));; $this->paypal->run(); $fields = $this->paypal->post_fields; if($this->paypal->verified){ $data = array( 'user_id' => $fields['buyer_id'], 'txn_id' => $fields['txn_id'], 'payment_gross' => $fields['mc_gross'], 'currency_code' => $fields['mc_currency'], 'payer_email' => $fields['payer_email'], 'plan_id' => $fields['item_number'], 'payment_status' => $fields['payment_status'] ); $this->subscription->create_payment($data); } $this->load->library('email'); $this->email->to('*******@gmail.com'); $this->email->from('**************'); $this->email->subject('PayPal IPN'); $this->email->message($this->paypal->result."\nAmount: ".$fields['mc_gross']."\nCurrency: ".$fields['mc_currency']."\nUser ID: ".$fields['buyer_id']); $this->email->send(); } 

All fields are empty in the email, and the result $ this-> paypal-> always returns "INVALID". Does anyone have any ideas? Thank you for your time.

+6
source share
1 answer

In your CI controller, if you wrote your code as follows:

 function paypalipn(){ $this->load->model('subscription'); $this->load->library('paypal', array('sandbox' => true));; $this->paypal->run(); $fields = $this->paypal->post_fields; if($this->paypal->verified){ $data = array( 'user_id' => $fields['buyer_id'], 'txn_id' => $fields['txn_id'], 'payment_gross' => $fields['mc_gross'], 'currency_code' => $fields['mc_currency'], 'payer_email' => $fields['payer_email'], 'plan_id' => $fields['item_number'], 'payment_status' => $fields['payment_status'] ); $this->subscription->create_payment($data); $this->load->library('email'); $this->email->to('*******@gmail.com'); $this->email->from('**************'); $this->email->subject('PayPal IPN'); $this->email->message($this->paypal->result."\nAmount: ".$fields['mc_gross']."\nCurrency: ".$fields['mc_currency']."\nUser ID: ".$fields['buyer_id']); $this->email->send(); } } 

OR if you stopped the script if the if statement failed

 if($this->paypal->verified){ $data = array( 'user_id' => $fields['buyer_id'], 'txn_id' => $fields['txn_id'], 'payment_gross' => $fields['mc_gross'], 'currency_code' => $fields['mc_currency'], 'payer_email' => $fields['payer_email'], 'plan_id' => $fields['item_number'], 'payment_status' => $fields['payment_status'] ); $this->subscription->create_payment($data); } else { exit("We are sad to inform you that verification FAILED. Bye!"); } 

you would not receive any email. The problem is the public function run() in your paypal class, and this is most likely the bad part.

  if ( !($res = curl_exec($ch)) ) { curl_close($ch); die('curl did not work<br>'.FCPATH.'cacert.pem'); } curl_close($ch); if (strcmp ($res, "VERIFIED") == 0) { $this->verified = true; } 

Try rewriting it like this:

  $res=curl_exec($ch); // define $res if($res==null){ // check if $res is null exit('curl did not work<br>'.FCPATH.'cacert.pem'); } curl_close($ch); if (strcmp ($res, "VERIFIED") === 0) { $this->verified = true; } 

Regarding the last 3 lines where strcmp() , and based on a custom comment in strcmp() documentation.

  • strcmp () will return NULL on failure.
  • This has the side effect of equating coincidence when using comparative comparison (==).
  • Instead, you can test for matches using an identical comparison (===), which should not capture NULL returns.

What does the foregoing mean? In a small example.

 if(null==0) { echo "1"; } if(null===0) { echo "2"; } 

The above example will output => 1 , which in your case means that if strcmp() fails, you must set verified to true , which is incorrect.

0
source

All Articles