如何使用PHP使用HTTP缓存头?

时间:2021-02-08 20:16:01

I have a PHP 5.1.0 website (actually it's 5.2.9 but it must also run on 5.1.0+).

我有一个PHP 5.1.0的网站(实际上是5.2.9,但它也必须运行在5.1.0+)。

Pages are generated dynamically but many of them are mostly static. By static I mean the content don't change but the "template" around the content can change over time.

页面是动态生成的,但大多数页面都是静态的。所谓静态,我的意思是内容不会改变,但是内容周围的“模板”会随着时间而改变。

I know they are several cache systems and PHP frameworks already out there, but my host don't have APC or Memcached installed and I'm not using any framework for this particular project.

我知道已经有几个缓存系统和PHP框架了,但是我的主机没有安装APC或Memcached,我也没有为这个项目使用任何框架。

I want the pages to be cached (I think by default PHP "disallow" cache). So far I'm using:

我希望缓存页面(我认为默认情况下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");

I read many tutorials but I can't find something simple (I know cache is something complex, but I only need some basic stuff).

我读了很多教程,但是我找不到简单的东西(我知道缓存很复杂,但我只需要一些基本的东西)。

What are "must" have headers to send to help caching?

什么是“必须”要发送的头来帮助缓存?

6 个解决方案

#1


41  

You might want to use private_no_expire instead of private, but set a long expiration for content you know is not going to change and make sure you process if-modified-since and if-none-match requests similar to Emil's post.

您可能希望使用private_no_expire而不是private,但是为您知道不会更改的内容设置一个长过期,并确保您处理与Emil的post类似的if-modified-since和if-non -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}\"");
}

Where $etag could be a checksum based on the content or the user ID, language, and timestamp, e.g.

$etag可以是基于内容或用户ID、语言和时间戳的校验和。

$etag = md5($language . $timestamp);

#2


11  

You must have an Expires header. Technically, there are other solutions, but the Expires header is really the best one out there, because it tells the browser to not recheck the page before the expiration date and time and just serve the content from the cache. It works really great!

您必须有一个过期头。从技术上讲,还有其他的解决方案,但是Expires header确实是最好的解决方案,因为它告诉浏览器不要在过期日期和时间之前重新检查页面,而只是从缓存中提供内容。它真的太棒了!

It is also useful to check for a If-Modified-Since header in the request from the browser. This header is sent when the browser is "unsure" if the content in it's cache is still the right version. If your page is not modified since that time, just send back an HTTP 304 code (Not Modified). Here is an example that sends a 304 code for ten minutes:

检查浏览器请求中的If-Modified-Since头也很有用。当浏览器“不确定”是否仍然是正确的版本时,就会发送这个消息头。如果您的页面自那以后没有被修改,只需返回一个HTTP 304代码(未修改)。这里有一个发送304代码10分钟的例子:

<?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;
  }
}
?>

You can put this check early on in your code to save server resources.

您可以在代码中尽早进行检查,以保存服务器资源。

#3


7  

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

Setting an expiration date for the cached page is one useful way to cache it on the client side.

为缓存的页面设置过期日期是在客户端缓存它的一种有用方法。

#4


7  

Here's a small class that does http caching for you. It has a static function called 'Init' that needs 2 parameters, a timestamp of the date that the page (or any other file requested by the browser) was last modified and the maximum age, in seconds, that this page can be held in cache by the browser.

这是一个为您做http缓存的小类。它有一个名为“Init”的静态函数,需要两个参数,一个页面(或浏览器请求的任何其他文件)最后修改的日期的时间戳,以及这个页面可以被浏览器缓存的最大时间(以秒为单位)。

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);
    }
}

#5


6  

Take your pick - or use them all! :-)

拿起你的选择——或者全部用完!:-)

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');

#6


2  

I was doing json caching at the server coming from facebook feed nothing was working untill I put flush and hid error reporting. I know this the demon code but wanted a quick fix asap.

我在facebook feed的服务器上做json缓存,在我输入刷新和隐藏错误报告之前没有任何工作。我知道这是恶魔的代码,但想尽快修复。

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

WORKED like charm.

工作就像魅力。

#1


41  

You might want to use private_no_expire instead of private, but set a long expiration for content you know is not going to change and make sure you process if-modified-since and if-none-match requests similar to Emil's post.

您可能希望使用private_no_expire而不是private,但是为您知道不会更改的内容设置一个长过期,并确保您处理与Emil的post类似的if-modified-since和if-non -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}\"");
}

Where $etag could be a checksum based on the content or the user ID, language, and timestamp, e.g.

$etag可以是基于内容或用户ID、语言和时间戳的校验和。

$etag = md5($language . $timestamp);

#2


11  

You must have an Expires header. Technically, there are other solutions, but the Expires header is really the best one out there, because it tells the browser to not recheck the page before the expiration date and time and just serve the content from the cache. It works really great!

您必须有一个过期头。从技术上讲,还有其他的解决方案,但是Expires header确实是最好的解决方案,因为它告诉浏览器不要在过期日期和时间之前重新检查页面,而只是从缓存中提供内容。它真的太棒了!

It is also useful to check for a If-Modified-Since header in the request from the browser. This header is sent when the browser is "unsure" if the content in it's cache is still the right version. If your page is not modified since that time, just send back an HTTP 304 code (Not Modified). Here is an example that sends a 304 code for ten minutes:

检查浏览器请求中的If-Modified-Since头也很有用。当浏览器“不确定”是否仍然是正确的版本时,就会发送这个消息头。如果您的页面自那以后没有被修改,只需返回一个HTTP 304代码(未修改)。这里有一个发送304代码10分钟的例子:

<?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;
  }
}
?>

You can put this check early on in your code to save server resources.

您可以在代码中尽早进行检查,以保存服务器资源。

#3


7  

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

Setting an expiration date for the cached page is one useful way to cache it on the client side.

为缓存的页面设置过期日期是在客户端缓存它的一种有用方法。

#4


7  

Here's a small class that does http caching for you. It has a static function called 'Init' that needs 2 parameters, a timestamp of the date that the page (or any other file requested by the browser) was last modified and the maximum age, in seconds, that this page can be held in cache by the browser.

这是一个为您做http缓存的小类。它有一个名为“Init”的静态函数,需要两个参数,一个页面(或浏览器请求的任何其他文件)最后修改的日期的时间戳,以及这个页面可以被浏览器缓存的最大时间(以秒为单位)。

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);
    }
}

#5


6  

Take your pick - or use them all! :-)

拿起你的选择——或者全部用完!:-)

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');

#6


2  

I was doing json caching at the server coming from facebook feed nothing was working untill I put flush and hid error reporting. I know this the demon code but wanted a quick fix asap.

我在facebook feed的服务器上做json缓存,在我输入刷新和隐藏错误报告之前没有任何工作。我知道这是恶魔的代码,但想尽快修复。

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

WORKED like charm.

工作就像魅力。