How do you add results from PayPal IPN to update database - php

I am looking to be able to take the info from the PayPal IPN post, and use certain items to update my database. This is the current code I have for my ipn.php
<?php
// tell PHP to log errors to ipn_errors.log in this directory
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');
// intantiate the IPN listener
include('ipnlistener.php');
$listener = new IpnListener();
// tell the IPN listener to use the PayPal test sandbox
$listener->use_sandbox = true;
// try to process the IPN POST
try {
$listener->requirePostMethod();
$verified = $listener->processIpn();
} catch (Exception $e) {
error_log($e->getMessage());
exit(0);
}
if ($verified) {
$errmsg = ''; // stores errors from fraud checks
// 1. Make sure the payment status is "Completed"
if ($_POST['payment_status'] != 'Completed') {
// simply ignore any IPN that is not completed
exit(0);
}
// 2. Make sure seller email matches your primary account email.
if ($_POST['receiver_email'] != 'PRIMARY EMAIL ADDRESS') {
$errmsg .= "'receiver_email' does not match: ";
$errmsg .= $_POST['receiver_email']."\n";
}
// 3. Make sure the currency code matches
if ($_POST['mc_currency'] != 'USD') {
$errmsg .= "'mc_currency' does not match: ";
$errmsg .= $_POST['mc_currency']."\n";
}
// 4. Ensure the transaction is not a duplicate.
mysql_connect('localhost', '[DB_USER]', '[DB_PW') or exit(0);
mysql_select_db('DB_NAME') or exit(0);
$txn_id = mysql_real_escape_string($_POST['txn_id']);
$sql = "SELECT COUNT(*) FROM orders WHERE txn_id = '$txn_id'";
$r = mysql_query($sql);
if (!$r) {
error_log(mysql_error());
exit(0);
}
$exists = mysql_result($r, 0);
mysql_free_result($r);
if ($exists) {
$errmsg .= "'txn_id' has already been processed: ".$_POST['txn_id']."\n";
}
if (!empty($errmsg)) {
// manually investigate errors from the fraud checking
$body = "IPN failed fraud checks: \n$errmsg\n\n";
$body .= $listener->getTextReport();
mail('NOTIFICATION EMAIL ADDRESS', 'IPN Fraud Warning', $body);
} else {
<?php
$csvData = file_get_contents($_POST['custom']);
$csvNumColumns = 3;
$csvDelim = ";";
$data = array_chunk(str_getcsv($csvData, $csvDelim), $csvNumColumns);
?>
// add this order to a table
$user_id = mysql_real_escape_string($_POST['item_name']);
$credit_amount = mysql_real_escape_string($_POST['item_number']);
$type = mysql_real_escape_string($_POST['custom']);
$sql = "INSERT INTO TABLE_NAME VALUES
(NULL, '$user_id', '$credit_amount', '$type')";
if (!mysql_query($sql)) {
error_log(mysql_error());
exit(0);
}
}
} else {
// manually investigate the invalid IPN
mail('NOTIFICATION EMAIL ADDRESS', 'Invalid IPN', $listener->getTextReport());
}
?>
This seemed to work fine when testing it with PayPal Sandbox's IPN testing service and I could enter in the needed values for item_name, item_number, and custom (or when using the below code)
<form name="_xclick" action="https://www.sandbox.paypal.com/cgi-bin/webscr"
method="post">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="SANDBOX EMAIL ADDRESS">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="amount" value="9.99">
<input type="hidden" name="custom" value="<?=$this->package['0']['delivered'];?>"
<input type="hidden" name="item_name" value="<?=$_SESSION["user_id"]?>"
<input type="hidden" name="item_number" value="<?=$this->package['0']['number'];?>"
<input type="hidden" name="return" value="WEBSITE_URL/success">
<input type="hidden" name="notify_url" value="WEBSITE_URL/ipn.php">
<input type="image" src="http://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
</form>
However I soon realized that it would be much better for the 'item_name' to be something recognizable by the customer, rather than having it be defined as the 'user_id'. Is it possible to have the 'custom' pass through defined as all 3 of the variables that I need, separating them within the PayPal button with semicolons (as seem below)
<input type="hidden" name="custom" value="<?=$_SESSION["user_id"]?>;<?=$this->package['0']['number'];?>;<?=$this->package['0']['delivered'];?>"
then using something like
<?php
$csvData = file_get_contents($_POST['custom']);
$csvNumColumns = 3;
$csvDelim = ";";
$data = array_chunk(str_getcsv($csvData, $csvDelim), $csvNumColumns);
?>
to give me separate variables that can then be defined as 'user_id', 'credit_amount', and 'type'
once these variables are separated and defined, they are to be posted to the database, however, if there is already a column within the table that has the same 'user_id' as is trying to be posted AS WELL AS the same 'type' that is trying to be posted, then it should only update that row (the row already within the table before the attempted addition) by ADDING the 'credit_amount' to the corresponding 'credit_amount' cell in the old row.

You can pass multiple values, and have them populated into a single variable such as the variable "custom". There would not be an issue with this. I have done this myself as well in the past. When I coded this, I used the | to separate the values, and then had my IPN parse out the values within my IPN script.

Related

Stripe Payment Gateway - Variable Amounts

I have found lots of questions for this topic, but none seems to answer my question...
NB. Using Larry Ullman's Blog at http://www.larryullman.com/2012/11/28/creating-a-form-for-handling-payments-with-stripe/
Trying to use
$amount = $_REQUEST['amount'];
instead of
$amount = 23400; //EXAMPLE ONLY
But the value of $_REQUEST['amount']; is being ignored?
<?php
// Check for a form submission:
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Stores errors:
$errors = array();
// Need a payment token:
if (isset($_POST['stripeToken'])) {
$token = $_POST['stripeToken'];
$StripeAmount = $_REQUEST['amount']; // $20, in cents
// Check for a duplicate submission, just in case:
// Uses sessions, you could use a cookie instead.
if (isset($_SESSION['token']) && ($_SESSION['token'] == $token)) {
$errors['token'] = 'You have apparently resubmitted the form. Please do not do that.';
} else { // New submission.
$_SESSION['token'] = $token;
}
} else {
$errors['token'] = 'The order cannot be processed. Please make sure you have JavaScript enabled and try again.';
}
// Set the order amount somehow:
// $20, in cents
$amount = $_REQUEST['amount']; // in cents
// Validate other form data!
// If no errors, process the order:
if (empty($errors)) {
// create the charge on Stripe's servers - this will charge the user's card
try {
// Include the Stripe library:
// Assumes you've installed the Stripe PHP library using Composer!
require_once('stripe/init.php');
// set your secret key: remember to change this to your live secret key in production
// see your keys here https://manage.stripe.com/account
\Stripe\Stripe::setApiKey(STRIPE_PRIVATE_KEY);
// Charge the order:
$charge = \Stripe\Charge::create(array(
"amount" => $amount, // amount in cents, again
"currency" => "aud",
"source" => $token,
"description" => $email
)
);
// Check that it was paid:
if ($charge->paid == true) {
$OrderID = $_GET['order_id']; //reference from shop OrderId
$txn_id = $_GET['id']; //transaction number form payment Gateway
$objBooking->updateVisitorOrderRecord($OrderID, $txn_id);
header('location:visitor_payment_thanks.php');
} else { // Charge was not paid!
header('location:visitor_payment_error.php');
}
} catch (\Stripe\Error\Card $e) {
// Card was declined.
$e_json = $e->getJsonBody();
$err = $e_json['error'];
$errors['stripe'] = $err['message'];
} catch (\Stripe\Error\ApiConnection $e) {
// Network problem, perhaps try again.
} catch (\Stripe\Error\InvalidRequest $e) {
// You screwed up in your programming. Shouldn't happen!
} catch (\Stripe\Error\Api $e) {
// Stripe's servers are down!
} catch (\Stripe\Error\Base $e) {
// Something else that's not the customer's fault.
}
} // A user form submission error occurred, handled below.
} // Form submission.
// Set the Stripe key:
// Uses STRIPE_PUBLIC_KEY from the config file.
echo '<script type="text/javascript">Stripe.setPublishableKey("' . STRIPE_PUBLIC_KEY . '");</script>';
?>
<h1>Buy This Thing</h1>
<form action="buy.php" method="POST" id="payment-form">
<?php // Show PHP errors, if they exist:
if (isset($errors) && !empty($errors) && is_array($errors)) {
echo '<div class="alert alert-error"><h4>Error!</h4>The following error(s) occurred:<ul>';
foreach ($errors as $e) {
echo "<li>$e</li>";
}
echo '</ul></div>';
}?>
<div id="payment-errors"></div>
<span class="help-block">You can pay using: Mastercard, Visa, American Express, JCB, Discover, and Diners Club.</span>
<div class="alert alert-info"><h4>JavaScript Required!</h4>For security purposes, JavaScript is required in order to complete an order.</div>
<label>Card Number</label>
<input type="text" size="20" autocomplete="off" class="card-number input-medium">
<span class="help-block">Enter the number without spaces or hyphens.</span>
<label>CVC</label>
<input type="text" size="4" autocomplete="off" class="card-cvc input-mini">
<label>Expiration (MM/YYYY)</label>
<input type="text" size="2" class="card-expiry-month input-mini">
<span> / </span>
<input type="text" size="4" class="card-expiry-year input-mini">
<button type="submit" class="btn" id="submitBtn">Submit Payment</button>
</form>
<script src="buy.js"></script>
Thx Guys
I emailed STRIPE and based on feedback, the issue was that I should have been using SESSIONS....
PHP Manual Page on Session Handling

PayPal Payment Verification, How the IPN works

I am searching for how to use the PayPal IPN (Instant Payment Notification) from past 2 weeks and couldn't understand how exactly to use it in my code.
I am using the following HTML code to create a PayPal button
button.html
<form name="paypalForm" action="paypal.php" method="post">
<input type="hidden" name="id" value="123">
<input type="hidden" name="CatDescription" value="20Percents (12 Credits)">
<input type="hidden" name="payment" value="10">
<input type="hidden" name="key" value="<? echo md5(date("Y-m-d:").rand()); ?>">
<input TYPE="image" SRC="http://www.coachsbr.com/images/site/paypal_button.gif" name="paypal" value="Payment via Paypal" >
</form>
And, the following code to process the payment and verify it
paypal.php
<?php
require_once('paypal.class.php'); // include the class file
$p = new paypal_class; // initiate an instance of the class
$p->paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'; // testing paypal url
//$p->paypal_url = 'https://www.paypal.com/cgi-bin/webscr'; // paypal url
// setup a variable for this script (ie: 'http://www.micahcarrick.com/paypal.php')
$this_script = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
// if there is not action variable, set the default action of 'process'
if (empty($_GET['action'])) $_GET['action'] = 'process';
switch ($_GET['action']) {
case 'process': // Process and order...
$CatDescription = $_REQUEST['CatDescription'];
$payment = $_REQUEST['payment'];
$id = $_REQUEST['id'];
$key = $_REQUEST['key'];
$p->add_field('business', 'info#aoptrading.com');
$p->add_field('return', $this_script.'?action=success');
$p->add_field('cancel_return', $this_script.'?action=cancel');
$p->add_field('notify_url', $this_script.'?action=ipn');
$p->add_field('item_name', $CatDescription);
$p->add_field('amount', $payment);
$p->add_field('key', $key);
$p->add_field('item_number', $id);
$p->submit_paypal_post(); // submit the fields to paypal
//$p->dump_fields(); // for debugging, output a table of all the fields
break;
case 'success': // Order was successful...
echo "<br/><p><b>Payment Successful.</b><br /></p>";
foreach ($_POST as $key => $value) { echo "$key: $value<br>"; }
break;
case 'cancel': // Order was canceled...
echo "<br/><p><b>The order was canceled!</b></p><br />";
foreach ($_POST as $key => $value) { echo "$key: $value<br>"; }
break;
case 'ipn': // Paypal is calling page for IPN validation...
if ($p->validate_ipn()) {
// For this example, we'll just email ourselves ALL the data.
$dated = date("D, d M Y H:i:s", time());
$subject = 'Instant Payment Notification - Recieved Payment';
$to = 'info#aoptrading.com'; // your email
$body = "An instant payment notification was successfully recieved\n";
$body .= "from ".$p->ipn_data['payer_email']." on ".date('m/d/Y');
$body .= " at ".date('g:i A')."\n\nDetails:\n";
$headers = "";
$headers .= "From: Test Paypal \r\n";
$headers .= "Date: $dated \r\n";
$PaymentStatus = $p->ipn_data['payment_status'];
$Email = $p->ipn_data['payer_email'];
$id = $p->ipn_data['item_number'];
if($PaymentStatus == 'Completed' or $PaymentStatus == 'Pending'){
$PaymentStatus = '2';
}else{
$PaymentStatus = '1';
}
foreach ($p->ipn_data as $key => $value) { $body .= "\n$key: $value"; }
fopen("http://www.virtualphoneline.com/admins/TestHMS.php?to=".urlencode($to)."&subject=".urlencode($subject)."&message=".urlencode($body)."&headers=".urlencode($headers)."","r");
}
break;
}
?>
An extra class file: (can be found here) http://pastebin.com/auCdYhaR
The code is working fine, but I am having big issue now, I am trying to validate whether the payment is successful or not from the following lines and doing the action (adding 10 credits to the database for the user on session).
case 'success': // Order was successful...
echo "<br/><p><b>Payment Successful.</b><br /></p>";
foreach ($_POST as $key => $value)
{
/*echo "$key: $value<br>";*/
// Do the required action, **add 10 credits in the database for the user on session**
}
break;
Finally, the issue is when I click on the button from button.html page it redirects to the Paypal.php page and when I enter my PayPal login details, payment is successful
THERE COMES A SMALL LITTLE TEXT -> RETURN TO THE SENDER'S WEBSITE I NEED TO CLICK ON IT, WHEN I CLICK ON IT, IT WILL BRING ME BACK TO PAYPAL.PHP PAGE AND THEN THE CASE 'SUCCESS' IS FIRED. IF I MAKE THE PAYMENT AND JUST CLOSE THE PAYPAL PAGE WITHOUT CLICKING ON RETURN TO THE SENDER'S WEBSITE AND DIDN'T WAIT TILL THE PAGE PAYPAL.PHP LOADS WEBSITE COULDN'T VERIFY THE PAYMENT AND COULDN'T ADD THE CREDITS.
HOW CAN I AUTOMATE THIS PROCESS AND ADD CREDITS UPON SUCCESSFUL PAYMENT NOT UPON SUCCESSFUL RETURN TO THE PAGE PAYPAL.PHP.
THANKS
It sounds to me like you're confusing PDT and IPN. PDT works by sending data to your return URL, but that is not the recommended way to handle post-payment processing tasks.
That's where IPN comes into play, which is a silent POST of data to your listener URL regardless of whether or not the user makes it back to your return URL. That way that code will always run no matter what (assuming you've got everything configured correctly.)
Sounds to me like you're sort of mixing the two and getting mixed results because of it.

Can´t save paypal ipn values into a database

I have implemented a paypal ipn process. I want to retrieve some data from the ipn and save it in a database table. The problem is it doesn´t work. I used the part of the procedure from a tutorial http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/
Nelow is the code I have used.
ipn.php
<?php
require "paypal_integration_class/paypal.class.php";
require "config.php";
require "connect.php";
$p = new paypal_class;
$p->paypal_url = $payPalURL;
if ($p->validate_ipn()) {
if($p->ipn_data['payment_status']=='Completed')
{
$amount = $p->ipn_data['mc_gross'] - $p->ipn_data['mc_fee'];
mysql_query(" INSERT INTO dc_donations (transaction_id,donor_email,amount,original_request)
VALUES (
'".esc($p->ipn_data['txn_id'])."',
'".esc($p->ipn_data['payer_email'])."',
".(float)$amount.",
'".esc(http_build_query($_POST))."'
)");
}
}
function esc($str)
{
global $link;
return mysql_real_escape_string($str,$link);
}
?>
connect.php
/* Database config */
$db_host = "localhost";
$db_user = "egesachi_ipn";
$db_pass = "lollipop";
$db_database = "egesachi_ipn";
/* End config */
$link = #mysql_connect($db_host,$db_user,$db_pass) or die('Unable to establish a DB connection');
mysql_set_charset('utf8');
mysql_select_db($db_database,$link);
?>
config.php
<?php
// Fill your PayPal email below.
// This is where you will receive the donations.
$myPayPalEmail = 'ben#center.org';
// The paypal URL:
$payPalURL = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
// Your goal in USD:
$goal = 100;
// Demo mode is set - set it to false to enable donations.
// When enabled PayPal is bypassed.
$demoMode = false;
if($demoMode)
{
$payPalURL = 'demo_mode.php';
}
?>
paypal_integration_class/paypal.class.php
Below is the URL where the script above is from.
http://www.phpclasses.org/package/2249-PHP-Process-Paypal-payment-interactions.html
class paypal_class {
var $last_error; // holds the last error encountered
var $ipn_log; // bool: log IPN results to text file?
var $ipn_log_file; // filename of the IPN log
var $ipn_response; // holds the IPN response from paypal
var $ipn_data = array(); // array contains the POST values for IPN
var $fields = array(); // array holds the fields to submit to paypal
function paypal_class() {
// initialization constructor. Called when class is created.
$this->paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
$this->last_error = '';
$this->ipn_log_file = 'ipn_log.txt';
$this->ipn_log = true;
$this->ipn_response = '';
// populate $fields array with a few default values. See the paypal
// documentation for a list of fields and their data types. These defaul
// values can be overwritten by the calling script.
$this->add_field('rm','2'); // Return method = POST
$this->add_field('cmd','_xclick');
}
function add_field($field, $value) {
// adds a key=>value pair to the fields array, which is what will be
// sent to paypal as POST variables. If the value is already in the
// array, it will be overwritten.
$this->fields["$field"] = $value;
}
function submit_paypal_post() {
// this function actually generates an entire HTML page consisting of
// a form with hidden elements which is submitted to paypal via the
// BODY element's onLoad attribute. We do this so that you can validate
// any POST vars from you custom form before submitting to paypal. So
// basically, you'll have your own form which is submitted to your script
// to validate the data, which in turn calls this function to create
// another hidden form and submit to paypal.
// The user will briefly see a message on the screen that reads:
// "Please wait, your order is being processed..." and then immediately
// is redirected to paypal.
echo "<html>\n";
echo "<head><title>Processing Payment...</title></head>\n";
echo "<body onLoad=\"document.form.submit();\">\n";
echo "<center><h3>Please wait, your order is being processed...</h3></center>\n";
echo "<form method=\"post\" name=\"form\" action=\"".$this->paypal_url."\">\n";
foreach ($this->fields as $name => $value) {
echo "<input type=\"hidden\" name=\"$name\" value=\"$value\">";
}
echo "</form>\n";
echo "</body></html>\n";
}
function validate_ipn() {
// parse the paypal URL
$url_parsed=parse_url($this->paypal_url);
// generate the post string from the _POST vars aswell as load the
// _POST vars into an arry so we can play with them from the calling
// script.
$post_string = '';
foreach ($_POST as $field=>$value) {
$this->ipn_data["$field"] = $value;
$post_string .= $field.'='.urlencode($value).'&';
}
$post_string.="cmd=_notify-validate"; // append ipn command
// open the connection to paypal
$fp = fsockopen($url_parsed[host],"80",$err_num,$err_str,30);
if(!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$this->last_error = "fsockopen error no. $errnum: $errstr";
$this->log_ipn_results(false);
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($post_string)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while(!feof($fp)) {
$this->ipn_response .= fgets($fp, 1024);
}
fclose($fp); // close connection
}
if (eregi("VERIFIED",$this->ipn_response)) {
// Valid IPN transaction.
$this->log_ipn_results(true);
return true;
} else {
// Invalid IPN transaction. Check the log for details.
$this->last_error = 'IPN Validation Failed.';
$this->log_ipn_results(false);
return false;
}
}
function log_ipn_results($success) {
if (!$this->ipn_log) return; // is logging turned off?
// Timestamp
$text = '['.date('m/d/Y g:i A').'] - ';
// Success or failure being logged?
if ($success) $text .= "SUCCESS!\n";
else $text .= 'FAIL: '.$this->last_error."\n";
// Log the POST variables
$text .= "IPN POST Vars from Paypal:\n";
foreach ($this->ipn_data as $key=>$value) {
$text .= "$key=$value, ";
}
// Log the response from the paypal server
$text .= "\nIPN Response from Paypal Server:\n ".$this->ipn_response;
// Write to log
$fp=fopen($this->ipn_log_file,'a');
fwrite($fp, $text . "\n\n");
fclose($fp); // close file
}
function dump_fields() {
// Used for debugging, this function will output all the field/value pairs
// that are currently defined in the instance of the class using the
// add_field() function.
echo "<h3>paypal_class->dump_fields() Output:</h3>";
echo "<table width=\"95%\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
<tr>
<td bgcolor=\"black\"><b><font color=\"white\">Field Name</font></b></td>
<td bgcolor=\"black\"><b><font color=\"white\">Value</font></b></td>
</tr>";
ksort($this->fields);
foreach ($this->fields as $key => $value) {
echo "<tr><td>$key</td><td>".urldecode($value)." </td></tr>";
}
echo "</table><br>";
}
}
paypal html checkout form
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
<!-- Identify your business so that you can collect the payments. -->
<input type="hidden" name="business"
value="ben#egesachildrencenter.org">
<!-- Specify a Donate button. -->
<input type="hidden" name="cmd" value="_donations">
<!-- Specify details about the contribution -->
<input type="hidden" name="item_name" value="<?php echo $sponsored; ?>">
<input type="hidden" name="item_number" value="<?php echo $pupilid; ?>">
<input type="hidden" name="amount" value="25.00">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="return" value="http://www.center.org/pap/needy.php">
<input type="hidden" name="notify_url" value="http://www.center.org/pap/ipn.php">
<!-- Display the payment button. -->
<input type="image" name="submit" border="0"
src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif"
alt="PayPal - The safer, easier way to pay online">
<img alt="" border="0" width="1" height="1"
src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" >
</form>
Please help me to find where I am going wrong or suggest another way of achieving th same result. Thanks.

PayPal IPN development

I'm having some moderate success with setting up PayPal IPN on my website to manage subscription payments. I'm currently at the point where I have the payment set up in PayPal fine, and sending a completed payment from PayPal sandbox to my IPN works great and sets the MySQL row to is_paid to Yes instead of No, which then in turn allows the user to log in.
I am wondering now, how the IPN will let me know when the user's subscription payment fails or they cancel (all those bad and nasty things that happen in the real world!)? I'll want the IPN to send an email to the admin em
<?php
// tell PHP to log errors to ipn_errors.log in this directory
ini_set('log_errors', true);
ini_set('error_log', dirname(__FILE__).'/ipn_errors.log');
// intantiate the IPN listener
include('ipnlistener.php');
$listener = new IpnListener();
// tell the IPN listener to use the PayPal test sandbox
$listener->use_sandbox = true;
// try to process the IPN POST
try {
$listener->requirePostMethod();
$verified = $listener->processIpn();
} catch (Exception $e) {
error_log($e->getMessage());
exit(0);
}
// TODO: Handle IPN Response here
if ($verified) {
$errmsg = ''; // stores errors from fraud checks
// 1. Make sure the payment status is "Completed"
if ($_POST['payment_status'] != 'Completed') {
// simply ignore any IPN that is not completed
exit(0);
}
// 2. Make sure seller email matches your primary account email.
if ($_POST['receiver_email'] != 'EMAILHERE') {
$errmsg .= "'receiver_email' does not match: ";
$errmsg .= $_POST['receiver_email']."\n";
}
// 3. Make sure the amount(s) paid match
if ($_POST['mc_gross'] != '3.99') {
$errmsg .= "'mc_gross' does not match: ";
$errmsg .= $_POST['mc_gross']."\n";
}
// 4. Make sure the currency code matches
if ($_POST['mc_currency'] != 'GBP') {
$errmsg .= "'mc_currency' does not match: ";
$errmsg .= $_POST['mc_currency']."\n";
}
// 5. Ensure the transaction is not a duplicate.
mysql_connect('', '', '') or exit(0);
mysql_select_db('') or exit(0);
$txn_id = mysql_real_escape_string($_POST['txn_id']);
$sql = "SELECT COUNT(*) FROM payments WHERE txn_id = '$txn_id'";
$r = mysql_query($sql);
if (!$r) {
error_log(mysql_error());
exit(0);
}
$exists = mysql_result($r, 0);
mysql_free_result($r);
if ($exists) {
$errmsg .= "'txn_id' has already been processed: ".$_POST['txn_id']."\n";
}
if (!empty($errmsg)) {
// manually investigate errors from the fraud checking
$body = "IPN failed fraud checks: \n$errmsg\n\n";
$body .= $listener->getTextReport();
mail('EMAILHERE', 'PayPal IPN Fraud Warning', $body);
} else {
// add this order to a table of completed orders
$payer_email = mysql_real_escape_string($_POST['payer_email']);
$mc_gross = mysql_real_escape_string($_POST['mc_gross']);
$sql = "INSERT INTO payments VALUES
(NULL, '$txn_id', '$payer_email', $mc_gross)";
if (!mysql_query($sql)) {
error_log(mysql_error());
exit(0);
}
// sends an email to the user to confirm subscription
$websitepath="http://www.gaymate.co.uk";
$message='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>gaymate.co.uk</title>
<style type="text/css">
p {
font-family: Arial;
font-size: 12px;
padding: 0 20px 0 20px; }
.boldTitle {
font-size: 13px;
font-weight: bold; }
.headerTitle {
font-size: 16px;
font-weight: bold; }
.divider2 {
padding: 0 20px 0 20px; }
</style>
</head>
<body>
<table width="500" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<img src="http://www.gaymate.co.uk/images/email-header.jpg">
<img class="divider2" src="'.$websitepath.'/images/email/email-divider2.gif" alt="email-divider2" width="460" height="4" />
<p>We have recieved confirmation from PayPal that you have completed payment and we are pleased to tell you that your account will be live on our site as soon as it has been approved by one of the moderators.</br></br>The Admin Team # GayMate.co.uk</p>
<img src="'.$websitepath.'/images/email/email-divider.gif" alt="email-divider" width="500" height="10" />
</td>
</tr>
</table>
<p> </p>
</body>
</html>
';
$to = filter_var($_POST['payer_email'], FILTER_SANITIZE_EMAIL);
$subject = "GayMate.co.uk Subscription Set-Up Completed";
$header = "MIME-Version: 1.0\r\n";
$header .= "From: EMAILHERE\r\n";
$header .= "Reply-To: EMAILHERE\r\n";
$header .= "Content-type: text/html; charset=iso-8859-1\r\n";
mail($to, $subject, $message, $header);
}
$sql = "UPDATE member SET is_paid='Yes' WHERE email='$to'";
if (!mysql_query($sql)) {
error_log(mysql_error());
exit(0);
}
} else {
// manually investigate the invalid IPN
mail('EMAILHERE', 'Invalid IPN', $listener->getTextReport());
}
?>
Add those to your code and change the // email code // comment to your email code and it will work fine.
Before:
if ($_POST['payment_status'] != 'Completed') {
Add:
// denied payment
if ($_POST['payment_status'] == 'Denied') {
// email code
exit(0);
}
// failed subscription payment
if ($_POST['txn_type'] == 'subscr_failed') {
// email code
exit(0);
}
// canceled subscription
if ($_POST['txn_type'] == 'subscr_cancel') {
// email code
exit(0);
}
and just create the necessary for sending the email inside the comment.
You need to check the value of $_POST['txn_type'] in order to know what the notification is about.
From PayPal's documentation: https://www.paypal.com/cgi-bin/webscr?cmd=p/acc/ipn-subscriptions-outside
I believe you are interested in subscr_eot and subscr_failed.
Some extra information that might help you:
subscr_cancel is sent as soon as the user cancels their subscription.
subscr_eot is send once the subscription is due and they payment did not go through.
Once the user cancels their subscription, PayPal will send you subscr_cancel, and it will then send subscr_eot when their next payment was due.
You might also want to read this related question: Subscriptions with Paypal IPN

System not acting as should (can't really be more specific)

I have a system where the user sends an email using a form (simple).
HTML form
<form method="post" action="process.php">
<label class="fieldLabel">Your email:</label><label class="errorLabel"><?php echo $form->error("email"); ?></label>
<input type="text" name="email" maxlength="100" class="email" value="<?php echo $form->value("email"); ?>" />
<label class="fieldLabel">Your enquiry:</label><label class="errorLabel"><?php echo $form->error("body"); ?></label>
<textarea name="body" class="enquiry"><?php echo $form->value("body"); ?></textarea>
<input type="submit" name="enquiry" class="button" value="Send Message"/>
</form>
On the same page, I have this if statement
if(isset($_SESSION['enq'])){
if($_SESSION['enq']){
echo "<h2>Your message has successfully been sent to Alan Slough.</h2>";
}
else{
echo"<h2>Oops, something went wrong. Please try again.</h2>";
}
unset($_SESSION['enq']);
}
Now the process.php file the form directs to
class Process{
//class constructor
function Process(){
if(isset($_POST['enquiry'])){
$this->enquiry();
}
}
function enquiry(){
global $session, $form;
//Registration attempt
$retval = $session->enquiry($_POST['email'], $_POST['body']);
//Successful
if($retval == 0){
$_SESSION['enq'] = true;
header("Location: contact-us.php");
}
//Error found with form
else if($retval == 1){
$_SESSION['value_array'] = $_POST;
$_SESSION['error_array'] = $form->getErrorArray();
header("Location: contact-us.php");
}
//Failed
else if($retval == 2){
$_SESSION['enq'] = false;
header("Location: contact-us.php");
}
}
};
And now the session page where everything happens
//enquiry being made
function enquiry($email, $body){
global $form;
//check email entered
$field = "email";
if(!$email || strlen($email = trim($email)) == 0){
$form->setError($field, "* Not entered");
}
//check body(s) entered
$field = "body";
if(!$body || strlen($body = trim($body)) == 0){
$form->setError($field, "* Not entered");
}
//if errors exist, send them back to the user
if($form->num_errors > 0){
return 1; //errors with form
}
else if($form->num_errors == 0){
$this->customerEnquiry($email, $body);
return 0; //successful
}
else{
return 2; //failed
}
}
//send the enquiry to the account email
function customerEnquiry($email, $body){
$from = "From: ".$email." <".$email.">";
$to = "random#email.com";
$subject = "Website enquiry from ".$email."";
return mail($to,$subject,$body,$from);
}
Ok my problem is that the errors aren't coming back if I don't fill in the form. Also, the success text isn't being displayed if I don't?
Anyone see a problem with how this flows?
Hoping I have just missed something simple!
Thanks!
I noticed this bit of code.
if(isset($_SESSION['enq'])){ // <---This...
if($_SESSION['enq']){ // <---And This
echo "<h2>Your message has successfully been sent to Alan Slough.</h2>";
}
else{
echo"<h2>Oops, something went wrong. Please try again.</h2>";
}
unset($_SESSION['enq']);
}
If $_SESSION['enq'] is not set, then the IF statement inside that will never execute, meaning you will see neither the success nor failure message.
Also, are you starting the session anywhere on the page? If you never start a session, then $_SESSION['enq'] will never be set.
http://www.php.net/manual/en/function.session-start.php
This is a very strange way to go about this. For example you're displaying success/failure message before the e-mail has been sent.
Have you copy and pasted this?
The usual method to do this would be to have the logic in process.php only, this is where you'd do your validation (return message to user if failed) and ultimately send the e-mail.
In the long run I think you'd be better off modifying the flow as I'm currently having a hard time trying to follow it.

Categories