Correct Last-Modified header processing

Posted by Dmytro Shteflyuk on under PHP

This is quick post about Last-Modified header. Please imagine following situation: you have image stored in your database and you need to send it to the browser on some request. But image extraction from database takes some time, and if there are more than one image you Web-server’s productivity will decrease dramatically. Is this case you need to implement caching functionality in your application. All images can be changed therefor you need to have ability to check image modified date (for example, this date can be stored in same database).

Every browser has its own cache, and if you will send right Cache-Control header, your image will be cached for some time. After cache time expiring browser will send request to your application to get fresh version of image. But if your image was not updated you can send 304 code in response to tell browser about this. Look at the following code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// --- Your code ---

// You need past following before any output

// here you need to select modified date from DB in UNIX timestamp format
// (same as time() function in PHP or UNIX_TIMESTAMP() function in MySQL)
$date = time();

$last_modified = gmdate('D, d M Y H:i:s', $date) . ' GMT';
// did the browser send an if-modified-since request?
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
  // parse header
  $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);

  if ($if_modified_since == $last_modified) {
    // the browser's cache is still up to date
    header('HTTP/1.0 304 Not Modified');
    header('Cache-Control: max-age=86400, must-revalidate');
    exit;
  }
}

header('Cache-Control: max-age=86400, must-revalidate');
header('Last-Modified: ' . $last_modified);

// --- Your code ---

In this code I check HTTP_IF_MODIFIED_SINCE request variable which will be sent by browser when cache is expired. If image was not modified, special header will be sent. Default cache period in this sample is 24 hours (86400 seconds). This is very simple and powerful issue which can be used in your Web-application as-is to increase perfomance.

Hint: you can create static-like URLs using following lines in .htaccess file (mod_rewrite):

1
2
RewriteEngine On
RewriteRule ^image_([0-9]+).php$ getimage.php?image=$1 [L]

In this case your images will have URLs like http://example.com/image_10.php, and all request will be redirected to getimage.php with parameter image=10.

Useful links

12 Responses to this entry

Subscribe to comments with RSS

said on April 10th, 2006 at 22:59 · Permalink

Thanks for useful post! I’m working now on simple data caching system and I will use this information in cache validation part.

Great thanks! Keep writing such interesting and usefull stuff!

Валерий Пешков
said on May 19th, 2006 at 06:53 · Permalink

Дмитрий большое спасибо за статью! Небольшое замечание. Мне кажется нужно использовать time() вместо date()?

said on May 19th, 2006 at 11:11 · Permalink

Валерий, большое спасибо за комментарий, Вы действительно правы, использовать нужно функцию time(). В заметке исправил.

Oleg
said on May 26th, 2006 at 10:08 · Permalink

Для $_SERVER['HTTP_IF_MODIFIED_SINCE'] лучше, imho, использовать strip_tags() или что-то подобное

Alexander
said on October 30th, 2006 at 00:47 · Permalink

Спасибо. То что доктор прописал…

said on January 15th, 2007 at 12:25 · Permalink

Спасибо, Дмитрий. Полезная статья, замечательный блог.

peregrino
said on September 6th, 2007 at 15:59 · Permalink

But still the *same image* is requested to the database multiple times (one for the first time each browser requests that image). It would be great if we could order to the web server to cache the images it’s sending to the browsers.

without a server cache, storing images in a database still introduces some penalties over storing them in the file system.

said on November 27th, 2007 at 01:34 · Permalink

I tried out your code, and have a problem, maybe someone can help. When I try it locally on my ubuntu box, it works great. Teh site loads instantly if cached.

But when I tried it on my actual server (dreamhost) it didn’t work at all, the images disappeared. Humm

Did that happen to anyone?

Oleg
said on March 22nd, 2008 at 12:21 · Permalink

А этот код подходит для динамического контента, где данные вытаскиваются из базы (WORDPRESS)?

Oleg
said on March 22nd, 2008 at 12:25 · Permalink

Просто стоит задача удовлетворить пожелания Яндекса по выдаче кода 304 на запрос «If-Modified-Since». Не знаю как это сделать, если не сложно, подскажите, пожалуйста. Спасибо.

said on May 29th, 2008 at 02:28 · Permalink

А насколько адекватно яндекс оценивает заголовок last-modified?

дима
said on December 9th, 2008 at 12:28 · Permalink

Здравствуйте.
Дима, полезная статья спасибо. Но я пробовал с её помощью решить обратную задачу ) в Опере. Мне надо наоборот ,что бы в Опере(именно в Опере) страница не кэшировалась – у меня ничего не получилось – Опера по умолчанию всё кэширует . Не знаете ,что можно придумать ,что бы Опера не кэшировала страницу?
Спасибо

Comments are closed

Comments for this entry are closed for a while. If you have anything to say – use a contact form. Thank you for your patience.