Update database when IPN payment is made - php

I'm trying to figure out how to update a a column in my table called Premium_Access when a payment has gone thru with Paypal.
What i have figured out myself is how to update Premium_Access with typing in a specific memberID myself. Like you can see down below in my code.
How and where should i get the memberID for the logged in user?
Here is my listener.php
header('HTTP/1.1 200 OK');
//
// STEP 2 - create the response we need to send back to PayPal for them to confirm that it's legit
//
$resp = 'cmd=_notify-validate';
foreach ($_POST as $parm => $var)
{
$var = urlencode(stripslashes($var));
$resp .= "&$parm=$var";
}
// STEP 3 - Extract the data PayPal IPN has sent us, into 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'];
$record_id = $_POST['custom'];
// Right.. we've pre-pended "cmd=_notify-validate" to the same data that PayPal sent us (I've just shown some of the data PayPal gives us. A complete list
// is on their developer site. Now we need to send it back to PayPal via HTTP. To do that, we create a file with the right HTTP headers followed by
// the data block we just createdand then send the whole bally lot back to PayPal using fsockopen
// STEP 4 - Get the HTTP header into a variable and send back the data we received so that PayPal can confirm it's genuine
$httphead = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$httphead .= "Content-Type: application/x-www-form-urlencoded\r\n";
$httphead .= "Content-Length: " . strlen($resp) . "\r\n\r\n";
// Now create a ="file handle" for writing to a URL to paypal.com on Port 443 (the IPN port)
$errno ='';
$errstr='';
$fh = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
// STEP 5 - Nearly done. Now send the data back to PayPal so it can tell us if the IPN notification was genuine
if (!$fh) {
// Uh oh. This means that we have not been able to get thru to the PayPal server. It's an HTTP failure
//
// You need to handle this here according to your preferred business logic. An email, a log message, a trip to the pub..
}
// Connection opened, so spit back the response and get PayPal's view whether it was an authentic notification
else {
fputs ($fh, $httphead . $resp);
while (!feof($fh))
{
$readresp = fgets ($fh, 1024);
if (strcmp ($readresp, "VERIFIED") == 0)
{
$servername = "my db ip";
$username = "my db username";
$password = "my db password";
$dbname = "my database";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//When the payment is made i want to update Premiumaccsess in members to YES (for the logged in user)
//Im not sure if i should find out who is logged in by memberID or username
$sql = "UPDATE members SET Premium_Accsess='YES' WHERE memberID=15";
if ($conn->query($sql) === TRUE) {
echo "Record updated successfully";
} else {
echo "Error updating record: " . $conn->error;
}
$conn->close();
}
else if (strcmp ($readresp, "INVALID") == 0)
{
// Man alive! A hacking attempt?
}
}
fclose ($fh);
}
?>
And here is my user.php (I dont think i have to do anything more here but if you can see something wrong please tell.)
<?php
include('password.php');
class User extends Password{
private $_db;
function __construct($db){
parent::__construct();
$this->_db = $db;
}
private function get_user_hash($username){
try {
$stmt = $this->_db->prepare('SELECT password, username, memberID, Premium_Accsess FROM members WHERE username = :username AND active="Yes" ');
$stmt->execute(array('username' => $username));
return $stmt->fetch();
} catch(PDOException $e) {
echo '<p class="bg-danger">'.$e->getMessage().'</p>';
}
}
public function isValidUsername($username){
if (strlen($username) < 3) return false;
if (strlen($username) > 17) return false;
if (!ctype_alnum($username)) return false;
return true;
}
public function login($username,$password){
if (!$this->isValidUsername($username)) return false;
if (strlen($password) < 3) return false;
$row = $this->get_user_hash($username);
if($this->password_verify($password,$row['password']) == 1){
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $row['username'];
$_SESSION['memberID'] = $row['memberID'];
return true;
}
}
public function logout(){
session_destroy();
}
public function is_logged_in(){
if(isset($_SESSION['loggedin']) && $_SESSION['loggedin'] == true){
return true;
}
}
}

Related

Paypal IPN listener not sending mysql insert statement

I got a paypal ipn code from somewhere. Cant remember where but it works with the ipn simulator when you delete the date from the date field. It does not work with the date. I am now testing with a live payment and it sends the ipn successfully from paypal and no error log. The HTTP response is 200 but nothing is inserted into my database.
Any ideas why it is not working?
Here is the code:
<?php
class PayPal_IPN{
function infotuts_ipn($im_debut_ipn) {
define('SSL_P_URL', 'https://www.paypal.com/cgi-bin/webscr');
define('SSL_SAND_URL', 'https://www.sandbox.paypal.com/cgi-bin/webscr');
$hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
if (!preg_match('/paypal\.com$/', $hostname)) {
$ipn_status = 'Validation post isn\'t from PayPal';
if ($im_debut_ipn == true) {
// mail test
}
return false;
}
// parse the paypal URL
$paypal_url = ($_REQUEST['test_ipn'] == 1) ? SSL_SAND_URL : SSL_P_URL;
$url_parsed = parse_url($paypal_url);
$post_string = '';
foreach ($_REQUEST as $field => $value) {
$post_string .= $field . '=' . urlencode(stripslashes($value)) . '&';
}
$post_string.="cmd=_notify-validate"; // append ipn command
// get the correct paypal url to post request to
$paypal_mode_status = $im_debut_ipn; //get_option('im_sabdbox_mode');
if ($paypal_mode_status == true)
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
else
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60);
$ipn_response = '';
if (!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$ipn_status = "fsockopen error no. $err_num: $err_str";
if ($im_debut_ipn == true) {
echo 'fsockopen fail';
}
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($post_string) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while (!feof($fp)) {
$ipn_response .= fgets($fp, 1024);
}
fclose($fp); // close connection
}
// Invalid IPN transaction. Check the $ipn_status and log for details.
if (!preg_match("/VERIFIED/s", $ipn_response)) {
$ipn_status = 'IPN Validation Failed';
if ($im_debut_ipn == true) {
echo 'Validation fail';
print_r($_REQUEST);
}
return false;
} else {
$ipn_status = "IPN VERIFIED";
if ($im_debut_ipn == true) {
echo 'SUCCESS';
}
return true;
}
}
function ipn_response($request){
mail("info#vertexskysports.com","Order Recieved",print_r($request,true));
$im_debut_ipn=true;
if ($this->infotuts_ipn($im_debut_ipn)) {
// if paypal sends a response code back let's handle it
if ($im_debut_ipn == true) {
$sub = 'PayPal IPN Debug Email Main';
$msg = print_r($request, true);
$aname = 'infotuts';
//mail send
}
// process the membership since paypal gave us a valid +
$this->insert_data($request);
}
}
function issetCheck($post,$key){
if(isset($post[$key])){
$return=$post[$key];
}
else{
$return='';
}
return $return;
}
function insert_data($request){
$con=mysql_connect("xxx.xxx.xx.xx","USERNAME","PASSWORD") or die("Failed to connect with database!!!!");
mysql_select_db("DATABASENAME", $con);
$datetime = date("Y-m-d H:i:s");
$order_number = $_POST['custom'];
$receiver_email = $_POST['receiver_email'];
$txn_id = $_POST['txn_id'];
$payer_email = $_POST['payer_email'];
$payer_id = $_POST['payer_id'];
$payer_status = $_POST['payer_status'];
$first_name = $_POST['first_name'];
$last_name = $_POST['last_name'];
$address_city = $_POST['address_city'];
$address_country = $_POST['address_country'];
$address_state = $_POST['address_state'];
$address_status = $_POST['address_status'];
$address_country_code = $_POST['address_country_code'];
$address_name = $_POST['address_name'];
$address_street = $_POST['address_street'];
$address_zip = $_POST['address_zip'];
$item_name = $_POST['item_name1'];
$fee = $_POST['mc_fee'];
$amount = $_POST['mc_gross_1'];
$payment_status = $_POST['payment_status'];
$shipping = $_POST['mc_shipping'];
$design = "INSERT INTO orders(datetime, order_number, receiver_email, txn_id, payer_email, payer_id, payer_status, first_name, last_name, address_city, address_country, address_state, address_country_code, address_name, address_street, address_zip, item_name, fee, amount, payment_status, shipping)
VALUES('".$datetime."', '".$order_number."', '".$receiver_email."', '".$txn_id."', '".$payer_email."', '".$payer_id."', '".$payer_status."', '".$first_name."', '".$last_name."', '".$address_city."', '".$address_country."', '".$address_state."', '".$address_country_code."', '".$address_name."', '".$address_street."', '".$address_zip."', '".$item_name."', '".$fee."', '".$amount."', '".$payment_status."', '".$shipping."')";
mysql_query($design);
$design2 = "INSERT INTO order_status(datetime, order_number, status) VALUES('".$datetime."','".$order_number."','Received')";
mysql_query($design2);
}
}
$obj = New PayPal_IPN();
$obj->ipn_response($_REQUEST);
?>
The best way to test that sort of thing is to setup your own simulator so you can run it in a browser and see the result on screen. This will help you troubleshoot any potential SQL insert problems, missing data, or whatever might be causing the problem.
So just setup an HTML form with hidden fields matching the fields you expect to get from IPN. Submit that directly to your listener in a browser.
Of course, make sure to handle the fact that the data isn't coming from PayPal, so it won't verify, but you can setup logic to handle that accordingly.
More details are available in this article I wrote about how to test PayPal IPN.

PayPal IPN Listener works inside sandbox but not outside

I am running this PayPal IPN listener written by tutsplus, it's modified a bit to suit my needs. Everything worked fine until I have moved from sandbox to live mode. I have went over the code, and don't quite understand if I need to switch anything or it is checking for sandbox/live itself.
<?php
class PayPal_IPN{
function infotuts_ipn($im_debut_ipn) {
define('SSL_P_URL', 'https://www.paypal.com/cgi-bin/webscr');
define('SSL_SAND_URL', 'https://www.sandbox.paypal.com/cgi-bin/webscr');
$hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
if (!preg_match('/paypal\.com$/', $hostname)) {
$ipn_status = 'Validation post isn\'t from PayPal';
if ($im_debut_ipn == true) {
// mail test
}
return false;
}
// parse the paypal URL
$paypal_url = ($_REQUEST['test_ipn'] == 1) ? SSL_SAND_URL : SSL_P_URL;
$url_parsed = parse_url($paypal_url);
$post_string = '';
foreach ($_REQUEST as $field => $value) {
$post_string .= $field . '=' . urlencode(stripslashes($value)) . '&';
}
$post_string.="cmd=_notify-validate"; // append ipn command
// get the correct paypal url to post request to
$paypal_mode_status = $im_debut_ipn; //get_option('im_sabdbox_mode');
if ($paypal_mode_status == true)
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
else
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60);
$ipn_response = '';
if (!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$ipn_status = "fsockopen error no. $err_num: $err_str";
if ($im_debut_ipn == true) {
echo 'fsockopen fail';
}
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: " . strlen($post_string) . "\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while (!feof($fp)) {
$ipn_response .= fgets($fp, 1024);
}
fclose($fp); // close connection
}
// Invalid IPN transaction. Check the $ipn_status and log for details.
if (!preg_match("/VERIFIED/s", $ipn_response)) {
$ipn_status = 'IPN Validation Failed';
if ($im_debut_ipn == true) {
echo 'Validation fail';
print_r($_REQUEST);
}
return false;
} else {
$ipn_status = "IPN VERIFIED";
if ($im_debut_ipn == true) {
echo 'SUCCESS';
}
return true;
}
}
function ipn_response($request){
mail("mssoad#gmail.com","My subject",print_r($request,true));
$im_debut_ipn=true;
if ($this->infotuts_ipn($im_debut_ipn)) {
// if paypal sends a response code back let's handle it
if ($im_debut_ipn == true) {
$sub = 'PayPal IPN Debug Email Main';
$msg = print_r($request, true);
$aname = 'infotuts';
//mail send
}
// process the membership since paypal gave us a valid +
$this->insert_data($request);
}
}
function issetCheck($post,$key){
if(isset($post[$key])){
$return=$post[$key];
}
else{
$return='';
}
return $return;
}
function insert_data($request){
require_once('dbconnect.php');
$post=$request;
$item_name=$this->issetCheck($post,'item_name');
$amount=$this->issetCheck($post,'mc_gross');
$currency=$this->issetCheck($post,'mc_currency');
$payer_email=$this->issetCheck($post,'payer_email');
$first_name=$this->issetCheck($post,'first_name');
$last_name=$this->issetCheck($post,'last_name');
$country=$this->issetCheck($post,'residence_country');
$txn_id=$this->issetCheck($post,'txn_id');
$txn_type=$this->issetCheck($post,'txn_type');
$payment_status=$this->issetCheck($post,'payment_status');
$payment_type=$this->issetCheck($post,'payment_type');
$payer_id=$this->issetCheck($post,'payer_id');
$date=$this->issetCheck($post,'custom');
$create_date=date('Y-m-d H:i:s');
$payment_date=date('Y-m-d H:i:s');
$firstLast = $first_name . $last_name;
$explode = explode('|', $item_name);
foreach($explode as $slot) {
if(strlen($slot) > 0) {
$query = "INSERT INTO bookings (date, start, name, email, phone, order_id) VALUES ('$date', '$slot', '$firstLast', '$payer_email', '$phone', '$orderid')";
$result = mysqli_query($con, $query) or die(mysqli_error($link));
} // Close if
} // Close foreach
mysqli_query($con,"INSERT INTO trans_tbl (item_name,ride_day,payer_email,first_name,last_name,amount,currency,country,txn_id,txn_type,payer_id,payment_status,payment_type,create_date,payment_date)
VALUES ('$item_name','$date','$payer_email','$first_name','$last_name','$amount','$currency','$country','$txn_id','$txn_type','$payer_id','$payment_status','$payment_type','$create_date','$payment_date')");
mysqli_close($con);
}
}
$obj = New PayPal_IPN();
$obj->ipn_response($_REQUEST);
?>
On the IPN History of the paypal website it is stuck at sent - resending.
I have setup IPN settings and notify URL in profile settings, and have a business account. My email is verified on the account as well.
Another thing to note, I have been doing simple $0.01 to test this outside sandbox mode, and the return page is working fine just not the ipn listener.
Any help is much appreciated, thanks.
$paypal_mode_status = $im_debut_ipn; //get_option('im_sabdbox_mode');
if ($paypal_mode_status == true)
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
else
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60);
Could be incorrect, you should test to confirm, but I think it's because your $im_debut_ipn variable, when set to TRUE, is not only "debugging" but for some reason is also being used to determine the paypal url. It then sets the url to be paypals sandbox url (see above).
i.e, When
$im_debut_ipn = true
then,
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60);
is also true.
Note that I think $im_debut_ipn is actually a typo and should be ..debug.., meaning a debug mode that lets error messages be shown.

How do I use Paypal to sell something and have something in SQL change after the payment is confirmed?

I have a website I am making in PHP and I need to sell an online product. When someone buys this product I need a way to have my website notified and change some information in an SQL table. I have googled this for the past five hours and I read things about paypal IPN and paypal sandbox. I am still very confused about what paypal IPN is and how to use it. As for paypal sandbox, several tutorials for what I am asking say to use paypal sandbox. I have tried, but every time I try to login to my account it says the password is wrong, and when I try to make another it redirects me to paypal.com.
My main question is: How do I make buying something on paypal change information in an SQL table on my website?
Update:
I have been trying to use this tutorial: http://www.evoluted.net/thinktank/web-development/paypal-php-integration
I have this php code here (modified from the tutorial):
<?php // Database variables
$host = "localhost"; //database location
$user = "user"; //database username
$pass = "pass"; //database password
$db_name = "db"; //database name
// PayPal settings
$paypal_email = 'my sandbox business email is here';
$return_url = 'http://painlessnotes.com/';
$cancel_url = 'http://painlessnotes.com/';
$notify_url = 'http://painlessnotes.com/Paypal/payments.php';
$item_name = 'Test Item';
$item_amount = 10.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"])){
echo "<script type='text/javascript'>alert('send start');</script>";
$querystring = "";
// 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;
echo "<script type='text/javascript'>alert('{$querystring}');</script>";
// Redirect to paypal IPN
header('location:https://www.sandbox.paypal.com/cgi-bin/webscr'.$querystring);
exit();
}else{
// Response from Paypal
mail("my email", "response", "TEST", "From: my email is here");//I am using this to check if it works
// 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 {
mail('my email', '0', '0');//used to check if it works
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);
}
}
?>
The receiving part of this code works when I use IPN simulator in developer.paypal.com for paypal sandbox. The functions.php and the html code giving in the tutorial is the same as what is in the tutorial. When I test this I get the javascript alert boxes coming up and it all looks correct to me, but for some reason I am not getting a response after sending the paypal sandbox request.
What am I doing wrong and how do I fix it? I have create a buyer with a normal paypal account in the sandbox and a business account.
After doing more research and searching I found a paypal page called Paypal Integration Wizard.
This will generate the code needed for what I have asked. It gives a step by step process and is easy to follow. After reading the code I now understand more on how it works.

paypal IPN doesnt add data to the mysql?

The paypal IPN doesn't enter the data into the mysql database for some reason!!
I am using paypal sandbox and the payments go through and they show in my sandbox account but the details wont show in the mysql!!
this is my IPN file. although I called it payments.php and I also used the IPN simulator to point to it and it did it said the IPN sent succesfully. So I don't know what the issue is here:
<?php
// Database variables
$host = "localhost"; //database location
$user = "my details"; //database username
$pass = "pass"; //database password
$db_name = "my details"; //database name
// PayPal settings
$paypal_email = 'MYSANDBOXEMAIL#PAYPAL.COM';
$return_url = 'http://some site/';
$cancel_url = 'http://some site/';
$notify_url = 'http://some site/thanks.php';
$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
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("you#youremail.com", "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("you#youremail.com", "PAYPAL DEBUGGING", "Invalid Response<br />data = <pre>".print_r($post, true)."</pre>");
}
}
fclose ($fp);
}
}
?>
Updated: Here is the function.php.. i hope this helps someone to help me resolve this!
<?php
// 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
/*
$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);
}
}
?>
It looks as if you are working a bit 'blind' because this is a 'headless' script and you don't know where it is failing.
Add some error_log lines at various points so that you can check the flow through the script. In particular, adding error_log($sql) just before you execute the DB query will print the statement to the error log. Take this and try to run it independently in the DB. It could be that some table constraints are failing rather than being an error in the PHP
Adding log lines at various points through the flow and printing out variables at those points will also help you diagnose where failure is happening and hopefully let you pinpoint the error more precisely.
Try Printing or echoing these values replacing - // Payment has been made & successfully inserted into the Database
print $data['item_name'];
print $data['item_number'];.......
And from there I could update till where it is correct and from where it is wrong.

Paypal sandbox IPN and mysql

I'm using Paypal Sandbox to test IPN, which is successful but it isn't updating my MYSQL database. How can i change the code below so that when Paypal sends IPN to my website it updates the mysql database? The below code is paypalipn.php
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// 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.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) {
// PAYMENT VALIDATED & VERIFIED!
$email = $_POST['payer_email'];
$email = mysql_escape_string($email);
$voted = mysql_query("INSERT INTO user VALUES ('','','','','','','','','','','','','','',''")or die(mysql_error());
mysql_query("UPDATE users SET `suscribed`=1 WHERE `email`='$email'")or die(mysql_error());
}
else if (strcmp ($res, "INVALID") == 0) {
// PAYMENT INVALID & INVESTIGATE MANUALY!
}
}
fclose ($fp);
}
Firstly always enable error reporting with error_reporting(E_ALL) when developing, plus log the IPN's to a text file (in a safe place obviously) to reference and see if the actual IPN's are being received & getting through your router ect
At first glance I see that your trying to insert a blank record in user table, also have not added a close bracket ) for the statement.
Then your updating a different table users with maybe a typo: suscribed, dont use the deprecated mysql_escape_string function... mysql_real_escape_string should be used instead, or better yet use prepared statements.
EDIT:
A Simple example you can work from, this includes PDO and logging for the IPN. Hope it helps.
<?php
/**Simple Paypal validation class**/
class paypal_class {
var $last_error;
var $ipn_log;
var $ipn_log_file;
var $ipn_response;
var $ipn_data = array();
function paypal_class() {
$this->paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
$this->last_error = '';
$this->ipn_response = '';
$this->ipn_log_file = 'ipn_results.log';
$this->ipn_log = true;
}
function validate_ipn(){
$url_parsed=parse_url($this->paypal_url);
$post_string = '';
foreach($_POST as $field=>$value){
$this->ipn_data["$field"] = $value;
$post_string .= $field.'='.urlencode(stripslashes($value)).'&';
}
$post_string.="cmd=_notify-validate";
$fp = fsockopen($url_parsed[host],"80",$err_num,$err_str,30);
if(!$fp){
$this->last_error = "fsockopen error no. $errnum: $errstr";
$this->log_ipn_results(false);
return false;
}else{
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($post_string)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
while(!feof($fp)){
$this->ipn_response .= fgets($fp, 1024);
}
fclose($fp);
}
if(eregi("VERIFIED",$this->ipn_response)){
$this->ipn_log(true);
return true;
}else{
$this->last_error = 'IPN Validation Failed.';
$this->ipn_log(false);
return false;
}
}
function ipn_log($success){
if (!$this->ipn_log) return;
$text = '['.date('m/d/Y g:i A').'] - ';
if ($success) $text .= "SUCCESS!\n";
else $text .= 'FAIL: '.$this->last_error."\n";
$text .= "IPN POST Vars from Paypal:\n";
foreach ($this->ipn_data as $key=>$value) {
$text .= "$key=$value, ";
}
$text .= "\nIPN Response from Paypal Server:\n ".$this->ipn_response;
$fp=fopen($this->ipn_log_file,'a');
fwrite($fp, $text . "\n\n");
fclose($fp);
}
}
class database{
/**PDO Connect**/
public function connect($host,$db,$user,$pass){
$this->dbh = new PDO('mysql:host='.$host.';dbname='.$db, $user, $pass);
}
/**Pre Query for prepared statement**/
public function update_valid($email){
$this->value = $email;
$this->prepare();
}
/**Delete pending user, when user clicks cancel # paypal**/
public function delete_pending($email){
$this->result = $this->dbh->prepare('DELETE FROM users where email=":value" and subscribed=0');
$this->result->bindParam(':value', $email);
$this->execute();
}
/**Prepare query for insert**/
private function prepare(){
/* Execute a prepared statement by binding PHP variables */
$this->result = $this->dbh->prepare('UPDATE users SET subscribed=1 WHERE email=":value"');
$this->result->bindParam(':value', $this->value);
$this->execute();
}
/**Execute prepared statement**/
private function execute(){
$this->result->execute();
}
/**Close db**/
public function close(){
$this->result = null;
}
}
?>
<?php
//Handle payment (Set You IPN url too http://yoursite.com?payment=ipn & Cancel url to http://yoursite.com?payment=cancel)
if(isset($_GET['payment'])){
switch ($_GET['payment']) {
case 'cancel':
//Order Cancelled
$db=new database();
$db->connect('localhost','table','root','password');
$db->delete_pending($_SESSION['email']); //hold email in session after submitting form
$db->close();
header('Location: index.php');
die();
break;
case 'ipn':
$pp = new paypal_class;
if ($pp->validate_ipn()){
//Success
$db=new database();
$db->connect('localhost','table','root','password');
$db->update_valid($ipn['payer_email']);
$db->close();
}
die();
break;
}
}
?>

Categories