By using this site you agree to the use of cookies by Brugbart and our partners.

Learn more

Using HTTP IF MODIFIED SINCE with PHP

Article Explaining how to use the HTTP IF MODIFIED SINCE with PHP, and enjoy the benefits from lower bandwidth usage.

Edited: 2012-08-31 22:20

The HTTP IF_MODIFIED_SINCE request-header, is a header which is sent by most browsers. It contains the modification date provided in the Last-Modified header by the server on the last visit.

If the requested resource wasn't modified since the last visit, the server returns a 304 Not Modified http Response code, and the resource is fetched from the browser cache.

There is a difference when dealing with static pages and dynamic pages. The IF_MODIFIED_SINCE header is normally set by the server, but when you use a server-sided scripting language, like php, then you must set these on your own.

If-Modified-Since with PHP

Below is an example of how to use IF_MODIFIED_SINCE with PHP.

$fp = fopen($_SERVER["SCRIPT_FILENAME"], "r"); 
$etag = md5(serialize(fstat($fp))); 
fclose($fp); 
header("Cache-Control: must-revalidate");
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $SelectS['timestamp'])." GMT"); 
header('Etag: '.$etag);
header("Expires: -1");

You should note that the $SelectS['timestamp'] Variable holds the timestamp from the timestamp field in your database, this is the date/time at which the requested content was last modified, assuming a unix format in this case. As mentioned, the timestamp is saved in the database using the unix format with php time(), but it may be better to use a real date format, to avoid having to deal with leap years etc.

Note. Its a good idea to have a field in your table, for both the date of postage, and the date of which the entry was last edited.

Now its just a PHP if then else, situation. I.e.

if ((@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $SelectS['LTIME']) && ( 
    trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) { 
    header("HTTP/1.1 304 Not Modified");
    exit;
}

The Cache-Control Header

The cache-control header is used to instruct user agents how a given resource should be cached, in this case we just want to make sure that the user agent re-validates with the server, so we have set this to must-revalidate. This should save some bandwidth on repeated views, etc.

The Etag Header

The Etag header is often used to check if the CMS or script it self has changed. If the script or CMS is updated, you would usually want all content to be re-downloaded.

The Expires Header

This is only provided in an attempth to force re-validation in all browsers. Setting this to a date in the past, or a negative value like above, should trigger a conditional get request, and hence the re-validation that we expect, even when clicking visited links.

Full PHP If-modified-since example

The full example code, including the code for the etag, is shown below:

$fp = fopen($_SERVER["SCRIPT_FILENAME"], "r"); 
$etag = md5(serialize(fstat($fp))); 
fclose($fp);
header("Cache-Control: must-revalidate");
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $SelectS['timestamp'])." GMT"); 
header('Etag: '.$etag);
header("Expires: -1");

if ((@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $SelectS['timestamp']) && ( 
    trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) { 
    header("HTTP/1.1 304 Not Modified");
    exit;
}

You should place this somewhat in the top of your source code, either directly in the script, or as an include. And before any output is sent to the browser, including http headers.

See also

  1. Must-revalidate not working as expected