I think that this problem occurs often on a web application development. But I'll try to explain in details my problem.
I'd like to know how to correct this behavior, for example, when I have a block of code like this :
<?
if (isset($_POST['name'])) {
... operation on database, like to insert $_POST['name'] in a table ...
echo "Operation Done";
die();
}
?>
<form action='page.php' method='post' name="myForm">
<input type="text" maxlength="50" name="name" class="input400" />
<input type="submit" name="Submit" />
</form>
When the form gets submitted, the data get inserted into the database, and the message Operation Done is produced. Then, if I refreshed the page, the data would get inserted into the database again.
How this problem can be avoided? Any suggestion will be appreciated :)
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;
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 } ?>
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
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>
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>
So, for what I needed this is what works.
Based on all of the above solutions this allows me to go from a form to another form, and to the n^ form , all the while preventing the same exact data from being "saved" over and over when a page is refreshed (and the post data from before lingers onto the new page).
Thanks to those who posted their solution which quickly led me to my own.
<?php
//Check if there was a post
if ($_POST) {
//Assuming there was a post, was it identical as the last time?
if (isset($_SESSION['pastData']) AND $_SESSION['pastData'] != $_POST) {
//No, Save
} else {
//Yes, Don't save
}
} else {
//Save
}
//Set the session to the most current post.
$_session['pastData'] = $_POST;
?>
We work on web apps where we design number of php forms. It is heck to write another page to get the data and submit it for each and every form. To avoid re-submission, in every table we created a 'random_check' field which is marked as 'Unique'.
On page loading generate a random value and store it in a text field (which is obviously hidden).
On SUBMIT save this random text value in 'random_check' field in your table. In case of re-submission query will through error because it can't insert the duplicate value.
After that you can display the error like
if ( !$result ) {
die( '<script>alertify.alert("Error while saving data OR you are resubmitting the form.");</script>' );
}
No need to redirect...
replace die(); with
isset(! $_POST['name']);
, setting the isset to isset not equal to $_POST['name'], so when you refresh it, it would not add anymore to your database, unless you click the submit button again.
<?
if (isset($_POST['name'])) {
... operation on database, like to insert $_POST['name'] in a table ...
echo "Operation Done";
isset(! $_POST['name']);
}
?>
<form action='page.php' method='post' name="myForm">
<input type="text" maxlength="50" name="name" class="input400" />
<input type="submit" name="Submit" />
</form>
This happen because of simply on refresh it will submit your request again.
So the idea to solve this issue by cure its root of cause.
I mean we can set up one session variable inside the form and check it when update.
if($_SESSION["csrf_token"] == $_POST['csrf_token'] )
{
// submit data
}
//inside from
$_SESSION["csrf_token"] = md5(rand(0,10000000)).time();
<input type="hidden" name="csrf_token" value="
htmlspecialchars($_SESSION["csrf_token"]);">
I think following is the better way to avoid resubmit or refresh the page.
$sample = $_POST['submit'];
if ($sample == "true")
{
//do it your code here
$sample = "false";
}
I have an HTML form that will return as HTML format with JQuery Ajax after the insertion query is successful.
comment.php
$post_id=$_POST['id'];
mysql_query("INSERT INTO comment(comment,post_id,)VALUES('$comment','$post_id')");
if(!mysql_errno()){
?>
<p><?php echo $comment; ?></p>
This is my JQuery code that will send the request and values and return the HTML form after the insertion query succeeds.
index.php
// on post comment click
$('.bt-add-com').click(function(){
var theCom=$(this).siblings('.the-new-com');
if(!theCom.val()){
alert('You need to write a comment!');
}else{
var post_id=$(this).parents(".post_id").attr("id");
$.ajax({
type: "POST",
url: "comment.php",
data: "act=add-com&comment="+theCom.val()+"&id="+post_id,
success: function(html){
theCom.val('');
$('.the-new-com').hide('fast', function(){
$('.new-comment-line').show('fast');
$('.new-comment-line').after(html);
});
}
});
}
});
This my form. It's running within a loop of posts submitted by the user every time.
<form action="" method="POST" class="post_id" id="<?php echo $post_id; ?>">
<span>Write a comment ...</span>
</div>
<div class="new-comment-line"></div><----here is a line before the comment initiates..--->
<textarea class="the-new-com"></textarea>
<div class="bt-add-com">Post comment</div>
</form>
And now my question is that my all code works very well except last few lines of JQuery code.
$('.new-comment-line').after(html);
The line of code when my form returns the HTML form from comment.php after the Ajax request has the problem. The form prints every time, in every post, that the user submitted the status.
How should I handle the form? I want my comments to print every time only in the specific post submitted by the user.
Obviously $('.new-comment-line') is a class selector and you are selecting all elements in this class. As you start your function by clicking on a button, I suggest the selection of correct element relative to the clicked button. So immediately after clicking a button, select the correct element:
var correctElement=$(this).siblings('.new-comment-line');
and then add the html to it when needed:
correctElement.after(html);
I have built a follow/unfollow Twitter like system using PHP. Now I would like to run the follow-unfollow PHP script in the background using AJAX/JQUERY to avoid refreshing the page when you follow/unfollow a user. To make things simpler, I will be here just using the example of “unfollow”. As you notice, I am running an iteration to output all the members in the database. I am outputting here (as well for simplicity) just the member’s name and an unfollow button to each one.
This is the code using php.
members.php
<?php foreach($members as $member){ ?>
<p class="member_name"><?php echo $member->name; ?></p>
<p class="follow_button">Unfollow</p>
<?php } ?>
unfollow.php
<?php
if($_GET['unfollow_id']){
$unfollow_id=$_GET['unfollow_id'];
$unfollow=Following::unfollow($id, $unfollow_id); //Function that will make the changes in the database.
// $id argument will be gotten from a $_SESSION.
}
I am trying to achieve the same result running unfollow.php in the background to avoid any refreshing. This is what I have come up with, as you might imagine it is not working properly. I am including the Jquery script inside the iteration which I think is the only way of obtaining the $member->id property to then assign it to the Jquery variable.
members.php THE NEW ONE THAT TRYS TO RUN THE SCRIPT WITH AJAX JQUERY
<?php foreach($members as $member){ ?>
<p class="member_name"><?php echo $member_name; ?></p>
<button type="button" class="unfollow_button" id="unfollow">Unfollow</button>
<script type="text/javascript">
$(document).ready(function(){
$("#unfollow").click(function(){
// Get value from input element on the page
var memberId = "<?php $member->id ?>";
// Send the input data to the server using get
$.get("unfollow.php", {unfollow_id: memberId} , function(data){
// Success
});
});
});
</script>
<?php } ?>
Can you provide me any help for this to work?
Thanks in advance.
Remember, in HTML, id attributes have to be unique.
Because you're rendering multiple members on a single page, you should not use an id selector in jQuery, but a class selector (e.g. button.unfollow). If you use #unfollow, you'll run into ID conflicts between each of the members' buttons.
First, render all of your members with unfollow buttons without ids. I'm adding the member_id in the markup using a data attribute called data-member_id.
<?php foreach($members as $member) { ?>
<p class="member_name"><?=$member_name?></p>
<button type="button" class="unfollow_button" data-member_id="<?=$member->id?>">Unfollow</button>
<?php } ?>
Then add a single click handler for all button.follow buttons, which extracts the member_id from the clicked button's data-member_id attribute and sends it to the server.
<script type="text/javascript">
$(document).ready(function() {
$("button.unfollow_button").on('click', function() {
// Get value from input element on the page
var memberId = $(this).attr('data-member_id');
// Send the input data to the server using get
$.get("unfollow.php", {unfollow_id: memberId} , function(data) {
// Success
});
});
});
</script>
On a side-note, you should probably look into building a RESTful service for this, to which you can post proper HTTP requests using http://api.jquery.com/jquery.ajax/.
See here for an intro on REST in PHP I wrote a while back:
Create a RESTful API in PHP?
So I'm creating a code portfolio based upon what's in my svn repo.
I'm currently set up like this:
PHP loops through my JSON and creates these little menus for each file in each project. Here's some (very poorly structured) code showing how I generate each of these:
<form action = "" method = 'post'><select name = "s2" id = "s2"> <?php
foreach($proj2->item_vers as $ver)
{
?>
<option value = <?php
$base_str = (string)$ver->revision;
$full_str = "\"".$base_str."\"";
echo($full_str); ?> > <?php
echo($base_str); ?> </option>
<?php
} ?> </select><input type = 'submit'/></form>
<a href = <?php
if (isset($_POST['2']))
{
$rev2 = $_POST['s2'];
}
else
$rev2 = "";
$full_url = "https://myrepo".
$proj2->name."?p=".$rev2;
$ret_url = "\"".$full_url."\"";
echo($ret_url); ?> > Code </a></td>
So I have a form, select, option. The select will post the selected version from the drop down. Then I have a hyperlink which forms the correct url based upon the posted version number. This hyperlink will need to be replaced with an iframe. For the sake of simplicity, lets say that each project has its own iframe which is updated with appropriate project file any time you click one of the submit buttons.
So like this:
I'm looking for the simplest way to set this up to work asynchronously.
My thoughts:
I've already set up an asynchronous comment system using jQuery. The difference was that I only had three little inputs and a button to submit the comment. This just seems like it will be much more complicated as the code I posted above will loop through about 100 times. I cant just hard code a different id to every single submit button and write 100 different .js scripts to operate when each individual button is clicked.
OK, so im going to simplify your form generation code to make this clearer. I am including the outer loop you dont show:
<div id="forms-holder">
<!--this is the outer loop-->
<?php foreach ($projects as $project):?>
<!-- remove any ids in the loop, they can not be duplicated-->
<form action="" class="projectform">
<!-- add name to data attribute for easy retrieval by js-->
<select name="s2" data-projectname="<?php echo $project->name;?>">
<?php foreach ($project->item_vers as $ver):?>
<option value="<?php echo'"'. $ver->revision .'"';?>"><?php echo $ver->revision;?></option>
<?php endforeach;?>
</select>
<input type = 'submit'/>
<form>
<?php endforeach;?>
</div>
<iframe src="" frameborder="0" id="myiframe"></iframe>
<script type="text/javascript">
$(function(){
//when any form is submitted
$('.projectform').submit(function(ev){
ev.preventDefault();
//grab revision and project name
var revision = $(this).find('select').val();
var projname = $(this).find('select').attr('data-projectname');
//generate the url
var iframeurl = "https://myrepo"+projname+"?p="+revision;
//set the iframes url
$('#myiframe').attr('src', iframeurl);
})
});
</script>
I have created a comment-reply system for my blog in php. Comments are stored in a table called comments(comments_id, comment, comment_date, user, flag). I use a script which displays comments and near to each comment there is a link called "delete" in order for the user to delete its own comment in case want to do so.
my php script for displaying comments is :
<?php
// ... above code
$comments .= $row['comment']; // comment printed succesfully here
if($comment_user_id == $session_user_id){
$comments .="<table border='1' style='display:inline-table;'><td><h2><font size='2'>
<form action='deletepost.php' method='post'>
<input type='hidden' name='var' value='$comment_id;'>
<input type='submit' value='delete'>
</form>
</h2></font></td></table>";
}
?>
in order to delete a comment, I update the table comments and set flag=1, so my script will not display comments having their flag=1 in table. In order to do this I use script deletepost.php
<?php
$comment = mysql_real_escape_string($_POST['var']);
if(isset($comment) && !empty($comment)){
mysql_query("UPDATE `comments` SET `flag`=1 WHERE (`user`='$session_user_id' AND `comments_id`='$comment')");
header('Location: wall.php');
}
?>
My script until now works perfect without problem and the user that posts a comment can delete its own comment without any error. The problem started when I decided to insert a lightbox in javascript, so that the user will be asked before deleting a comment. So I have changed my first script to the following:
<?php
// ... above code
$comments .= $row['comment']; // comment printed succesfully here
if($comment_user_id == $session_user_id){
$comments .="<table border='1' style='display:inline-table;'><td><h2><font size='2'>
// at this point problem occurs when inserting javascript lightbox
<a href = javascript:void(0) onclick = document.getElementById('light').style.display='block';document.getElementById('fade').style.display='block'><h2><font color=green size=3>Delete All</font></h2></a>
<div id=light class=white_content>DELETE THIS COMMENT?
<form action='deletepost.php' method='post'>
<input type='hidden' name='var' value='$comment_id;'>
<input type='submit' value='delete'>
</form>
<a href = javascript:void(0) onclick = document.getElementById('light').style.display='none';document.getElementById('fade').style.display='none'><div id=pading><button>Cancel</button></div></a></div>
<div id=fade class=black_overlay></div>
</h2></font></td></table>";
}
?>
By using the javascript lightbox as shown above, when the user will press delete, a lightbox starts and asks user if wants to delete the comment. The problem is that now when the user press delete button, it is not deleting the certain comment but the last comment that finds in comments table. Probably there is something else I need to write in my javascript to correct this, in order to know which comment to delete (set its flag to 1). Any idea how to fix it?
Make sure the 'deletepost.php' is getting the correct comment id($comment) that you wanted to delete.
May be that can be the cause.