Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save xcommerce-gists/3440401 to your computer and use it in GitHub Desktop.

Select an option

Save xcommerce-gists/3440401 to your computer and use it in GitHub Desktop.
PayPal IPN How To guide
<?php
// 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);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$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 ($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";
}
// STEP 2: POST IPN data back to PayPal to validate
$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');
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, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// check whether the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process the notification
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key." = ". $value."<br>";
}
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
?>
<?php
// 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);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$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 ($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";
}
// Step 2: POST IPN data back to PayPal to validate
$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');
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, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
<?php
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// check whether the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process the notification
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key." = ". $value."<br>";
}
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
?>
<?php
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
}
?>
@boomx09
Copy link
Copy Markdown

boomx09 commented Jan 2, 2015

Super helpful, this finally worked! Thank you! One small detail that threw me for a bit is that during testing you want to use

$ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');

instead of

$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');

on line 32

@gogolmogol
Copy link
Copy Markdown

There is much easier solution:

$postdata = 'cmd=_notify-validate&';
$postdata.= file_get_contents('php://input');

$URL = "https://www.paypal.com/cgi-bin/webscr";
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata));
$context = stream_context_create($opts);
$result = file_get_contents($URL, false, $context);

Enjoy! :)

@blue-ice
Copy link
Copy Markdown

blue-ice commented Jul 9, 2015

If you are getting unverified IPNs during testing with the Paypal Sandbox, what boomx09 did fixed my problem- change this:

$ch = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');

from this:

$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');

Thanks, boomx09 :)

@hypeJunction
Copy link
Copy Markdown

Payload sent by IPN may contain a multidimensional array that is not properly URL encoded.
The format chosen by PayPal (one may never know why):

transaction[0].status=Completed&transaction[1].status=Completed

instead of a nicely formatted:

transaction[0][status]=Completed&transaction[1][status]=Completed

You can use this regexp (which is probably not entirely bullet proof):

$postData = file_get_contents('php://input');
$ipn = new PPIPNMessage($postData);
if (!$ipn->validate()) {
    exit;
}
$data = array();
$fixArr = preg_replace("/\b(\w+)\\%5B(\w+)\\%5D\.([^=]*)[=]([^\&]*)([\&$])\b/", "$1%5B$2%5D%5B$3%5D=$4$5", $postData);
parse_str($fixArr, $data);

@joaorocha123
Copy link
Copy Markdown

Hello,
Could you tell me how to use the code? I created a ipn-listener.php file, uploaded it to the server and tried to use it but some thing does't work. I'm using IPN simulator from PAYPAL website but I ca´nt see nothing.

Thank you in advance.
João

@deshmukhlalit
Copy link
Copy Markdown

Hello,
Could you tell me how to use the code? I created a ipn-listener.php file, uploaded it to the server and tried to use it but some thing does't work. I'm using IPN simulator from PAYPAL website but I ca´nt see nothing.

@deshmukhlalit
Copy link
Copy Markdown

How do you assign Notification URL within PHP script?

@braebot
Copy link
Copy Markdown

braebot commented Sep 15, 2016

Please see https://github.com/paypal/ipn-code-samples/blob/master/paypal_ipn.php for the up-to-date php code. This gist has gotten quite stale. 🌽 🍞

@yzamorac
Copy link
Copy Markdown

yzamorac commented Oct 1, 2016

It's normal that Paypal send many notifycations by ipn to my site for the same purchase???? By each one Paypal send 9 or 10 notifycations, all of completed payment. ...??

@Sinziiana91
Copy link
Copy Markdown

Hello,

I am looking to build an application using code from this gist but I do not know under which license it is.
Can you please clarify this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment