Правильная обработка заголовка Last-Modified

Posted by Dmytro Shteflyuk on under PHP · English (41,111 views)

Это короткая заметка о заголовке Last-Modified. Представьте следующую ситуацию: у Вас есть изображение, которое хранится в базе данных, и Вам нужно отправить это изображение браузеру в ответ на некоторый запрос. Но извлечение изображения из базы данных занимает некоторое время, а если этих изображений несколько – производительность Вашего Веб-сервера начинает стремительно падать. В этом случае Вам необходимо реализовать некоторую функциональность для кэширования в приложении. Все изображения могут изменяться, потому необходимо иметь возможность проверять дату изменения (например, хранить ее в той же базе данных).

У каждого браузера есть свой кэш, и если Вы отдадите правильный заголовок Cache-Control, Ваше изображение будет закэшировано на некоторое время, по истечении которого браузер пошлет запрос еще раз, чтобы получить свежую версию изображения. Но если оно не менялось, можно просто послать код 304 в ответе, чтобы сообщить браузеру об отсутствии изменений. Посмотрите на следующий кусок кода:

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
27
28
// --- Ваш код ---

// Вам необходимо вставить следующие строки до любого вывода

// здесь необходимо получить дату модификации из БД в формате UNIX
// (как возвращает функция time() в PHP или функция UNIX_TIMESTAMP() в MySQL)
$date = time();

$last_modified = gmdate('D, d M Y H:i:s', $date) . ' GMT';
// отправил ли браузер запрос if-modified-since request?
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
  // разобрать заголовок
  $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);

  if ($if_modified_since == $last_modified) {
    // кэш браузера до сих пор актуален
    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);

// --- Ваш код ---

?>

В этом коде я проверил переменную запроса HTTP_IF_MODIFIED_SINCE, которая будет отправлена браузеров, когда кэш станет недействительным. Если изображение не изменилось, будет отправлен специальный заголовок. Время жизни кэша в этом примере составляет 24 часа (86400 секунд). Это очень простой и мощный пример, который может использоваться в Ваших Веб-приложениях для увеличения производительности.

Подсказка: Вы можете создать URL, похожие на статические, используя следующие строки в файле .htaccess (mod_rewrite):

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

В этом случае Ваши изображения будут иметь URL подобный следующему: http://example.com/image_10.php, и все запросы будут перенаправлены скрипту getimage.php с параметром image=10.

Полезные ссылки

12 Responses to this entry

Subscribe to comments with RSS

said on Апрель 10, 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 Май 19, 2006 at 06:53 · Permalink

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

said on Май 19, 2006 at 11:11 · Permalink

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

Oleg
said on Май 26, 2006 at 10:08 · Permalink

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

Alexander
said on Октябрь 30, 2006 at 00:47 · Permalink

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

said on Январь 15, 2007 at 12:25 · Permalink

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

peregrino
said on Сентябрь 6, 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 Ноябрь 27, 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 Март 22, 2008 at 12:21 · Permalink

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

Oleg @
said on Март 22, 2008 at 12:25 · Permalink

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

said on Май 29, 2008 at 02:28 · Permalink

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

дима
said on Декабрь 9, 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.