Jump to content

Recommended Posts

Hello,

 

I have a multi page form.  On the third and final page, the user submits payment information.  Upon form submission, it sends payment information to a payment processor.  If it is successful, the form submits all of the form data to my database.  It includes a payment successful field in my database, but of course no credit card information is stored - that's all handled on the payment processor site.  If the payment is not successful, the page loads errors to the user and the form is not submitted to my database until the payment is successful.

 

I am starting to see an issue where I am receiving duplicate payments.  I am assuming that people are clicking the submit button multiple times while the payment is processing, and it's sending multiple authorization requests to the payment processor.  The payment processor automatically catches some of these, but not all.  

 

My question is to what logic is most appropriate reduce duplicate payments.  The solution that came to mind was disabling the submit button upon click, but then re-activating if the payment was declined, so the user could re-submit.  Of course, I would rather solve this on the server side with php.

 

Is this best handled with cookies?  If so, can someone explain the basic logic on how that would work?

 

Thanks for your help as always.

Link to comment
https://forums.phpfreaks.com/topic/301556-preventing-duplicate-form-submissions/
Share on other sites

That makes sense, and I can see how that would prevent refresh and back button resubmission. Does that protect against multiple submit button presses while awaiting the success notification from the payment processor? I think people are pressing submit again during the lag that is occurring while the payment is being processed before they are sent to the thank-you page.

You could set a session/cookie variable value with a boolean. Like, iniitated_payment. Set to true on click of successful submission (no form errors) and only allow logic to occur when that cookie's value is false. If your payment engine throws an error, then set it back the cookie back to false... or whatever. Several things you could do; it's your UX.

Any serious transaction must involve a unique transaction ID or nonce.

 

Client-side techniques like disabled buttons, cookies etc. may be sufficient for unimportant actions, but they are by no means reliable. When actual money is involved, you must implement a server-side mechanism which is technically guaranteed to only accept a single submission.

 

What exactly is this payment processor? A professional service? Then it should already have transaction IDs.

well i've learned something here :happy-04:

 

had a read and this seems to do the trick on duplicate posts, unless i missed something

<?php
session_start();

if (isset($_SESSION['form']))
{
    print_r($_SESSION);
    print_r($_POST);
    
    // use data
    
    unset($_SESSION['form']);
}
else if (isset($_POST['submit'])) 
{
    $_SESSION['form'] = $_POST;
    header("Location: " . $_SERVER['REQUEST_URI']);
    exit;
}
else 
{
?>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Demo</title>
</head>
<body>
    <h1>The Form</h1>
    <form action="" method="POST">
        Some Data:
        <input type="text" value="some data" name="data" id="data" /><br />
        <input name='submit' type="submit" />
    </form>
</body>
</html>
<?php
}
?>

This is about a transaction to an external site, not a simple POST request within the application.

 

And as I already said, anything that involves money falls into a different category than normal operations. Relying on (session) cookies is perfectly fine if the goal is to, say, prevent duplicate blog posts. If it fails, there isn't really any damage. But if the user ends up with duplicate payment transactions, that is a problem which must be prevented at all cost.

Any serious transaction must involve a unique transaction ID or nonce.

 

Client-side techniques like disabled buttons, cookies etc. may be sufficient for unimportant actions, but they are by no means reliable. When actual money is involved, you must implement a server-side mechanism which is technically guaranteed to only accept a single submission.

 

What exactly is this payment processor? A professional service? Then it should already have transaction IDs.

 

 

I'm using Braintree, but I must be doing something wrong with the unique transaction ID/nonce.  In looking at the code, it seems to post the transaction_id after success.  

if($_POST['month']) {

$result = Braintree_Transaction::sale(array(
	"amount" => $fields[total_cost] . ".00",
	"creditCard" => array(
	"number" => $_POST["number"],
	"cvv" => $_POST["cvv"],
	"expirationMonth" => $_POST["month"],
	"expirationYear" => $_POST["year"],
	"cardholderName" => $_POST['first_name'] . " " . $_POST['last_name'],
),
	"customer" => array(
	"firstName" => $_POST['first_name'],
	"lastName" => $_POST['last_name'],
	"email" => $_POST["billing_email"],
),
	'customFields' => array(
	"class_name" => $fields[class_drop_down],
	"token" => $fields[token],
),

'billing' => array(
"postalCode" => $_POST["billing_zip"],
),

));
	
    if ($result->success) {

        $_POST['transaction_id'] = $result->transaction->id;

        $params = array(
          "submit_button" => "submit",
          "form_data" => $_POST,
          "no_sessions_url" => "registration.php",
          "next_page" => "registration-page4.php",
          "finalize" => true,
        );
        ft_api_process_form($params);

	$passing_transaction_identification = ($result->transaction->id);

    } else {
		 $declined_error = "TRUE";
		 
        foreach (($result->errors->deepAll()) as $error) {
            $braintreeError[] = $error->message;
        }
		
    }
}
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.