Understanding the "post/redirect/get" pattern - php

I am having a very hard time understanding the exact process of "post/redirect/get".
I have combed through this site and the web for several hours and cannot find anything other than "here's the concept".
How to understand the post/redirect/get pattern?

Wikipedia explains this so well!
The Problem
The Solution

As you may know from your research, POST-redirect-GET looks like this:
The client gets a page with a form.
The form POSTs to the server.
The server performs the action, and then redirects to another page.
The client follows the redirect.
For example, say we have this structure of the website:
/posts (shows a list of posts and a link to "add post")
/<id> (view a particular post)
/create (if requested with the GET method, returns a form posting to itself; if it's a POST request, creates the post and redirects to the /<id> endpoint)
/posts itself isn't really relevant to this particular pattern, so I'll leave it out.
/posts/<id> might be implemented like this:
Find the post with that ID in the database.
Render a template with the content of that post.
/posts/create might be implemented like this:
If the request is a GET request:
Show an empty form with the target set to itself and the method set to POST.
If the request is a POST request:
Validate the fields.
If there are invalid fields, show the form again with errors indicated.
Otherwise, if all fields are valid:
Add the post to the database.
Redirect to /posts/<id> (where <id> is returned from the call to the database)

I'll try explaining it. Maybe the different perspective does the trick for you.
With PRG the browser ends up making two requests. The first request is a POST request and is typically used to modify data. The server responds with a Location header in the response and no HTML in the body. This causes the browser to be redirected to a new URL. The browser then makes a GET request to the new URL which responds with HTML content which the browser renders.
I'll try to explain why PRG should be used. The GET method is never supposed to modify data. When a user clicks a link the browser or proxy server may return a cached response and not send the request to the server; this means the data wasn't modified when you wanted it to be modified. Also, a POST request shouldn't be used to return data because if the user wants to just get a fresh copy of the data they're forced to re-execute the request which will make the server modify the data again. This is why the browser will give you that vague dialog asking you if you are sure you want to re-send the request and possibly modify data a second time or send an e-mail a second time.
PRG is a combination of POST and GET that uses each for what they are intended to be used for.

Just so people can see a code example (this is using express):
app.post('/data', function(req, res) {
data = req.body; //do stuff with data
res.redirect('public/db.html');
});
So to clarify, it instantly refreshes the webpage and so on refresh of that webpage (e.g. if you updated an element on it) it won't repost the form data.
My code used to look like this:
app.post('/data', function(req, res) {
data = req.body;
res.sendFile('public/db.html');
});
So here the response is sending the html file at the /data address. So in the address bar, after pressing the submit button it would say for me: localhost:8080/data.
But this means that on refresh of that page, if you have just submitted the form, it will submit it again. And you don't want the same form submitted twice in your database. So redirecting it to the webpage (res.redirect) instead of sending the file (res.sendFile) , stops the resubmission of that form.

It is all a matter of concept, there is no much more to understand :
POST is for the client to send data to the server
GET is for the client to request data from the server
So, conceptually, there is no sense for the server to answer with a resource data on a POST request, that's why there is a redirection to the (usually) same resource that has been created/updated. So, if POST is successful, the server opiniates that the client would want to fetch the fresh data, thus informing it to make a GET on it.

Related

How to forward (not redirect) requests in PHP?

I am working on a simple PHP site that involves needing to be able to forward a request made by the user to another page (note that I said forward, and not redirect). I am aware of how to redirect by manipulating the header variable, but I do not wish to do this, as explained below.
I am trying to write a very simple MVC-patterned mailing list app in PHP, drawing from my knowledge of the same in JSP. One of the things that I appreciated about JSP was that you could both forward or redirect a request. For my purposes, I need forward as I wish to keep the request parameters (whereas redirect will drop them).
Here is a description of what I wish to accomplish:
Retrieve input from a form (ie. /add.php)
Process the input in the page called by the form's action (ie. /process.php) and add a success message to the request object
Forward to another page (ie. /display.php) to display the success message in the request object
The only way I am aware of passing the request message to display is to add it to the request object and then access it from the forwarded page. However, the only way I have had success in transitioning to another page is through using the header method, which drops the request object (from what I can tell). I want to find a way to forward the request (object) to the new page, so that I can access the request variables from the new page.
Is there actually anyway to do this in PHP? Java's getRequestDispatcher.forward() is so nice, but I can't find an equivalent through searching. I've tried several similar questions, including the following, but I've never actually found one where both the question and the answer were what I wanted. Most of the answers seem to have something to do with cURL, but I don't want to actually retrieve a file, but simply forward a request in order to access the request object from another page.
Does PHP have an equivalent of Java's getRequestDispatcher.forward()?
Let me know if I should include anything else?
I believe you can do this with include. Before submitting the form just use, as inclusion, in main page:
include ("add.php"); - where the input forms are
after processing the information, include the display.php in the same way; using this, display.php will use same parameters from header, because is included in the same main page.
briefly: add.php, process.php and display.php will be modules for the mother page, but loaded in different state of form processing.
Hope it helps!
use curl with different method get,post. it will sent a request and also get back the response.
The most common method I see of passing messages to the end user from page to page is called session flashing.
This is when you store a variable temporarily in the session until it is read.
Assuming you already have sessions in use:
On process.php:
$_SESSION['message'] = 'Your data has been saved!';
On display.php:
if (isset($_SESSION['message'])) {
echo $_SESSION['message'];
unset($_SESSION['message']);
}
You could also store the entire Request object in the session.
So if I am aware, PHP provides just basic set of tools in this case. And there is nothing like "forward" in HTTP originally. It is just frameworks' abstraction/idea. There are two ways to achieve that: copying all params from request and doing new real HTTP request (with redirect) or internal forward: so framework would create fake request and call another controller and action without issuing a new physical HTTP request.

How to do two POST requests for visitors with JS disabled on one submit button?

I got help with solving a problem in this thead: Redirect with POST data. Now that I decided that the whole site and even this function must work when JS is disabled I need to get some suggestions for a non JS solution as well.
The need is:
User fills in a form and click on a button.
When clicked part of the form is saved in the db and part is posted to another server (payment-server). The user should only need to click once.
If you want to make the browser to re-send the data of a HTTP Post request to another URI, the HTTP/1.1 protocol offers the 307 (temporary redirect) response status code to signal such to the HTTP-client (Browser):
header('HTTP/1.0 307 Temporary Redirect',$replace=true,307);
header('Location: some_new_url_here');
Read the specs carefully and see the notes on the 302 status as well.
It's much more useful to handle the payment over an API on server-side instead of risking a user being irritated by additional messages displayed by the browser where the user must actually decide whether or not the additional redirect is to be performed.
Use CURL extension to post request to payment server when processing your user's request on server-side.
If your user must be redirected to some external web site, than save needed data first and then redirect him using header() function. Keep in mind that in this case you wouldn't be able to use POST method for making request to remote payment server.
A redirection with HTTP Location would have your user end on another site. I suggest you trigger an HTTP-request from your server using curl or streams.
The reason they initially suggested AJAX is for user experience, and is not a requirement for a form to be able to post. You will need to either present the user with a separate step to choose a form or have the same page reload or load another page.
Some pseudocode for example:
<?php
if (!isset($_POST['form_type']) {
display_form_selection();
} else {
switch ($_GET['form_type']) {
case 'credit_card': display_form('credit_card');
exit;
case 'cash': display_form('cash');
exit;
default: display_form_selection();
die()
}
}
Your form_selection() routine should draw a form which has a select, checkbox, radio button or whatever that will POST a string or integer (for the switch) back to the script you are running from.
When the page reloads it will call the correct display_form() based on the value it passed to itself. These functions will set up the form for whatever you want to post to the gateway.
I have read elsewhere on this site that using for your form action is not a good idea, and you should rather manually type your script name in.

POST in PHP AND redirect the user to that page?

I'm a bit confused. How do I POST data to a URL and then redirect the user's browser to that location - all in one operation?
I see
header('Location: page.php?' . http_build_query($_POST));
but that is GET, not POST and ppl think thats really bad practice - PHP open another webpage with POST data (why?)
My kludgy workflow involves setting up a form and then submitting it via javascript - anything has to be better than that...
I think I can do a set of header() stmts but this action happens for the user way after the page has been geenrated, so i dont think that would work
You cannot redirect POST requests. As simple as that. Any redirect will always turn into a GET request.
If you want to receive POST data, then send that data to another page, you have two choices:
if both pages are on the same server, use sessions to save the data server-side, don't make the client carry it over
if the destination is on another server and you need to send the client there together with the data, set up another intermediate form like you are
Use AJAX to save the data before you leave the page. Use the answer you get back to fire a redirection to the new url right within the current page. Don't be affraid of Javascript and ajax. Try this light AJAX library: http://www.openjs.com/scripts/jx/

Ctrl+r in firefox for refreshing page and my php code

i have create a form (so it's PHP and HTML hybrid-code). it has ability to send '$_POST'. And when i click it, it work perfectly on sending and displaying input.
But there's something happening when i click Ctrl+R in firefox for represhing the page. I got this confim dialog : "To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier"
my question
what is it, (this confirm dialog ?)
what i have to do on my code so it able to suppress this dialog ?
You probably have created an HTML page that contains a <form>. The form is used to send data to the HTTP server (that is, the webserver that hosts your site).
The HTTP protocol defines different request types used to send data to the server and to retrieve data from the server. The most used are GET and POST. You must learn about all this if you want to be anything more than a very bad PHP programmer, which is unfortunately (or fortunately, if you are on the hacker side) very common.
Your problem is that Firefox has arrived on the page you are talking about after sending a POST request. If you reload the page, it has to send the same data again in the form of a POST. Due to the conventions on what a POST request should be used for (usually to modify data on a database), the browser asks the user if he is sure about what he wants to do.
There are mainly two options to circumvent this:
Change the form method to GET; or
Use a redirection after the POST.
To use the first method, you could simply add a method="get" parameter to your form tag:
<form action="senddata.php" method="get"> ... </form>
To use the second method, you simply redirect the user after the POST request, using something like
header("Location: blahblahblah")
The most used pattern is the POST-Redirect, that is, the second method I told you about. There are many security implications on using GET to change data on a database (if you are interested on that, and you should be, as every PHP programmer should, read about XSRF).
Submitting a form (sending a POST request) is commonly used to confirm an order on eCommerce sites. Therefore, submitting it twice would submit the order, twice. Therefore browsers, tend to ask for confirmation that a user wants to send the POST request again.
In order to prevent this, you need to make the refresh do a GET request instead of a POST request. To do this, simply redirect to the same page after processing the form.
header("Location: /path/to/self");
This will make it so when the user hits refresh, it will be sending a GET request instead of a POST request, and it won't prompt for confirmation.
To clairify, it goes like this:
Form gets sent via POST (User clicks on form)
Form gets processed
User gets redirected to the same page (via GET)
User now will be refreshing a GET request instead of a POST request.
I guess whenever your form (php, asps, static html etc) contains post information that may either form field infor or other, is sent to the server via firefox, it displays such a message before sending the data again to server. it serves as a security protection from Mozilla developers. I guess it can be disabled via about:config but it is not recommended to so.
Also it is a normal behaviour. It should be like this and have been like this for a fairly long time in firefox.
You may like to have a look here:
http://forums.mozillazine.org/viewtopic.php?f=38&t=682835&st=0&sk=t&sd=a&hilit=Firefox+must+send
alternatively use GET instead of POST to send your data...
Regards
If the form was submitted successfully, answer with the status code 303:
header('Location: http://www.example.com/', TRUE, 303);
This forces the browser to use a GET request for the resulting page. A reload won’t send any POST data, and no pop up is shown.

Prevent Back button from showing POST confirmation alert

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

Categories