PHP handle download request when session is expired - php

I'm looking for some help in how best to handle page navigation/redirection from a PHP application. We don't offer many downloads so this has only just now come up as an issue. The gist is that a user loads a webpage to view some data and this page offers a hyperlink to download the data into a spreadsheet (dynamically built). The issue that I'm struggling to come up with a slick solution to is if the user sits on the webpage for long enough to where their session expires in PHP. Suppose in that case the user comes back to the page and clicks the download link.
There are two scenarios I need to handle. The first is with old browsers like IE (have to support it for the time being). IE doesn't support the download attribute for ANCHOR elements. Therefore, when the link is clicked and the session is invalid, the user is presented with a login form but the browser URL now reflects the endpoint of the download. Upon logging in, the download functions correctly but the user is left at the login form because the presence of the Content-Type: attachment makes the browser not navigate. I am looking for how to best get the user back to what is essentially the initial HTTP_REFERER when the download was requested. The only idea I can come up with is either a standard endpoint or query string parameter to use so that my login form handling code can properly redirect after successful login for a download request.
The other scenario is for modern browsers that support the download attribute. My code does set the HTTP response code to 401 when it determines the login form needs to be rendered (maybe that's not correct though). I do not see anything within $_SERVER that alludes to that fact though which suggests, again, a standard endpoint or query string parameter to use for identification. Modern browsers handle this case well by simply denying the download and actually displays that the request needs authorization. So, this works well as long as setting the status to 401 on all login form renders is correct otherwise, I'd again need some way to know that the requested endpoint is a download.
I'd like to avoid any kind of JavaScript solution if possible.

Related

How to prevent URLs that lead to a 301 redirect to show up in browser history?

Using the PayPal API, when the user cancels the process or is redirected back to the shopping cart page in order to review the order, the page URL includes the GET paramenter "token". I don't want the user to see that token, so I redirect the page to itself without the query string, using a 301 redirect. Hovewer, the URL including the token is saved in the browser history (at least in Firefox and Chrome) and shows up as autocomplete option when typing in the address bar.
The PayPal express checkout API doesn't have a parameter to make the return requests POST instead of GET (as opposed to the form-based method with hidden fields). Is there any way to do a redirect that won't have the original URL saved in the browser history?
I also tried 302 and Refresh: 0; url=... - but that still saves the URL...
I don't think this can be done because the browser is seeing it as a unique URL and recording it to be helpful to the user. It's important for the browser to know the history, but I understand why you don't need to show this to the user.
If you weren't using the PayPal API, I'd suggest not using querytring values in the URL, but that's probably unavoidable in this case.
Sorry to say, but I think you're stuck with it. I never found a way around this in any PHP or Classic ASP applications.

Simultaneous redirect to App Store and another page

After having completed an online registration process, I want to check if the user is using an iPhone, and in that case give the option of opening App Store to download the app. Here's what I've coded so far:
In PHP, check $_SERVER['HTTP_USER_AGENT'] for the presence of the substring "iPhone".
If so, output JavaScript code that, before redirecting to the welcome page, offers the possibility of going to App Store using a confirm box.
Redirect to itms-apps://itunes.apple.com/url-to-my-app using window.location = ... in JavaScript.
This works. However, when the user once again opens Safari, the page which I redirected from is still open. This doesn't make any sense in my case. I want to redirect to the welcome page regardless of whether the user chooses to open the App Store. If I try to write another window.location line below the first one to perform a second redirect, Safari simply skips the link to the App Store.
I've considered redirecting from a hidden iframe, placing some kind of timer on the second redirect, experimenting with different combinations of JavaScript and HTTP header redirects and so on. None of the solutions I've thought of so far seems really solid, though. How do I do this if I want it to work gracefully across browsers and versions?
The only way to do this is to use the welcome page itself to do the iTunes redirect.

Return HTML or XML based on request in PHP

There's an existing website written in PHP. Originally only the website existed, but now an Android application is being built that would benefit from re-using some of the PHP logic.
The PHP site was structured such that there are many pages that perform an action, set success/error information in $_SESSION, and then redirect to a visual page without outputting any content themselves. For example, there's action_login.php:
The page accepts a username and password (from GET or POST variables), validates the credentials, sets success/failure messages in $_SESSION, and then redirects to the logged-in homepage on success or back to the login screen on failure. Let's call this behavior the "HTML response".
The Android application will need to call the same page but somehow tell it that it wants an "XML response" instead. When the page detects this, it will output success/error message in an XML format instead of putting them in $_SESSION and won't redirect. That's the idea anyway. This helps prevent duplicate code. I don't want to have action_login.php and action_login.xml.php floating around.
I've read that the Accept Header isn't reliable enough to use (see: Unacceptable Browser HTTP Accept Headers (Yes, You Safari and Internet Explorer)). My fallback solution is to POST xml=1 or use {url}?xml=1 for GET requests. Is there a better way?
No frameworks are being used, this is plain PHP.
That's what the Accept Header is for. Have the Android request the page as application/xml and then check what was requested in your script. You might also be interested in mod_negotiation when using Apache. Or use WURFL to detect the UserAgent and serve as XML when Android.
I'd go with the android app sending a cookie for every request (really I would prefer the Accept header, but with the problems you pointed out with webkit I understand your reluctance to do so). The cookie simplifies the code server-side to not have to check for $_GET['xml'] or $_POST['xml'], and if some android user shares an URL of your application and it had a ?xml=1, the user who opens this in a computer browser would receive XML instead of the normal web output.
I wouldn't rely on $_SESSION for mobile applications because users (or at least I do) on mobile platforms tend to open your app, play 5 minutes, put mobile on pocket and 2 hours later return to your app. Do you want to set a session lifetime so long?
why not set a specific session for the app and then only set the header if the session is set something along the lines of
$_SESSION['app'] = "andriod app";
if ($_SESSION['app'] == "andriod app") {
header..
not really sure how to implement this into an app as I've done really little work with apps but hope this helps your thought process

GET an POST data for Mozilla

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.

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