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 Functions
include(
"functions.php"
);
//Database Connection
$link = mysql_connect($host, $user, $pass);
mysql_select_db($db_name);
// Check if paypal request or response
if
(!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.php
function 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
;