I have two simple HTML form buttons that call PHP functions to send emails now. Everything works fine except for one thing. If one of the buttons is clicked to send a report, and then the page is refreshed, the function seemed to be called again and the emails well go out again with a page refresh by a user using a browser refresh button.
If the page is refreshed, the email will go out again for the last button clicked. So, if I click on Button 1 and then refresh the page, I will get two reports for button 1. If I click on button #1, and then click on Button #2, only the second report will go out. If I click on button #2 and then #1, only Report #1 will go out again.
So, no matter how many buttons are clicked, refreshing the page will cause the last button click (only to repeat). Trying to unset the request parameter (in code below) has no effect all on the repeats caused by a page refresh.
I don't understand why (on a Page Refresh) the page is seeing the last button click made as set, and why the unset command is not working.
Thanks for any help.
if( isset( $_REQUEST['email_this_weeks_report'] )) {
unset($_REQUEST['email_last_weeks_report']);
#send email now email code for this week
}
if( isset( $_REQUEST['email_last_weeks_report'] )) {
unset($_REQUEST['email_last_weeks_report']);
#send email now email code for last week
}
<form>
<input class="ui-button ui-widget ui-corner-all" type="submit"
name="email_this_weeks_report" value="Email This Weeks Report Now" />
</form>
<form>
<input class="ui-button ui-widget ui-corner-all" type="submit"
name="email_last_weeks_report" value="Email Last Weeks Report Now" />
</form>
Clicking the button submits the form.
The data in the form is bundled up and included in the request.
Aside: You're using method=GET
, the default, but you're not making a "safe" request. You are doing something, not just getting information. You should use a POST request.
When you click refresh, you tell the browser to make the request again and display a new version of the page.
Since the request includes the query string which says "send a particular email", it sends that email again.
Unsetting values in $_REQUEST
has no effect because when the browser makes a new request with the same data in it: $_REQUEST
just gets filled up again.
You should deal with this by using the PRG pattern:
method=POST
Change
<form>
To
<form method='POST'>
A simple way to prevent multiple submissions is to add a random token to the form in a hidden input.
<input type='hidden' name='formtoken' value='<?= uniqueid() ?>'/>
Every time the page is fetched from the server, the value of this hidden variable will change. So on the server side, you can prevent the same form being resubmitted by checking whether a form with this unique ID has been submitted before.
session_start();
$sessionToken = $_SESSION['formtoken']? : null;
$currentToken = $_POST['formtoken']? : null;
// If no session token yet: form has never been submitted
if(!$sessionToken):
// save the current token in session so we'll recognize it next time
$_SESSION['formtoken'] = $currentToken;
/* ok to send the email */
// ElseIf current token was already used: Duplicate form submission
elseif($sessionToken === $currentToken):
/* don't send the email!*/
// Else session token exists, but current token is new: User fetched a new form from server
else:
// update the session token
$_SESSION['formtoken'] = $currentToken;
/* ok to send the email */
endif;
When the user refreshes, the browser will ask if she wants to re-submit the form. If she does, you will know because the current token and the session token will be the same. It's up to you to decide how to handle it.
Refreshing a page with a GET or a POST form will resubmit the data (albeit it will ask you first in the POST scenario, which you should use by the way).
Try redirecting the user after form submit
if( isset(...) ){
// Do your logic
header('Location: https://you_site.com/your-form-page?thank-you');
exit;
}
This must be done before anything else is outputted on the page.