PHP Paypal IPN class

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 ?
sydronAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Beverley PortlockCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Ray PaseurCommented:
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
sydronAuthor Commented:
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
Ray PaseurCommented:
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
Ray PaseurCommented:
Hey, sydron: Post another question so I can get some points, too!

Just kidding. Good luck with your project, ~Ray
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.