My IPN handler is no longer inserting any values into the 'payments' table. The transaction is still taking place in the PayPal sandbox perfectly. I've also tried using the IPN simulator, it says 'IPN sent successfully' but still nothing is inserted into the table.
I did have it working fine last week, but since then have made some changes to the site and I can't figure out which changes have affected this.
Any help on this is greatly appreciated.
This is the form I'm using
<form class="paypal" action="payments.php" method="post" id="paypal_form" target="_blank">
<input type="hidden" name="cmd" value="_xclick" />
<input type="hidden" name="no_note" value="1" />
<input type="hidden" name="currency_code" value="AUD" />
<input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest" />
<input type="hidden" name="item_name" value="Membership" />
<input type="hidden" name="item_number" value="Membership" />
<input type="submit" value="Submit Payment"/>
</form>
Here is my IPN handler/listener (payments.php)
<?php
// Database variables
$host = "localhost"; //database location
$user = "xxxx"; //database username
$pass = "xxxx"; //database password
$db_name = "xxxx"; //database name
// PayPal settings
$paypal_email = '[email protected]';
$return_url = 'xxxx';
$cancel_url = 'xxxx';
$notify_url = 'xxxx';
$item_amount = $_POST["item_amount"];
// Include Functions
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
/*
$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);
}
}
//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
header('location:https://www.sandbox.paypal.com/cgi-bin/webscr'.$querystring);
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";
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp($res, "VERIFIED") == 0) {
// Used for debugging
//@mail("[email protected]", "PAYPAL DEBUGGING", "Verified Response<br />data = <pre>".print_r($post, true)."</pre>");
// 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
// Used for debugging
//@mail("[email protected]", "PAYPAL DEBUGGING", "Invalid Response<br />data = <pre>".print_r($post, true)."</pre>");
}
}
fclose ($fp);
}
}
?>
It turns out nothing was wrong with my code, after de-bugging I found the IPN was not being verified using PayPal's Sandbox (so that's obviously a problem on their end). But when I ran it through the real PayPal site it worked perfectly.
Thanks Michael for the heads up on the SQL injection.