Как использовать заголовки кеша HTTP с PHP
У меня есть веб-сайт PHP 5.1.0 (на самом деле это 5.2.9, но он также должен работать на 5.1.0+).
Страницы генерируются динамически, но многие из них в основном статические. Под статическим я подразумеваю, что контент не меняется, но "шаблон" вокруг контента может меняться со временем.
Я знаю, что это уже несколько систем кеша и фреймворков PHP, но на моем хосте не установлены APC или Memcached, и я не использую фреймворк для этого конкретного проекта.
Я хочу, чтобы страницы кэшировались (я думаю, что по умолчанию PHP "запрещает" кэш). Пока что я использую:
session_cache_limiter('private'); //Aim at 'public'
session_cache_expire(180);
header("Content-type: $documentMimeType; charset=$documentCharset");
header('Vary: Accept');
header("Content-language: $currentLanguage");
Я прочитал много уроков, но не могу найти что-то простое (я знаю, что кеш - это нечто сложное, но мне нужны только некоторые базовые вещи).
Какие "должны" иметь заголовки для отправки, чтобы помочь кэшированию?
6 ответов
Вы можете использовать private_no_expire
вместо private
, но установите длительный срок действия для контента, который, как вы знаете, не изменится, и убедитесь, что вы обрабатываете if-modified-since
а также if-none-match
запросы похожие на пост Эмиля.
$tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT';
$etag = $language . $timestamp;
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false;
if ((($if_none_match && $if_none_match == $etag) || (!$if_none_match)) &&
($if_modified_since && $if_modified_since == $tsstring))
{
header('HTTP/1.1 304 Not Modified');
exit();
}
else
{
header("Last-Modified: $tsstring");
header("ETag: \"{$etag}\"");
}
куда $etag
может быть контрольной суммой на основе содержимого или идентификатора пользователя, языка и отметки времени, например
$etag = md5($language . $timestamp);
У вас должен быть заголовок Expires. Технически, есть и другие решения, но заголовок Expires действительно лучший, потому что он говорит браузеру не перепроверять страницу до истечения срока и даты, а просто подавать контент из кеша. Это работает действительно здорово!
Также полезно проверить заголовок If-Modified-Since в запросе от браузера. Этот заголовок отправляется, когда браузер "не уверен", если содержимое его кэша по-прежнему имеет правильную версию. Если ваша страница с тех пор не изменилась, просто отправьте обратно код HTTP 304 (не изменен). Вот пример, который отправляет код 304 в течение десяти минут:
<?php
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < time() - 600) {
header('HTTP/1.1 304 Not Modified');
exit;
}
}
?>
Вы можете поставить эту проверку на ранней стадии в своем коде, чтобы сэкономить ресурсы сервера.
Выберите - или используйте их все!:-)
заголовок ("Истекает: четверг, 01 января -70 00:00:01 по Гринвичу"); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); заголовок ("Cache-Control: нет хранилища, нет кэша, необходимо подтвердить заново"); заголовок ('Cache-Control: post-check=0, pre-check=0', false); заголовок ("Pragma: no-cache");
Это лучшее решение для php cache. Просто используйте это в верхней части скрипта.
$seconds_to_cache = 3600;
$ts = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT";
header("Expires: $ts");
header("Pragma: cache");
header("Cache-Control: max-age=$seconds_to_cache");
Вот небольшой класс, который делает кеширование http для вас. Он имеет статическую функцию с именем 'Init', для которой нужны 2 параметра: временная метка даты последнего изменения страницы (или любого другого файла, запрошенного браузером) и максимальный срок хранения этой страницы в секундах. кеш браузером.
class HttpCache
{
public static function Init($lastModifiedTimestamp, $maxAge)
{
if (self::IsModifiedSince($lastModifiedTimestamp))
{
self::SetLastModifiedHeader($lastModifiedTimestamp, $maxAge);
}
else
{
self::SetNotModifiedHeader($maxAge);
}
}
private static function IsModifiedSince($lastModifiedTimestamp)
{
$allHeaders = getallheaders();
if (array_key_exists("If-Modified-Since", $allHeaders))
{
$gmtSinceDate = $allHeaders["If-Modified-Since"];
$sinceTimestamp = strtotime($gmtSinceDate);
// Can the browser get it from the cache?
if ($sinceTimestamp != false && $lastModifiedTimestamp <= $sinceTimestamp)
{
return false;
}
}
return true;
}
private static function SetNotModifiedHeader($maxAge)
{
// Set headers
header("HTTP/1.1 304 Not Modified", true);
header("Cache-Control: public, max-age=$maxAge", true);
die();
}
private static function SetLastModifiedHeader($lastModifiedTimestamp, $maxAge)
{
// Fetching the last modified time of the XML file
$date = gmdate("D, j M Y H:i:s", $lastModifiedTimestamp)." GMT";
// Set headers
header("HTTP/1.1 200 OK", true);
header("Cache-Control: public, max-age=$maxAge", true);
header("Last-Modified: $date", true);
}
}
<?php
header("Expires: Sat, 26 Jul 2020 05:00:00 GMT"); // Date in the future
?>
Установка даты окончания срока действия для кэшированной страницы является одним из полезных способов кэширования ее на стороне клиента.
Я занимался кэшированием JSON на сервере, поступающем из фида Facebook, ничего не работало до тех пор, пока я не установил сброс и скрыл отчеты об ошибках. Я знаю, что это не идеальный код, но хотел быстро исправить.
error_reporting(0);
$headers = apache_request_headers();
//print_r($headers);
$timestamp = time();
$tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT';
$etag = md5($timestamp);
header("Last-Modified: $tsstring");
header("ETag: \"{$etag}\"");
header('Expires: Thu, 01-Jan-70 00:00:01 GMT');
if(isset($headers['If-Modified-Since'])) {
//echo 'set modified header';
if(intval(time()) - intval(strtotime($headers['IF-MODIFIED-SINCE'])) < 300) {
header('HTTP/1.1 304 Not Modified');
exit();
}
}
flush();
//JSON OP HERE
Это сработало очень хорошо.