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 am looking to develop a website containing stages. I want for example to pass by the stage 2 only when i click on the finish button in the page of stage 1 so the stage 2 page can't be accessible by its url or whatever only if the user pass by another page.
Is there a method to do this ??? i am a beginner in security so please try to help me, thanks in advance coders
Make use of sessions to develop this model.
index.php
<?php
#extract($_POST);
if(isset($sub))
{
session_start();
$_SESSION['authenticate']=true;
header("location:test1.php");
exit;
}
?>
<form action='' method="post">
<input type="SUBMIT" name="sub" value="Finish" />
</form>
open.php
<?php
session_start();
if(!isset($_SESSION['authenticate']))
{
echo "You are not allowed to access";
}
else { echo "You came from index.php ! so you are a valid user"; }
session_destroy(); //<-- I added this so you can test your example multiple times.
I think, this show work :)
Use can either redirect your user directly from index.php to open.php
header('Location : open.php');
Or,
in open.php, put this
if($_SERVER['HTTP_REFERER'] == 'index.php page's full link') {
//Do or Show whatever you want to show here
} else {
// Tell the user that you are not authorized
}
If that doesn't work, echo $_SERVER['HTTP_REFERER'] and see what link it gives you. And put that link where specified above.
Cool? :)
Edit (As per the comments) --
Lets say you have a form in your form in stage1.php
<form method="post" action="">
<span class="error"><?php echo $error; ?></span>
Name: <input type="text" name="name"><br/>
Email: <input type="text" name="email"><br/>
<input type="submit" name="submit" value="Submit">
</form>
use this php in stage1.php
if (isset($_POST['name'])||isset($_POST['email'])) {
if (!empty($_POST["name"])||!empty($_POST["email"])) {
$error = "Please fill in all the fields correctly";
}
else {
$name = $_POST['name'];
$email = $_POST['email'];
//You can also save the above Variables Globally by $GLOBALS['name'] = $_POST['name'];
//So that you can use the details when you reach the final stage
header('Location : stage2 page's link');
}
}
?>
and in Page 2 lets say you have another form, then there also check
<?php
if(!empty($name)||!empty($email)) {
//the above is check for global variables email and name are not empty - means stage 2 was filled properly
//Do things for the second page's form like you did for stage 1
} else {
header('Location : stage1 page's link');
//redirect back to stage 1.
}
?>
I have a Customer Details PHP page. To get to this page, the user either signs up with new details on signup.php or they log in on login.php.
Ive been told the best way to submit data and be redirected to the correct page is to use action="details.php" in the form, and then at the start of the details.php file use the values from the $_POST array to populate my SQL database.
However, I need to do the same sort of thing with the login.php code, so at the top of details.php there will be the code to enter the form data from signup.php and the verifying code from login.php.
Surely there is a way of doing the data submission directly from signup.php so there isnt two sets of PHP in the details.php file? If not how do i differentiate so that login only uses the login code and signup uses the submit code?
Common practice is to have PHP check for form data+possible redirect and after that form print
Example: (my common usage)(i merged login&signup into one file)
<?php
$error = "";
if( !empty($_POST['signup']) ){
//do signup
//$signup = assign true/false whether sign up was successfull or not
if( !$signup ){ //if signup wasnt successfull generate error
$error = "Sign up error.";
}
}
if( !empty($_POST['login']) ){
//do login
//$login = assign true/false whether login was successfull or not
if( !$login ){ //if login wasnt successfull generate error
$error = "Log in error.";
}
}
if( empty($error) ){
//there were no errors
header("Location: details.php"); //redirect to details.php
exit(); //send nothing else!
}
?>
<div class="error"><?php if(!empty($error)){ echo htmlspecialchars($error); /*escape*/ } ?></div>
<form action="#" method="POST">
<input type="hidden" name="signup" value="yes">
<!-- ...some other input fields... -->
<button type="submit">Sign Up</button>
</form>
<br>
<form action="#" method="POST">
<input type="hidden" name="login" value="yes">
<!-- ...some other input fields... -->
<button type="submit">Log In</button>
</form>
You could set a hidden field on each page as below:
<input type=hidden name='referrerpage' value='signup'>
AND
<input type=hidden name='referrerpage' value='login'>
and do:
if ($_POST['referrerpage']=='signup'){
//do this
} else{
//do this
}
I'm having a rather irritating issue when trying to submit data from a html button tag via POST to a PHP processing script.
Here's my code...
(1) HTML form:
<form id="pub-form1" method="post">
<button type="submit" name="All" value="true">All Publishers</button>
<button type="submit" name="Current" value="true">Current Publishers</button>
<button type="submit" name="Users" value="true">User Priveleges</button>
</form>
(2) jQuery script to handle POST request:
$(document).ready(function () {
$('#pub-form1').submit(function (e) {
e.preventDefault();
$('#results').contents().remove();
var formData = $(this).serialize();
$("input").prop("disabled", true);
request = $.post('VRC_PublishersProcess.php', formData, resultsMessage);
request.fail(function() {
$('#results').append("<span id=\"reply\">Your search failed for an unknown reason. Please try again in a few minutes.</ span>");
$("input").prop("disabled", false); });
function resultsMessage(data) {
$('#results').append(data);
$("input").prop("disabled", false);
}
});
});
(3) PHP processing script:
//All Publishers
if(isset($_POST['All'])) {
if(!empty($_POST['All'])) {
$result = $members->selectAllMembers();
if($result === true) {
exit(); //Kill the process
}
else {
echo $result;
exit(); //Kill the process
}
}
else {
$error = "<span id=\"reply\">Not all fields were entered correctly!</ span>";
echo $error;
exit(); //Kill the process
}
}
//Current Publishers
if(isset($_POST['Current'])) {
if(!empty($_POST['Current'])) {
$result = $members->selectCurrentPublishers();
if($result === true) {
exit(); //Kill the process
}
else {
echo $result;
exit(); //Kill the process
}
}
else {
$error = "<span id=\"reply\">Not all fields were entered correctly!</ span>";
echo $error;
exit(); //Kill the process
}
}
//Users
if(isset($_POST['Users'])) {
if(!empty($_POST['Users'])) {
$result = $members->selectUserPublishers();
if($result === true) {
exit(); //Kill the process
}
else {
echo $result;
exit(); //Kill the process
}
}
else {
$error = "<span id=\"reply\">Not all fields were entered correctly!</ span>";
echo $error;
exit(); //Kill the process
}
}
I'm not quite sure what the cause of the issue is. No errors were thrown by javascript or PHP; the page remains blank with no results.
The jQuery function seems to be working correctly. I've use that particular several times on other forms and it handles the POST request properly. I was even able to trigger a failure on it; it responded correctly.
The PHP processing script also appears to be functioning properly. Again, it derived from other scripts that have successfully processed POST requests from the same page.
My suspicion is focused on the HTML form itself. These are my theories: (1) The button isn't submitting "itself." In other words, since there is no text or other forms of input, there's really nothing to submit. (2) For some reason the name is not corresponding to what my PHP script is looking for. For instance, if "All Publishers" was submitted, my PHP script is looking for $_POST['All']. But for some reason, that request isn't saved under that identifier in the PHP superglobal array.
My goal is to provide the end user with three options of displaying data. Right now, that isn't working.
Any feedback is appreciated.
Final Solution:
<div id="pub1">
Other
<div id="displayselect" method="post">
<form id="select1" method="post">
<input type="hidden" name="All" value="1" />
</form>
<form id="select2" method="post">
<input type="hidden" name="Current" value="1" />
</form>
<form id="select3" method="post">
<input type="hidden" name="Users" value="1" />
</form>
<button type="submit" name="All" form="select1">All Publishers</button>
<button type="submit" name="Current" form="select2">Current Publishers</button>
<button type="submit" name="Users" form="select3">User Priveleges</button>
</div>
</div>
Obviously, appropriate modifications were made in the jQuery...
Figured it out,
jQuery.serialize didn't work out on the button (http://api.jquery.com/serialize/) it only works on input, textarea, select so I tried switching your HTML button elements into <input type="submit" ... but that didn't work out as well because jQuery ignores the submit tags when serializing, I tried to add an <input type="hidden" name="test" value="1" /> and checked out what it serialized was test=1 so you'd have to change your form a bit.
jsFiddle for testing: http://jsfiddle.net/4D8Nz/
I am using a feature of popup box in my project. When a user come to the site a popup box apears on the top of the page hiding the rest of the content. In that popup form the user has to give a download key. if the user has the key he can go forward otherwise he cannot see anything else. When the user provide the key he goes to the main page.
Now the problem is once the user comes to the main page after providing the key and when he clicks again on the header again the page is reloaded and again tht popup form comes. How can I prevent it to apear again if some user has already given the download key . I am using php with code igniter. My code
<?php if($download_key != null && !isset($_POST['popup'])){?>
<script type="text/javascript">
$(document).ready(function(){
loadPopup();
});
</script>
<?php } ?>
downlaod key is database column and popup is a hidden input that is set when the form is submitted on the popup box.
The form that appears on popup box is as
<form name="form" method="post" onsubmit="return validateForm('<?php echo $download_key ?>')">
<div style="width:530px;">
<input style="display:none; height:25px;" id="downloadkey" name="downloadkey" type="text" />
<input style="display:none;" type="submit" id="submit" name="submit" value="<?php echo $variable['QUESTION_BUTTON']['value']?>"/>
</div>
</form>
Any ideas ?
Thanks
You should have a session_start() at the beginning of pageload
EDIT: changed a bit
session_start();
//check if key has already been seen:
if(isset($_SESSION['download_key']) && $_SESSION['download_key'] != null ...
// then if not check if the key is submitted
else if ( isset($_POST['popup']) ... // and other checks
// set session variable
$_SESSION['download_key'] = $key;
else
// load the ask for key page
Set a session variable, and check to see if it's present, as it will be on subsequent pageloads, and just skip the popup etc.
<?php
session_start();
if ($download_key != null && !isset($_POST['popup'])) {
if ($_SESSION['key_ok']!=true) { //you should check if it's set first with isset()
echo '<script type="text/javascript">';
echo '$(document).ready(function(){';
echo 'loadPopup();';
echo '});';
echo '</script>';
}
if (key_is_correct) {$_SESSION['key_ok']=true}
}
?>