Building a CCS and Javascript cache for serving / who has the know how?

Hi,

i’m looking for something special. But first here what i use since a long time (putted it together from stuff i found):

<?php
ob_start('ob_gzhandler');
header('Content-type: text/css; charset: UTF-8');
header('Cache-Control: public');
header('Vary: Accept-Encoding');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($_SERVER['SCRIPT_FILENAME'])). ' GMT', true, 200); $expires = 60*60*24*365; // 1 year
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT'); // 1 month

define('DS', DIRECTORY_SEPARATOR);
define('PATH_ROOT', dirname(__FILE__) . DS);

$cssPath = PATH_ROOT;

//css browser = "all" for all browser, "browser1,browser2,..." for defined various browser only
//IE = msie 6
//IE with various version = msie parent version or full version, e.g. "msie 6" or "msie 5.5" or "msie 5.0.1"
//Opera = opera
//Opera with various version = opera/version, e.g. "opera/9.10"
//Firefox = firefox
//Firefox with various version = firefox/version, e.g. "firefox/2.0.0.14"

$cssGZIP[] = $cssPath."|css-file1.css|all";
$cssGZIP[] = $cssPath."|css-file2.css|all";
$cssGZIP[] = $cssPath."./patches/|ie8.css|msie 8";

foreach($cssGZIP as $GZIP) {
	$css = explode("|", $GZIP);
	if($css[2]=="all") {
	if(file_exists($css[0].$css[1])) {
		$buffer .= file_get_contents($css[0].$css[1]);
	}
    } else {
		$browsers = explode(",", $css[2]);
		$loadThisCSS = false;
		foreach($browsers as $browser) {
			if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), $browser) !== false) {
			   $loadThisCSS = true;
			}
		}
		if($loadThisCSS == true) {
			if(file_exists($css[0].$css[1])) {
			$buffer .= file_get_contents($css[0].$css[1]);
			}
	   }
   }
}

// Remove comments
$buffer = preg_replace('!/\\*[^*]*\\*+([^/][^*]*\\*+)*/!', '', $buffer);

// Remove space after colons
$buffer = str_replace(': ', ':', $buffer);

// Remove whitespace
$buffer = str_replace(array("\\r\
", "\\r", "\
", "\	", '  ', '    ', '    '), '', $buffer);

echo($buffer);
?>

So it combines all style sheets (you have just one http request) and compiles them. The nice thing is that its easy and i can set my header in one place how i want them.

The next thing i do that visitors get the new style sheet (if i changed something), because of the far future expires header (and not the one from the browser cache), i write it:

<link rel="stylesheet" href="css-fb20110611.php" />

and make a redirect:

RewriteRule (.*)-fb\\d+\\.(.*)$ $1.$2 [L]

So every time i change the style sheet i change the number and the visitors browser gets the new one. So “css-fb20110611.php” always points to “css.php” and you don’t have to rename every time the “css.php”.

Everybody knows the “css.php?v=1231” way to serve the new style sheet without the need for renaming the sheet itself. But “?v=1231” is not a good idea because proxy servers have problems with it.

Ok, this all is really the way i want it and works great. By the way - i do the same thing for javascript.

But i want a little bit more. How about extending this script that it snatch’s the number “fb20110611” and saves a file “css-fb20110611.css” in a folder. So if the browser comes and the "link rel=“stylesheet” href=“css-fb20110611.php” matchs the “css-fb20110611.css” in the cache folder, he gets directly this file. So there is just a quick number comparison and the script does not need to combine/compile every time.

I know there are solutions out there who do similar. But all i can find is to much. All of them use some compilers like the one from yahoo. Also you cant set the headers that easy and every setting is spread in different files. The other thing is that they use the save-time-stamp of the file to look if the file has changed. But thats not really save if you use different OS’s.

I saw some who generate a md5 hash. But i think that means also everything go’s every time through the script and than checks if the hash has changed.

I personally, would not use mod_rewrite or do anything fancy just a simple “style.php?v=####” and let the server handle any and all caching. Its been a while since I played with Apache and its modules. But you should beable to find one that mimics IIS 7 Output Caching. With that you wouldn’t need to do anything special within your code, the server itself will handle the caching and recalling without ever executing PHP until you change the version number.

Configure IIS 7 Output Caching : Optimizing Performance : Managing and Maintaining IIS 7 : The Official Microsoft IIS Site

And what proxy servers have trouble with query strings? That would make for a bad proxy server not being able to support query strings seeing as most of the web uses them.

So that means most proxys are bad?
Optimizing cache

I’m through all cache/speed/optimizing articles i have found on the web i think *lol

If they cannot support valid legal URIs then yes, they are bad and broken. They have no business being online if they are broken in such a way. Its simple as that. However, be aware that proxy caching is not that important. Majority of people are not behind a caching proxy. Their browsers also cache resources making it even less of an issue.

Anyways you are now asking about server caching not client caching in this thread. And my advice is to let the server handle it. That way it bypasses executing PHP.

The server does nothing by itself. I’m the one who tells the server what to do. Im the one who needs to set the headers. You tell the proxys how to handle the files with “Cache-Control” and “Vary”.

So if most proxys are bad, why they are online and not get fixed? And if they are bad its still my problem to fix it. There is enough stuff about this thing out there to read.

Their browsers also cache resources making it even less of an issue.

Thats the reason for the version thing (fingerprinting) of the files.

Hm, most people are not behind a proxy? I read it like that that proxys are everywhere (server that cache the stuff) and the visitor gets it from the fastest/nearest.

Okay we are getting off track…What you asked for has nothing to do with HTTP headers or anything else. What you asked for was server caching to avoid recompiling the CSS over and over again. I gave you my point of view. Use a caching mechanism that avoids calling PHP. An example would be IIS’s Output Caching which I’m sure an equivalent for Apache exists.

Web servers like Apache and IIS excel at serving static content like HTML and CSS, if the caching mechanism avoids having to call PHP you can serve a lot more visitors. That also frees up more resources on the server as well.

Ok, if i read it right than “IIS output cache” is what for apache are the “PHP accelerator’s”?

Thats something i can’t do on a shared server. And maybe thats the reason why there are so many css, javascript caches out there who make similar what i want.

minify - Combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads. - Google Project Hosting
CSS Minification on the Fly | Shiny Blog
Lateral Cache: Now you too can have a well organized cache without the work!