PayPal IPN fails to work on my custom store - php

I am using PayPal IPN in Sandbox mode and this code isn't working for some reason.
What I want to happen is where it says "VERIFIED" to do the thing between the brackets. But it isnt and I don't know any PhP but I need this to work for my money.
Here is my store's index.php
<head>
<title>Donation Store | EndersoulsRH</title>
</head>
<body>
<center>
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="text" name="username" placeholder="Your Minecraft Username"> <br>
<input type="hidden" name="itemname" value="VIP">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="SHW4WRJBFNDQA">
<input type="image" src="http://www.endersouls.us/img/buynow.png" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!" width="200px;">
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="text" name="username" placeholder="Your Minecraft Username"> <br>
<input type="hidden" name="itemname" value="VIP">
<input type="hidden" name="command" value="warp Ranks Hayno">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="XU8NQN8EVPMYG">
<input type="image" src="https://www.endersouls.us/img/buynow.png" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!" width="200px">
<img alt="" border="0" src="https://www.sandbox.paypal.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
</center>
</body>
</html>
Here is my paypal ipn.php
<?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['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'];
$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) {
die("Connection to and from PayPal has bee lost");
} else {
fputs ($fh, $httphead . $resp);
while (!feof($fh)) {
$readresp = fgets ($fh, 1024);
if (strcmp ($readresp, "VERIFIED") == 0) {
$command = "warp ranks Hayno";
require_once("WebsenderAPI.php"); // Load Library
$wsr = new WebsenderAPI("*****","*****","*****"); // HOST , PASSWORD , PORT
if($wsr->connect()){ //Open Connect
$wsr->sendCommand($command);
}
$wsr->disconnect(); //Close connection.
} else if (strcmp ($readresp, "INVALID") == 0) {
}
fclose ($fh);
}
}
?>

I think your URL is wrong. try to put
$fh = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
instead of `$fh = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
in your test pay now button also put sandbox.paypal.com/blahglah`
so put sandbox.paypal.com..... instead of paypal.com....
// 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('https://www.paypal.com/cgi-bin/webscr'); // change to [...]sandbox.paypal[...] when using sandbox to test
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, array('Connection: Close'));
// In wamp like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below.
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordinglyq
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 variablesq
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
if ($_POST['mc_gross'] != NULL)
$payment_amount = $_POST['mc_gross'];
else
$payment_amount = $_POST['mc_gross1'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
$custom = $_POST['custom'];
$servername = "*****";
$username = "*****";
$password = "*****";
$dbname = "*****";
$nizz = (explode('|', $custom));
$var1 = $nizz[0];
$var2 = $nizz[1];
$var3 = $nizz[2];
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// DO YOUR QUERY HERE OR WHATEVER YOU WANT
// --------------------
if ($conn->query($sql) === TRUE) {
$email_from = 'mymail#example.com';
//send mail from here to notify yourself
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
}

Related

php paypal returns INVALID on live

So I am working on a small site which takes a single payment per user.
When I do payments through the sandbox, if the payment is a success then i always get a IPN response and am able to use that to update my DB
BUT when using live even if paypal says it was a success the IPN returns INVALID
I have looked around for an answer and people have been saying make sure you are using paypal.com and not sandbox.paypal.com, I have done all the suggestions but still no luck.
A working answer to this would be much appreciated!
Here is my code:
This is the html form:
<form class="paypal" action="payments.php" method="post" id="paypal_form" target="_blank">
<input type="hidden" name="cmd" value="_xclick" />
<input type="hidden" name="no_note" value="1" />
<input type="hidden" name="lc" value="UK" />
<input type="hidden" name="currency_code" value="GBP" />
<input type="hidden" name="first_name" value="Customer's First Name" />
<input type="hidden" name="last_name" value="Customer's Last Name" />
<input type="hidden" name="payer_email" value="customer#example.com" />
<input type="hidden" name="item_number" value="123456" / >
<input type="hidden" name="invoice" value="<?php echo $invoice ?>" / >
<input class="submit" type="submit" name="submit" value="Start Payment Process"/>
</form>
This code starts the payment:
<?php
// Database variables
$servername = "localhost";
$username = "un";
$password = "pw";
$dbname = "dbn";
// PayPal settings
$paypal_email = 'email#email.com';
$return_url = 'http://domain.co.uk/paypal/test.php';
$cancel_url = 'http://domain.co.uk/paypal/payment-cancelled';
$notify_url = 'http:/domain.co.uk/paypal/test.php';
$item_name = 'Item Name';
$item_amount = 1.00;
$invoice = $_POST['invoice'];
// Include Functions
include("functions.php");
// Check if paypal request or response
if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){
$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)."&";
$querystring .= "invoice=".urlencode($invoice)."&";
//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 {
//Database Connection
$link = mysql_connect($servername, $username, $password);
mysql_select_db($db_name);
// 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.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('user#domain.com', 'PAYPAL POST - VERIFIED RESPONSE', print_r($post, true));
// 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
mail("email#email.com","Success","Payment made successfully");
echo "updated";
} else {
// Error inserting into DB
// E-mail admin or alert user
mail('email#email.com', 'PAYPAL POST - INSERT INTO DB WENT WRONG', print_r($data, true));
}
} 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("user#domain.com", "PAYPAL DEBUGGING", "Invalid Response<br />data = <pre>".print_r($post, true)."</pre>");
}
}
fclose ($fp);
}
}
?>
This code handles the response from paypal:
<?php
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$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 IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$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('https://www.paypal.com/cgi-bin/webscr');
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, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set
// the directory path of the certificate as shown below:
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if ( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
}
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// 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 the notification
// 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'];
$invoice = $_POST['invoice'];
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key . " = " . $value . "<br>";
}
echo $res;
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "Error! Paypal stated payment as: <b>" .$res ."<br />";
}
?>

Can i update the database without paypal redirecting to success page?

Sorry i'm a newbie at this PAYPAL IPN
so i got my IPN file.
so my question is, once the user has paid gets redirected to the success/ipn page my script updates the records. but what if the user didnt get redirected, i tested it myself paypal redirects me to the PAYPAL THANK YOU ORDER page and then mozilla pops up a window alert saying that "your connecting to an insecure site bla bla CLICK (yes) or (cancel)" if i click yes then i get redirected to my success/ipn page, but if i click cancel i will stay on the PAYPAL THANK YOU PAGE so im worried that the user might click cancel and he wont get redirected and the data wont be updated
so how do i update the database without paypal redirecting me to my success/ipn page
Please advise, and dont vote down please,
$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('https://www.sandbox.paypal.com/cgi-bin/webscr'); // change to [...]sandbox.paypal[...] when using sandbox to test
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// In wamp like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below.
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// WRITE LOG
$fh = fopen('result.txt', 'w');
fwrite($fh, $res .'--'. $req);
fclose($fh);
// 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'];
if ($_POST['mc_gross'] != NULL){
$payment_amount = $_POST['mc_gross'];
}else{
$payment_amount = $_POST['mc_gross1'];
}
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
$custom = $_POST['custom'];
// Insert your actions here
if(($payment_status == 'Completed') && ($receiver_email == 'paypal-test#bolddata-ap.com')){
include('php/config.php'); //Open Database connection
$check = $dbo->prepare('SELECT * FROM order_bytes WHERE trans_id = ?');
$check->execute(array($txn_id));
if($check->rowCount() >= 1){
die('ERROR FOUND SAME TXN ID IN DATABASE');
}else{
/*Data token = EAZZn0OkC2zo4H3CF9vrrSlU-grBGr0oQzE8NZ6jnYGRTuJkJS0howDNK48*/
$stmt = $dbo->prepare("UPDATE `order_bytes` SET stat=? ,paid=?, trans_id=? WHERE `tracker`=? AND `user_id`=?");
/*$stmt->bindValue(":stats", 'PAID', PDO::PARAM_STR);
$stmt->bindParam(":pay", $item_price, PDO::PARAM_STR);
$stmt->bindParam(":it", $item_transaction, PDO::PARAM_STR);
$stmt->bindParam(":trackers", $_SESSION['random_id'], PDO::PARAM_STR);
$stmt->bindParam(":uid", $_SESSION['byte_user'], PDO::PARAM_STR);*/
if(!$stmt->execute(array($payment_status,$payment_amount,$txn_id,$_SESSION['tracker'],$_SESSION['byte_user']))){
//print_r($stmt->errorInfo());
}else {
if($stmt->rowCount() == 1){
notify(getbyteuser($item_no),'A User Ordered your Byte<br />Tracker ID: '.$_SESSION['tracker'].'','NEW ORDER');
//mail_booked($item_transaction);
echo "<div class=\"alert alert-success\"><h3>Thank you<br>Your payment has been successfull</h3>
<p>Keep track of your order in your Dashboard</p>
</div>";
echo 'Done';
}else{
print alert_danger('Error');
}
}
}
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
?>
You are confused about IPN and return page.
This is wrong:
so my question is, once the user has paid gets redirected to the success/ipn page
IPN is not a success page. It is a page that PayPal calls in the background to notify you about a transaction status. It is independent of the user session. (notify_url)
The page that PayPal redirects the user after complete (or cancel) a payment is different from the IPN. This is related to the user session (return_url)

Really struggling with Paypal IPN

Update - I removed the validation, and added an $item_id = $_POST['option_selection1']; to my field, and suddenly it worked!
I have a website for a photographer, and she is selling time slots throughout the day. I am trying to set her up so that someone chooses a time slot, purchases it through paypal, and then when the data is returned via IPN, I capture the email address used to make the purchase, as well as an id that I have associated with the time slot. With that ID, I am setting a toggle in the database that causes that time slot to no longer populate on the form, so others can't purchase the same time slot. Every time I make a test transaction, the database doesn't update, and I don't know why. When I manually set the values of the variables $payer_email and $item_number, the database does what I would expect it to do. From this, I'm under the impression that PayPal isn't validating the data, or it isn't sending the data in a way I'd expect it to.
Here is my code for the form that is running through PayPal:
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT id,hour,minute,toggle FROM mini ORDER BY id ASC";
$result = $conn->query($sql);
echo '<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">';
echo '<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="B6XDLRPVAUBQJ">
<input type="hidden" name="on0" value="item_number">
<select name="os0">';
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
if ($row["toggle"] == 0){
echo '<option value="'.$row["id"].'">'.$row["hour"].':'.$row["minute"].' '; //id is what I'm trying to extract from paypal via IPN
if ($row["id"] < 13){echo 'AM';}else{echo 'PM';}; //if-then statement determines if it is AM or PM based on id
echo '</option>';
};
}
} else {
echo "Sorry, I'm fully booked!";
}
?>
</select>
<input type="submit" name="submit" value="Book Your Session">
</form>
Here is my code for the IPN
<?php
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$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 IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$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('https://www.paypal.com/cgi-bin/webscr');
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, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set
// the directory path of the certificate as shown below:
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// 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 the notification
// 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'];
// IPN message values depend upon the type of notification sent.
// To loop thffrough the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key." = ". $value."<br>";
}
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
//database credentials intentionally omitted :)
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "UPDATE mini SET toggle='1',email='".$payer_email."' WHERE id=('".$item_number."')";
if ($conn->query($sql) === TRUE) {
echo "<br/> - Record updated successfully";
} else {
echo "Error updating record: " . $conn->error;
}
?>
I'd suggest you to try using PaymentDetails API to debug the payment statuses that you are testing.
https://developer.paypal.com/docs/classic/api/adaptive-payments/PaymentDetails_API_Operation/
Also with PayPal sandbox is a little bit different, slower and buggier - so you should employ some logging. Log everything that is posted and the validation response. After having that you could focus on the app's logic.

PHP Mysql PayPal IPN Not Updating Database

I'm using paypals IPN for players to purchase points from my game. Once they purchase them it should update the users table where their Id is and give them points and energy, and then insert into a different table named transactions. I've tested it and the IPN is sending but it's not updating the database or inserting into the table. Here's the code:
<?php session_start() ?>
<?php require 'connect.php' ?>
<?php
// check if logged into PsychoWars
if(!$id) {
die('Error: Not Logged In! Contact Us With The Transaction ID!');
}
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$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 IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$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('https://sandbox.paypal.com/cgi-bin/webscr');
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, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set
// the directory path of the certificate as shown below:
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);
// STEP 3: Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// check whether the payment_status is Completed (Done)
// check that txn_id has not been previously processed ()
// check that receiver_email is your Primary PayPal email (Done)
// check that payment_amount/payment_currency are correct (Done)
// process the notification
// 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'];
// Checking if package exists
$get_points = mysql_query("SELECT * FROM buying_offers WHERE id=".$item_number."");
if(mysql_num_rows($get_points) == 0) {
die('Error: Boss Point Offer Doesn\'t Exist!');
}
// Get Points Info
$points_info = mysql_fetch_array($get_points);
$points_cost = $points_info['cost'];
$points_amount = $points_info['points'];
$points_energy = $points_info['energy'];
$points_name = $points_info['package'];
// check that payment_amount/payment_currency are correct
if($payment_amount != $points_cost) {
die('Error: Payment Doesn\'t Equal Package Cost!');
}
if($receiver_email != 'bad.karma12323#gmail.com') {
die('Error: Paypal Email Doesn\'t Match!');
}
// checking payment status
if($payment_status == 'Completed'){
echo 'Success: You Were Rewarded '.$points_amount.' Boss Points And '.$points_energy.' Energy!';
$update_user = mysql_query("UPDATE users SET points=(points+".$points_amount."),energy=(energy+".$points_energy.") WHERE id=".$id."");
$add_trans = mysql_query("INSERT INTO transactions (user_id,txn_id,item_name,payment_status,cost,time) VALUES ('$id','$txn_id','$points_name','$payment_status','$payment_amount','".time()."')");
}
elseif($payment_status == 'Denied' || $payment_status == 'Failed' || $payment_status == 'Refunded' || $payment_status == 'Reversed' || $payment_status == 'Voided'){
die('Error: There Was An Issue With The Transaction!');
}
elseif($payment_status == 'In-Progress' || $payment_status == 'Pending' || $payment_status == 'Processed'){
//Do something
}
elseif($payment_status == 'Canceled_Reversal'){
die('Error: The Transaction Was Cancelled!');
}
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key." = ". $value."<br>";
}
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
echo mysql_error();
?>
The IPN Message from paypal shows all of the variables going through, but like I said, Nothing's updating. Any help would be appreciated!

PayPal IPN Troubles

I recently worked on a PayPal IPN script, and had it working. However, I recently moved the files over to another server, and it appears to not be functioning properly anymore. I have included the PayPal IPN code and HTML form below.
What is happening is that the script is not being ran at all. I added some debug to test and see what steps were being missed, and I came to the conclusion that PayPal is not alerting the ipn.php at all. On IPN history on PayPal, it just says that it is "Retrying". My code is below.
HTML:
<form action="https://<?php echo $url; ?>/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_xclick-subscriptions"/>
<input type="hidden" name="business" value="<?php echo $email; ?>"/>
<input type="hidden" name="item_name" value="<?php echo $pname; ?>"/>
<input type="hidden" name="item_number" value="<?php echo $id; ?>"/>
<input type="hidden" name="amount" value="<?php echo $prices[$id - 1] . ".00"; ?>"/>
<input type="hidden" name="quantity" value="1"/>
<input type="hidden" name="no_note" value="1"/>
<input type="hidden" name="currency_code" value="USD"/>
<input type="hidden" name="lc" value="US"/>
<input type="hidden" name="bn" value="PP-BuyNowBF"/>
<input type="hidden" name="a3" value="<?php echo $prices[$id - 1] . ".00"; ?>"/>
<input type="hidden" name="p3" value="1"/>
<input type="hidden" name="t3" value="M"/>
<input type="hidden" name="src" value="1"/>
<input type="hidden" name="sra" value="1"/>
<input type="hidden" name="return"
value="https://bvpn.biz/success.php?id=<?php echo $id; ?>&met=<?php echo $met; ?>"/>
<input type="hidden" name="cancel_return"
value="https://bvpn.biz/success.php?id=<?php echo $id; ?>&met=<?php echo $met; ?>&do=2"/>
<input type="hidden" name="rm" value="2"/>
<input type="hidden" name="notify_url" value="https://bvpn.biz/ipn.php"/>
<input type="hidden" name="custom" value="<?php echo $_SESSION['username'].'|'.getUserId($_SESSION["username"]).'|'.getUserEmail($_SESSION["username"]); ?>"/>
<div style="padding-top:100px; padding-right: 40%; padding-left: 40%;">
<center><input type="submit" name="submit" class="btn" value="Checkout with PayPal"></center>
</div>
</form>
ipn.php:
<?php
include("inc/er.php");
include("inc/database.php");
include("inc/functions.php");
$debug = true;
require("inc/ipn.config.php");
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
if ($debug)
{
$ourFileName = "debug/debug1_postdata.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fwrite($ourFileHandle, $postback);
fclose($ourFileHandle);
}
// post back to PayPal system to validate //
$header .= "POST cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Host: " . $url . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$header .= "Connection: close\r\n\r\n";
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
//email
$mail_From = "From: IPN#tester.com";
$mail_To = $email;
$mail_Subject = "HTTP ERROR";
$mail_Body = $errstr;
mail($mail_To, $mail_Subject, $mail_Body, $mail_From);
}
else
{
if ($debug)
{
$ourFileName = "debug/debug2_connected.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
$ids = explode("|", $_POST['custom']);
$item_username = $ids[0];
$item_userid = $ids[1];
$item_email = $ids[2];
$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'];
$price = 5;
$payment_amount = str_replace('.00', '', $payment_amount);
fputs ($fp, $header . $req);
while (!feof($fp)) {
if ($debug)
{
$ourFileName = "debug/debug3_fgets.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fwrite($ourFileHandle, $response);
fclose($ourFileHandle);
}
$res = fgets ($fp, 1024);
$res = trim($res);
if (strcmp ($res, "VERIFIED") == 0) {
if ($debug)
{
$ourFileName = "debug/debug4_verified.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
if($payment_status == "Completed") {
$ourFileName = "debug/debug_completed";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
if($payment_amount == $price)
{
$ourFileName = "debug/debug_price";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
if($payment_currency == "USD")
{
$ourFileName = "debug/debug_currency";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
if(checkTxnId($txnId) == 0) {
$ourFileName = "debug/debug_txn";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
if(($payment_status == "Completed") && ($receiver_email == $email) && ($payment_amount == $price) && ($payment_currency == "USD") && (checkTxnId($txnId) == 0)) {
addPaypalPayment($item_name, $item_number, $item_username, $item_userid, $item_email, $payment_status, $payment_amount, $payment_currency, $txnId, $receiver_email, $payer_email, '1');
serviceAdd($item_userid, $item_number, getNumServices($item_userid));
setServiceActive($item_userid, $item_packageid);
sendEmailWithUsername("Carwash", "PayPal IPN", "Success!");
if ($debug)
{
$ourFileName = "debug/debug5_confirmedok.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
sendEmailWithUsername($_SESSION["username"], "Your new VPN purchase", "You can gain access to your new VPN account by visiting <a href='https://bvpn.biz/manage.php?do=activate'>this</a> link.");
}
else
{
if ($debug)
{
$ourFileName = "debug/debug6_confirmedok.txt";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
}
$mail_To = $email;
$mail_Subject = "PayPal IPN status not completed or security check fail";
$mail_Body = "Something wrong. \n\nThe transaction ID number is: $txn_id \n\n Payment status = $payment_status \n\n Payment amount = $payment_amount";
mail($mail_To, $mail_Subject, $mail_Body);
}
}
else if (strcmp ($res, "INVALID") == 0) {
$mail_To = $email;
$mail_Subject = "PayPal - Invalid IPN ";
$mail_Body = "We have had an INVALID response. \n\nThe transaction ID number is: $txn_id \n\n username = $username";
mail($mail_To, $mail_Subject, $mail_Body);
}
} //end of while
fclose ($fp);
}
?>
ipn.config.php:
<?php
$url = "www.sandbox.paypal.com";
$email = "bking-facilitator#inbox.com";
?>
I have been struggling with this for a while now, and really need any help that I can possibly get. Thanks!
I recently had a similar issue when moved a site to a new server and both fopen and fsockopen were unavailable on the new host, maybe you're having the same problem here.
Here is the IPN class I'm using now based on CURL, maybe you can convert yours: https://gist.github.com/thehelvetian/6098154
Full code:
<?php
class PayPal_IPN {
var $paypal_post_vars;
var $paypal_response;
var $error_email;
var $sandbox;
private $sandboxUrl = "https://www.sandbox.paypal.com/cgi-bin/webscr";
private $productionUrl = "https://www.paypal.com/cgi-bin/webscr";
private $serviceUrl = NULL;
function __construct( $sandbox = false ) {
$this->sandbox = $sandbox;
$this->send_response();
}
function send_response() {
// 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]);
}
}
$this->paypal_post_vars = $myPost;
// 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";
}
// Set the service URL
$this->serviceUrl = ($this->sandbox) ? $this->sandboxUrl : $this->productionUrl;
// STEP 2: Post IPN data back to paypal to validate
$ch = curl_init($this->serviceUrl);
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, array('Connection: Close'));
// In wamp like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below.
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if( !($res = curl_exec($ch)) ) {
$this->write_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
$this->paypal_response = $res;
curl_close($ch);
}
function is_verified() {
if (strcmp ($this->paypal_response, "VERIFIED") == 0) {
return true;
} else if (strcmp ($this->paypal_response, "INVALID") == 0) {
return false;
}
}
function get_payment_status() {
return $this->paypal_post_vars['payment_status'];
}
function error_out($message, $em_headers) {
$date = date("D M j G:i:s T Y", time());
$message .= "\n\nThe following data was received from PayPal:\n\n";
#reset($this->paypal_post_vars);
while( #list($key,$value) = #each($this->paypal_post_vars)) {
$message .= $key . ':' . " \t$value\n";
}
mail($this->error_email, "[$date] PayPal IPN Notification", $message, $em_headers);
}
function write_log($text) {
$filename = "ipn.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("Y-m-d H:i:s").": $text\r\n") or die("Could not write file!");
fclose($fh);
}
}

Categories