0

I have a php file called main.css.php that collects multiple css files and outputs them as one large css file. The number of css files that it collects can range from 1-10. The code is something like this:

header('Content-type: text/css');
header('Cache-Control: max-age=31536000');
ob_start("compress");
function compress($buffer) {
    /* remove comments */
    $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
    /* remove tabs, spaces, newlines, etc. */
    $buffer = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $buffer);
    return $buffer;
}

// include css files
foreach ($css_files as $path) {
    if (file_exists($path)) {
        include_once($path);
    }
}
ob_end_flush();

So I have that part sorted but now I'm not sure how to cache it with a way that lets me update the cache if any of the original css files change. As suggested in this answer I was going to do something like:

$cache = "";
foreach ($css_files as $path) {
    $cache.= filemtime($path);
}
...
echo "<link rel='stylesheet' href='/css/base.{$cache}.css'>";

However I can't use this apache rewrite rule:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

as I'm not sure how long the $cache will be as it will contain multiple unix timestamps.

Summary

I need to combine multiple css files into one php file that is sent to the browser with a css header. I then needed to correctly cache this file but with a way that allows me to update the cache if any of the original css files change.

Any advice, suggestions, or better ways to go about what I am doing would be much appreciated.

Community
  • 1
  • 1
joshhunt
  • 5,197
  • 4
  • 37
  • 60

2 Answers2

1

You should make a hash of the $cache variable and use that in the filename. It would be something like this:

<?php

$cache = "";
foreach ($css_files as $path) {
    $cache .= filemtime($path);
}

$cache = md5($cache);

And your rewrite rule would use the length of the hash function; in this case, we use md5, which is 32 characters long:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{32}\.(css|js)$ $1.$2 [L]

Hope that helps

wavemode
  • 2,076
  • 1
  • 19
  • 24
1

Why not store cache info on disk? This way you don't need to worry about .htaccess.

$prevTimes = filegetcontents('/cache/css.txt')
if(array_sum($filetimes) != (int) $prevTimes){
  //recompile css
  //update csscacheinfo.txt with $newTimes
  //echo css file link for stylesheet using $newTimes.css as css file
} else {
  //echo css file link for stylesheet using $prevTimes.css as css file
}

FYI: It's faster to store / add integers than to concatenate and compare strings.

Calvin Froedge
  • 16,135
  • 16
  • 55
  • 61
  • If it was cached, how would the browser know when to look for a new version? – joshhunt Sep 11 '14 at 04:51
  • This is a cleaner solution certainly, but your FYI comment is misleading; whatever microseconds of performance are gained by avoiding string concatenation are lost by going to disk and converting to int at every page access. But, again, the difference is minute, so this is still the best way to cache the file. – wavemode Sep 11 '14 at 04:52
  • @wavemode PHP is constantly reading files from disk. require, etc. In my comment I was simply referring to the fact that he's adding all of the times together as a string. So he's converting data type, then building a new string, and presumably later comparing strings. – Calvin Froedge Sep 11 '14 at 04:54
  • @joshhunt Just change the filename. You could use the sum of file modification times, for example. If the browser reads a new file URL, it's going to load the changes because it doesn't have that file cached. – Calvin Froedge Sep 11 '14 at 05:02
  • Right which is what .htaccess rewrite is for so that it's automated. Unless I'm missing something? – joshhunt Sep 11 '14 at 05:05