可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a PHP 5.1.0 website (actually it's 5.2.9 but it must also run on 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.
I want the pages to be cached (I think by default PHP "disallow" cache). So far I'm using:
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?
回答1:
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.
$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 = md5($language . $timestamp);
回答2:
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!
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:
<?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:
<?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:
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');
回答5:
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.
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:
I was doing JSON caching at the server coming from Facebook feed nothing was working until I put flush and hid error reporting. I know this is not ideal code, but wanted a quick fix.
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
This worked very well.
回答7:
This is the best solution for php cache Just use this in the top of the script
$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");