Home » Php » php – how to use control-cache headers?

php – how to use control-cache headers?

Posted by: admin July 12, 2020 Leave a comment


I downloaded Google speed tracer for Google chrome to see how my site does performance wise and it tells me I need to enable caching for certain files like my style.css, images, etc.

I’ve read that the below php code should tell browsers to cache html content. I wrote a quick php page with a couple of images on it and stuck the below code at the top (before the headers are sent) to test to see how it worked.

Header("Cache-Control: public, max-age=3600, must-revalidate");

When I go back to speed tracer’s analysis it says…

From Cache: false

Request Headers
Pragma: no cache
Cache-Control: max-age=0

but under Response Headers
Cache-Control: public, max-age=3600, must-revalidate (exactly what I specified)

I’m a little confused, what’s going on…? When it says from cache: false does that mean from the server cache and not the client’s cache?

How to&Answers:

The key is must-revalidate: This means, that the client is asking the server if the file has changed. If you don’t handle this case, the browser will fetch a new copy.

Read Mark Nottingham’s fantastic Caching Tutorial for more information.
As an example for a PHP implementation you may use my code.

Look into $_SERVER['HTTP_IF_NONE_MATCH']and $_SERVER['HTTP_IF_MODIFIED_SINCE'] for validating clients. And be aware that both headers may contain malicious code. 😉


When it says from cache: false does
that mean from the server cache and
not the client’s cache?

^ This is referring to the client cache.

Setting up caching in this manner will cover your PHP files, but you’ll need to implement something else server side to cache your images, CSS, scripts, etc. This can be done using .htaccess, if your server supports it.

For example, this is what I’m using in my .htaccess file for a couple sites.

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)(\.gz)?$">
  Header set Expires "Thu, 15 Apr 2012 20:00:00 GMT"
  Header unset ETag
  FileETag None


I’m not familiar with this tool, however until any browser has fetched content with caching headers it won’t be able to cache it. It appears that your server is sending back the expected headers and the page should be cached by the browser – your browser should now have a copy in its cache. If you try fetching the same page again then it will be fetched from the cache rather than the origin server (assuming the 1 hour time limit hasn’t expired).

Note that some browsers will interpret a refresh request as an explicit request to ignore the cache and fetch the page again – try accessing it via link rather than hitting the refresh button.



You need understand what these Cache-Control header field directives actually mean:

  • public:

    Indicates that the response MAY be cached by any cache, even if it would normally be non-cacheable or cacheable only within a non-shared cache. (See also Authorization, section 14.8, for additional details.)

  • max-age=3600 specified that the response is fresh for 3600 seconds:

    When the max-age cache-control directive is present in a cached response, the response is stale if its current age is greater than the age value given (in seconds) at the time of a new request for that resource. The max-age directive on a response implies that the response is cacheable (i.e., “public”) unless some other, more restrictive cache directive is also present.

  • must-revalidate specifies that a cache must revalidate a cached response after it became stale before using that cached response to satisfy the request:

    When the must-revalidate directive is present in a response received by a cache, that cache MUST NOT use the entry after it becomes stale to respond to a subsequent request without first revalidating it with the origin server. (I.e., the cache MUST do an end-to-end revalidation every time, if, based solely on the origin server’s Expires or max-age value, the cached response is stale.) […] Servers SHOULD send the must-revalidate directive if and only if failure to revalidate a request on the entity could result in incorrect operation, such as a silently unexecuted financial transaction.

Now this is the intended meaning of these directives.

But as always, the reality is a little different: Especially must-revalidate is not interpreted to only revalidate a cached response only after it became stale but that it has to be revalidated on every subsequent request or that it must not be cached at all (that’s probably why it sends Cache-Control: max-age=0 in the subsequent request).

The “From Cache: false” seems to indicate that the response did not come from a cache but directly from the server.