Wh1T3h4Ck5
Wh1T3h4Ck5

Reputation: 8509

Setting up cache to consider file-modification date/time

I'm having problems with serving CSS files from PHP. For test I'm just loading content from existing CSS file into PHP variable and than echo it. I want to set headers to allow caching of file until it was modified.

PHP code

  $css_file_path = "path-to-existing-css-file";
  $file_content = file_get_contents ($css_file_path);
  $fmtime = date ("r", filemtime ($css_file_path));

  header ("Content-type: text/css");
  header ("X-Content-Type-Options: nosniff");
  header ("Last-Modified: " . $fmtime);

  die ($file_contents);

This is done by simple PHP code as shown above. For some reason it's never cached (tested in latest Firefox only).

I have tried to put this line before die() function to test it.

  echo date ("r", time());

And it gets updated all the time. I'm such a caching noob, I admit it, so all I want to do is to make file being cached until new modification arrives.

So far, I have read tones of different posts here and web-wide and mostly found nothing or very poor information on this subject.

What am I missing and is it possible to achieve at all?

Upvotes: 1

Views: 1526

Answers (1)

Peter van der Wal
Peter van der Wal

Reputation: 11836

To start with

I want to do is to make file being cached until new modification arrives

The only way a browser can know there is a new modification, is by asking the server whether their cached version is still valid.

This is done as followed:

1. Browser requests /style.css
GET /style.css

2. Server sends to browser
HTTP/1.1 200 OK
Last-Modified: Wed 2 Aug 2017 21:28:00 GMT
Cache-Control: must-revalidate, max-age=31536000

... file-contents ...

// 31536000 is about 1 year

3. Next time browser wants that file it sends
GET /style.css
If-Modified-Since: Wed 2 Aug 2017 21:28:00 GMT

4a. Your server can read that header, and verify if the file isn't modified after
    the given date. If it isn't, you can reply with a single:
HTTP/1.1 304 Not Modified

... without sending the contents again 

4b. If your file was hower modified after Aug 2, you should sent a response simalar 
    as in step 2

So in code, step 2, add the Cache-Control-header:

header('Cache-Control: must-revalidate, max-age=31536000');

And step 4a, act to the If-Modified-Since request-header:

$css_file_path = "path-to-existing-css-file";
$fmtimestamp = filemtime ($css_file_path);

// Check header set by browser
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $fmtimestamp <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
    die(); // We're done here
}

// Otherwise continue as ussualy
$file_content = file_get_contents ($css_file_path);

Alternative solution, without using the If-Modified-Since, but it depends on the situation if this is usable for you:

// Somewhere in your HTML
<link rel="stylesheet" href="/style.css?version=<?php echo filemtime($pathToStyle.css) ?>" />

When your file changes, the link changes and the browser would see it as a new file. In that case you can leave the must-revalidate-part out of the Cache-Control-header and the browser won't reload the style.css unless the max-age expires or cache is cleaned up.

Upvotes: 4

Related Questions