?
Solved

PHP Paypal IPN class

Posted on 2008-11-16
5
Medium Priority
?
896 Views
Last Modified: 2012-06-27
i have downloaded the paypal.class.php from phpclasses.

I am have a few questions that I need to clarify.

1. What happens if the user closes the browser after they have finished the payment on the paypal page?

2. What is the transaction id on the success page ? I use txn_id but this is different to the transaction id shown on the paypal page.

3. At what point do i run the insert into the database table ? On the success action or the ipn action?

4. I also do not get any email once which should be sent on the action of "ipn". Do you know why I am not getting this ?
0
Comment
Question by:sydron
  • 3
5 Comments
 
LVL 34

Accepted Solution

by:
Beverley Portlock earned 2000 total points
ID: 22970345
I have answered a similar question http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_23886979.html and documented the return variables

With IPN there are 3 URLs

One takes you to the success page where you write stuff like  "Thank you for purchasing widget xxx"

One takes you to the failure page where you write stuff like  "Sorry, your card was declined"

The third one is the IPN call back where your server is informed of the transaction.  You should predicate a "completed transaction" as occurring when you get the IPN callback. The user either completes the transaction of they do not. If they do not then you will not receive the callback. SO, to answer your questions


1. What happens if the user closes the browser after they have finished the payment on the paypal page?

Not your problem. Either you receive a callback or you do not. If you do then the transaction completed


2. What is the transaction id on the success page ? I use txn_id but this is different to the transaction id shown on the paypal page.

I can't recall off hand about the transaction_id, but you can use txn_id as it is needed if you have to reverse a transaction.


3. At what point do i run the insert into the database table ? On the success action or the ipn action?

On the IPN. That's what tells your server that everything is complete


4. I also do not get any email once which should be sent on the action of "ipn". Do you know why I am not getting this ?

Emails should get sent to you when a transaction completes.  Check spam filters and such like. Also log in to your paypal account and edit your profile. Go into "Notifications" (left hand column) and check that Payment notifications are ticked. Go to "Instant payment notification" in the third column and make sure it is turned on and that your callback address is correctly set.
0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 22970990
Instead of phpclasses, go to PayPal for the correct information.  They change it, and they don't necessarily tell phpclasses about the changes.  PayPal has a robust developer group.  There are excellent examples (that work) in the PayPal site.

Everything bportlock says is true.

If you want a sample of my IPN script, please post back here and I'll get you one.

best, ~Ray
0
 

Author Comment

by:sydron
ID: 22972405
This is PERFECT bportlock. I will test what you have told me and get back to you. I am going to do alot of my testing on my local machine intially then move to the live test server , so I know that the ipn action will NOT work as paypal can not see my local machine. This should when deploying it to the live-test server.

Ray_Paseur, I am happy with the php class that I use. It seems to do the job BUT I would like to see a few others and see how they work. Do you mind if you can post the code / class here? I would love to see the class and sample code to use it.

Thank you both.

I will update the points in the next couple of days.
0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 22975397
You will find a couple of local function calls, but their names should make it obvious what they do. Let me know if you have any questions, and good luck with your project! ~Ray
<?php // RAY_sample_paypal_ipn.php - CUSTOM PayPal IPN PROCESSING
 
// LOCAL FUNCTIONS AND VARIABLES
require_once('_config.php');
 
// READ THE POST FROM PayPal AND ADD 'cmd'
$postdata	= '';
$req		= 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
	$postdata	.= "\n $key = $value ";				// SAVE THE COLLECTION
	$$key		= trim(stripslashes($value));		// ASSIGN LOCAL VARIABLES
	$value		= urlencode(stripslashes($value));	// ENCODE FOR BOUNCE-BACK
	$req		.= "&$key=$value";
}
 
// POST BACK TO PayPal SYSTEM TO VALIDATE
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
 
// TEST FOR VERIFICATION
if (!$fp) { // HTTP ERROR
	warning_RAY("IPN HTTP ERROR", "fsockopen failed \n\n ERRNO=$errno \n\n ERRSTR=$errstr \n\n");
	die();
}
 
// HTTP OPEN - WRITE HEADER AND REQUEST
fputs ($fp, $header . $req);
 
// HTTP OPEN - READ PayPal RESPONSE, DISCARDING HEADERS TO THE VERY END
$paypal_reply 	= '';
$paypal_headers	= '';
while (!feof($fp)) {
	$paypal_reply	= fgets ($fp, 1024);
	$paypal_headers	.= $paypal_reply;
}
fclose ($fp);
 
// IF THIS IS TRULY A POST FROM PAYPAL, PROCESS ORDER NOTIFICATION
if (strcmp ($paypal_reply, "VERIFIED") == 0) {
	$errormsg = "";
 
// IF PAYMENT IS NOT COMPLETED (MAY BE E-CHECK?)
	if ($payment_status != "Completed") { $errormsg .= "\nE: payment_status"; }
 
// IF PAYMENT WAS NOT SENT TO ME?
	$receiver_email = strtolower($receiver_email);
	if ($receiver_email == "me@my.org") { } else { $errormsg .= "\nE: receiver_email"; } // ??? SET EMAIL ADDRESS
 
// I AM NOT CHECKING SOME THINGS BECAUSE WE ARE USING ENCRYPTED OR STORED BUY-NOW BUTTONS
	if ($mc_currency != 'USD') { $errormsg .= "\nE: mc_currency"; }
 
// CHECK FOR TXN_ID ALREADY PROCESSED - NORMAL FOR E-CHECK
	$sql = "SELECT txn_id FROM PAYPAL_ORDER_LOG WHERE txn_id = \"$txn_id\" ";
	if (!$result = mysql_query($sql, $db_connection)) { fatal_query_error($sql); }
	$num_rows = mysql_num_rows($result);
	if ($num_rows  > 0) { $errormsg .= "\nE: Transaction id $txn_id already processed $num_rows time(s)"; }
 
// LOG THE TRANSACTION
	$order_date		= date('Y-m-d\TH:i:s');
	$item_number	= mysql_real_escape_string($item_number, $db_connection);
	$mc_gross 		= mysql_real_escape_string($mc_gross,    $db_connection);
	$address_zip	= mysql_real_escape_string($address_zip, $db_connection);
	$txn_id 		= mysql_real_escape_string($txn_id,      $db_connection);
	$receipt_id		= mysql_real_escape_string($receipt_id,  $db_connection);
	$last_name		= mysql_real_escape_string($last_name,   $db_connection);
	$payer_email	= mysql_real_escape_string($payer_email, $db_connection);
	$postdata		= mysql_real_escape_string($postdata,    $db_connection);
	$sql = "INSERT INTO PAYPAL_ORDER_LOG (    order_date,      item_number,      mc_gross,      address_zip,      txn_id,      receipt_id,      last_name,      payer_email,      postdata)
			VALUES						 ( \"$order_date\", \"$item_number\", \"$mc_gross\", \"$address_zip\", \"$txn_id\", \"$receipt_id\", \"$last_name\", \"$payer_email\", \"$postdata\")";
	if (!$result = mysql_query($sql, $db_connection)) { fatal_query_error($sql); }
 
// ISSUE A MESSAGE TO THE HOME OFFICE ?
	warning_RAY("IPN VERIFIED", "IPN REPLY $paypal_headers \n\n$errormsg \n\nPOST DATA FOLLOWS: $postdata \n\n");
 
// GENERATE ARRAYS OF PURCHASE DATA FROM THE WEIRD PAYPAL VARIABLE NAMES
// ACHTUNG: NO POSITION ZERO IN THESE ARRAYS
	$w_item_number	= array();
	$w_quantity		= array();
	$w_mc_gross		= array();
	$w_item_name	= array();
 
// IF TRANSACTION TYPE IS CART, MAY BE MULTIPLE ITEMS IN DIFFERENT QUANTITIES - LOAD ARRAYS
// NO POSITION ZERO IN THESE ARRAYS
	if ($txn_type == "cart") {
		while ($num_cart_items > 0) {
			$proxy	= "item_number" . "$num_cart_items";
			$w_item_number[$num_cart_items] = $$proxy;
 
			$proxy	= "quantity" . "$num_cart_items";
			$w_quantity[$num_cart_items] = $$proxy;
 
			$proxy	= "mc_gross_" . "$num_cart_items";
			$w_mc_gross[$num_cart_items] = $$proxy;
 
			$proxy	= "item_name" . "$num_cart_items";
			$w_item_name[$num_cart_items] = $$proxy;
 
			$num_cart_items--;
		}
	} else {
// NOT A CART - SINGLETON ITEM ONLY - NORMALIZE INTO ARRAY
// NO POSITION ZERO IN THESE ARRAYS
		$w_item_number[1]	= $item_number;
		$w_quantity[1]		= $quantity;
		$w_mc_gross[1]		= $mc_gross;
		$w_item_name[1]		= $item_name;
	}
 
// *****************************************************
// ACTIVATE THIS CODE BLOCK TO SEE WHAT IS IN THE ORDER ARRAYS
//
//	ob_start();
//	echo "<pre>\n";
//	echo "\nW_ITEM_NUMBER"; var_dump($w_item_number);
//	echo "\nW_QUANTITY";    var_dump($w_quantity);
//	echo "\nW_MC_GROSS";    var_dump($w_mc_gross);
//	echo "\nW_ITEM_NAME";   var_dump($w_item_name);
//	$foo	= ob_get_contents();
//	ob_end_clean();
//	warning_RAY("IPN VARDUMPS", "$foo \n\n");
// *****************************************************
 
 
// ITERATE OVER THE ARRAYS
	$kount = 0; // NO POSITION ZERO IN THESE ARRAYS
	while ($kount < count($w_item_number)) {
		$kount++; // BUMP BEFORE WORKING
		$my_item_number	= $w_item_number[$kount];
		$my_quantity	= $w_quantity[$kount];
		$my_mc_gross	= $w_mc_gross[$kount];
		$my_item_name	= $w_item_name[$kount];
 
//
// PROCESS THE ORDERS ???
//
 
	} // END ITERATION
 
// END OF NORMAL PAYPAL IPN PROCESSING
	die();
}
 
// NOT NORMAL PROCESSING
// LOG INVALID POSTS FOR MANUAL INVESTIGATION AND INTERVENTION
if (strcmp ($paypal_reply, "INVALID") == 0) {
	warning_RAY("IPN INVALID", "IPN REPLY $paypal_headers \n\n$errormsg \n\nPOST DATA FOLLOWS: $postdata \n\n");
	die();
}
 
// OTHERWISE, PayPal RETURNED BAD DATA (OR INTERNET HTTP ERRORS OR TIMEOUT)
warning_RAY("IPN REPLY UNKNOWN", "IPN REPLY $paypal_headers \n\n$errormsg \n\nPOST DATA FOLLOWS: $postdata \n\n");
die();
 
?>

Open in new window

0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 23410901
Hey, sydron: Post another question so I can get some points, too!

Just kidding. Good luck with your project, ~Ray
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

There are times when I have encountered the need to decompress a response from a PHP request. This is how it's done, but you must have control of the request and you can set the Accept-Encoding header.
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Suggested Courses
Course of the Month13 days, 20 hours left to enroll

807 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question