I solved my problem but I don't know why it works. I was hoping someone could shed some light?
I have a WordPress site. If a new user visits the site, they see a generic element on the homepage. When they visit an internal page, a cookie is created. When the user visits the homepage again, they see a customized element based on the cookie.
The problem I was having was that when the user returned to the homepage from an internal page, even though the new cookie was set with the right value, the $COOKIE superglobal was not reset until a refresh was performed. You could naviagte to as many different pages as you'd like, but still the superglobal was not reset until a literal refresh was performed. This was using both setcookie() and the setting the super global directly.
This was fixed by adding session_start() to the header. I thought session_start() affected the SESSION super global. Why did this solution also affect the COOKIE superglobal?
Why did this solution also affect the COOKIE superglobal?
Most likely it didn't, not directly - but by sending different headers regarding caching, it influenced how your browser was instructed to check for changes when displaying the same URL again, whereas before you simply got a stale copy presented from the cache.
it just seemed odd to me that cookies would be cached as well
Well not the cookie itself got "cached" - but the document in which you made any output depending on the cookie was. You still saw the first version of the page you loaded - the PHP code behind this was not executed again, because the browser did not actually request the URL from the server again.
But when the server sent a response header indicating that this page should not be cached (or that the client you check with the server before displaying the resource again) the first time it was loaded - it caused the browser to make a new request when you returned to the page.
Related
The application I'm working with accepts three different types of login. Automatically if the client connects from certain IP-adresses, or a POST request, either from a normal browser rendered form, or towards a JSON reading API-endpoint.
All three options boil down to calling the same functions for registering the user as logged in, and generating a session.
Despite the code paths being the same as far as I can determine, two of these consistently work, while one consistently fails to add a 'Set-Cookie' header to the response, even though the application logic generates a sessionid that gets sent in the reponse body.
Never having needed to dig into how session authentication works to this level of detail, I realise I don't understand. where the 'Set-Cookie' header, should come from. Should application logic always build the header manually? Will PHP do it automatically once session_start() is called? Does Apache do it based on other parts of the header?
I sort of ruled out 1 by failing to find anything with grep -ri "set.cookie" * in the codebase I'm working with.
session_start sends a session cache limiter and a session cookie (or sets a $_GET key with your PHPSESSID).
This function is where the Set-Cookie paramater is sent from. Apache will then pass it back to the browser when it sends the page back.
You need to remember however that storing the cookie is actually up to the browser. By and large they will be set without issue, but certain conditions will stop this from happening, such as the security settings in Internet Explorer or the user rejecting cookies entirely.
Further reading:
http://www.php.net/manual/en/function.session-start.php
http://www.php.net/manual/en/function.session-get-cookie-params.php
http://www.php.net/manual/en/function.session-status.php
I have the following situation:
User makes request to PAGE A that displays a form (server stores cache of this page)
User submits the form to CONTROLLER that is used for form submit
CONTROLLER finds an error in user submitted data, sets a cookie ERRORS detailing such, and redirects the user back to PAGE A
PAGE A shows the original content plus the ERRORS (server stores cache of this page)
PAGE A deletes ERRORS cookie
This works, but only if I don't use cache on my system for PAGE A.
Problem is that, after deleting the cookie, browser makes a request to my server without the cookie and gets a 304 Not Modified error and, as a result, the browser still shows the page with the error, instead of without (from the original request). Server stores cache properly (for page that has an error as well as an error-free page).
Basically the server has two cached pages now: PAGE A and PAGE A WITH ERRORS.
Browser, whose last known page was PAGE A WITH ERRORS asks for server a page with conditions of PAGE A, instead of PAGE A WITH ERRORS, since cookie does not exist anymore. But it thinks that the 304 response is about the PAGE A WITH ERRORS, instead of PAGE A. I even checked the data sent by the browser, it knows that it got PAGE A WITH ERRORS with the ERRORS cookie, yet accepts 304 not modified when making requests without that cookie. It does not validate its own cache against the conditions it was created under.
Doesn't browser validate its cache with the cookies it has set?
And is there a workaround for it without setting some GET variables for each request? Another alternative is to tell servers to never cache pages that have such an ERRORS state set, but that would be a hack.
Apparently the solution was to include this as a response header:
Vary: Cookie
This will take cookies into account in caching engines.
EDIT:
There is a problem though: Chrome, Internet Explorer and Firefox work as expected, but Safari and Opera both ignore 'Vary' header when storing and validating cache.
client-side sessions (a.k.a cookies) are probably not sufficient for this scenario...
would suggest server-side sessions instead. Even if Vary headers might work - with $_SESSION you'll be on the save side.
Cache-control: public is probably not what you want. Public essentially says that you're working with static, globally accessible data. It doesn't change per user. It's caching globally because you're claiming that the data is global.
As soon as you start changing per user, caches are having their assumptions violated. 'private' is more akin to what you want.
That will mean that you get less of the good middle-man caching, however. You might be able to hit some middle ground with re-validation, or with appropriate use of Vary headers.
I can't find a good answer for this anywhere.
I have a login page, and after a good login it redirects to main page.
In FF, and chrome - works perfect. On IE it doesn't work. I keep losing the session when I get to the main page.
I have checked the following:
- session_start at top
- no blanks or anything befoer header redirect
- one line before the redirect, IE knows the session user id, but after the redirect, just one line after the session start, it loses the session user id
- I've checked it also on other computer - same results
What is wrong with IE? or what could be wrong with my script ?
Thanks
Set PHP's error_reporting to -1; reproduce error; check logs
Check IE's privacy settings--$_SESSION relies on either a cookie or URL-based session identifier. It seems as though it's having trouble saving the cookie
Is there anything you're doing to the response that is not standard (eg modifying headers)
Can you build an extremely simple version of this code and test it using nothing but the bare essentials (narrow down the problem to a specific bit of code)
[Edit]
Make sure you aren't calling session_start() twice ;)
Ok,
Problem solved. I can't find the logic behind this solution, but although I had session_start() at the top of the page, I added another session_start() just before writing the session vars.
I have secured pages that all check for a set session variable to determine logged in users, pretty standard stuff. Where I run into problems is when I submit form information to a backend page that will process that data and then redirect to a success/failure confirmation page. In that time the session gets lost, at least the session with the variable. The session is still around because I can manually navigate to a secured page after and it works. Just auto redirects from a backend page to a secured page or a link on one of the unsecured pages after a redirect from the backend will fail. It may or may not be related, but after visiting multiple secured pages or doing one of the operations that use the problematic backend pages, there are two session cookies on my computer from the domain-- one registered to domain.com and the other to www.domain.com. At the end of my wits about this, thanks.
I see two problems here, but they're related.
The first is that you seem to be bouncing between secured (https://) and un-secured (http://) pages. Cookies aren't supposed to be shared between those, so that's why your session appears to break (PHP sets a cookie with the session ID).
The other is closely related and that is sharing between domain.com and www.domain.com. Cookies can share in one direction, but not the other. Don't worry about which: just pick one hostname and stick with it. Then check that you're setting the session's cookie domain to the correct one.
You must call session_start() from your PHP page before you output anything, preferably at the start of the page.
If the session has been already created, it will resume it for that page.
http://php.net/manual/en/function.session-start.php
I have a login setup on a site that stores login information in PHP's $_SESSION, and additionally sets a two-week cookie with login information if a checkbox is checked. The user is considered logged in if valid login information is either submitted by POST or either cookie is true.
The behavior on FF3/Chrome is as intended, at least with the "Remember me" checkbox checked: log in anywhere and everywhere on the site you are treated as being logged in.
However, someone working with IE6 said that she logged on one place, clicked around on links to other sections of the site, and was asked to log in again. I ran into some trouble with my (Multiple IE) IE6, but I reproduced similar behavior on IE8, including setting Advanced Privacy Settings->Always allow session cookies, and otherwise set cookie permissions to be as tolerant as I could. The behavior was identical: log in one place in a way that should set both _SESSION and the two-week cookie, click on links to another pages, and the page presents you with a login screen because it doesn't recognize you as logged in. PHP is 5.2.8 on a Gentoo server.
Any suggestions or resources to getting recognized cookies?
--
[Added after checking on traffic with Fiddler:]
Thank you; I have downloaded Fiddler 2.
Fiddler is reporting Set-Cookie: [name]=deleted... on the logouts in question. I'm presently puzzled as to why. The included file that checks and displays a login screen only has one area where it can delete the relevant cookies, inside a conditional if $_GET['logout'] is set. I didn't see that happening, and when I put an error_log() statement inside the conditional before the statements to delete cookies, no additional messages appear to be being logged.
Couple of suggestions
Try using Fiddler or similar to examine the HTTP requests and responses to see the cookies being sent and transmitted. This provide more insight into what is going wrong
Try having your app output a P3P header, e.g. header('P3P: CP="CAO PSA OUR"');
One thing that's kinda subtle that may jump out and bite you is that IE doesn't allow domain names with underscores (ie: developer_1_test.example.com) while other browsers let you get away with this. You're not v.likely to do this in production but it's an easy oversight to make in a development environment where you're setting up a bunch of vhosts for different developers/code branches/etc.
You'll need to be more specific. Find out exactly how you can replicate this behaviour on both browsers, and you've found your bug. For instance, there might be one or two pages where you're failing to call session_start().
It's important to remember that, if your particular $_SESSION variable is not being seen, and causing a redirect to your login, it's most probably part of your system that is broken.
The first thing I check when this happens is that the domain parameter for the setcookie() function is set properly.
I've seen instances where the cookie domain is set to 'example.com' but the site is being accessed via 'www.example.com'.
For example if you logged into the page at example.com, then clicked a link that took you to a page on www.example.com, you would no longer be logged in.
The workaround is to either make sure all your internal linking is consistent or that you set your cookie with '.example.com' which will enable the cookie for all subdomains.
What I eventually found was as follows: Firefox and IE were behaving differently because they were treating caching differently when a missing document was within the 14 day Expires: headers that had been set.
Firefox was apparently checking once for missing data, and then not requesting it again.
IE, on the other hand, kept on checking for an item a stylesheet gave the wrong path for, got 404 pages, and the custom 404 page did a boilerplate invitation to log in that triggered the user being logged out (perhaps not the best boilerplate). I guess the stylesheet was cached, but IE kept on asking for items that were missing.
So it was caching differences plus indirect inclusion plus 404 page behavior.