Best way to avoid the submit due to a refresh of the page

Solution 1:

Don't show the response after your create action; redirect to another page after the action completes instead. If someone refreshes, they're refreshing the GET requested page you redirected to.

// submit
// set success flash message (you are using a framework, right?)
header('Location: /path/to/record');
exit;

Solution 2:

Set a random number in a session when the form is displayed, and also put that number in a hidden field. If the posted number and the session number match, delete the session, run the query; if they don't, redisplay the form, and generate a new session number. This is the basic idea of XSRF tokens, you can read more about them, and their uses for security here: http://en.wikipedia.org/wiki/Cross-site_request_forgery

Here is an example:

<?php
session_start();

if (isset($_POST['formid']) && isset($_SESSION['formid']) && $_POST["formid"] == $_SESSION["formid"])
{
    $_SESSION["formid"] = '';
    echo 'Process form';
}
else
{
    $_SESSION["formid"] = md5(rand(0,10000000));
?>
    <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
    <input type="hidden" name="formid" value="<?php echo htmlspecialchars($_SESSION["formid"]); ?>" />
    <input type="submit" name="submit" />
</form>
<?php } ?>

Solution 3:

I ran into a similar problem. I need to show the user the result of the POST. I don't want to use sessions and I don't want to redirect with the result in the URL (it's kinda secure, I don't want it accidentally bookmarked). I found a pretty simple solution that should work for the cases mentioned in other answers.

On successfully submitting the form, include this bit of Javascript on the page:

<script>history.pushState({}, "", "")</script>

It pushes the current URL onto the history stack. Since this is a new item in history, refreshing won't re-POST.

UPDATE: This doesn't work in Safari. It's a known bug. But since it was originally reported in 2017, it may not be fixed soon. I've tried a few things (replaceState, etc), but haven't found a workaround in Safari. Here are some pertinent links regarding the issue:

  • Safari send POST request when refresh after pushState/replaceState
  • https://bugs.webkit.org/show_bug.cgi?id=202963
  • https://github.com/aurelia/history-browser/issues/34

Solution 4:

Like this:

<?php
if(isset($_POST['uniqid']) AND $_POST['uniqid'] == $_SESSION['uniqid']){
    // can't submit again
}
else{
    // submit!
    $_SESSION['uniqid'] = $_POST['uniqid'];
}
?>

<form action="page.php" method="post" name="myForm">
    <input type="hidden" name="uniqid" value="<?php echo uniqid();?>" />
    <!-- the rest of the fields here -->
</form>

Solution 5:

I think it is simpler,

page.php

<?php
   session_start();
   if (isset($_POST['name'])) {
        ... operation on database, like to insert $_POST['name'] in a table ...
        $_SESSION["message"]="Operation Done";
        header("Location:page.php");
        exit;
    }
?>

<html>
<body>
<div style='some styles'>
<?php
//message here
echo $_SESSION["message"];
?>
</div>
<form action='page.php' method='post'>
<!--elements-->
</form>
</body>
</html>