How can I refresh a page with a form on submission pending the outcome of the submitted data and display a result.
e.g I have a page with a form:
<form action="" method="post">
<input type="name" value="" name="name" placeholder="Your Name" />
<input type="button" name="submit" value="submit form "/>
</form>
The engine that handles the form is external, but required in the page:
require_once 'form_engine.php';
form_engine.php checks the input,
$success = "true";
$errorMessage = " ";
$name = $_POST['name'];
if ( $name == '') {
$errorMessage = 'Please enter your name';
$success = false;
}
else (if $success = true) {
// do something with the data
}
The form page contains the result:
<form action="" method="post">
<input type="name" value="" name="name" placeholder="Your Name" />
<input type="button" name="submit" value="submit form "/>
</form>
<p><?php echo $errorMessage; ?></p>
Will the error message get displayed after the form is submitted incorrectly? Or do I have to use a session to store it?
You need something like this:
if (!isset($_POST['name']))
instead of
if ( $name == 'name')
UPDATE
Try this, it should give you the idea:
<?php
$errorMessage = false;
if (isset($_POST['submit'])) {
if (!isset($_POST['name']) || $_POST['name']=='') {
$errorMessage = 'Please enter your name';
}
else {
// do something with the data
echo "Success!!";
}
}
?>
<form method="post">
<input type="name" value="" name="name" placeholder="Your Name" />
<input type="submit" name="submit" />
</form>
<p><?php if ($errorMessage) echo $errorMessage; ?></p>
Note: leaving out the action attribute will just submit the form to the current page
Note 2: The PHP here could very well be stored in another page. Using require() is the same as putting the code directly into the page.
You can use redirect on php side:
header('Location: www.mysite.com/index.php');
You seem to be a little confused in terms of the exact process that occurs in terms of rendering a page, as do some of those commenting. You do not need to use sessions to solve this problem. There is no need to store anything server-side between page requests because the user's browser with retain everything that you need, at least for this situation. My guess is the others took you mentioning an "external engine" and thought that the form would be submitting away to a different site/page.
form loops
Below is a diagram showing a typical form request loop:
You do not have to do this, as coding is as much about personal preference to anything else, but typically people will design their form to submit back to the same URI that generated it — as you seem to be doing in your example, by leaving the action attribute blank. By doing this, as long as you embed everything you wish to pass back to the server side within the form — each time the user submits — that information will be resent and be available in PHP.
Obviously you need to be wary of what information might constitute as sensitive, as this data should only ever be written into markup if your requests are protected by HTTPS/SSL. You should also filter/escape any user input to prevent markup injection into your site. You can prevent many problems by using htmlentities, however this can cause issues depending on the values you are trying to capture from the user. Because you are using double quoted HTML attributes (the right way to do them ;) I have not set the ENT_QUOTES option.
back to the point
So in the above loop the user will be shown the form for the first time, and after any subsequent submit, which means that each time your PHP notices that there is an error you can just add your message into the page flow. The trick with this kind of system is what exactly do you do once the form is fully complete. To get out of the loop most people will use a header location call:
<?php
require_once 'form_engine.php';
$name = !empty($_POST['name']) ? trim($_POST['name']) : '';
$name = htmlentities($name);
if ( $success ) {
header('location: next-step.php');
exit;
}
?>
<form action="" method="post">
<input type="name" value="<?php echo $name; ?>" name="name" placeholder="Your Name" />
<input type="button" name="submit" value="submit form "/>
</form>
<?php
if ( $errorMessage ) {
echo "<p>$errorMessage</p>";
}
?>
form engine repairs
You should also rectify your form_engine.php as per my comments above and Shekhar Joshi's answer, although I would keep the header code outside of your engine logic, and leave that decision to the code that requires in the engine — as the above does.
may be, you are looking for this! the header() method.
$success = true;
$errorMessage = " ";
$name = $_POST['name'];
if(isset($_POST['name'])) {
if ( $_POST['name'] == '') {
$errorMessage = 'Please enter your name';
$success = false;
header('Location: www.something.com/some.php');
}
else if ($success == true) {
// do something with the data
}
}
Related
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 want to use back option on php without losing the form data.
I've tried this way;
if ($username==""){
echo 'Please fill. <input type="button" value="Back" onClick="history.back()">';
} else{
$doaction;
}
And this way;
$url= $_SERVER['HTTP_REFERER'];
if ($username==""){
echo "Please fill.";
header("refresh: 2; url=$url");
}
else{
$doaction;
}
On both ways I lose my data. How can I make this better?
This worked for me and using ob_start(); (in PHP below) needs to be included, otherwise it will throw an error, such as:
PHP Warning: Cannot modify header information - headers already sent by (output started)
Use the following exactly as shown, then modify to suit later.
Using Sessions is a way to achieve this. Each field will re-appear in the input boxes, if they were filled.
HTML form (form.php)
<?php
session_start();
?>
<form method="post" action="submitted.php">
<p>
<label for='name'>Your Name:</label>
<br>
<input type="text" name="username" value="<?php echo isset($_SESSION['username']) ? $_SESSION['username'] : '' ?>">
</p>
<p>
<label for='name'>Email:</label>
<br>
<input type="text" name="email" value="<?php echo isset($_SESSION['email']) ? $_SESSION['email'] : '' ?>">
</p>
<input type="submit" name="submit" value="Submit">
<br>
</form>
PHP (submitted.php)
<?php
ob_start();
session_start();
$_SESSION['username'] = $_POST['username'];
$_SESSION['email'] = $_POST['email'];
$url= $_SERVER['HTTP_REFERER'];
$username=$_POST['username'];
$email=$_POST['email'];
// use this one below, if you want to check more than one field
// if (empty($_POST['username']) || empty($_POST['email']) ){
if (empty($_POST['username'])){
echo "Fill in all fields.";
header("refresh: 2; url=$url");
}
else{
echo "OK, redirecting back to show fields are showing, or not.";
header("refresh: 2; url=$url");
}
Your approach reloads the formular, so the webserver will send a clean form to the client. If you want a prefilled form you will have to use a PHP script which knows the formerly filled in values and creates a prefilled form.
In the code you have used, (assuming you have a form further up) there is no data being passed between the pages because nothing is telling the script to transfer the data between that page and it's destination.
In your first example, history.back() simply tells the browser to go back to the last page viewed before the current one. In your second example, your header line essentially just tells the browser to go back to the previous page after two seconds.
To keep data between page transfers, without any further knowledge of what you're doing, I would suggest using JavaScript to fetch your form data and pass it into a URL used in a window.location call (forming a GET request with your form data in it), OR by using javascript to set a cookie containing the data input before you tell the browser to switch page.
In the first solution, you could then use php's $_GET global to access your form data.
In the second solution, you could use javascript to re-populate the form on page load (or at will)
I have two input fields and whenever I open my page, it displays errors since at the start user has not entered any input to any of the field (& the errors are displayed because the user input is used in sql queries to retrieve data).
I just want to display those two forms at start of the page not the errors.
Both inputs are required to execute the Compare button. If user has not entered either one of the inputs it should not send request to php for scripting.
I mean the Compare button should send request only if both inputs are filled otherwise it should give a message to user to Type the required fields.
How to do this?
$trimUser= trim ($_POST['name']);
if(empty($name) || empty($name2))
{
echo "Enter a name ";
}
else if (isset($_POST['name']))
{
$name=$_POST['name'];
}
else if (isset($_POST['name2']))
{
$name2=$_POST['name2'];
}
& here is my form:
<form action="index.php" method="POST">
<input class="span3 search-query" placeholder="Type User A" type="text" name="name" id="field"/
<input class="span3 search-query" placeholder="Type User B" name="name2" type="text"
id="field2"/>
<button class="btn btn-primary" data-loading-text="Loading..." >Compare</button>
You have to use java script or jQuery for validate both fields are not empty. For Example..
<form action="index.php" method="POST" onsubmit="return validate()">
<input class="span3 search-query" placeholder="Type User A" type="text" name="name" id="field"/>
<input class="span3 search-query" placeholder="Type User B" name="name2" type="text"
id="field2"/>
<button class="btn btn-primary" data-loading-text="Loading..." >Compare</button>
</form>
<script type="text/javascript">
function validate(){
var field1 = document.getElementById('field').value;
var field2 = document.getElementById('field2').value;
if(field1 != '' && field2 != '' ){
return true;
} else{
alert('Type the required fields');
return false;
}
}
</script>
Here if Both fields are not empty then it will be allow to submit form. And In PHP script Add
if(isset($_POST) && !empty($_POST)){
//code comes here
}
I hope it will be helpful for you.
thanks
You can add a check to verify if the request is a post request :
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Place your error checking code here
}
Ehs4n is right, but I would be more specific and do something like :
if(!empty($_POST['compare'])) {
#validation
}
Your button code would have to be changed to :
<button name="compare" value="1" class="btn btn-primary" data-loading-text="Loading..." >Compare</button>
There are two reasons I would do this:
Using !empty() makes sure you don't get an error when $_POST['compare'] is empty
Checking $_POST['compare'] instead of just $_POST makes sure errors are only shown if someone clicks the button.
This last point is key because if you have multiple forms on the page or you happen to set a $_POST variable elsewhere you would still be showing errors.
Use the if condition with isset($_POST) before loading the post.i.e.,
if (isset($_POST)) {
if(empty($name) || empty($name2))
{
echo "Enter a name ";
}
else if (isset($_POST['name']))
{
$name=$_POST['name'];
}
else if (isset($_POST['name2']))
{
$name2=$_POST['name2'];
}
I simply got rid all of all the errors by adding this error_reporting(E_ERROR | E_PARSE); at the start of my code.
However if anyone want to check display validation error messages , one can do easily by what others have mentioned . i.e By using if($_Post).
Anyway ,Thank you everyone for the help.
Add if clause like
if($_POST) {
...your validation code
}
Think of redirecting people AFTER the error to the same page they were:
echo '<script>location.href=\'example.php\'</script>';
I have an email form that checks three fields, name, valid email and comments. But the way it's set up now, since name and comments are in one function it first checks name and comments even if email is not valid, how can I re-write it so it checks the fields in order. Also, I would like to re-display the fields that have no errors, so the user doesn't have to type again. Please help. Thanks
<?php
$myemail = "comments#myemail.com";
$yourname = check_input($_POST['yourname'], "Enter your name!");
$email = check_input($_POST['email']);
$phone = check_input($_POST['phone']);
$subject = check_input($_POST['subject']);
$comments = check_input($_POST['comments'], "Write your comments!");
if (!preg_match("/([\w\-]+\#[\w\-]+\.[\w\-]+)/", $email))
{
show_error("Enter a valid E-mail address!");
}
exit();
function check_input($data, $problem='')
{
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
if ($problem && strlen($data) == 0)
{
show_error($problem);
}
return $data;
}
function show_error($myError)
{
?>
<!doctype html>
<html>
<body>
<form action="myform.php" method="post">
<p style="color: red;"><b>Please correct the following error:</b><br />
<?php echo $myError; ?></p>
<p>Name: <input type="text" name="yourname" /></P>
<P>Email: <input type="text" name="email" /></p>
<P>Phone: <input type="text" name="phone" /></p><br />
<P>Subject: <input type="text" style="width:75%;" name="subject" /></p>
<p>Comments:<br />
<textarea name="comments" rows="10" cols="50" style="width: 100%;"></textarea></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
<?php
exit();
}
?>
First off, I would suggest you validate ALL of the fields at once, and display all appropriate error messages on the form. The primary reason is that it can be bad user experience if they have to submit your form a whole bunch of times because they have to address one error at a time. I'd rather correct my email address, password, comments, and selection in one try instead of fixing one at a time just to reveal what the next error is.
That said, here are some pointers on validating the form like you want. This is typically how I approach a form doing what you want to do. This assumes your form HTML and form processor (PHP) are together in the same file (which is what you have now). You can split the two, but the methods for doing that can be a bit different.
Have one function or code block that outputs the form and is aware of your error messages and has access to the previous form input (if any). Typically, this can be left outside of a function and can be the last block of code in your PHP script.
Set up an array for error messages (e.g. $errors = array()). When this array is empty, you know there were no errors with the submission
Check to see if the form was submitted near the top of your script before the form is output.
If the form was submitted, validate each field one at a time, if a field contained an error, add the error message to the $errors array (e.g. $errors['password'] = 'Passwords must be at least 8 characters long';)
To re-populate the form inputs with the previous values, you have to store the entered values somewhere (you can either just use the $_POST array, or sanitize and assign the $_POST values to individual variables or an array.
Once all the processing is done, you can check for any errors to decide whether the form can be processed at this point, or needs new input from the user.
To do this, I typically do something like if (sizeof($errors) > 0) { // show messages } else { // process form }
If you are re-displaying the form, you simply need to add a value="" attribute to each form element and echo the value that was submitted by the user. It is very important to escape the output using htmlspecialchars() or similar functions
With those things in place, here is some re-work of your form to do that:
<?php
$myemail = "comments#myemail.com";
$errors = array();
$values = array();
$errmsg = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
foreach($_POST as $key => $value) {
$values[$key] = trim(stripslashes($value)); // basic input filter
}
if (check_input($values['yourname']) == false) {
$errors['yourname'] = 'Enter your name!';
}
if (check_input($values['email']) == false) {
$errors['email'] = 'Please enter your email address.';
} else if (!preg_match('/([\w\-]+\#[\w\-]+\.[\w\-]+)/', $values['email'])) {
$errors['email'] = 'Invalid email address format.';
}
if (check_input($values['comments']) == false) {
$errors['comments'] = 'Write your comments!';
}
if (sizeof($errors) == 0) {
// you can process your for here and redirect or show a success message
$values = array(); // empty values array
echo "Form was OK! Good to process...<br />";
} else {
// one or more errors
foreach($errors as $error) {
$errmsg .= $error . '<br />';
}
}
}
function check_input($input) {
if (strlen($input) == 0) {
return false;
} else {
// TODO: other checks?
return true;
}
}
?>
<!doctype html>
<html>
<body>
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post">
<?php if ($errmsg != ''): ?>
<p style="color: red;"><b>Please correct the following errors:</b><br />
<?php echo $errmsg; ?>
</p>
<?php endif; ?>
<p>Name: <input type="text" name="yourname" value="<?php echo htmlspecialchars(#$values['yourname']) ?>" /></P>
<P>Email: <input type="text" name="email" value="<?php echo htmlspecialchars(#$values['email']) ?>" /></p>
<P>Phone: <input type="text" name="phone" value="<?php echo htmlspecialchars(#$values['phone']) ?>"/></p><br />
<P>Subject: <input type="text" style="width:75%;" name="subject" value="<?php echo htmlspecialchars(#$values['subject']) ?>" /></p>
<p>Comments:<br />
<textarea name="comments" rows="10" cols="50" style="width: 100%;"><?php echo htmlspecialchars(#$values['comments']) ?></textarea></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
I have a more advanced example which you can see here that may give you some guidance as well.
Hope that helps.
The simplest option is to use a form validation library. PHP's filter extension, for example, offers validation and sanitization for some types, though it's not a complete solution.
If you insist on implementing it yourself, one issue you'll have to consider is what counts as the order: the order of the elements in the form or the order of the user input in $_POST. On most browsers, these should be the same, but there's no standard that enforces this. If you want to go off of form order, you'll need to define the form structure in one place, and use that information to do things like generating or validating the form (a consequence of the Don't Repeat Yourself (DRY) principle). Iterating over the appropriate structure will give you the order you desire: looping over the form gives you form order, whereas looping over $_POST gives you user input order.
It looks like you want to more than simply validate the data; you also want to prepare it for use, a process called "sanitization".
When it comes to sanitization, define different kinds of sanitizers, rather than a single check_input function. Specific sanitizers could be functions, or objects with an __invoke method. Create a map of form fields to sanitizers (for example, an array of input name to sanitizer callbacks). The order of the elements in the mapping sets the order of the sanitization; if you use a single structure to define the form information, the display order and sanitization order will thus be the same.
Here's a very broad outline:
# $fields could be form structure or user input
foreach ($fields as $name => $data) {
# sanitize dispatches to the appropriate sanitizer for the given field name
$form->sanitize($name, $data);
# or:
//sanitize($name, $data);
# or however you choose to structure your sanitization dispatch mechanism
}
As for setting an input's value to the user-supplied data, simply output the element value when outputting the element. As with all user input (really, all formatted output), properly escape the data when outputting it. For HTML attributes, this means using (e.g.) htmlspecialchars. Note you should only escape outgoing data. This means your sanitization functions shouldn't call htmlspecialchars.
You can improve usability by placing each error next to the corresponding input, adding an "error" class to the element and styling the "error" class to make it stand out. Improve accessibility by wrapping <label> elements around the label text.
Use this structure of script:
<?php
$errors = array();
if (isset($_POST['send'])) {
// check data validity
if (!mailValid($_POST['email']))
$errors[] = 'Mail is not valid';
...
// send data by email
if (!$errors) {
// send mail and redirect
}
}
?>
<html>
...
<?php
if ($errors) {
// display errors
foreach ($errors as $error) {
echo "$error<br />";
}
}
?>
<form ...>
...
Email: <input type="text" name="email" value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : '' ?>" />
...
</form>
...
</html>
You could always do it like this, using filter_var and in_array checks:
<?php
$myemail = "comments#myemail.com";
//Pre made errors array
$errors=array('name'=>'Enter Your name',
'email'=>'Please enter valid email',
'phone'=>'Please enter valid phone number',
'subject'=>'Please enter valid subject, more then 10 chars',
'comment'=>'Please enter valid comment, more then 10 chars');
//Allowed post params and its validation type
$types = array('name'=>'string',
'email'=>'email',
'phone'=>'phone',
'subject'=>'string',
'comment'=>'string');
//A simple validation function using filter_var
function validate($value,$type){
switch ($type){
case "email":
return ((filter_var($value, FILTER_VALIDATE_EMAIL))?true:false);
break;
case "phone":
return ((preg_match("/^[0-9]{3}-[0-9]{4}-[0-9]{4}$/", $value))?true:false);
break;
case "string":
return ((strlen($value) >=10 )?true:false);
break;
default:
return false;
break;
}
}
//If forms been posted
if(!empty($_POST) && $_SERVER['REQUEST_METHOD'] == 'POST'){
//Assign true, if all is good then this will still be true
$cont=true;
$error=array();
foreach($_POST as $key=>$value){
//if key is in $types array
if(in_array($key,$types)){
//If validation true
if(validate($value, $types[$key])==true){
$$key=filter_var($value, FILTER_SANITIZE_STRING);
}else{
//Validation failed assign error and swithc cont to false
$error[$key]=$errors[$key];
$cont=false;
}
}
}
}
if($cont==true && empty($error)){
//Send mail / do insert ect
}else{
//Default to form
?>
<!doctype html>
<html>
<body>
<form action="" method="post">
<p>Name: <input type="text" name="name" value="<?=#htmlentities($name);?>"/> <?=#$error['name'];?></P>
<P>Email: <input type="text" name="email" value="<?=#htmlentities($email);?>" /> <?=#$error['email'];?></p>
<P>Phone: <input type="text" name="phone" value="<?=#htmlentities($phone);?>"/> <?=#$error['phone'];?></p><br />
<P>Subject: <input type="text" style="width:75%;" name="subject" /> <?=#$error['subject'];?></p>
<p>Comments: <?=#$error['comment'];?><br />
<textarea name="comment" rows="10" cols="50" style="width: 100%;"><?=#htmlentities($comment);?></textarea></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
<?php
}?>
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";
}