8

My CSS file is acutally a PHP file which is served with content-type text/css so that I can use PHP variables in that file. style.php looks like this:

<?php
header('Content-Type: text/css');
$bgColor = '#000';
?>

body { background:<?php print $bgColor; ?>; }

It works as expected, but I am a bit worried if the browser caches the dynamically created css file.

When looking at the requests in firebug, it seems to me that the browser is loading style.php anew everytime I reload the page.

I already tried to add these cache headers:

header('Cache-control: must-revalidate');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 60 * 60 * 24) . ' GMT');

But no luck. The file is still loaded everytime the page is loaded. What are the appropriate headers in order to force the browser to cache the file for a certain amount of time?

Max
  • 15,693
  • 14
  • 81
  • 131

2 Answers2

2

If you want a file to be cached by browsers, you should set the Cache-control header to public:

header('Cache-control: public');

must-revalidate means that the browser will check to see if the file has been updated, which will invoke your PHP script.

Inspire
  • 2,052
  • 15
  • 14
  • 5
    According to the HTTP/1.1 spec, that's not what must-validate is supposed to mean — it's only supposed to kick in after the cached content has become stale (as directed by the Expires header, or a max-age value within Cache-Control), but some browsers do seem to ignore the spec and send the request anyway. 'public' isn't really applicable, though, unless the connection is authenticated. I would use 'Cache-Control: max-age=86400' to reinforce the time in the Expires header. – Brock Batsell Mar 07 '10 at 08:41
  • @Brock Batsell: thanks for the comment! That clarified it and it works now with max-age=XXXX – Max Mar 07 '10 at 09:11
  • If the file content is changed, the requested file won't be updated. The OP requests that the file shouldn't be cached if the content is changed. If the file content hasn't changed, then it should be cached. The code you provided turns on the "caching" feature. It doesn't solve the OP's problem. – Wissam El-Kik Dec 09 '14 at 14:30
  • The answer above must be updated to reflect the comments and solution. – Basil Musa Jun 15 '15 at 12:53
2

This code solves your problem.

It checks the "last modified" variable and assign an eTag for the file. If the eTag is modified (or the file is modified), the file is displayed. Otherwise, there's a 304 HTTP error stating that the page was not modified.

The eTag is actually what you're looking for.

Code:

<?php 
// Custom variables
$variables = array('#CCC','#800'); // from db

// CSS Content
header('Content-type: text/css');

// Last Modified
$lastModified = filemtime(__FILE__);

// Get a unique hash of this file (etag)
$etagFile = md5_file(__FILE__);

// Get the HTTP_IF_MODIFIED_SINCE header if set
$ifModifiedSince = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false);

// Get the HTTP_IF_NONE_MATCH header if set (etag: unique file hash)
$etagHeader = (isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);

// Set last-modified header
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $lastModified)." GMT");

// Set etag-header
header("Etag: $etagFile");

// Make sure caching is turned on
header('Cache-Control: public');

// Check if page has changed. If not, send 304 and exit
if(@strtotime($ifModifiedSince) == $lastModified || $etagHeader == $etagFile){
   header("HTTP/1.1 304 Not Modified");
   exit;
}
?>
body {background: <?php echo $variables[0]; ?>;}
Wissam El-Kik
  • 2,469
  • 1
  • 17
  • 21