PayPal Callback not working

I’m a but confused atm, I found this PayPal class online and it works great in PHP 5.6 with callback working perfectly but when i upgraded to PHP 7 and tried to do a payment everything still worked except the bit that says Completed|Failed, the class has an email func and all which only sends if purchase is successful but for some reason it doesn’t work.

I thought it might of been an error so i deleted all the tables in the db and tried again then it worked for the id = 1 so i thought woo its fixed but i thought id try it again just to be sure but then the callback came back as a fail again so im unsure why.

My Code:

public function add($userID,$amount,$product='0',$type,$callback){
	global $crypt;
	global $user;
	
	    $date = date("Y-m-d");
	    $userEnc = $userID;
	    $userID = $crypt->decrypt($userID,'USER');
	    $add = $this->db->prepare("INSERT INTO " . PFX . "transactions (`id`, `user_id`, `amount`,`product`,`type`,`callback`,`date`) VALUES (NULL, '$userID' , '$amount', '$product', '$type','$callback','$date')");
		$add->execute();
	    $trans_id = $this->db->lastInsertId();
	    if($add){
		if($_SESSION['payment']['use_prepaid']){
		$userDetails= $user->details($userEnc);
		$balance = $userDetails['balance'] - $amount;
		$update = $user->update($userEnc,'balance',$balance);
		if($update ){
		return $crypt->encrypt($trans_id ,'TRANSACTION'); 
		}	else	{
				$this->error = "Oops something wrong happened. Please try later.";
				return false;
				}
		}
		return $crypt->encrypt($trans_id ,'TRANSACTION');
		}
		$this->error = "Oops something wrong happened. Please try later.";
		return false;
		
}

Above is the function responsible for inserting the transaction

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('../config-user.php');
$paypal_email = 'test@test.com'; // Set Your Paypal Email HERE
$redir = $_SESSION['payment']['redir'];
if(isset($_REQUEST) && isset($_REQUEST['crf'])){
$order_id= $_REQUEST['transaction_id'];
$a_amount = $_REQUEST['amount'];
$c_amount = $_REQUEST['amount'];
$detail = $_REQUEST['detail'];
$amount = $_REQUEST['amount'];
$admin_curr = $_REQUEST['currency'];
$chk_curr = $_REQUEST['currency'];


}
class paypal_class {
    
   var $last_error;                 
   
   var $ipn_log;                    
   
   var $ipn_log_file;               
   var $ipn_response;               
   var $ipn_data = array();         
   
   var $fields = array();           

   
   function __construct() {
       
     
      $this->paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
      
      $this->last_error = '';
      
      $this->ipn_log_file = '.ipn_results.log';
      $this->ipn_log = true; 
      $this->ipn_response = '';
      
    

      $this->add_field('rm','2');           
      $this->add_field('cmd','_xclick'); 
      
   }
   
   function add_field($field, $value) {
      
   $this->fields["$field"] = $value;
   }

   function submit_paypal_post() {
 
     

      echo "<html>\n";
      echo "<head><title>Processing Order...</title></head>\n";
      echo "<body>\n";
      echo "<center><h2>Please wait, your order is being processed and you";
      echo " will be redirected to the paypal website.</h2></center>\n";
	  echo " <center><img src=\"../img/gateway.gif\"></center>\n";
      echo "<form method=\"post\" name=\"paypal_form\" ";
      echo "action=\"".$this->paypal_url."\">\n";

      foreach ($this->fields as $name => $value) {
         echo "<input type=\"hidden\" name=\"$name\" value=\"$value\"/>\n";
      }
      echo "<center><br/><br/>If you are not automatically redirected to ";
      echo "paypal within 5 seconds...<br/><br/>\n";
      echo "<input type=\"submit\" value=\"Click Here\"></center>\n";
      
      echo "</form>\n";
      echo "</body></html>\n";
    
   }
   
   function validate_ipn() {

      
      $url_parsed=parse_url($this->paypal_url);        

     
      $post_string = '';    
      foreach ($_POST as $field=>$value) { 
         $this->ipn_data["$field"] = $value;
         $post_string .= $field.'='.urlencode(stripslashes($value)).'&'; 
      }
      $post_string.="cmd=_notify-validate"; // append ipn command

      // open the connection to paypal
      $fp = fsockopen($url_parsed[host],"80",$err_num,$err_str,30); 
      if(!$fp) {
          
         // could not open the connection.  If loggin is on, the error message
         // will be in the log.
         $this->last_error = "fsockopen error no. $errnum: $errstr";
         $this->log_ipn_results(false);       
         return false;
         
      } else { 
 
         // Post the data back to paypal
         fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n"); 
         fputs($fp, "Host: $url_parsed[host]\r\n"); 
         fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); 
         fputs($fp, "Content-length: ".strlen($post_string)."\r\n"); 
         fputs($fp, "Connection: close\r\n\r\n"); 
         fputs($fp, $post_string . "\r\n\r\n"); 

         // loop through the response from the server and append to variable
         while(!feof($fp)) { 
            $this->ipn_response .= fgets($fp, 1024); 
         } 

         fclose($fp); // close connection

      }
      
      if (eregi("VERIFIED",$this->ipn_response)) {
  
         // Valid IPN transaction.
         $this->log_ipn_results(true);
         return true;       
         
      } else {
  
         // Invalid IPN transaction.  Check the log for details.
         $this->last_error = 'IPN Validation Failed.';
         $this->log_ipn_results(false);   
         return false;
         
      }
      
   }
   
   function log_ipn_results($success) {
       
      if (!$this->ipn_log) return;  // is logging turned off?
      
      // Timestamp
      $text = '['.date('m/d/Y g:i A').'] - '; 
      
      // Success or failure being logged?
      if ($success) $text .= "SUCCESS!\n";
      else $text .= 'FAIL: '.$this->last_error."\n";
      
      // Log the POST variables
      $text .= "IPN POST Vars from Paypal:\n";
      foreach ($this->ipn_data as $key=>$value) {
         $text .= "$key=$value, ";
      }
 
      // Log the response from the paypal server
      $text .= "\nIPN Response from Paypal Server:\n ".$this->ipn_response;
      
      // Write to log
      $fp=fopen($this->ipn_log_file,'a');
      fwrite($fp, $text . "\n\n"); 

      fclose($fp);  // close file
   }

   function dump_fields() {
 
      // Used for debugging, this function will output all the field/value pairs
      // that are currently defined in the instance of the class using the
      // add_field() function.
      
      echo "<h3>paypal_class->dump_fields() Output:</h3>";
      echo "<table width=\"95%\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
            <tr>
               <td bgcolor=\"black\"><b><font color=\"white\">Field Name</font></b></td>
               <td bgcolor=\"black\"><b><font color=\"white\">Value</font></b></td>
            </tr>"; 
      
      ksort($this->fields);
      foreach ($this->fields as $key => $value) {
         echo "<tr><td>$key</td><td>".urldecode($value)."&nbsp;</td></tr>";
      }
 
      echo "</table><br>"; 
   }
}         

$p = new paypal_class;             // initiate an instance of the class
$p->paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';   // testing paypal url

//$p->paypal_url = 'https://www.paypal.com/cgi-bin/webscr';     // paypal url
            
// setup a variable for this script (ie: 'http://www.micahcarrick.com/paypal.php')
$this_script = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];

// if there is not action variable, set the default action of 'process'
if (empty($_GET['action'])) $_GET['action'] = 'process';  

switch ($_GET['action']) {
    
   case 'process':      // Process and order...

      
      
      $p->add_field('business', $paypal_email);
      $p->add_field('return', $this_script.'?action=success');
      $p->add_field('cancel_return', $this_script.'?action=cancel');
     // $p->add_field('notify_url', $this_script.'?action=ipn');
      $p->add_field('item_name', $detail);
      $p->add_field('amount', $amount);

      $p->submit_paypal_post(); // submit the fields to paypal
     
      break;
      
   case 'success':      // Order was successful...
   
   
 
if(isset($_SESSION['payment']['id'] )){
$order_id = $_SESSION['payment']['id'] ;
}else{
$order_id = 0;
$_SESSION['payment']['id']  = $order_id;
}
switch ($_POST['payment_status']){
	case 'Completed':
		$transaction->update($_SESSION['payment']['id'] ,'callback','1');
						if($_SESSION['payment']['action']== "deposit"){
				$curr = $user->details($_SESSION['uid']);
				$newBal = $curr['balance'] + $_SESSION['payment']['amount'];
				$user->update($_SESSION['uid'],'balance',$newBal);
				}	
				if($_SESSION['payment']['action']== "purchase"){
				$buy = $purchases->add($_SESSION['uid'],$_SESSION['payment']['product_id'],$_SESSION['payment']['id'],'1');
				}
				
	$headers  = "MIME-Version: 1.0\n";
    $headers .= "Content-type: text/html; charset=utf-8\n";
    $headers .= "From: 'Success Email' <noreply@".$_SERVER['HTTP_HOST']."> \n";
	$subject = "Account Information";
	$message = "<h4>Hello, ".$_SESSION['curr_user'] ."</h4><br />";
	$message .= "You just made a transaction of ".$setting['currency']. $_SESSION['payment']['amount']."<br />";
	$message .= "transaction ID:".$_SESSION['payment']['id']."<br />";
	$message .= "&copy; ".$_SERVER['HTTP_HOST'];
	mail($_SESSION['curr_user'],$subject,$message,$headers);
				
				
unset($_SESSION['payment']);header('location:../../user/'.$redir.'?msg=Transaction Successfull&type=alert-success');
		exit;	break;	
	case 'Pending':
	unset($_SESSION['payment']);header('location:../../user/'.$redir.'?msg=Transaction Failed&type=alert-error');
			
	exit;	break;
	unset($_SESSION['payment']);header('location:../../user/'.$redir.'?msg=Transaction Failed&type=alert-error');
	exit;	break;
	default:
	unset($_SESSION['payment']);header('location:../../user/'.$redir.'?msg=Transaction Failed&type=alert-error');
			
}
  case 'cancel':  
unset($_SESSION['payment']);header('location:../../user/'.$redir.'?msg=Transaction Failed&type=alert-error');
		break;  
}

?>

Above is the PayPal Class

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('../system/config-user.php');
require_once('../system/gateways.php');

$gateway = $_SESSION['payment']['gateway'] ;
$amount = $_SESSION['payment']['amount'] ;
$detail = $_SESSION['payment']['detail'] ;
$crf = $_SESSION['payment']['crf'] ;
$currency = $setting['currency'];
$crf_gen = md5("test" . date('YMD'));
if($crf_gen != $crf || !$gateway || !$amount){
?>
 <head><title>Error</title></head>
 <center><h2>Unknown Transaction.</h2></center>
 <?php
exit;
}

switch($_GET['action']){
case 'process':
if($_SESSION['payment']['action'] == "deposit"){
$transaction_id = $transaction->add($_SESSION['uid'],$amount,'0','2','2');
}elseif($_SESSION['payment']['action'] == "purchase"){
$transaction_id = $transaction->add($_SESSION['uid'],$amount,$_SESSION['payment']['product_id'],'1','2');
}

if(!$transaction_id){
?>
 <head><title>Error</title></head>
 <center><h2>Unable to process transaction.</h2></center>
 <?php
exit;
}
$_SESSION['payment']['id'] = $transaction_id;
$detail .= " (" .$transaction_id .")";
$_SESSION['payment']['hash']= md5($crf.$transaction_id.$amount);
header("location:../system/gateways/$gateway?transaction_id=$transaction_id&detail=$detail&amount=$amount&currency=$currency&crf=$crf");
break;
case 'callback':
if(!$_SESSION['payment']['id']){
?>
 <head><title>Error</title></head>
 <center><h2>Unknown Transaction.</h2></center>
 <?php
}
$transaction_id = $_SESSION['payment']['id']  ;
$status = $_POST['auth'];
$txn = $_POST['txn'];
$amt = $_POST['amt'];
$gcrf = $_POST['crf'];
$hsh = $_SESSION['payment']['hash'];
$hash = md5($gcrf.$txn_id.$amt);
$crf = md5($gateway,$transaction_id,$amount,$crf);
if($transaction_id != $txn || $amount != $amt || $crf != $gcrf || $hash != $hsh){
?>
 <head><title>Error</title></head>
 <center><h2>Transaction rejected.</h2></center>
 <?php
}
$action = $transaction->update($transaction_id,'callback',$status);
unset($_SESSION['payment']);
$type = ($status='1'?'alert-success':'alert-error');
$msg = ($status='1'?'Transaction completed':'Transaction failed');
?>
<html>
     <head><title>Processing payment...</title></head>
   <body onLoad="document.forms['payment_form'].submit();" >
     <center><h2>Please wait, your order is being processed and you will be redirected back to our website.</h2></center>
	   <center></center>
	<form method="post" name="payment_form"  action="statement.php">
	<input type="hidden" name="msg" value="<?php echo $msg;?>">
	<input type="hidden" name="type" value="<?php echo $type; ?>">
	</form></body></html>
<?php
break;
default:
?>
 <head><title>Error</title></head>
 <center><h2>Unknown Transaction.</h2></center>
 <?php
}
?>

Above is the processing code

Thanks all help really appreciated

Im not seeing where in your code the string “Completed|Failed” is coming from. Can you point it out to me please.

Sorry its the bits where there is the ‘1’?’

the 1 = completed
the ? = failed

thanks

I’ve looked for $trans['callback'] in the code in the first post, but I didn’t see it. I assume the value is coming from the database table’s callback field, but I didn’t see where in the code that’s being done.

If the code is in the first post, please help me by pointing out where it is. If it isn’t in any code you’ve posted, please post the function that does the INSERT as I have a feeling that’s where the problem is. Also of interest is the code involved with passing values to that function.

Both the calls to ‘add’ that I can see in the final code snippet seem to hard-code the callback value (the last parameter) to ‘2’:

$transaction_id = $transaction->add($_SESSION['uid'],$amount,'0','2','2');
...
$transaction_id = $transaction->add($_SESSION['uid'],$amount,$_SESSION['payment']['product_id'],'1','2');

Thanks for all your help but i figured out the problem myself

if ($result->fetchColumn() == 1){

if ($result){

The fetch column was the one that broke it

I may be blind, but I can’t see that in any of the code you posted.

I thought eregi was deprecated? I remembered my very first time using PHP. It was already deprecated then and that was like 8 or so years ago. You must be using 5.2 or lower to omit the warnings or not have error logs/warnings turned on.

Yes, you’re quite right:

Warning
This function was DEPRECATED in PHP 5.3.0, and REMOVED in PHP 7.0.0.

2 Likes

Thanks ive changed it to this, will that fix this?

if (preg_match("VERIFIED",$this->ipn_response)) {

Thanks for your help!

That looks like it’s far too simple for a regular expression, but what happens if you try it out?

If all you want to do is check whether the ipn_response is equal to “VERIFIED”, why is a regular expression required?

(I should add that I steer clear of regex whenever I can, so know virtually nothing about it. Hence for a straight string comparison, I wouldn’t use it).

2 Likes

To wit

Tip
Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() instead as it will be faster.

1 Like

You should test the types of responses you get back but according to this documentation you can just use stcmp() instead of a regular expression.

https://developer.paypal.com/docs/classic/ipn/ht_ipn/

Edit: Actually I think you need to use a regular expression or other method. I think this is the type of response you will receive.

mc_gross=19.95&protection_eligibility=Eligible&address_status=confirmed&payer_id=LPLWNMTBWMFAY&tax=0.00&address_street=1+Main+St&payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&payment_status=Completed&charset=windows-1252&address_zip=95131&first_name=Test&mc_fee=0.88&address_country_code=US&address_name=Test+User&notify_version=2.6&custom=&payer_status=verified&address_country=United+States&address_city=San+Jose&quantity=1&verify_sign=AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS6nMXgysbElEn9v-1XcmSoGtf&payer_email=gpmac_1231902590_per%40paypal.com&txn_id=61E67681CH3238416&payment_type=instant&last_name=User&address_state=CA&receiver_email=gpmac_1231902686_biz%40paypal.com&payment_fee=0.88&receiver_id=S8XGHLYDW9T3S&txn_type=express_checkout&item_name=&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&handling_amount=0.00&transaction_subject=&payment_gross=19.95&shipping=0.00

This can be sorted out by printing the value of ipn_response.

I think as per the note on that page I’d be tempted to split that response string down into an array and just check the appropriate element.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.