How to use HTTP cache headers with PHP

I have a PHP 5.1.0 website (actually it is 5.2.9, but it should also work on 5.1. 0+).

Pages are generated dynamically, but many of them are mostly static. By static, I mean that the content does not change, but the “pattern” around the content may change over time.

I know that these are already several cache systems and PHP frameworks, but APC or Memcached are not installed on my host, and I do not use the framework for this particular project.

I want pages to be cached (I think PHP defaults to "denying" 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 have read many lessons, but I can’t find something simple (I know that cache is something complicated, but I need only some basic things).

What "should" have headers to send to help caching?

+59
php caching
Dec 28 '09 at 21:43
source share
7 answers

You might want to use private_no_expire instead of private , but set a long expiration time for content that you know will not change and make sure that you handle if-modified-since and if-none-match requests similar to Emil’s message.

 $tsstring = gmdate('D, d MYH: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 can be a checksum based on content or user id, language and timestamp, e.g.

 $etag = md5($language . $timestamp); 
+45
Dec 29 '09 at 5:07
source

You should have an Expires header. Technically, there are other solutions, but the Expires header is really the best of them, because it tells the browser not to double-check the page before the time and time has expired and just serve the contents from the cache. It works great!

It is also useful to check the If-Modified-Since header in the request from the browser. This header is sent when the browser is "unsure" if the contents in the cache are still the correct version. If your page does not change from now on, just send the HTTP 304 (Not Modified) code. Here is an example that sends code 304 in 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 at an early stage in your code to save server resources.

+12
Dec 28 '09 at 23:07
source
 <?php header("Expires: Sat, 26 Jul 2020 05:00:00 GMT"); // Date in the future ?> 

Setting the expiration date of a cached page is one of the useful ways to cache it on the client side.

+8
Dec 28 '09 at 21:51
source

Make your choice - or use them all !:-)

 header ('Expires: Thu, 01-Jan-70 00:00:01 GMT');
 header ('Last-Modified:'. gmdate ('D, d MYH: 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');
+7
Dec 28 '09 at 22:04
source

Here is a small class that does http caching for you. It has a static function called "Init", which requires 2 parameters, the timestamp at which the last page (or any other file requested by the browser) was the last modification, and the maximum age in seconds that this page can be saved to cache by 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 MYH: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); } } 
+7
Sep 08 '13 at 15:50
source

I did JSON caching on a server coming from a Facebook feed, nothing worked until I installed a reset and hid the error reports. I know this is not perfect code, but I wanted to fix it quickly.

 error_reporting(0); $headers = apache_request_headers(); //print_r($headers); $timestamp = time(); $tsstring = gmdate('D, d MYH: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 

It worked very well.

+2
Aug 07 '13 at 9:34 on
source

This is the best php cache solution. Just use this at the top of the script

 $seconds_to_cache = 3600; $ts = gmdate("D, d MYH:i:s", time() + $seconds_to_cache) . " GMT"; header("Expires: $ts"); header("Pragma: cache"); header("Cache-Control: max-age=$seconds_to_cache"); 
0
Aug 19 '19 at 9:22
source



All Articles