I have a simple form that submits text to my SQL table. The problem is that after the user submits the text, they can refresh the page and the data gets submitted again with
A pretty surefire way is to implement a unique ID into the post and cache it in the
<input type='hidden' name='post_id' value='".createPassword(64)."'>
Then in your code do this:
if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
$_SESSION['post_id'] = $_POST['post_id'];
//do post stuff
} else {
//normal display
}
function createPassword($length)
{
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= ($length - 1)) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
A refined version of Moob's post. Create a hash of the POST, save it as a session cookie, and compare hashes every session.
// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );
$post_hash = md5( json_encode( $_POST ) );
if( session_start() )
{
$post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
$_SESSION[ 'post_hash' ] = $post_hash;
session_write_close();
}
else
{
$post_resubmitted = false;
}
if ( $post_resubmitted ) {
// POST was resubmitted
}
else
{
// POST was submitted normally
}
Use the Post/Redirect/Get pattern. http://en.wikipedia.org/wiki/Post/Redirect/Get
With my website, I will store a message in a cookie or session, redirect after the post, read the cookie/session, and then clear the value of that session or cookie variable.
I searched for solution to prevent resubmission in a huge project afterwards. The code highly works with $_GET and $_POST and I can't change the form elements behaviour without the risk of unforeseen bugs. So, here is my code:
<!-- language: lang-php -->
<?php
// Very top of your code:
// Start session:
session_start();
// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
// Store Post Form Data in Session Variable
$_SESSION["POST"] = $_POST;
// Reload Page if there were no outputs
if ( ! headers_sent() ) {
// Build URL to reload with GET Parameters
// Change https to http if your site has no ssl
$location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// Reload Page
header( "location: " . $location, true, 303 );
// Stop any further progress
die();
}
}
// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
$_POST = $_SESSION["POST"];
// Tell PHP that POST is sent
$_SERVER['REQUEST_METHOD'] = 'POST';
}
// Your code:
?><html>
<head>
<title>GET/POST Resubmit</title>
</head>
<body>
<h1>Forms:</h1>
<h2>GET Form:</h2>
<form action="index.php" method="get">
<input type="text" id="text_get" value="test text get" name="text_get"/>
<input type="submit" value="submit">
</form>
<h2>POST Form:</h2>
<form action="index.php" method="post">
<input type="text" id="text_post" value="test text post" name="text_post"/>
<input type="submit" value="submit">
</form>
<h2>POST Form with GET action:</h2>
<form action="index.php?text_get2=getwithpost" method="post">
<input type="text" id="text_post2" value="test text get post" name="text_post2"/>
<input type="submit" value="submit">
</form>
<h2>File Upload Form:</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" value="submit">
</form>
<h1>Results:</h1>
<h2>GET Form Result:</h2>
<p>text_get: <?php echo $_GET["text_get"]; ?></p>
<h2>POST Form Result:</h2>
<p>text_post: <?php echo $_POST["text_post"]; ?></p>
<h2>POST Form with GET Result:</h2>
<p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
<p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
<h2>File Upload:</h2>
<p>file:
<pre><?php if ( ! empty( $_FILES ) ) {
echo print_r( $_FILES, true );
} ?></pre>
</p>
<p></p>
</body>
</html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );
It only works to avoid the resubmit of $_POST, not $_GET. But this is the behaviour I need. The resubmit issue doesn't work with file uploads!
This form.php
sample shows how to use PRG correct (when form is valid or not).
<?php
session_start();
function doSelfRedirect()
{
header('Location:'.$_SERVER['PHP_SELF']);
exit;
}
function setFlashMessage($msg)
{
$_SESSION['message'] = $msg;
}
function getFlashMessage()
{
if (!empty($_SESSION['message'])) {
$msg = $_SESSION['message'];
unset($_SESSION['message']);
} else {
$msg = null;
}
return $msg;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validation primitive example.
if (empty($_POST['valid'])) {
$formIsValid = false;
setFlashMessage('Invalid form submit');
} else {
$formIsValid = true;
}
if ($formIsValid) {
// Perform any actions here.
// ...
// Cool!
setFlashMessage('Form is valid. Action performed.');
// Prevent form resubmission.
doSelfRedirect();
}
}
?>
<h1>Hello form</h1>
<?php if ($msg = getFlashMessage()): ?>
<div><?= $msg ?></div>
<?php endif; ?>
<form method="post">
<input type="text" name="foo" value="bar"><br><br>
<button type="submit" name="invalid" value="0">Invalid submit</button>
<button type="submit" name="valid" value="1">Valid submit</button>
</form>
Javascript
This method is quite easy and blocks the pop up asking for form resubmission on refresh once the form is submitted. Just place this line of javascript code at the footer of your file and see the magic.
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>