-1

I'm using form like this to add records to database:

<form class="col s12" action="" method="post">

                <div class="row">

                    <div class="input-field col s6">
                        <input placeholder="" name="n" id="n" type="text" class="validate">
                        <label for="n">Name</label>
                    </div>

                    <div class="input-field col s4">
                        <input placeholder="" name="price" id="price" type="text" class="validate">
                        <label for="price">Price</label>
                    </div>

                    <div class="input-field col s2">
                        <input placeholder="" name="catid" id="catid" type="number" class="validate">
                        <label for="catid">Category</label>
                    </div>

                </div>

                <div class="row">

                    <div class="input-field col s12">
                        <input placeholder="" name="desc" id="desc" type="text" class="validate">
                        <label for="desc">Description</label>
                    </div>

                </div>

        </div>
        <div class="modal-footer">
            <button class="btn waves-effect waves-light" type="submit" name="create" style="float:left; margin: 5px;" onClick="clearform();">
                <i class="material-icons left">add</i>Create
            </button>
            <a href="#!" class="modal-action modal-close waves-effect waves-light btn" style="float:left; margin: 5px"><i class="material-icons left">clear</i>Close</a>
        </div>
        </form>

here is the function to add records:

public function create($n, $desc, $price, $catid) {
    $this->conn->prepare("INSERT INTO `products` (`ID`, `Name`, `Description`, `Price`, `CategoryID`, `Created`, `Modified`) VALUES (NULL, '$n', '$desc', '$price', '$catid', NOW(), NOW())")->execute();
    $this->name = $n;
    $this->description = $desc;
    $this->price = $price;
    $this->catid = $catid;
}

if($_SERVER['REQUEST_METHOD'] == 'POST'){
if ( isset( $_POST['create'], $_POST['n'], $_POST['desc'], $_POST['price'], $_POST['catid']) ) {

    $cat = new Product($conn);

    $n = filter_input ( INPUT_POST , 'n', FILTER_SANITIZE_STRING );
    $desc = filter_input ( INPUT_POST , 'desc', FILTER_SANITIZE_STRING );
    $price = filter_input ( INPUT_POST , 'price', FILTER_SANITIZE_STRING );
    $catid = filter_input ( INPUT_POST , 'catid', FILTER_SANITIZE_NUMBER_INT );
    $cat->create($n, $desc, $price, $catid);
}
}

Records are added to the db, but the problem is, that every time I refresh the page, they are added again. How to solve that?

artur47wien
  • 355
  • 2
  • 4
  • 13
  • Redirect using header after data are stored to db. Typical is redirect to the same script. – Fanda May 21 '16 at 22:38
  • Also keep in mind that your query is open to SQL injection attacks. You should fix that. Use bound parameters in your prepared statements. `FILTER_SANITIZE_STRING` does not sanitize your values to be inserted in a database query. – Mike May 21 '16 at 22:42

3 Answers3

3

You should use redirection if the information is not available and after the information has been added:

if($_SERVER['REQUEST_METHOD'] != 'POST'){
  header("Location: add_product.php"); // or something else
} else {
  if ( isset( $_POST['create'], $_POST['n'], $_POST['desc'], $_POST['price'], $_POST['catid']) ) {

  $cat = new Product($conn);

  $n = filter_input ( INPUT_POST , 'n', FILTER_SANITIZE_STRING );
  $desc = filter_input ( INPUT_POST , 'desc', FILTER_SANITIZE_STRING );
  $price = filter_input ( INPUT_POST , 'price', FILTER_SANITIZE_STRING );
  $catid = filter_input ( INPUT_POST , 'catid', FILTER_SANITIZE_NUMBER_INT );
  $cat->create($n, $desc, $price, $catid);

  header("Location: success.php"); // or something other ....
  }
}

That way you will avoid those back button or refresh button double posts.

I hope it helps.

Kirito
  • 307
  • 2
  • 7
1

Unset the $_POST data and redirect after initial submit. If you want to keep the user on the same page redirect to it. This will empty the form.

unset($_POST); header("Location:your_page.php");

Romeo Mihalcea
  • 9,714
  • 12
  • 50
  • 102
  • Why `unset($_POST);`? – Mike May 21 '16 at 22:39
  • Haven't used PHP in almost 8 years but, playing it from my memory, I think I was marking unused vars for the gc to pick them up. You can certainly go without `unset` – Romeo Mihalcea May 21 '16 at 22:44
  • 1
    There are *very* few times you really have to worry about the GC in PHP, especially if you're just cleaning up (typically) a few bytes from `$_POST`. One thing you might want to include, though, is an `exit;` after your header, which prevents the script from executing anything past that point. – Mike May 21 '16 at 22:48
1

The best way to prevent double entires is to have some hidden token that is once generated for every form loaded. On receiving the POST you now check if this token is still valid (time expired, already used) and if so proceed with the transaction.

This does not only help against refresh and back-button but impatient users, too!