Good guess. Sessions are the reason, you have two options:
2. Use session cache limiter [php.net...]
For me, it only works like this:
You can use the http cache headers and setup the css, js or other resource scripts in the server language you use.
// check the header val
header("Expires: " . $expiry);
header('Cache-Control: must-revalidate, max-age=86400, s-maxage=86400, private');
header('HTTP/1.1 304 Not Modified');
// stylesheet css code
where $expiry is the time to check whether to send the cache headers or the main css.
Of course you can, but the thing is, if sessions are started php will always send a no cache header no matter if you custom build your headers, php will ignore them and will not send them, unless you use
There is no good reason to start sessions for the resource files (css, js etc). These files stay static and even if you need to customize the files it can be done via the main script with a parameter that can stay the same for the same user. The only reason to use the PHP in this case is to check the headers from the application level. It's like with an image thumbnailer there is no reason to start a session.
For the main php scripts and the default headers php emits, sending the same header again can override the last and then is up to the browser for interpretation. (see the header php function param replace), why you need to start the session before the cache check anyways?
A side note, I don't use the php sessions as you need to setup way more code for the custom handlers than customize the whole session process with a simple class.
I fully agree with you, sessions should not be started for resource files, however, sessions are needed for other reasons and starting a session will affect the way php handles these resources if they are in the same server, ideally these static resource files should be hosted on a CDN and not on the same server dynamic content is served from but not everybody can afford it, that's the reason why I said using a subdomain/different domain could be a solution, actually that is the only current way to make sure you have total control over cache headers.
Param replace does not work for the header function if a session has been started, it should but it does not, try it, I spent hours debuging to figure that out. php does not allow (cache) headers to be modified if a session has been started unless you use session_cache_limiter(false).
I haven't experienced the same problem you describe and it is strange because for static resource files the browser will cache them automatically and php will not emit any headers for the static files because they aren't php after all. The HTTP_IF_MODIFIED_SINCE in this case could be used for php files. Maybe the firewall or some other plugin blocks the cache header on FF I don't know.
And the last-modified/expires headers alone aren't enough. It requires pragma, cache-control, etag for the cache to be effective otherwise the browser may discard the cache headers. One thing to check is the client request whether or not sends the HTTP_IF_MODIFIED_SINCE
Also are you using session auto-start or you use the php with custom session callbacks? I noticed variations between different php versions with this sending the session cookie and so I had it with all the convoluted code to cover each case and implemented a custom class to handle all this. Now I can open/close a simulated session anyway I like and is far simpler to maintain.
They are php, I use php to remove comments, bloat and blankspaces, compress and set headers for js and css nearly in the same way as your example above, the issue here is handling headers through php, it seems to me that is what the OP meant, they are php parsed files for all purposes, therefore these files will be affected if there is an open session.
I may be wrong but I think the behaviour changed starting from php 5, I do recall I did not have any of these issues in php 4 age, the reason is unknown to me.
No auto start or custom session callbacks here, I do send Pragma, cache-control, expires, I did have issues with Etag, solved by "Etag none" in apache's httpd.conf. I like your idea of a session handling class, I will start one as soon as I can.
I am curios about the s-maxage param in your example I'd never seen it before, what is it for?
The header that includes the s-max-age is an attempt to force the browser to cache the content always and leave the cache control to the server to decide when to expire the cache. Because of the older browsers and the http 1.0 spec which isn't too clear about the cache headers I was seeing browsers to behave differently and sometimes not caching the pages.
The s-maxage can override the expiry and so the server may tell the client whether or not to fetch the page again or use the cached version. It applies to a shared cache and supposed to be used with the public pragma as of the HTTP 1.1 spec and forces revalidation with the server.
Since you mentioned the compress (gzip I suppose) in none of the PHP versions I could make this working reliably (with the standard browsers at least). It will work most of the time but occasionally the browser would display the encoded page and could have to do with the session cookie or cache headers sent to the client.
Now with js you could initialize variables in the main script and the js resource file can use them without the need of php parsing. For example in the main script
var jq = init_control;
jq.baseURL = 'http://www.example.com/file_to_call/somefile.php';
So after the page is loaded the ready js function is executed initializing the baseURL member var of the jq object. And inside the init_control class you use the value of the baseURL in the js code. Then the link can be used by the js to do something (redirect, ajax calls etc). In this way you don't have to parse the side js files but indirectly pass the parameters you want from the main php script. But for css it needs the php extension if you want to do something due to the lack of variables support.
For the Etag I found it critical for some browsers at least. Without it I could not cache the pages.
And yea I don't understand why the session complexity with PHP and why they need it. There are also so many initialization values with the session id having different formats, default time limits, then with classes you can't close the session with the destructor because it is already closed, if safe mode is in effect it checks the path for the session storage even if you are storing sessions in the database and gives warnings;
and after all it doesn't provide any session validation. You just keep calling the same page blocking cookies and a new session is created. And you need to remember to define object classes before the session starts otherwise you get more warnings. That's just some of the problems I recall.
The same functionality I had with the standard sessions I have now but is more reliable and I use around 30% less code.