Welcome Guest, Not a member yet? Register   Sign In
Client-side caching mechanism / hook based (HTTP/1.1 304 Not Modified)
#1

[eluser]Patrick Savalle[/eluser]
I built a simple mechanism to activate client-side caching into a pre-system hook. It seems to work fine. Let me know if anything is wrong with it, otherwise use it to your advantage! It is based on the HTTP 304 header. This code instructs the browser to use its cache and returns without sending any content. Superfast.

The code is completely generic and configuration is very simple: just insert the URL patterns for which the browser cache should be used.

/hooks/client_side_caching.php

Code:
<?php

function client_side_caching(array $params )
{
    foreach( $params as $k => $v)
    {
        if (preg_match($k, $_SERVER['REQUEST_URI'])>0)
        {
            session_cache_limiter(false);
            header('Cache-Control: private');
    
            // --------------------------------------------------------------
            // simple browser caching mechanisme: if browser requests content
            // younger then ? minutes, just inform it to use its cache
            // --------------------------------------------------------------
    
            if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= (time() - ($v * 60)))
            {
                header('HTTP/1.1 304 Not Modified');
                exit;
            }
            else
            {
                // ----------------------
                  // return NOW() in header
                // ----------------------
                header('Last-Modified: '.gmdate("D, d M Y H:i:s\G\M\T"));
            }
            break;
        }
    }
}

/config/hooks.php

Code:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| Hooks
| -------------------------------------------------------------------------
| This file lets you define "hooks" to extend CI without hacking the core
| files.  Please see the user guide for info:
|
|    http://ellislab.com/codeigniter/user-guide/general/hooks.html
|
*/

$hook['pre_system'] = array(
                                'function' => 'client_side_caching',
                                'filename' => 'clientsidecaching.php',
                                'filepath' => 'hooks',
                                'params'   => array(
                                                '@^/$@' => '60',
                                                '@^/badge.*@i' => '5',
                                                '@^/widget.*@i' => '5',
                                                '@.*\.css$@i' => '60',
                                                '@.*\.js$@i' => '60' );

/* End of file hooks.php */
/* Location: ./application/config/hooks.php */

The URL-patterns of course are system specific, you should enter your own. The number after the URL-pattern, is the number of minutes the browser should cache the file.
#2

[eluser]n0xie[/eluser]
While I think the solution is pretty clever, why not just solve it via .htaccess so it never hits CI at all?
#3

[eluser]Patrick Savalle[/eluser]
Ah, Yes, that part was missing Smile and that details are missing after making the example generic.

Because we use CI/PHP-generated images and widgets (think of vote buttons with vote counts in it) and need to be able to control the response / cache. If there is a change in content, CI can act on that by invalidating 'the cache'. An eTag is impossible (too costly to calculate).

It was build in combination with this 'solution'.

http://ellislab.com/forums/viewthread/194426/

So I should add: use this mechanism if you need application control over the client-cache. Am I still overlooking something?
#4

[eluser]n0xie[/eluser]
No that makes perfect sense :-)

Although you might also want to look into using Nginx + Memcache. When setup correctly Nginx will save all the responses for certain requests. (say some widget you want to serve from your webserver). The first request will be generated by PHP, and then cached by Nginx. When another request comes for the same url/resource, it will serve it straight from (Mem)cache. It won't hit CodeIgniter at all this way. You can easily invalidate the cache by just updating your Mem(cache) with updated data.
#5

[eluser]Patrick Savalle[/eluser]
Yes, thank you! At the moment I see they are trying Nginx. We went from Apache, to lighttp, to Nginx now. I will mail them your reply!

I don't understand however why CI doesn't integrate this clientside caching mechanism in their output caching. I would take only 4, 5 lines of code added to _display_cache in output.php. Instead of retrieving and serving the disk-image of a page, CI could just respond with a 304 reply if the clients indicates it will understand.
#6

[eluser]n0xie[/eluser]
Because you don't want to produce a 304 to a _new_ client.




Theme © iAndrew 2016 - Forum software by © MyBB