There are 3 main parts to the PayPal IPN system.
- A webpage that initiates a request to PayPal to make a payment.
- A PHP page on your webserver that PayPal calls to notify you that payment has been made.
- A webpage that confirms the above payment and continues on to the next phase of your web application, such as a ‘Thank You’ page.
Step 1 – Setup PayPal Account
Sign up for a PayPal account if you don’t already have one. Select an appropriate account type, either Personal or Business.
Once you have a registered PayPal account your account must be setup correctly to use IPN.
Select ‘edit profile’ from your PayPal account and check the following settings.
- Under ‘Selling Preferences’ >> ‘Instant Payment Notification Preferences’
- Set the IPN value to ‘On’
- Set the IPN URL to the PHP page containing the IPN code shown in steps 3 & 4 of this tutorial. (http://www.example.com/payment.php)
- Under ‘Selling Preferences’ >> ‘payment receiving preferences’
- Block payments from users who pay with echeck. (This is because these will not be instant payments)
- Under ‘account information’ >> ‘email’
- Note down your primary email address. This email will be visible to users so make it a professional one. User’s may feel apprehensive about sending money to an e-mail address with the domain ‘hotmail.com’ or ‘Yahoo.com’ etc…
Step 2 – Simple HTML Form
<form action="payments.php"class="paypal"id="paypal_form"method="post"><input name="cmd"value="_xclick"type="hidden"><input name="no_note"value="1"type="hidden"><input name="lc"value="UK"type="hidden"><input name="currency_code"value="USD"type="hidden"><input name="bn"value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest"type="hidden"><input name="first_name"value="Your First Name"type="hidden"><input name="last_name"value="Your Last Name"type="hidden"><input name="payer_email"value="customer@example.com"type="hidden"><input name="item_number"value="ep4590"type="hidden"><input value="Buy Now"type="submit"></form>
Note:A full list of the values to send can be found at the PayPal website under the title “A Sample IPN Message and Response”
Step 3 – Payments.php (The Request)
The payment.php page will be used to handle the outgoing request to PayPal and also to handle the incoming response after the payment has been processed.
// Database variables$host = "localhost"; //database location$user = ""; //database username$pass = ""; //database password$db_name = ""; //database name// PayPal settings$paypal_email = 'paypal@host.com';$item_name = 'Test Item';$item_amount = 5.00;// Include Functionsinclude("functions.php");//Database Connection$link = mysql_connect($host, $user, $pass);mysql_select_db($db_name);// Check if paypal request or responseif (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){ // Firstly Append paypal account to querystring $querystring .= "?business=".urlencode($paypal_email)."&"; // Append amount& currency (£) to quersytring so it cannot be edited in html //The item name and amount can be brought in dynamically by querying the $_POST['item_number'] variable. $querystring .= "item_name=".urlencode($item_name)."&"; $querystring .= "amount=".urlencode($item_amount)."&"; //loop for posted values and append to querystring foreach($_POST as $key => $value){ $value = urlencode(stripslashes($value)); $querystring .= "$key=$value&"; } // Append paypal return addresses $querystring .= "return=".urlencode(stripslashes($return_url))."&"; $querystring .= "cancel_return=".urlencode(stripslashes($cancel_url))."&"; $querystring .= "notify_url=".urlencode($notify_url); // Append querystring with custom field //$querystring .= "&custom=".USERID; // Redirect to paypal IPN exit();}else{ // Response from PayPal// read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; foreach ($_POST as $key => $value) { $value = urlencode(stripslashes($value)); $value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i','${1}%0D%0A${3}',$value);// IPN fix $req .= "&$key=$value"; } // assign posted variables to local variables $data['item_name'] = $_POST['item_name']; $data['item_number'] = $_POST['item_number']; $data['payment_status'] = $_POST['payment_status']; $data['payment_amount'] = $_POST['mc_gross']; $data['payment_currency'] = $_POST['mc_currency']; $data['txn_id'] = $_POST['txn_id']; $data['receiver_email'] = $_POST['receiver_email']; $data['payer_email'] = $_POST['payer_email']; $data['custom'] = $_POST['custom']; // 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"; if (!$fp) { // HTTP ERROR } else { mail('adiyya@gmail.com', '0', '0'); fputs ($fp, $header . $req); while (!feof($fp)) { $res = fgets ($fp, 1024); if (strcmp ($res, "VERIFIED") == 0) { // Validate payment (Check unique txnid & correct price) $valid_txnid = check_txnid($data['txn_id']); $valid_price = check_price($data['payment_amount'], $data['item_number']); // PAYMENT VALIDATED & VERIFIED! if($valid_txnid && $valid_price){ $orderid = updatePayments($data); if($orderid){ // Payment has been made & successfully inserted into the Database }else{ // Error inserting into DB // E-mail admin or alert user } }else{ // Payment made but data has been changed // E-mail admin or alert user } }else if (strcmp ($res, "INVALID") == 0) { // PAYMENT INVALID & INVESTIGATE MANUALY! // E-mail admin or alert user } } fclose ($fp); }}
Step 5 – Functions.php
The payments.php page calls upon a number of functions used to validate the returned data and store the response in the database.
// functions.phpfunction check_txnid($tnxid){ global $link; return true; $valid_txnid = true; //get result set $sql = mysql_query("SELECT * FROM `payments` WHERE txnid = '$tnxid'", $link); if($row = mysql_fetch_array($sql)) { $valid_txnid = false; } return $valid_txnid;}function check_price($price, $id){ $valid_price = false; /* you could use the below to check whether the correct price has been paid for the product if so uncomment the below code $sql = mysql_query("SELECT amount FROM `products` WHERE id = '$id'"); if (mysql_numrows($sql) != 0) { while ($row = mysql_fetch_array($sql)) { $num = (float)$row['amount']; if($num == $price){ $valid_price = true; } } } return $valid_price; */ return true;}function updatePayments($data){ global $link; if(is_array($data)){ $sql = mysql_query("INSERT INTO `payments` (txnid, payment_amount, payment_status, itemid, createdtime) VALUES ( '".$data['txn_id']."' , '".$data['payment_amount']."' , '".$data['payment_status']."' , '".$data['item_number']."' , '".date("Y-m-d H:i:s")."' )", $link); return mysql_insert_id($link); }}CREATE TABLE IF NOT EXISTS `payments` ( `id` int(6) NOT NULL AUTO_INCREMENT, `txnid` varchar(20) NOT NULL, `payment_amount` decimal(7,2) NOT NULL, `payment_status` varchar(25) NOT NULL, `itemid` varchar(25) NOT NULL, `createdtime` datetime NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;