Link to home
Create AccountLog in
Avatar of kadin
kadinFlag for United States of America

asked on

Preventing multiple form submissions.

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; ?>" />
ASKER CERTIFIED SOLUTION
Avatar of MichaelT_
MichaelT_
Flag of Australia image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Avatar of kadin

ASKER

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.
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.
Avatar of kadin

ASKER

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']);
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

Avatar of kadin

ASKER

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
}

Avatar of kadin

ASKER

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.
Glad to hear you got it working, and you learnt a few things along the way :)