Webmasters Stack Exchange is a question and answer site for pro webmasters. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a website in which I update the content approximately once monthly. When I check the HTTP request header fields, I get the following output:

Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache

My question is, given the frequency at which I update content, I am thinking about manually setting these fields to allow cache of the site. I am using the php header(); command to do so.

Therefore, my question is: what should my expires, cache-control, and pragma HTTP request header fields be set to? Also, should I be setting any other fields in addition to those?

share|improve this question

As it stands, your cache settings don't appear to match your update cycle, so I think you're on the right track. Adding indicators that allow your site to be cached by your end users and inline caches will improve your users' experience and has the potential to reduce your bandwidth and server load.

What you set the above to depends on your tolerance for stale content. I would recommend not setting Cache-Control or Pragma at all, and set Expires to some value that you are comfortable with (8 hours? One day?) offset from the user's visit. This is really subjective though and depends on your content.

In addition to setting the above to some reasonable value you should also be setting a header like Last-Modified or ETag which allow for conditional HEAD requests and ensuring that you respond with a 304 and no content if the page isn't modified. This can be based on a database date_modified field (if one exists) or for an ETag you could base it on a hash of the page contents.

I personally take a couple approaches. On static pages, I make my PHP output script write the output buffer into a cache directory, and have an Apache rewrite rule that serves from the static location if the file already exists. Then in the cache directory, I enable caching and DEFLATE handling of the static HTML pages using more Apache directives. The code for writing the output buffer is site-specific, but here is the mod-rewrite I use (in an .htaccess file in the articles subdirectory)

RewriteEngine On
RewriteBase /articles/
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI} -f
RewriteRule .? /cache%{REQUEST_URI} [L]

This basically says that if the file exists in the cache then redirect to it and stop rewriting.

Then in the cache directory, I have settings like:

ExpiresActive On
ExpiresByType text/html "access plus 1 day"
AddOutputFilterByType DEFLATE text/html

And I combine this with code in my update area that deletes the content of /htdocs/cache/articles when modifying the site template or content of the articles.

The beauty of this is that Apache takes care of all of the conditional requests and compression for me, and I'm not hitting PHP for each request.

For dynamic PHP code, I use the following all-in-one library that handles GZip Compression, Expires, 304 If-Modified-Since responses, etc:


You could even combine the two, modifying Alexandre's script to write the output buffer to the cache folder on the first render of static pages.

share|improve this answer
Is that secure? What if I request articles/../.htpasswd or something? – DisgruntledGoat Sep 29 '10 at 14:52
The test for file existence is filesytem-based, but the rewrite rule is web-based and doesn't bypass Apache's security. In this case you get a 403 because the .htpasswd is configured not to be served. If I'm missing something here, please let me know :) – JasonBirch Sep 29 '10 at 17:49

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.