Stripe Payment Gateway - Variable Amounts - php

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

Related

How to compare randomly generated OTP/Number in PHP with the user input

I have viewed other similar threads but could not find what I was looking for.
So here I am generating a random number for Otp and sending it to the end user. Now my problem is how do I compare the value input by the user and the randmoly generated number in PHP.
I am not using any database for this purpose so I require a database free solution.
Here is my HTML form.
<html>
<head>
<h1> Working Otp sample</h1>
</head>
<body>
<form method="POST" action="sendotp.php">
<input type="tel" name="phone"> <br>
<button type="submit" name="sub">Submit</button>
</form>
<form method="POST" action="sendotp.php">
<input type="tel" name="otp"> <br>
<button type="submit" name="sub2">Submit</button>
</form>
</body>
</html>
Here is the code which sends and verifies the OTP.
I think the if part in "else if" is not executed & also calling $myotp there(in else if) generates a new number every time.
I can't seem to find a solution for it, please Help.
Thanks in advance for your time and input on this!
<?php
require __DIR__ . '/vendor/autoload.php';
use Twilio\Rest\Client;
if(isset ($_POST['sub']))
{
$phone = $_POST['phone'];
function generate()
{
$digits_needed=6;
$random_number=''; // set up a blank string
$count=0;
while ( $count < $digits_needed ) {
$random_digit = mt_rand(0, 9);
$random_number .= $random_digit;
$count++;
}
return $random_number;
}
$myotp = generate();
$account_sid = 'ACxxxxxxxxxxxxxxxxx';
$auth_token = 'xxxxxxxxxxxxxxxxxx';
$twilio_number = "+1234567890";
$client = new Client($account_sid, $auth_token);
$client->messages->create(
// Where to send a text message (your cell phone?)
$phone,
array(
'from' => $twilio_number,
'body' => "Your OTP is $myotp"
)
);
}
else if(isset ($_POST['sub2']))
{
$otp = $_POST['otp'];
echo "OTP is $otp";
if($otp == $myotp)
{
echo "OTP successfully verified!";
}
else
{
echo "Please enter valid OTP";
}
}

How can I trigger an email from this php script?

I'm new to php and I'm trying to work out how to send myself an email upon successful payment. How would I go about that? If you see half way down the script there is an 'if' statement that defines a successful Stripe Payment Call - so that is the point where an email ought to be sent.
Do I include a POST Email request - like this:
($_POST['email'])) {
$email_to = "me#example.com";
$email_subject = "Email subject line";
And here's the php script that currently works - you'll see the 'IF' statement half way throught the script.
<?php
require('config.inc.php');
session_start();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$email=$_POST['email'];
// Stores errors:
$errors = array();
// Need a payment token:
if (isset($_POST['stripeToken'])) {
$token = $_POST['stripeToken'];
// 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.';
} else { // New submission.
$_SESSION['token'] = $token;
}
} else {
$errors['token'] = 'Your subscription cannot be processed because you must have JavaScript enabled. Please try again.';
}
// Set the order amount somehow:
$amount = 2700; // $20, 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:
require_once('lib/Stripe.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::setApiKey(STRIPE_PRIVATE_KEY);
// Charge the order:
$charge=Stripe_Customer::create(array(
"card"=>$token,
"email" => $email,
"plan" =>"newsletter",
));
// Check that it was paid:
if (!empty($charge)) {
//echo $amount;
// Store the order in the database.
// Send the email.
// Celebrate!
/*$cookie_name = "success_msg";
$cookie_value = "Your Payment is successfully done";
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/");*/
$_SESSION['success_msg']="Your subcription was successfull - thank you!<br><br>We will send you further details shortly on how to access your account.";
echo "<script>window.location.href='index.php'</script>";
exit(0);
} else { // Charge was not paid!
echo '<div class="alert alert-error"><h4>Payment System Error!</h4>Your payment could NOT be processed (i.e., you have not been charged) because the payment system rejected the transaction. You can try again or use another card.</div>';
}
} catch (Stripe_CardError $e) {
// Card was declined.
$e_json = $e->getJsonBody();
$err = $e_json['error'];
$errors['stripe'] = $err['message'];
} catch (Stripe_ApiConnectionError $e) {
// Network problem, perhaps try again.
} catch (Stripe_InvalidRequestError $e) {
// You screwed up in your programming. Shouldn't happen!
} catch (Stripe_ApiError $e) {
// Stripe's servers are down!
} catch (Stripe_CardError $e) {
// Something else that's not the customer's fault.
}
} // A user form submission error occurred, handled below.
} // Form submission.
?>
asdasd
You could create a function that sends the email:
function sendEmail () {
$email_to = "me#example.com";
$email_subject = "Email subject line";
... ETC ...
}
Then in your script where the payment is successful, just before notifying the user you can include the function:
...
if (!empty($charge)) {
...
// Include your function if you wrote this to an external script
require_once '/path/to/php/sendEmail.function.php';
// Then make use of it:
sendEmail();
/*$cookie_name = "success_msg";
$cookie_value = "Your Payment is successfully done";
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/");*/
$_SESSION['success_msg']="Your subcription was successfull - thank you!<br><br>We will send you further details shortly on how to access your account.";
// Redirect the user to a new page
echo "<script>window.location.href='index.php'</script>";
// Then you can exit runtime
exit(0);
}
// Charge was not paid!
else {
echo '<div class="alert alert-error"><h4>Payment System Error!</h4>Your payment could NOT be processed (i.e., you have not been charged) because the payment system rejected the transaction. You can try again or use another card.</div>';
}
...
It's pretty important that the email function will either send the email or just continue as normal as you'd not want a failed email to interupt the users experience. You could have a fallback so that if the email doesnt send it writes it to the database or something but do not exit with an error during this process.

CSRF session token

I'm trying to implement a simple CSRF protection on a form, but I can't get it right. If someone can point out what I'm doing wrong, I would appreciate it.
The error: Every time I submit the form, I get "Invalid Submission2" because the token changes (after the form is submitted), since is being generated on the same page?
Edit -- I forgot to mention, another file (config.php) already has session_start().
<?php
class Module_Post extends Base_Module {
public function start()
{
requireLogin();
if (isset($_GET['act'])) {
switch($_GET['act']) {
case 'text':
$this->text();
break;
case 'image':
$this->image();
break;
default:
$this->text();
break;
}
} else {
$this->text();
}
}
private function text()
{
// Generate random unique token to prevent cross-site request forgery (CSRF).
if(empty($_SESSION['form_token']))
{
$form_token = md5(uniqid(rand(), TRUE));
$_SESSION['form_token'] = $form_token;
}
if(isset($_POST['submit']))
{
// Clean the content from cross-site scripting (xss)
$content = trim($_POST['content']);
$content = Xss::clean($content);
// Validate that the form token
if(!isset($_POST['form_token'], $_SESSION['form_token'])) {
$err = 'Invalid Submission';
} elseif ($_POST['form_token'] != $_SESSION['form_token']) {
$err = 'Invalid Submission2';
} elseif (strlen($content) < 10) {
$err = 'Your content contains too few characters.';
}
if(isset($err)) {
unset( $_SESSION['form_token']);
$this->setMessage($err, 'FAIL');
header('Location: index.php?mod=post');
exit;
}
// Insert database data here, then redirect
$this->setMessage('Your post was published successfully.', 'GOOD');
header('Location: index.php');
exit;
}
$this->tpl->assign('form_token', $form_token);
$this->tpl->display('new/text.tpl');
}
}
?>
The HTML (text.tpl file)
<form method='post' enctype='multipart/form-data' action='#'>
<fieldset>
<textarea rows="8" id="new_post" name="content" class="input-block-level"></textarea>
<input type="hidden" name="form_token" value="{$form_token}" />
<button type="submit" name="submit" class="btn btn-info pull-left">Create Post</button>
</fieldset>
</form>
You need to change this line
$this->tpl->assign('form_token', $form_token);
into:
$this->tpl->assign('form_token', $_SESSION['form_token']);
That's because you generate your token only with this condition:
if(empty($_SESSION['form_token']))
{
$form_token = md5(uniqid(rand(), TRUE));
$_SESSION['form_token'] = $form_token;
}
and unset it using this condition:
if(isset($err)) {
unset( $_SESSION['form_token']);
}
So if you send your form once and then reload page (without submitting form just url), $form_token variable is unknown because there is $_SESSION['form_token'] is not empty and then in your form you have empty token.
If you had displaying errors turned on in PHP you would see in this case in PHP:
Undefined variable: form_token in

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.

How do you add results from PayPal IPN to update database

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.

Categories