• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 948
  • Last Modified:

PHP - need helo with PayPal IPN listener.

Hi,
I have the following PayPal IPN listener script but need help understanding the foreach statements below and assigning posted variables to local variables.

Should I use

$address_street = $_POST['address_street'];

or

$address_street = $myPost['address_street'];


Thanks

<?php
// CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
// Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
// Set this to 0 once you go live or don't require logging.
define("DEBUG", 1);

// Set to 0 once you're ready to go live
define("USE_SANDBOX", 0);

define("LOG_FILE", "./ipn.log");

// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
	$keyval = explode ('=', $keyval);
	if (count($keyval) == 2)
		$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
	$get_magic_quotes_exists = true;
}
foreach ($myPost 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";
}


// Post IPN data back to PayPal to validate the IPN data is genuine
// Without this step anyone can fake IPN data


if(USE_SANDBOX == true) {
	$paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
} else {
	$paypal_url = "https://www.paypal.com/cgi-bin/webscr";
}


$ch = curl_init($paypal_url);
if ($ch == FALSE) {
	return FALSE;
}


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);


if(DEBUG == true) {
	curl_setopt($ch, CURLOPT_HEADER, 1);
	curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
}


// CONFIG: Optional proxy configuration
//curl_setopt($ch, CURLOPT_PROXY, $proxy);
//curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);


// Set TCP timeout to 30 seconds
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));


// CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below. Ensure the file is readable by the webserver.
// This is mandatory for some environments.


//$cert = __DIR__ . "./cacert.pem";
//curl_setopt($ch, CURLOPT_CAINFO, $cert);


$res = curl_exec($ch);
if (curl_errno($ch) != 0) // cURL error
	{
	if(DEBUG == true) {	
		error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
	}
	curl_close($ch);
	exit;


} else {
		// Log the entire HTTP response if debug is switched on.
		if(DEBUG == true) {
			error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
			error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);

			// Split response headers and payload
			list($headers, $res) = explode("\r\n\r\n", $res, 2);
		}
		curl_close($ch);
}


// Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
	
	// check whether the payment_status is Completed
	// check that txn_id has not been previously processed
	// check that receiver_email is your PayPal email
	// check that payment_amount/payment_currency are correct
	// process payment and mark item as paid.
	// assign posted variables to local variables

	$mc_gross = $_POST['mc_gross'];
	$invoice = $_POST['invoice'];
	$protection_eligibility = $_POST['protection_eligibility'];
	$address_status = $_POST['address_status'];
	$payer_id = $_POST['payer_id'];
	$tax = $_POST['tax'];
	$address_street = $_POST['address_street'];


} 


?>

Open in new window

0
sabecs
Asked:
sabecs
  • 3
2 Solutions
 
Andrew AngellCommented:
Technically, you should get basically the same thing.  It looks like they're just using $myPost to help generate the response back to PayPal for verification.  They loop through it later to generate $req, which is what is then sent to PayPal.

I've always stuck with $_POST['varname'] and it works (assuming your txn_type includes the parameter you're looking for) so that's what I'd go with.

I like to use shorthand if/else syntax on those to avoid warnings in situations where the variable isn't included.

$address_street = isset($_POST['address_street']) ? $_POST['address_street'] : '';

Open in new window

0
 
Ray PaseurCommented:
Where in the world did you find this thing?  It's surely not the PayPal example, right?!

There are a lot of moving parts in a PayPal IPN script!

A good foundation in PHP would be helpful here.
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_11769-And-by-the-way-I-am-new-to-PHP.html

If you only have time to study PHP from one book, I would go with Welling/Thompson.  Get the latest edition and when a new edition comes out, get the new edition and give the obsolete edition to one of your enemies.

I have some time later today, and I'll try to give you an annotated (comments) version of the script, but in between now and then go through the script line-by-line looking at the functions.  If you have any doubt about exactly how the function works, look it up on PHP.net and learn exactly how it works!  Example: urlencode()
0
 
Ray PaseurCommented:
assigning posted variables to local variables
This misunderstands the concept of variable scope.  "Posted" variables are found in $_POST which is a PHP superglobal array.  It is present in every scope and namespace, thus is it always a local variable.  It's also mutable and I think it should not be, but that's a philosophical argument for another time.

Reading the raw post data from stdin presents a security risk.  It takes too much time to explain it all, but if you want a reason, the reason is that php://input does not necessarily contain only the POST request variables.  The preferred way to handle posted data is to use $_POST.  That's why it's there.

I was going to annotate the script, but after reading it more carefully I'm going to recommend that you get rid of it and start over.  Make this exact Google search:
https://www.google.com/search?q=paypal+ipn

In the results you will find these references and code examples with very good explanations.  They cover the "Classic API" which seems to be what you're using.

Introducing IPN
IPN and PDT Variables
Getting Started
IPN Simulator
Testing
the IPN Guide PDF (70 pages)

The overview is this...

1. PayPal makes a POST-method request to your IPN script whenever a payment-related event occurs.  Usually, hopefully, this is a received payment, but it can also be things like a declined check or a reversal.  Your programming will have to account for these things, as shown in the IPN Guide.

2. Your IPN script makes a verification post back to PayPal with the exact information that PayPal sent in the POST request.

3. PayPal responds with VERIFIED and you thereby know you can trust the information.

Anything else is up to your business application needs.
0
 
sabecsAuthor Commented:
Thanks for your comments, very much appreciated.
I will need to have a closer look at all the documentation.

I can't remember exactly where I found the script I am using, but is looks very similar to the one PayPal suggest: https://developer.paypal.com/docs/classic/ipn/ht_ipn/
0
 
Ray PaseurCommented:
The PayPal suggestion look like it came from PHP4.  Maybe that is an artifact of the "classic" designation - meaning "from the 1950's" and it may be time to upgrade to the newer APIs.  Technology is always advancing.

In 2004 I would have copied the PayPal IPN example without understanding it.  Today I would try to understand it, forgive it where it was deficient, and improve it where I could.  It's been a few years since I went under the hood to look at PayPal inner workings.  If you can find a JSON or XML interface, that will be easier to use than the classic.
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now