I am trying a simple listener to update my user info database (like setting their account type from FREE to PREMIUM) after receiving the PayPal IPN. Upon checking the IPN history, the IPN is successfully sent to my listener but can't seem to update my database. I wanted to update the user's account type after VERIFIED part using the SESSION ID that my user is using. The listener.php that I am using is from a tutorial video that I followed.
Here is the code:
session_start();
require 'scr/db.inc.php';
header('HTTP:/1.1 200 OK');
$resp = "cmd=_notify-validate";
foreach ($_POST as $parm => $var) {
$var = urlencode (stripslashes($var));
$resp .= "&$parm=$var";
}
$item_name = $_POST['item_name'];
$item_number = $_POST['$item_number'];
$payment_status = $_POST['$payment_status'];
$payment_amount = $_POST['$payment_amount'];
$payment_currency = $_POST['$payment_currency'];
$txn_id = $_POST['$txn_id'];
$receiver_email = $_POST['$receiver_email'];
$payer_email = $_POST['$payer_email'];
$record_id = $_POST['$record_id'];
$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";
$errno = '';
$errstr = '';
$fh = fsockopen ('ssl:www.paypal.com',443,$errno,$errstr,30);
if (!$fh) {
} else {
fputs ($fh, $httphead . $resp);
while (!feof($fh)) {
$readresp = fgets ($fh, 1024);
if(strcmp ($readresp, "VERIFIED") == 0 ) {
$handler = new Dbh();
$sql = 'UPDATE `users` SET `type` = "PREMIUM" WHERE `id` = :id ';
$query = $handler->connect()->prepare($sql);
$query->execute(array(':id'=>$_SESSION['log_id']));
} else if (strcmp ($readresp, "INVALID") == 0) {
}
}
fclose($fh);
}
?>
I just added a couple of lines into it to hopefully update the database. These are those lines:
session start();
require 'scr/db.inc.php';
.
.
.
.
$handler = new Dbh(); // used to connect to database
$sql = 'UPDATE `users` SET `type` = "PREMIUM" WHERE `id` = :id ';
$query = $handler->connect()->prepare($sql);
$query->execute(array(':id'=>$_SESSION['log_id']));
.
.
.
.
When the PayPal server calls your IPN listener, it starts its own mini "session" between itself and your webserver. Your user's web browser is not a party to this direct HTTP communication between PayPal and your server, so none of the web session details of your user's browser with your server will be available.
If you need an ID to be available at the time you are processing an IPN, you need to pass it to PayPal as part of the transaction, using a variable such as INVNUM or CUSTOM.
When you write to the database, you will need to grab the appropriate variables from the IPN message body in $_POST (not from $_SESSION which will have absolutely nothing of value)
Side note: whenever I see IPN being used asynchronously like this on a server, I can't help noting a much nicer and more robust integration is to integrate a server-side pattern that captures synchronously from the server side and so gets an immediate API response of transaction success/failure, with the user $_SESSION active. Here's a demo pattern of the UI , and the backend v2/orders server-side calls
Related
I'm using Wordpress in my Website. I have attached a few plugins for processing purchase content on my website. I use the Easy Digital Downloads (https://wordpress.org/plugins/easy-digital-downloads) plugin for managing sales of digital content and Paypal IPN for WordPress (https://wordpress.org/plugins/paypal-ipn/) to get transaction details from my Paypal account.
I have to create an account on sandbox.paypal.com to test whether all functions are running properly or not. For the management of the plugin Easy Digital Downloads, current account and recorded properly. However I did not get a report on the Paypal IPN for WordPress plugin. I have entered the URL in the plugin into my Paypal account as an address when the transaction report. However I did not get a report from paypal altogether.
So I think to create their own web pages from scratch without a wordpress plugin and run all functions on top of the PHP script. So, am I better keep using Wordpress or rebuild the website from scratch by writing my own script.
If you have a reference about the use of the wordpress plugin, please share it in the comments. Thanks for your help.
First you will need to create a custom WordPress page and configure Paypal IPN script to post and get data. on such page you can also add features to store the data on a database, send it by mail, add cron jobs or whatever other IPN scripts ...
Also, you need to visit paypal website and set the ipn link, then post there the data from your website and configure it to post back to the url of the wordpress site with the page to receive paypal ipn post data...
here is a page example:
<?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("sanjeev00733#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');
$create_date=date('Y-m-d H:i:s');
$payment_date=date('Y-m-d H:i:s');
mysqli_query($con,"INSERT INTO infotuts_transection_tbl (item_name,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','$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);
?>
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.
I am trying to create a php file that will be called by paypal checkout and add the persons email and password to an sql database so they can login.
I found a file online but and I made my button send the customer to it. But I must be doing something wrong.
Any help would be greatly appreciated.
<?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);
// 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'];
$password = crypt($_POST['os0']);
if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// check 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 payment
$table = "checkout";
include("checkout-config.php");
// Connect to Mysql Database
mysql_connect("$dbhost","$dblogin","$dbpass");
mysql_select_db($dbname) or die("Unable to select database");
mysql_query("INSERT INTO $table
(email, password) VALUES ('$_GET[payer_email]', '$password')");
echo "Paid";
//Header( "Location: http://www.rollestonelectric.com/paid.php" );
}
else if (strcmp ($res, "INVALID") == 0) {
echo "Unpaid";
//Header( "Location: http://www.rollestonelectric.com/unpaid.php" );
// log for manual investigation
}
}
fclose ($fp);
}
The file you have found is the IPN listener file.
IPN : Instant Payment NOtification.
Instant Payment Notification (IPN) is a message service that notifies
you of events related to PayPal transactions. You can use IPN messages
to automate back-office and administrative functions, such as
fulfilling orders, tracking customers, and providing status and other
transaction-related information.
Yes, you are on right track. To insert the details to sql database after checkout you need to make use of IPN.
Steps:
Turn on the IPN in your Paypal Merchant Account.
You need to specify
a IPN return URL , for eg: www.yourdomain.com/testlistener.php, where
testlistener.php is your php file you found online in your account.
A user clicks a PayPal button to kick off a checkout flow; your web application makes an API call; your back-office system makes an API call; or PayPal observes an event.
PayPal HTTP POSTs your listener an IPN message that notifies you of this event.
Your listener returns an empty HTTP 200 response.
Your listener HTTP POSTs the complete, unaltered message back to PayPal.
Note: This message must contain the same fields, in the same order, as the original IPN from PayPal, all preceded by cmd=_notify-validate. Further, this message must use the same encoding as the original.
PayPal sends a single word back - either VERIFIED (if the message matches the original) or INVALID (if the message does not match the original).
For more help refer this link.
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.
I'm creating an IPN for a custom digital ecommerce but i have a problem:
everything works file,i create a "pending payment" in my database with an ID that i call PID (payment id),the user go to the paypal page and when the payment is completed paypal contact me on the IPN listener that checks if the payment is completed and enable all the media that the user bought.
I successfully created an IPN using the micah carrick php class
( http://www.micahcarrick.com/php-paypal-ipn-integration-class.html ) and everything is working exept i ALWAYS get a pendign payment status and i can't get a confirmed one.
I'm currently testing it in the paypal sandbox,i created 2 buyers and one seller and i have enabled the "payment review" for everybody.
I tryed also different approach but i always get the same result.
Code:
file_put_contents('ipn.log',"\n>IPN\n",FILE_APPEND);
//Check the Payment ID,i pass it to the IPN by GET
if(!isset($_GET['pid'])|| !is_numeric($_GET['pid'])){
file_put_contents('ipn.log',"\n!!!IPN:INVALID PID(".$_GET['pid'].")!!!\n",FILE_APPEND);
exit('PID INVALIDO!');
}
//Logging errors
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');
// instantiate the IpnListener class
require('ipnlistener.php');
$listener = new IpnListener();
//Use the sandbox instead of going "live"
$listener->use_sandbox = true;
//validate the request
try {
$listener->requirePostMethod();
$verified = $listener->processIpn();
}
catch (Exception $e) {
error_log($e->getMessage());
exit(0);
}
//Just for debug
file_put_contents('ipn.log',"\n###IPN:verifying...###\n",FILE_APPEND);
if($verified){//the payment is verified
file_put_contents('ipn.log',"\n###IPN:transaction verified(confirmed=".$_POST['payment_status'].")###\n".$listener->getTextReport(),FILE_APPEND);
/*
Once you have a verified IPN you need to do a few more checks on the POST
fields--typically against data you stored in your database during when the
end user made a purchase (such as in the "success" page on a web payments
standard button). The fields PayPal recommends checking are:
1. Check the $_POST['payment_status'] is "Completed"
2. Check that $_POST['txn_id'] has not been previously processed
3. Check that $_POST['receiver_email'] is your Primary PayPal email
4. Check that $_POST['payment_amount'] and $_POST['payment_currency']
are correct
Since implementations on this varies, I will leave these checks out of this
example and just send an email using the getTextReport() method to get all
of the details about the IPN.
*/
if($_POST['payment_status']=="Completed"){
//--check if the price is right and enable the user media--
confirm_payment($_GET['pid'],$_POST['payment_amount']);
file_put_contents('ipn.log',"\n###IPN:Transaction completed###\n".$listener->getTextReport(),FILE_APPEND);
}
}
else {
/*
An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's
a good idea to have a developer or sys admin manually investigate any
invalid IPN.
*/
file_put_contents('ipn.log',"\n###IPN:ERROR###\n".$listener->getTextReport(),FILE_APPEND);
}
The debug log i created is always like this
> IPN <--it states that the ipn was correctly called
##IPN:verifying...### <--the IPN is verifying the transaction
##IPN:transaction verified(confirmed=Pending)<--the transaction is verified but it's NOT confirmed because it's pending,i can't enable the download!
Disable Payment Review. Payment Review will always place them in a Pending state.
That's actually the whole point of it; to be able to use negative testing and payment review in order to test 'negative' scenario's to verify your error handling.
I am not familiar with the class you are using, but this is what i have been using for PP IPN in all my work and it works like a charm, maybe one day i'll make my own Object Oriented way but for now this seems to be doing the trick and i hope it helps you.
(Just to get you on the right track, i am using the same file for incoming and outcoming messages to/from PP)
$sandbox="sandbox.";
$paypal_email="seller_XXXXX_biz#twbooster.com";
$item_id = "1XN12PJ";
$cost = "22.30";
$item_name = 'My Item';
$return_url = "http://www.example.com/return";
$cancel_url = "http://www.example.com/cancel";
$notify_url = "http://www.example.com/notify";
function check_txnid($tnxid){
global $link;
$sql = mysql_query("SELECT * FROM `payments_pending` WHERE `txnid` = '$tnxid'", $link);
return mysql_num_rows($sql)==0;
}
function check_price($price, $id){
$sql = mysql_query("SELECT `cost` FROM `orders` WHERE `id` = '$id'");
if (mysql_numrows($sql) != 0) {
$row = mysql_fetch_array($sql);
$num = (float) $row['cost'];
if($num - $price == 0){
return true;
}
}
return false;
}
if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){ // Request TO Paypal
// Firstly Append paypal account to querystring
$querystring .= "?business=".urlencode($paypal_email)."&";
// Append amount& currency (£) to quersytring so it cannot be edited in html
$querystring .= "lc=CA&";
$querystring .= "currency_code=CAD&";
$querystring .= "item_number=".$item_id."&";
//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=".$cost."&";
//loop for posted values and append to querystring
foreach($_POST as $key => $value){
$value = urlencode(stripslashes($value));
$querystring .= "$key=$value&";
}
// Append paypal configs
$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) {
$req .= "&$key=$value";
}
// assign posted variables to local variables
$data = array();
$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 : Do something to notify you
}
else {
fputs($fp, $header.$req);
$res = "";
while (!feof($fp)){
$res .= fgets($fp, 1024);
}
if(strpos($res, "VERIFIED")!==false){
// Validate payment (Check unique txnid & correct price)
$valid_txnid = check_txnid($data['txn_id']);
// $valid_price = check_price($data['payment_amount'], $data['item_number']);
$valid_price = check_price($data['payment_amount'], $_POST['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
}
}
else{
// Payment made but data has been changed : Do something to notify you
}
}
else{
if(strpos($res, "VERIFIED")!==false){
// PAYMENT INVALID & INVESTIGATE MANUALY! : Do something to notify you
}
}
fclose($fp);
}
}