I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
Since application is built in such way that going Back is a quite common operation, this is really annoying to end users.
Basically, I would like to do it the way this page does:
http://www.pikanya.net/testcache/
Enter something, submit, and click Back button. No warning, it just goes back.
Googling I found out that this might be a bug in Firefox 3, but I'd like to somehow get this behavior even after they "fix" it.
I guess it could be doable with some HTTP headers, but which exactly?
See my golden rule of web programming here:
Stop data inserting into a database twice
It says: “Never ever respond with a body to a POST-request. Always do the work, and then respond with a Location: header to redirect to the updated page so that browser requests it with GET”
If browser ever asks user about re-POST, your web app is broken. User should not ever see this question.
One way round it is to redirect the POST to a page which redirects to a GET - see Post/Redirect/Get on wikipedia.
Say your POST is 4K of form data. Presumably your server does something with that data rather than just displaying it once and throwing it away, such as saving it in a database. Keep doing that, or if it's a huge search form create a temporary copy of it in a database that gets purged after a few days or on a LRU basis when a space limit is used. Now create a representation of the data which can be accessed using GET. If it's temporary, generate an ID for it and use that as the URL; if it's a permanent set of data it probably has an ID or something that can be used for the URL. At the worst case, an algorithm like tiny url uses can collapse a big URL to a much smaller one. Redirect the POST to GET the representation of the data.
As a historical note, this technique was established practice in 1995.
One way to avoid that warning/behavior is to do the POST via AJAX, then send the user to another page (or not) separately.
I have been using the Session variable to help in this situation. Here's the method I use that has been working great for me for years:
//If there's something in the POST, move it to the session and then redirect right back to where we are
if ($_POST) {
$_SESSION['POST']=$_POST;
redirect($_SERVER["REQUEST_URI"]);
}
//If there's something in the SESSION POST, move it back to the POST and clear the SESSION POST
if ($_SESSION['POST']) {
$_POST=$_SESSION['POST'];
unset($_SESSION['POST']);
}
Technically you don't even need to put it back into a variable called $_POST. But it helps me in keeping track of what data has come from where.
I have an application that supplies long list of parameters to a web page, so I have to use POST instead of GET. The problem is that when page gets displayed and user clicks the Back button, Firefox shows up a warning:
Your reasoning is wrong. If the request is without side effects, it should be GET. If it has side effects, it should be POST. The choice should not be based on the number of parameters you need to pass.
As another solution you may stop to use redirecting at all.
You may process and render the processing result at once with no POST confirmation alert. You should just manipulate the browser history object:
history.replaceState("", "", "/the/result/page")
See full or short answers
Related
I am working on a my site to allow users to take test so they can see how much they know of a particular subject. I am running into a little problem though. Once a user submits the test for grading, how do I prevent them from going back to the test page? I am on a Mac with Safari running and when I click the back button in my web browser after I submit the test it leaves all of the answers I answered filled out. I want it do this: When a user submits a test and they click the back button in their web browser it redirects them to the main test page.
I am using PHP and MYSQL. I even have the test pages setup so that the user must come from a certain url (I am using HTTP_REFERER) and I have tried other stuff such as sessions but I cannot seem to figure this out. Any help is greatly appreciated.
You don't stop them.
Instead change your application so that it still works even if they go back. You can embed a unique number in a hidden field on the page and if they resubmit the same test twice you can detect it and display an appropriate error message. You should also think about what should happen if they modify the unique number.
If you don't want people to post different answers once they have already answered, all you have to do is check, in the script that accepts the test for grading, that the user has never submitted the test before. If you don't, a clever student will always be able to to circumvent your protection by sending an appropriate request directly to that script.
If you don't want people to see previous answers (for instance, if you have two people grade their tests on the same computer), consider using AJAX on the test page to submit the answers and then erase them from the fields. This way, most browsers will not remember the answers and the back button will not un-erase data that was erased by JavaScript.
At the top of the grade page, put the following:
session_start();
$_SESSION['testcomplete'] = 'yes';
Then at the top of each page of the test, put this:
session_start()
if ($_SESSION['testcomplete'] == 'yes') {
header("Location:cheater.php");
}
You could simulate there being no page to go back to. From one page, generate each test page using jQuery, and provide no way to go back, only forward. The back button would take them to the page before they ever launched the test, and you could allow them to launch the test again and generate the right part where they should be. This would be pretty easy, if you haven't gone too far in development the current way.
You could run javascript that clears out all the answers. You might also just allow one submission so that subsequent submissions don't get processed. HTTP_REFERER is usually sent, but can be spoofed and forged by an altered browser.
On the top of the script POST-ing the answers, do a check whether you have the test results in the database for the current user for this test. If you do, redirect to results.
if(get_test_results($user)){
$test_url = get_test_url($user);
header( "Location: $test_url" ) ;
}
Disabling the back button is not a good idea.
I was facing a similar problem making an online examination myself
what I did is
I provided a session variable such that if the user pastes the previous page's URL in the address bar then on loading the page the page is automatically forwards to the next desired page. Whether the page whose URL was mentioned is the being visited the first time or being revisited is determined by the value of the session variable
If the user instead of loading the page does a go back via the browser button the it automatically redirects to the next page in history as :
javascript:window.history.forward(1);
Hope this helps :)
http://www.htmlgoodies.com/tutorials/buttons/article.php/3478911/Disabling-the-Back-Button.htm you should be able to do it in javascript.
I am using Laravel 5.2.15.
There are list of records in a webpage with Edit and Delete button with each record. I have two approaches for deleting the record
Use JQuery and send Ajax Request to server.
Place a form tag for delete button in each row.
I have following question
In case I use Approach 1, can it cause any issue when the site will be viewed from Android or iPhone? I have another option to do Server side validation using Request class.
In case of Approach 2, Will it make the page heavy? I am using Pagination, so 10 records will be displaced per page.
Please guide me if I should go with which approach or please suggest if both approaches are incorrect.
The questions you have don't really focus on the main reasons to choose one above the other. They differ mostly in how the request is sent to the server and how the page is refreshed to show the results.
Using Ajax is a very common approach and relies on using Javascript, a technology that has been available in all browsers for a very long time. Compatibility will not be a problem as most of the internet wouldn't function without it anyways (and you can even make it work using your second approach as a fallback mechanism). The request you sent is typically a HTTP DELETE request to a REST endpoint so that the server then knows to delete the record1. Upon receiving the success response from the server the page is responsible for updating itself by removing the row corresponding with the just deleted record, and possibly fetching new records to still have 10 rows on that page. No page refreshes required, but some Javascript required.
Your second approach is kind of old school in that the form you submit contains some kind of identifier such that the server knows what to do. This is a full page load and should be a HTTP POST request if you want to do it properly2. Following the Post/Redirect/Get idiom the server then sends a Redirect response so that the browser will then trigger yet another normal page load as GET request to show the user the updated list of records. You do not have to update the page manually by yourself, at the cost of having annoying page reloads (this isn't really expected anymore in the current day and age).
My advise would be to go with the first approach. It is the modern way of doing things and allows for having non-reloading pages. It does however require some additional work on the client side (in Javascript) to update the page accordingly.
As a side note, CSRF must be taken care of in both instances really. Always include a CSRF token with every 'update' action you perform on the server.
1 You have to program this yourself, of course :)
2 Browsers don't generally support anything other than GET and POST, although the HTTP specification allows for much more request methods.
It depends upon your requirements. But you should go with the 1st approch. If you will use 2nd approch the you will have to refresh the page since you can not handle the response. So basically if you delete 5 items the page needs to be refreshed 5 times and you may not send more than 1 delete request at a time. Now If you use 1st approch since It's ajax and javascript you can display appropriate message depending upon the result and no need of unnecessary page refresh.Plus as you mentioned you can do validaton using Request class. So you can handle bad or malicious request. And I am sure CSRF won't be that much of a problem since you can check whether the request is ajax or not using Request::ajax(). So 1st approch is better mostly because of that no page refresh.
Both approaches are fine ;)
But 2nd approach would be better than first one; Using this approach you can prevent CSRF attacks too;
I would suggest you to use method 1 with certain modifications.
Use get request to delete the record.
Send a CSRF token and dont forget to encrypt your id for the record
add your delete URL to href
Then when you do ajax request, use the url from href and you could send some additional parameter like is_ajax=1, but laravel already checks for the jquery header so Request::isAjax() method will let you know if the request was an ajax request or normal request.
Now all you need to do is send different response for ajax and normal request.
HOPE THIS HELPS :D
Another drawback of your second approach which haven't been mentioned is displaying validation errors. Specifically from your edit and even your delete actions.
If you have multiple forms for each set of data showing errors from validation would be a pain. But if you follow approach number 2 just by getting the reference of the row element submitted, you could easily append an alert div if ever an error from validation has occurred.
as for the delete action, somebody else might have already delete some shared data so you might also want to tell the user somebody already threw this out.
so I've hit a potential problem in my site....it's a post-based system, with the posts being in text files. Uses some Javascript and a lot of PHP.
When you make a submission on the form on the homepage, you are sent to a page where data is posted and processed, but you don't see it because you get redirected back. Then the homepage is changed based on what the post you made says. All that was working fine.
But now I'm trying to add a new feature that modifies the post you made, based on a button you hit which submits a hidden form using javascript, and sends to another process and redirect page you don't see, and it works fine until the block that I realized today. I don't know how to specify that the post being altered is the right one.
I anticipate a good amount of users of this site, so my concern is what if user X makes a post while user Y is making a post, and the post of user X becomes the top post, so user Y's options actually change user X's post.....
I was thinking of adding to the main processing page (the one that happens when you first submit) a COOKIE or something that would make note of the number of the line that post will become, by counting the number of the lines in that file at the time and adding 1 to it. Then checking it against the user's number (each user has a number) to see if it's that user's most recent post....but the problem is I don't know how I would pass that value around to be read in the next page.
Setting a COOKIE is out I think because the page both redirects, AND reads and writes to files. The only output to the page though are currently var_dumps.
POST/GET is out because to my knowledge the user would have to do SOMETHING to submit it, and the user's not even going to see the page.
Writing to a file would be messy if lots of users are trying to get their own data.
I think what I may be looking for is SESSION variables...but I don't know anything about those except that they're used to login to pages, and this site has no login.
To make things more fun, when a user posts the same content within a minute of another user, the first user's post is replaced and it gets a little +1 next to it...which makes it harder to check it against the user's number....
AND in the end I'm trying to use AJAX (which I dont know yet) to make the updates in real-time...now THAT is going to suck. But for now I'm worried about my static little site.
Baby steps.
Any ideas how to go about this??
Use Session variables, just as you have alluded. They aren't just used by login pages, they are used by everything. Sessions are the equivalent of server-side cookies / server-side storage, so you don't have to worry (as much) about your users tampering with them.
If you want to make life more difficult for yourself, you can json encode your variables and store them as an object in a database or even flat text file. But really, read up on sessions.
All you need to know is session_start(); before anything else then $_SESSION['var']=$yourvar; to save data and $_SESSION['yourvar'] to retrieve it later (such as on another page).
In my days of writing web applications, I'm missing a simple way for a PHP script to direct to another PHP script while passing along data without using the URL
Browsers can pass data invisibly to a PHP script using the $_POST array. So I'm devising a script that will dump the contents of $_SESSION["POST"] into the $_POST array to mimic the passing of post data, then clears $_SESSION["POST"].
For instance, a page X contains a login form. Page X directs to page Y to validate the data. Page Y discovers that the login information is incorrect, and redirects back to page X - which now displays the error message "Login information incorrect" from $_POST.
Am I crazy for missing this feature? Is there some other method of doing this easily that I'm missing?
Please respond with anything that can be helpful.
You could use the session. On page X, you'd put the data into the session. On page Y, you'd validate the data and handle the redirect. You can put your error message into the session too.
The session persists between requests, so it's the perfect place to store that kind of data.
EDIT
OK, I'd do things with session variables, but if you want to avoid that you do have a few other options I can think of besides posting:
You can use files on the server (such as temporary files). Use the user's session key to identify which file is theirs, and you can read and write whatever data you care to it.
You can put the data in a database. That would work too.
Of course neither of those is a true post. If you want a true post, you have another two options.
First, you can return the data to the page in a hidden form, and use JavaScript to trigger a POST. This is simple to do, but it requires the data to pass through the browser. This means you'd have to take care that a user didn't change the data, and the user would have to have JavaScript on. You can checksum the data to ensure it isn't modified, but the JavaScript problem is unsolvable.
Another way to do it would be to take the user out of the equation entirely. When the user submits to page A, page A could make a POST to page B, check the response, and then redirect the user to the proper place. This would be just like if you had to make a JSON or SOAP call to a 3rd party service, except you control that service. It's been a little while, but I believe that HttpRequest is the class to use to do this.
It would be ideal if that URL you check with returns a simple answer ("true", "false", "yes", "no", "good", "bad", whatever), but as long as you can tell by the response whether they were successful or not, you can do it.
Now I should note that I'd agree with mvds, this sounds like a function that should be included in page A so that it can do all the work but the code can be shared with other pages. Having page A post to page B and then redirect to A or C seems unnecessarily complex. Page A can easily accomplish all this. I read your comment on his answer, but it seems there should be another way to accomplish this.
Abstract the performed actions to functions and/or classes, and the need for such kludges will vanish. Concrete: both page X and Y could call the same function to validate the posted login data.
Page X redirecting to page Y to do validation means handing back control to the client, while you could (and should) validate the data right away.
I am doing my work in PHP.
I have 3 pages,
A is plain HTML and contains a search field.
B is .php and returns results of the search.
C is also php and allows user to update some details for the displayed results.
When I'm doing Refresh my B page or Go-Back from C to then I
get this message
"To display this page, Firefox must
send information that will repeat any
action (such as a search or order
confirmation) that was performed
earlier."
I saw "When i'm using "POST" method then I get this message, if I'm used GET then
I don't.
Any buddy Explain me ,why???
The GET method should be used to obtain information from a web page.
The POST method should be used to send information to a web page.
The reason it asks you to confirm whether or not to send information again is because it's not always the user's intention to repost a form if they press back. One example is at an online store, you would not want to repost a form to purchase a product twice, otherwise you could be billed for the product twice. This is theoretical of course since someone who makes an online store should ensure that an accidental purchase can't happen.
Also, if you use GET, then all information is appended to the URL of the PHP page. This is a potential security issue, especially if the form contents are private. For such forms, you should be using POST.
A wild guess,
POST is not written in the URL, so you need to resend it, while GET, when you click to return to B, the arguments are still in the URL so you dont need to resend.
Mozilla added this message to warn you from sending the information twice.
Like in the form of registration, you don't want to register twice.
Firefox developers added that warning for POST method. It will warn you for POST in case of back/forward also.
This is an added safeguard for users. Because, most shopping carts/banking portals use POST method for checkout/transaction confirmation (actually I have not seen or developed any web app to use get method for this purpose).
So, Firefox (and most other common browsers) warn you in this scenario (when your are sending POST request indirectly, i.e. using back/forward/refresh button). This prevents the user from multiple checkout.
Another reason to add this warning is, sometimes chekout is time consuming. So, when some time is passed after the original submission, some impatient users think that the browser/server has stopped working. So, they tend to press the refresh button. This warning gives them a good hint.
I think the point is that GET requests should be used to get information without changing anything on the server so if you reload the same information there's no issue. POST requests should be used to change data on the server so when you reload the page that may have undesirable effects.
Firefox should normally allow you to navigate back to your B page from your C page. However if your B page is not in the cache, possibly because it sends a Cache-control: no-store header, then you will get the POSTDATA warning.
On the other hand explicitly reloading page B will always generate a POSTDATA warning.
When you submit data in the POST method, it sends headers to the page you submit to. When you refresh the page or go back, your browser repeats your POST request and Firefox warns you of this.