Подтвердить что ты не робот

Как использовать заголовки кеша 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");

Я прочитал много уроков, но не могу найти что-то простое (я знаю, что кеш - это что-то сложное, но мне нужны только некоторые базовые вещи).

Какие "должны" иметь заголовки для отправки, чтобы помочь кэшированию?

4b9b3361

Ответ 1

Возможно, вы захотите использовать 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);

Ответ 2

У вас должен быть заголовок Expires. Технически есть и другие решения, но заголовок Expires действительно самый лучший из них, потому что он говорит браузеру не перепроверять страницу до истечения срока и времени и просто обслуживать содержимое из кеша. Он отлично работает!

Также полезно проверить заголовок If-Modified-Since в запросе из браузера. Этот заголовок отправляется, когда браузер "неуверен", если содержимое в кеше по-прежнему является правильной версией. Если с этого момента ваша страница не изменяется, просто отправьте код HTTP 304 (Not Modified). Вот пример, который отправляет код 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;
  }
}
?>

Вы можете поместить этот чек на раннем этапе в свой код, чтобы сохранить ресурсы сервера.

Ответ 3

<?php
header("Expires: Sat, 26 Jul 2020 05:00:00 GMT"); // Date in the future
?>

Установка даты истечения срока действия кэшированной страницы - один из полезных способов кэширования ее на стороне клиента.

Ответ 4

Сделайте свой выбор - или используйте их все!: -)

header('Expires: Thu, 01-Jan-70 00:00:01 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');

Ответ 5

Вот небольшой класс, который выполняет кэширование 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);
    }
}

Ответ 6

Я занимался кэшированием 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

Это сработало очень хорошо.

Ответ 7

Это лучшее решение для кеша php. Просто используйте это в верхней части скрипта

$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");