Preventing double form submission using tokens

I am trying to prevent a user from posting a forum twice by adding a hidden token field.

So, here is what I have done so far (before loading the forum, I have this code to create a token with the current time as the value.

$token = time();
setcookie('formToken', $token, time() + 3600);

on my forum I have a hidden input like this

<form method="post" action="'.$PHP_SELF.'?action=update">
<input type="hidden" name="token" value="'.$token.'" />
<input type="submit" value="go" />
</form>

now at the top of my page where $ action == "update" I have this code

if(isset($_POST)  &&  ($_POST['token'] != $_COOKIE['formToken'])){
    $error_list .= '<li>You can not submit this forum twise.</li>';
} 

if I press F5 to refresh the page, it will submit the form again without showing my error.

+5
source share
6 answers

: , , " POSTDATA "? , .

PRG (Post/Redirect/Get), phpbb.

Post/Redirect/Get (PRG) - -, , (). PRG , .

http://upload.wikimedia.org/wikipedia/commons/3/3c/PostRedirectGet_DoubleSubmitSolution.png

, , - - .:)

+9

, ?

so $_SESSION['submitted'] = 1;

.

Do

if(isset($_POST['submit'])  &&  ($_POST['token'] != $_COOKIE['formToken'])){
    $error_list .= '<li>You can not submit this forum twice.</li>';
}
+3

gd1 jQuery javascript.

, javascript, .

, , , , , . .

cookie , , , .

, , (, ..) , , , .

+3

1)

cookie (removeTokens)

    function removeToken()
{
    //set formToken cookie val to "" (or any default xxxx) and the past expiry date for it 
    setcookie("formToken", "", time()-3600);
    //try to unset - this is not needed ,we may try it
    unset($_COOKIE['formToken']);
}

.. , (isset ($ _ POST)) removeToken();

2)

, php f5

 header('Location: formsubmitSucess.php');
0

, . , , , PHP.

1: : YOUR-TABLE .

    ALTER TABLE `YOUR-TABLE` ADD `token` VARCHAR(35) NULL DEFAULT NULL AFTER    `creationtoken`, ADD UNIQUE (`token`) ;

2 : toke, , , , , .

    <?php 
    session_start(); 
    date_default_timezone_set('America/Chicago');
    $_SESSION['token'] = md5(session_id() . time());
    ?>

:

    // add this before the submit button
    // this will post the unique token to the processing page.

    <div style="width:100%; color:#C00; font-weight:normal;">Session Token: <?php echo strtolower($_SESSION['token']) ?></div>     

    <input type="hidden" name="token" id="token" value="<?php echo  $_SESSION['token']?>" />
    // add this before the submit button


    <input type="submit" id="submit" name="submit" class="button" value="Submit" />

3: process.php

    //this is where all of your form processing takes place.

    // this is where you call the database
    // if you need the database file let me know...
    include("../common/databaseclass.php");
    $db= new database();

    //here the token is posted then the database table is checked and 
    //if the form has already been added it will return a 1 and will 
    //cause the query to die and echo the error message. 

    $token = $_POST['token'];
    $query = "SELECT token FROM YOURTABLE WHERE token = '$token' LIMIT 1";
    $result = $db->query($query);
    $num = mysql_num_rows($result);

    if ($num>0) {die('your form has already been submitted, thank you');}


    else {

    $host = "localhost";
    $user = "user";
    $pass = "password";
    $db_name = "database";

    mysql_connect($host,$user,$pass);
    @mysql_select_db($db_name) or die( "Unable to select database");


    // table query      
    $sql1="INSERT INTO YOURTABLE (
    `token`,
    `user`,
    `email`,
    `password`,
    `newaccount`,
    `zipcode`,
    `city`,
    `state`,
    `country`,
    `telephone`,
    `creationip`,
    `createdaccount`
     ) 
     VALUES (
     '$token',
     '$username',
     '$email',
     '$password',
     '$newaccount',
     '$zipcode',
     '$city',
     '$state',
     '$country',
     '$phone',
     '$ipadress',
     '$createdaccount'

       )";

    $db->query($sql1);
    header("location:" http://home.php ");      

    }
0

, . PRG , PHP . , , .

class unPOSTer {

        private 
            $post = "KEEP_POST";

        public function __construct(string $name = null) {
            if (version_compare(PHP_VERSION, "5.4.0") >= 0) {
                if (session_status() == PHP_SESSION_NONE) {
                    session_start();
                }
            } else {
                if (!$_SESSION) {
                    session_start();
                }
            }
            $this->post = $name;
        }

        public function unPost() {
            if (session_status() !== PHP_SESSION_ACTIVE) {
                session_start();
            } elseif (strcasecmp($_SERVER["REQUEST_METHOD"],"POST") === 0) {
                $_SESSION[$this->post] = $_POST;
                header("Location: " . $_SERVER["PHP_SELF"] . "?" . $_SERVER["QUERY_STRING"]);
                exit;
            } elseif (isset($_SESSION[$this->post])) {
                $_POST = $_SESSION[$this->post];
            }
        }

        public function retrieve($data) {
            if (isset($_SESSION[$this->post])) {
                $posts = @$_SESSION[$this->post][$data];
                if (isset($posts)) {
                    return $posts;
                } else {
                    return null;
                }
            } 
        }

        public function reset() {
            if (isset($_SESSION[$this->post])) {
                unset($_SESSION[$this->post]);
            }
        }
    }

:

<?php
    require_once "unPOSTer.class.php";
    $unpost = new unPOSTer();
    $unpost->unPost();
?>
<form action='' method=POST>
    <input type=text name=fname value="<?php echo $unpost->retrieve("fname"); ?>" placeholder="First Name">
    <input type=text name=lname value="<?php echo $unpost->retrieve("lname"); ?>" placeholder="Last Name">
    <input type=submit name=send value=Send>
</form>
<?php echo $unpost->reset(); ?>

No need to configure, do it on every page you submit if you want. The method retrieve()spits out the data that you sent, in case you can go back and fix something. Feel free to expand / pull it on my GitHub page. I added 2 demos there.

0
source

All Articles