Solved

Preventing multiple form submissions.

Posted on 2010-11-09
8
822 Views
Last Modified: 2013-12-12
Use only PHP, no JavaScript.
A single form page. <form action="<?php $_SERVER['PHP_SELF'] ?>"
After form subitted a new page appears. (Thank you, your form has been submitted.)

After researching the books I have and google I have found two ways to do this. I am not convinced either way works.
The first inputs a unique random number into the database and also keeps it as a hidden value. When the user clicks submit they are redirected to a thank you page. If they click the back button they will see their sticky form again already filled out. If they click submit again the (pdo) database throws an error and they are redirected to a page that says already submitted. Great it seems to work except if they were to click the back and then click reload or refresh the page, a new unique hidden value is created and they can successfully resubmit the same form info again.


Is there a way to do this that really works?


The first example. The forms action is to self.

if (strlen($_POST['stamp']) == 32) {$stamp = ($_POST['stamp']);}
            else {$message = '<p>This page has been accessed in error.</p>'; $stamp = FALSE;}

$sql = "INSERT INTO table (id, f_name, l_name, email, stamp) VALUES(' ', $f_name, $l_name, $email, $stamp)";

// This creates 32 character random number
<input type="hidden" name="stamp" value="<?php echo md5(uniqid(rand(),true)); ?>" />


CREATE TABLE `table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `f_name` varchar(50) DEFAULT NULL,
  `l_name` varchar(50) DEFAULT NULL,
  `stamp` char(32) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE (stamp)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;




The second way uses sessions and the forms action takes the user to a second page.
Here is the tutorial. phpro dot org/tutorials/Preventing-Multiple-Submits
I have not made this work yet and don't know if it will work after refreshing the page.

session_start();
      $form_token = uniqid();
      $_SESSION['form_token'] = $form_token;
      
      if($_POST['form_token'] != $_SESSION['form_token'])
        {
                $message = 'Access denied';
        }
            
<input type="hidden" name="form_token" value="<?php echo $form_token; ?>" />
0
Comment
Question by:kadin
  • 4
  • 3
8 Comments
 
LVL 5

Accepted Solution

by:
MichaelT_ earned 500 total points
ID: 34099267
Is this a per session or per user restriction?

If it is per session then I would set a session variable, on the "Thank-you" page.  On the first page, before loading anything I would check to see if the session variable is set, if so send the message "Sorry you've already seen this page".  This is similar to the second example in your post, although they are using hidden fields.  

To answer your other question, yes a session variable will persist when a page is reloaded (unless you specifically unset it)

I have created two little example pages, save the first as e1.php and the second as e2.php and try them out :)

===========  e1.php  ===============
<?php
session_start();
if(isset($_SESSION['prevSet']))
{
      print "This has been set";
      //unset($_SESSION['prevSet']); // comment this out to persist the session being set
}
else
{

?>
<form action="e2.php" method="POST"
<input type="text" name="test" />
<input type="submit" name="submit"
</form>
<?php
}
?>
==================================
===========  e2.php  ===============
<?php
session_start();
if(isset($_POST['submit']))
{
$_SESSION['prevSet']=true;
}
print "Submitted, session has been set. Try <a href=e1.php>e1</a>";
?>
==================================
0
 

Author Comment

by:kadin
ID: 34099423
Thanks for your response.

I am not quite sure what you mean by (Is this a per session or per user restriction?)

As it is, all someone has to do to re-input or upload the same info is click four buttons over and over.
Click submit, click the back button, click reload, click submit again. (Clicking reload generates a new uniqid() stamp and sticky forms holds the original info, making it convenient and quick to resubmit the same info).

I will allow the user to fill out multiple forms, but only if they start from scratch and type everything in. I want to prevent or discourage vandals or the accident prone from making unnecessary submissions.

I am using sticky forms in case the user forgets to fill out every field, the form will display a PHP (not JavaScript) message near the empty field. While this happens the page is being reloaded.

I tried using sessions earlier today for the first time ever and noticed my sticky forms were no longer sticky. Is this normal?

I thought sessions were a replacement for sticky forms, however it was my understanding it required putting a cookie on someones computer. I really don't want to do that.

I will try out your examples.
0
 
LVL 5

Expert Comment

by:MichaelT_
ID: 34099462
What I meant by 'per session or per user' was could the user (actually I was thinking in the context of a member) only fill that form out once and never again (or only once per day / month / year), because obviously that is a little different than once and then refreshing the page type thing.

As for sticky forms that's a good way to go and very usual.  If your sticky forms were working and aren't now then that's another issue, but the example that I gave worked perfectly as retained the session information.

As for the meaning of "sticky forms" as I understand it it just means that the form retains user information on a error event etc, it doesn't have a particular definition on what method should be used to retain the information (i.e cookies, sessions, $_POST, $_GET or select the info from the db).

Let me know how the examples go.
0
 

Author Comment

by:kadin
ID: 34099882
Your little e1 and e2 program works well as it is, however when I integrate it into my form page it shows no sign of working.

I think I might know why.

Your e1 forms action refers to e2. So if(isset($_POST['submit'])) on e2.php collects the submit word from the form on e1.php.

My forms action refers to its own self page to process the form and then send and email. After sending the email the page is redirected

header('Location: http://localhost/confirm_sent.php'); exit;

confirm_sent.php is equivalent to your e2.php where I have this.

session_start();
if(isset($_POST['submitted']))
{
$_SESSION['prevSet']=true;
}

echo "A confirmation mail has been sent.";

Can it grab $_POST['submitted'] if the action from the previous page is to itself instead of to this confirm_sent.php?

I put these on confirm_sent.php and they seem to be empty.
print_r($_POST['submitted']);
print_r($_SESSION['prevSet']);
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 108

Expert Comment

by:Ray Paseur
ID: 34106048
Here is how I prevent multiple submissions.  Install this and run it to see how it works.  HTH, ~Ray
<?php // RAY_multi_submit.php

error_reporting(E_ALL);



// ALWAYS START SESSION ON EVERY PAGE

session_start();



// PREVENT MULTIPLE SUBMISSIONS DUE TO REPEATED CLICKS ON SUBMIT BUTTON

// EXAMPLE: 

//    if ( multi_submit() ) 

//    { 

//       handle error

//    } 

//    else 

//    { 

//       normal processing

//    }





function multi_submit($type="post")

{

    // MAKE THE FUNCTION WORK FOR EITHER GET OR POST SUBMITS

    $input_array = ($type == "get") ? $_GET : $_POST;



    // GATHER THE CONTENTS OF ALL THE SUBMITTED FIELDS AND MAKE A MESSAGE DIGEST

    $string = "";

    foreach ($input_array as $val) { $string .= $val; }

    $string = md5($string);



    // IF THE SESSION VARIABLE IS NOT SET, THIS IS NOT A MULTI-SUBMIT

    if (!isset($_SESSION["_multi_submit"]))

    {

        // SAVE THE SUBMITTED DATA MESSAGE DIGEST

        $_SESSION['_multi_submit'] = $string;

        return FALSE;

    }



    // IF THE SESSION DATA MATCHES THE MESSAGE DIGEST, THIS IS A MULTI-SUBMIT

    if ($_SESSION['_multi_submit'] === $string)

    {

        return TRUE;

    }

    else

    {

        // SAVE THE MESSAGE DIGEST

        $_SESSION['_multi_submit'] = $string;

        return FALSE;

    }

}



// SHOW HOW THIS IS DONE

if (!empty($_POST))

{

    if (multi_submit())

    {

        die("ALREADY GOT THAT");

    }

}

// END OF PHP - PUT UP THE FORM

?>

<form method="post">

ENTER SOMETHING, THEN REENTER IT

<input name="foo" />

<input type="submit">

</form>

Open in new window

0
 

Author Comment

by:kadin
ID: 34107377
I seem to have got it working and I learned more about sessions in the process.

The challenge was how to access $_POST from page two when page ones action="<?php $_SERVER['PHP_SELF'] ?>" does not send $_POST info to page two.

I tried adding two addresses to action="<?php $_SERVER['PHP_SELF'] ?>, page_two.php"

That did not work, so built from MichaelT's example program. I have three pages involved now. Form page1, thank you page2, and home page3.

Form page starts a session

session_start();
if(isset($_POST['submitted']))
{
$_SESSION['nprevSet']=true;
}

and then header(redirect to thank you page);

Thank you page

session_start();

if(isset($_SESSION['nprevSet']))
{
$_SESSION['prevSet']=true;
      unset($_SESSION['nprevSet']); // comment this out to persist the session being set
}

0
 

Author Comment

by:kadin
ID: 34107514
I pressed the tab and space bar and my comment automatically posted before I could finish it.

Any way while on the thank you page, click the back button to go back to the form page where a new session variable is set, the old one is unset and another header redirect, this time to the home page. The home page unsets the last session variable and the user is now free to navigate to the form page.

Thanks Ray for your example. I will save it and try to learn from it a little later. Right now in my stage of learning it is like a juggling act. It is hard to take on something new until my current understanding gets a little more stable.
0
 
LVL 5

Expert Comment

by:MichaelT_
ID: 34107535
Glad to hear you got it working, and you learnt a few things along the way :)
0

Featured Post

Easy Project Management (No User Manual Required)

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

These days socially coordinated efforts have turned into a critical requirement for enterprises.
This article discusses how to create an extensible mechanism for linked drop downs.
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now