tags:

views:

297

answers:

2

I've got over some tutorials on how to gzip a css file in which you create a public php file to include css files with compression. The problem is I cannot get it to cache my css files. I'm using firebug for reference and I've actually tried using the same code to compress some javascript and it caches it fine.

Here is the code:

if(extension_loaded('zlib')){
ob_start('ob_gzhandler');
}
$offset = 60 * 60 * 24 * 31;
header('Content-type: text/css');
header ('Cache-Control: max-age=' . $offset . ', must-revalidate');
header ('Expires: ' . gmdate ("D, d M Y H:i:s", time() + $offset) . ' GMT');
ob_start("compress");
function compress($buffer) {
    // Remove Comments, White Space, End ;'s
    $buffer = preg_replace('#/\*.*?\*/#s', '', $buffer);
    $buffer = preg_replace('/\s*([{}|:;,])\s+/', '$1', $buffer);
    $buffer = preg_replace('/\s\s+(.*)/', '$1', $buffer);
    $buffer = str_replace(';}', '}', $buffer);
    $buffer = str_replace(' {', '{', $buffer);
    return $buffer;
    }

    include('global.css');

    if(extension_loaded('zlib')){
    ob_end_flush();
}

Then I'm simply referencing my php file as a css document on other pages. As you can see I've tried adding max age to the mix which also proves unsuccessful.

Here are the response headers

Date    
Tue, 21 Jul 2009 19:59:19 GMT

Server  
Apache/1.3.41 (Darwin) PHP/4.4.9

X-Powered-By    
PHP/4.4.9

Cache-Control   
max-age=2592000, must-revalidate

Expires 
Thu, 20 Aug 2009 19:59:19 GMT

Content-Encoding    
gzip

Vary    
Accept-Encoding

Keep-Alive  
timeout=15, max=93

Connection  
Keep-Alive

Transfer-Encoding   
chunked

Content-Type    
text/css

Is there anything I'm missing, or a better way to go about doing this?

Thanks,

EDIT:

A script that detects whether or not the file has been changed & sending a 304 if it hasn't, in combination with proper headers has solved this problem.

Arthur

A: 

If you read python/django, you can read the code for django compressor. It puts multiple CSS files into one. The CSS part looks like it launches CSSTidy to clean up the CSS.

hughdbrown
+4  A: 

Try adding this to the set of headers:-

$offset = 60 * 60 * 24;
header('Content-type: text/css');
header('Cache-Control: max-age=' . $offset);
header('Expires: ' . gmdate ("D, d M Y H:i:s", time() + $offset) . ' GMT');
header('Last-Modified: ' . gmdate ("D, d M Y H:i:s", time()) . ' GMT');

The problem was the must-revalidate instruction in the cache control header. This would cause the client to re-request the css each time it is needed and your code has no handling for the If-Modified-Since header and the sending of a 304 Unmodified response status code.

The above approach reduces the cache period to 1 day and eliminates the must-revalidate instruction. It also adds the Last-Modified header (a cache may choose not to cache an item when a Last-Modified or ETag header is missing).

To improve this you could find the actual last modified time of the css file you are compressing and send that as the Last-Modified header. You could include in your code a comparison of the requests If-Modified-Since header with the value of the css files last modified time. If you find them the same send this set of headers but also send a 304 Unmodfied status and don't send the body at all. (I'm not really a PHP person so I'll leave that to the PHP experts to place in another answer).

Make a realistic assessment of how long you would want a client cache the css before it must make another attempt to retrieve it and set the max-age value accordingly.

AnthonyWJones
askon
@askon: Those weren't the critical factors, the key problem is you inclusion of must-revalidate directive in the Cache-Control header. Using that means the css will always be re-fetched. Also are you using page refresh (F5) in your testing? That won't prove anything, resources such as css are refetched under a refresh context and without a 304 mechanism built into your code that is going to result in a complete fetch of the resource.
AnthonyWJones
askon
I also forgot to note, yes I am using F5 to refresh the page, and using Firefox 3.5.1 with Firebug 1.4.0b7
askon
Try testing by simply adding ?x=1 to the url rather than refreshing. This should demonstrate that the css is being cached.
AnthonyWJones