I am using this code on my site, for paypal checkout
<?php
require('../includes/globals/config.php');
require('myCart.inc.php');
$mycart = new myCart;
$ppemail = $mycart->getPaypalEmail();
$paypal_email = $ppemail['email'];
$paypal_currency = 'USD';
//$shipping = 1.00;
// 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('www.sandbox.paypal.com', 80, $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'];
if (!$fp){
// HTTP ERROR
} else {
fputs($fp, $header . $req);
while(!feof($fp)) {
$res = fgets($fp, 1024);
if (strcmp($res,"VERIFIED") == 0){
//blah blah
}
else if (strcmp($res, "INVALID") == 0){
// log for manual investigation
}
}
fclose($fp);
}
?>
The problem is, after the transaction stuff, and I get redirected to a thank you page, the $_POST data doesn't appear on the form inputs, I meant, I extracted the contents of the $_POST data coming from the paypal transaction and placed the tidbits of data on each form fields..but when I clean browser cache/private data/session/cookies and do the same procedure, but this time with the
echo "<pre>",print_r($_POST),"</pre>";
the $_POST content gets printed on the page and the tidbits of $_POST are being displayed also inside the form fields..this happens when I use the print_r. Is there a workaround for this? so that the tidbits of data will immediately appear on the form fields without having to invoke the print_r() func and print the array of data somewhere on the page ?
Related
I have been at this for 3 days now and still can't get it to work.
What I want to do is to get PayPal response from the IPN listener so that I can modify my database accordingly, but no matter what I do, it just won't work. I have already done the following in my PayPal Sandbox account:
Enabled Auto Return
Set Auto Return URL ('paypal/success')
Enabled Payment Data Transfer (PDT)
Enabled IPN message reception
Set IPN URL ('paypal/ipn')
The redirect to Auto Return URL works fine and I receive the payment data in success page, but the IPN won't process for reasons beyond me. A quick look at the IPN history on my PayPal profile shows that the messages are being sent, but I don't receive them at my end.
Here is my current IPN listener: Paypal/ipn
public function ipn() {
//Build the data to post back to Paypal
$postback = 'cmd=_notify-validate';
// go through each of the posted vars and add them to the postback variable
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$postback .= "&$key=$value";
}
// build the header string to post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n";//or www.sandbox.paypal.com
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($postback) . "\r\n\r\n";
// Send to paypal or the sandbox depending on whether you're live or developing
// comment out one of the following lines
$fp = fsockopen ('www.sandbox.paypal.com', 443, $errno, $errstr, 30);//open the connection
//$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);
// or use port 443 for an SSL connection
//$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
if ( ! $fp ) {
// HTTP ERROR Failed to connect
$message = 'HTTP ERROR Failed to connect!';
$this->email_me($message);
} else { // if we've connected OK
fputs ($fp, $header . $postback); //post the data back
while ( ! feof($fp) ) {
$response = fgets ($fp, 1024);
if (strcmp (trim($response), "VERIFIED") == 0) { //It's verified
//read the payment details and the account holder
$payment_status = $_POST['payment_status'];
$receiver_email = urldecode($_POST['receiver_email']);
// further checks
if( ($payment_status == 'Completed') && ($receiver_email == $this->business_email) ) {
$message = 'IPN verified successfully!';
$this->email_me($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_me($message);
}
} else {
$message = 'IPN invalid!';
$this->email_me($message);
}
}
}
}
Can someone point me in the right direction please?
Also, is there anyway I can check the IPN response ("VERIFIED" or "INVALID") on chrome debugger or in my PayPal Sandbox dashboard? I can see delivery status in my dashboard but it doesn't say 'Verified' or 'Invalid' anywhere.
I found the solution! I wrote the IPN handler inside a controller that allows access to users who are logged in as admin. Apparently, the IPN method was denying access to PayPal to verify the transaction. I figured this out and wrote the IPN method in a different controller and everything worked perfectly.
I also changed my IPN handler to this code (although the original might still work... i didn't try it):
class Paypal_ipn extends MY_Controller {
public function __construct() {
parent::__construct();
$this->load->model('product_model');
$this->sandbox = $this->config->item('sandbox');
$this->paypal_host = $this->config->item('paypal_host');
$this->paypal_url = $this->config->item('paypal_url');
$this->business_email = $this->config->item('business');
}
public function ipn() {
// STEP 1: Read POST data
// reading posted data from directly from $_POST causes serialization
// issues with array data in POST
// reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// STEP 2: Post IPN data back to paypal to validate
$ch = curl_init($this->paypal_url);
$headers = array(
'POST /cgi-bin/webscr HTTP/1.1',
'Host: ' . $this->paypal_host,
'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
'Content-Length: ' . strlen($req),
'User-Agent: PayPal-IPN-VerificationScript',
'Connection: Close'
);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if( !($res = curl_exec($ch)) ) {
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// check whether 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
// 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 = urldecode($_POST['receiver_email']);
$payer_email = $_POST['payer_email'];
$school_id = $_POST['custom'];
// further checks
if($payment_status == 'Completed') {
$message = 'IPN verified successfully!';
$this->email_developer($message);
// Insert the transaction data in the database
$this->product_model->insert_transaction_details($_POST);
} else {
$message = 'Payment could not be verified!';
$this->email_developer($message);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
$message = 'IPN Invalid!';
$this->email_developer($message);
}
}
}
For those that might experience my predicament, ensure you also do the following:
If you enabled Cross Site Request Forgery (CSRF), ensure the IPN listener/handler is whitelisted, else IPN message will fail (Error 403 in PayPal IPN history).
To be sure your IPN listener is working well, run it as a URL and see the response. If there is any error, it won't work. For response, trying echoing "Verified" or "Invalid".
Use the PayPal IPN Simulator to test the process. Include a procedure that will submit information to the database upon success.
I hope it helps someone.
use php://input instead of $_POST
reson described here in details : PHP "php://input" vs $_POST
also paypal has documentation for implementing IPN Listener and its in php as well
Paypal tutorial
I have set up test accounts Business and Personal in developer for trying out sandbox mode.
I have made a payment button on my site. I click the button and go to paypal.
Test user personal account is used for paying.
Payment goes through and is Completed when i look in the Paypal business account.
Redirect to my site works good.
So in my eyes i should have a "working" system.
My IPN Listener though does not return either verified or invalid.
This is my listener:
<?php
require("../widgets/init.inc.php");
//Test the script is launced
$log_query = mysql_query("INSERT INTO `log` VALUES (' ','zz','ff','rr', 'rr')");
// Link to PayPal Codes //
// https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_html_IPNandPDTVariables //
// 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";
//For the below line i have tried "www.sandbox.paypal" as well as "www.paypal"
$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'];
$txnId = $_POST['txn_id'];
$receiverEmail = $_POST['receiver_email'];
$payerEmail = $_POST['payer_email'];
//$id = ($_POST['custom']);
if (!$fp) {
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
if ($payment_status=='Completed') {
//$txnIdCheck = mysql_query("SELECT `txnId` FROM `log` WHERE `txnId`='".$txnId."'");
//if (mysql_num_rows($txnIdCheck) !=1) {
// enter your email address associated with your paypal account here //
if ($receiverEmail=='biztester1#mydomain.dk') {
/* when a new premium member makes payment paypal will update our database. The txn_id from paypal, members email address, date of payment and members id we gave them when they joined our site will be inserted into the log table. At the same time the memberAdmin table for the member will be updated by adding a '1' to premium and the date of payment so the new premium member will have access to premium areas of your site. */
//Check if verified is launced
$log_query_2 = mysql_query("INSERT INTO `log` VALUES (' ','yes','yes','yes', 'yes')");
//$log_query = mysql_query("INSERT INTO `log` VALUES (' ','".intval($id)."','".$txnId."','".$payerEmail."', now())");
//$update_premium = mysql_query("UPDATE `memberAdmin` SET `premium`=1, `premiumDate`=now() WHERE `id`=".intval($id)."");
}
//}
}
}
else if (strcmp ($res, "INVALID") == 0) {
//Check if invalid is launced
$log_query_2 = mysql_query("INSERT INTO `log` VALUES (' ','no','no','no', 'no'");
}
}
fclose ($fp);
}
?>
I have activated the IPN at the paypal business account site.
I have made a txt file of the returned information from paypal, and it looks like this:
==== Thu, 18 Jul 2013 01:34:21 +0200 ====
POST: mc_gross = 0.01
POST: protection_eligibility = Ineligible
POST: payer_id = 73WPPK8HKSW7C
POST: tax = 0.00
POST: payment_date = 15:15:20 Jul 17, 2013 PDT
POST: payment_status = Completed
POST: charset = windows-1252
POST: first_name = Niels
POST: mc_fee = 0.01
POST: notify_version = 3.7
POST: payer_status = verified
POST: business = biztester1#mydomain.dk
POST: quantity = 1
POST: verify_sign = A-ddKAwtxju4TpHGJOGq6c3ewj26AyiHsD.XO90coZ.4rVzOT7VyooKO
POST: payer_email = tester1#mydomain.dk
POST: txn_id = 6WH41489RE087103M
POST: payment_type = instant
POST: last_name = Tester
POST: receiver_email = biztester1#mydomain.dk
POST: payment_fee = 0.01
POST: receiver_id = PCX638B2M7WPA
POST: txn_type = web_accept
POST: item_name = 500Credits
POST: mc_currency = USD
POST: item_number = 1
POST: residence_country = DE
POST: test_ipn = 1
POST: handling_amount = 0.00
POST: transaction_subject = 500Credits
POST: payment_gross = 0.01
POST: shipping = 0.00
POST: ipn_track_id = 2dffcbf8767d3
InvoiceID:
Custom1:
Custom2:
Custom3:
It seems like it is a lot harder to get this to work than what I think it should be.
I found the problem.. AND THE ANNOYING THING IS THAT PAYPAL DOCUMENTATION IS WRONG AGAIN.. I don't understand that the documentation can state press this button and press this button.. WHEN there are no buttons like this in the site...
For this problem - The documentation does state a wrong method / does not include full code needed.
THE PROBLEM:
The $res returned this:
HTTP/1.0 400 Bad Request
Server: BigIP
Connection: close
Content-Length: 19
Invalid Host header
what needs to be added is :
$header .= "Host: www.sandbox.paypal.com\r\n";
AND then the above code looks like this:
// post back to PayPal system to validate //
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: www.sandbox.paypal.com\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);
This was the full code i ended up using:
<?php
require("../widgets/init.inc.php");
// Link to PayPal Codes //
// https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_html_IPNandPDTVariables //
// 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 .= "Host: www.sandbox.paypal.com\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);
// 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'];
$txnId = $_POST['txn_id'];
$receiverEmail = $_POST['receiver_email'];
$payerEmail = $_POST['payer_email'];
//$id = ($_POST['custom']);
if (!$fp) {
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
$log_query_pre = mysql_query("INSERT INTO `log` VALUES (' ','$receiverEmail','$payment_status','$res', 'yes')");
if (strcmp ($res, "VERIFIED") == 0) {
if ($payment_status=='Completed') {
//$txnIdCheck = mysql_query("SELECT `txnId` FROM `log` WHERE `txnId`='".$txnId."'");
//if (mysql_num_rows($txnIdCheck) !=1) {
// enter your email address associated with your paypal account here //
if ($receiverEmail=='biztester1#mydomain.dk') {
/* when a new premium member makes payment paypal will update our database. The txn_id from paypal, members email address, date of payment and members id we gave them when they joined our site will be inserted into the log table. At the same time the memberAdmin table for the member will be updated by adding a '1' to premium and the date of payment so the new premium member will have access to premium areas of your site. */
//Check if verified is launced
$log_query_2 = mysql_query("INSERT INTO `log` VALUES (' ','yes','yes','yes', 'yes')");
//$log_query = mysql_query("INSERT INTO `log` VALUES (' ','".intval($id)."','".$txnId."','".$payerEmail."', now())");
//$update_premium = mysql_query("UPDATE `memberAdmin` SET `premium`=1, `premiumDate`=now() WHERE `id`=".intval($id)."");
}
//}
}
}
else if (strcmp ($res, "INVALID") == 0) {
//Check if invalid is launced
$log_query_2 = mysql_query("INSERT INTO `log` VALUES (' ','no','no','no', 'no')");
}
}
fclose ($fp);
}
?>
I have tried using a tutorial script for PayPal payment in the past and it worked. Now it doesn't. The script is simple, all I need is this one page for processing payment:
<?php
session_start();
include ('mydbconfig.php');
// payPal settings
$paypal_email = 'seller#yahoo.com';
$return_url = 'https://www.mytestsite.com/paypal-thanks.php';
$cancel_url = 'https://www.mytestsite.com/paypal-cancel.php';
$notify_url = 'https://www.mytestsite.com/paypal-notify.php';
$item_name = $_POST['item_name'];
$item_amount = $_POST['item_amount']; //price
// 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.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
header('location: https://www.mytestsite.com/paypal-error.php?tr='.$data['txn_id'].'&in='.$data['item_name'].'&pe='.$data['payer_email'].'&pa='.$data['payment_amount'].'&ps='.$data['payment_status']);
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
//payment accepted, insert transaction to my database
//function to insert transaction here
} else if (strcmp ($res, "INVALID") == 0) {
//something to do if failed
}
}
fclose ($fp);
}
}
?>
After the process is completed, I checked and the payment is paid successfully, but my function or anything I wrote in //function to insert transaction here won't be executed. In the end I'm forced to do the function on paypal-thanks.php page. Is there something's wrong in the script?
Is this script can be used to send more than one item purchasing? My cart is my own custom made and I only want to send Item name, number, and price detail, and total price to PayPal order summary.
I checked the other PayPal integration questions here, and most of them direct me to PayPal tutorial, documentation, or integration wizard which're confusing. I use this simple script before because I can't understand PayPal documentation (and the sample code, it didn't even let me know where to start) :(
And lastly my ultimate question, is this script is the correct and secure way to do a payment transaction?
use this
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
instead of
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
i think it is better to use CURL instead of socket
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I want to set things up so that when a user pays me through PayPal, a PHP script will be run. How can I set up this kind of notification?
It's called an IPN.
You just need to go into your settings, enable the IPN, tell it what file will be handling the call back and then write your php file.
Here's how I handle paypal ipns with php
<?php
if($_POST){
// 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) {
// check the payment_status is Completed
// assign posted variables to local variables - NOT NECESSARY..
$receiver_email = mysql_real_escape_string($_POST['receiver_email']);
$payer_email = mysql_real_escape_string($_POST['payer_email']);
$business_id = mysql_real_escape_string($_POST['item_number']);
$payment_gross = mysql_real_escape_string($_POST['mc_gross']);
$item_name = mysql_real_escape_string($_POST['item_name']);
$currency = mysql_real_escape_string($_POST['mc_currency']);
$payment_date = mysql_real_escape_string($_POST['payment_date']);
$payment_status = mysql_real_escape_string($_POST['payment_status']);
$address_street = mysql_real_escape_string($_POST['address_street']);
$first_name = mysql_real_escape_string($_POST['first_name']);
$last_name = mysql_real_escape_string($_POST['last_name']);
$address_street = mysql_real_escape_string($_POST['address_street']);
$address_city = mysql_real_escape_string($_POST['address_city']);
$address_state = mysql_real_escape_string($_POST['address_state']);
$address_country_code = mysql_real_escape_string($_POST['address_country_code']);
$address_zip = mysql_real_escape_string($_POST['address_zip']);
$quantity = mysql_real_escape_string($_POST['quantity']);
$payment_fee = mysql_real_escape_string($_POST['mc_fee']);
$address_name = mysql_real_escape_string($_POST['address_name']);
$payment_type = mysql_real_escape_string($_POST['payment_type']);
$payer_business_name = mysql_real_escape_string($_POST['payer_business_name']);
$item_number = mysql_real_escape_string($_POST['item_number']);
$transaction_subject = mysql_real_escape_string($_POST['transaction_subject']);
$parent_txn_id = mysql_real_escape_string($_POST['parent_txn_id']);
$txn_id = mysql_real_escape_string($_POST['txn_id']);
$custom = mysql_real_escape_string($_POST['custom']);
//insert into payments table
$result = mysql_query("INSERT INTO payments (payment_date, payment_type, receiver_email, payer_email, gross_amt, quantity, currency, payment_status, paypal_fee, transaction_subject, item_name, item_number, first_name, last_name, payer_business_name, address_name, address_street,address_city,address_state,address_zip,address_country_code,parent_txn_id, txn_id, custom) VALUES ('$payment_date','$payment_type', '$receiver_email', '$payer_email', '$payment_gross','$quantity','$currency','$payment_status','$payment_fee','$transaction_subject','$item_name','$item_number','$first_name','$last_name','$payer_business_name','$address_name','$address_street','$address_city','$address_state','$address_zip','$address_country_code','$parent_txn_id','$txn_id','$custom')") or die(mysql_error());
//end of if invalid
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
}
fclose ($fp);
}
//end of post
}
?>
PayPal offers the Instant Payment Notification system which you have to set up through your account.
Here is the link to their guide to get you started.
https://cms.paypal.com/cms_content/US/en_US/files/developer/IPNGuide.pdf
Also they offer a template for your IPN listener. Here is the one in PHP:
<?php
// read the post from PayPal system and add 'cmd'
$req = 'cmd=' . urlencode('_notify-validate');
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.paypal.com/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com'));
$res = curl_exec($ch);
curl_close($ch);
// 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'];
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
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
?>
I'm developing a lightweight e-commerce solution that uses PayPal as the payment gateway. However, my IPN callback is constantly returning an INVALID response. I even tried using the sample PHP script provided by PayPal:
// 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'];
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
}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}
}
fclose ($fp);
}
But as I say, I keep getting an INVALID response. This is in fact the response I get using a PHP class that writes the response to a log file:
[2011-06-02 19:18:49] - FAIL: IPN Validation Failed.
IPN POST data from PayPal:
test_ipn=1,
payment_type=instant,
payment_date=11:07:43 Jun 02, 2011 PDT,
payment_status=Completed,
payer_status=verified,
first_name=John,
last_name=Smith,
payer_email=buyer#paypalsandbox.com,
payer_id=TESTBUYERID01,
business=seller#paypalsandbox.com,
receiver_email=seller#paypalsandbox.com,
receiver_id=TESTSELLERID1,
residence_country=US,
item_name1=something,
item_number1=AK-1234,
quantity1=1,
tax=2.02,
mc_currency=USD,
mc_fee=0.44,
mc_gross=15.34,
mc_gross_1=12.34,
mc_handling=2.06,
mc_handling1=1.67,
mc_shipping=3.02,
mc_shipping1=1.02,
txn_type=cart,
txn_id=4362187,
notify_version=2.4,
custom=xyz123,
invoice=abc1234,
charset=windows-1252,
verify_sign=AjbdIvvDAW2fh1O9jAbEym4myX.WAV7-jCEiEWMqoSkewvM6L3Co6oUQ
This is from the official PayPal IPN test tool. So something between PayPal's sample code and test tool is causing my script to fail. Any one have any ideas?
what is encoding of your html/php page ? (charset=windows-1252) ?