Part of the EllisLab Network
   
 
Client side and server side cache control
Posted: 18 January 2008 09:45 AM   [ Ignore ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

The cache feature of CI is nice, but still limited. It could have a function to delete the cache file of the current controller. And a function to delete the entire cache as well.

But the main thing it could have is also control the browser cache. Please take a look at:

http://www.sitepoint.com/article/caching-php-performance

http://www.sitepoint.com/article/php-anthology-2-5-caching (optional reading)

I found this excellent tutorial which explains in detail how to control the client side cache with headers and implement a server-side cache as well. The examples are really useful to bring more performance to a web site, but pay attention that getallheaders() or apache_request_headers() only work when PHP is running as an Apache module. Unfortunatelly, these functions are not available when PHP run as a CGI/FastCGI. Another way to get this header is checking $_SERVER[‘HTTP_IF_MODIFIED_SINCE’].

I did some tests and it works, but more tests are necessary with different browsers. I tested with Firefox 2 and Internet Explorer 6 and I noticed that they work different. Firefox always checks the server and work nice, but IE 6 don’t. It display the page faster, but it is not accurate (may is necessary to send extra headers, I don’t know). My test code was something like this (note that it is just a test, not an adaptation for CI):

// at the end the application, creates the cached file:

// get the actual uri
if(isset($_SERVER['PATH_INFO'])) {
    $pathinfo
=$_SERVER['PATH_INFO'];
} else {
    $pathinfo
=@getenv('PATH_INFO');
}

// define the cache filename based on uri
$cache_file='cache/'.md5($pathinfo);

// get the page contents
$buffer=gzencode(ob_get_contents(),9);

// write page to the cache
$fp=fopen("{$cache_file}.gz",'w');
flock($fp, LOCK_EX);
fwrite($fp,$buffer);
flock($fp, LOCK_UN);
fclose($fp);

clearstatcache(); // is this line necessary?

// remove the old cache file, if exists
if(is_file("{$cache_file}.gz")) unlink("{$cache_file}.gz");

// rename the file to the final name (this is to prevent file locking problems)
rename("{$cache_file}_new.gz","{$cache_file}.gz");

// send headers to the browser
// updates the date of the file in the browser cache
header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');
// set to gzip compression
header("Content-Encoding: gzip");
// the line below brings a little more performance to the browsers
header('Content-Length: '.strlen($buffer));

// send the cached page to the browser
echo $buffer;

// at the beggining of the application, checks for a cached page:

clearstatcache(); // is this line necessary?

// get the actual uri
if(isset($_SERVER['PATH_INFO'])) {
    $pathinfo
=$_SERVER['PATH_INFO'];
} else {
    $pathinfo
=@getenv('PATH_INFO');
}

// define the cache filename based on uri
$cache_file='cache/'.md5($pathinfo);

// check if a cached file exists
if(is_file("{$cache_file}.gz")) {

    
// get the date and time when the cache file was created
    
$lastModified=filemtime("{$cache_file}.gz");

    
// get the date and time of the browser cached file
    
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        $modifiedSince
=strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    
} elseif(function_exists('getallheaders')) {
        $request
=getallheaders();  
        if(isset(
$request['If-Modified-Since'])) {  
            $modifiedSince
=explode(';', $request['If-Modified-Since']);  
            
$modifiedSince=strtotime($modifiedSince[0]);  
        
} else {
            $modifiedSince
=0;
        
}
    }
else {
        $modifiedSince
=0;
    
}

    
// if the browser cached file is not old, send a 304 code and exit
    
if($lastModified<=$modifiedSince) {
        header
('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
        
header('HTTP/1.1 304 Not Modified');
        exit;
    
} else {
        
// send the cached file to the browser
        
$file_size=filesize("{$cache_file}.gz");
        
// updates the date of the file in the browser cache
        
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
        
// set to gzip compression
        
header("Content-Encoding: gzip");
        
// the line below brings a little more performance to the browsers
        
header("Content-Length: $file_size");
        
readfile("{$cache_file}.gz");
        exit;
    
}
}
else { // no cached page
    
header('Expires: Mon, 1 Jan 1990 00:00:00 GMT');
    
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
    
header('Cache-Control: post-check=0, pre-check=0',false);
    
session_cache_limiter('must-revalidate');
}

As you can see, in my test I did gzip the cache files (may is necessary to check if server have support to it too). This can give more speed to browsers to load cached files and also reduces the disk space used. The only problem is that gzip uses more CPU power to compact the pages, but I think with a good cache control, this will not be an issue. May this be optional instead.

Well, more tests must be done before implement anything. And with delete cache functions we can control the server cache at our application, when pages are updated. The client side cache control will be done automatically by the framework.

There are more headers in HTTP 1.1 protocol to control proxy caches, etc, but I don’t think we must go more further on this, except if some are necessary to make this cache system to work correctly in all browsers.

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 21 January 2008 07:19 AM   [ Ignore ]   [ # 1 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

Nobody made comments…  oh oh

Well, I hope this suggestion at least take into consideration someday…

The correct control of client side cache saves bandwidth and makes the web sites even faster.

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 22 January 2008 11:15 AM   [ Ignore ]   [ # 2 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

Oh great master Derek! At least you read my post? smile

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 22 January 2008 06:06 PM   [ Ignore ]   [ # 3 ]  
Administrator
Avatar
RankRankRankRankRankRank
Total Posts:  7337
Joined  03-23-2006

LOL, I know you’re joking but no need to refer to either Derek as “master”.  We’re just like you, only with commit access wink

I confess I haven’t read through your post… that’s a heck of a lot of text there.  Does this have any implications on IE 7?

 Signature 

DerekAllard.com - CodeIgniter, ExpressionEngine, and the World of Web Design
BambooInvoice - Open Source, CodeIgniter powered invoicing.

Profile
MSG
 
 
Posted: 22 January 2008 06:37 PM   [ Ignore ]   [ # 4 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

Okay, okay, if I can’t call you “master”, may I call you “lord”?  grin
Just kidding!  wink  You are a really nice guy, man.
I think everybody here like you both very much. (I’m not an exception!) smile


Well, I did not test it in Internet Explorer 7 yet, but I think it will work better with IE 7 than IE 6, because IE 7 is more “W3C standard”, as Firefox is. Please take a look when you have time and make your own tests, because the right control of the client side cache can make CodeIgniter-based web sites even faster!

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 22 January 2008 09:12 PM   [ Ignore ]   [ # 5 ]  
Administrator
Avatar
RankRankRankRankRankRank
Total Posts:  7337
Joined  03-23-2006

The reason I asked is because IE 6 is now formally abandoned (ok, that’s not 100% technically accurate… but for our intents it is) as Microsoft is forcing users to update to IE 7 in a critical update.  So if this solves an IE 6 problem, I’m going to suggest we hold off.

Also, have you seen this in config?

/*
|--------------------------------------------------------------------------
| Output Compression
|--------------------------------------------------------------------------
|
| Enables Gzip output compression for faster page loads.  When enabled,
| the output class will test whether your server supports Gzip.
| Even if it does, however, not all browsers support compression
| so enable only if you are reasonably sure your visitors can handle it.
|
| VERY IMPORTANT:  If you are getting a blank page when compression is enabled it
| means you are prematurely outputting something to your browser. It could
| even be a line of whitespace at the end of one of your scripts.  For
| compression to work, nothing can be sent before the output buffer is called
| by the output class.  Do not "echo" any values with compression enabled.
|
*/
$config['compress_output'] = FALSE;

Lord Derek Autumbottom the third

 Signature 

DerekAllard.com - CodeIgniter, ExpressionEngine, and the World of Web Design
BambooInvoice - Open Source, CodeIgniter powered invoicing.

Profile
MSG
 
 
Posted: 23 January 2008 09:17 AM   [ Ignore ]   [ # 6 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

So if this solves an IE 6 problem, I’m going to suggest we hold off.

I am not sure about IE 6, but I can make more tests. The problem I found on it is that the page do not update in its cache, as it was always updated. May this have something to do with expire date, I don’t know. In Firefox it is working fine.

Also, have you seen this in config?

Yes, I did. But if you only have compression, the server will always send the page to the browser. With client side cache control, it will send the page only if it is not updated or if it doesn’t exist in the browser cache. When the page is updated, the script will just send a Not Modified HTTP header and quit. This saves bandwidth and speed up the web site.

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 23 January 2008 10:30 AM   [ Ignore ]   [ # 7 ]  
Administrator
Avatar
RankRankRankRankRankRank
Total Posts:  7337
Joined  03-23-2006

OK, well to be honest without reading 46 pages of linked documentation and then inspecting and interpreting your code in my head, and then inspecting the current code, I’m not sure how to bring myself up to speed on this.  This is also probably why you got very little feedback.  You might want to try distributing a CI-oriented patch and re-trying for community feedback.

 Signature 

DerekAllard.com - CodeIgniter, ExpressionEngine, and the World of Web Design
BambooInvoice - Open Source, CodeIgniter powered invoicing.

Profile
MSG
 
 
Posted: 23 January 2008 12:54 PM   [ Ignore ]   [ # 8 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

I understand. Well, I also don’t have too much spare time, but I will make some tests and try to create a CI patch. When I have something I will introduce it to the community, ok?

PS: if you are not a Jedi master, are you a Lord Sith? wink

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 28 January 2008 02:50 AM   [ Ignore ]   [ # 9 ]  
Summer Student
Avatar
Total Posts:  12
Joined  09-01-2007

I’m a bit late to the party, but just wanted to add my enthusiasm for some browser aware caching in CI.

Thanks for sharing that Edemilson.

Using this kind of caching is an excellent thing to do IMO. In practice it can be little fiddly to implement perfectly and tricky to debug.
I seem to remember that cacheable pages are supposed to be more search engine friendly, (on top of all the other benefits).

Unfortunately I’m a bit time poor at the moment to be able to offer anything more than this token comment (*_*).

Profile
 
 
Posted: 28 January 2008 08:51 AM   [ Ignore ]   [ # 10 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  286
Joined  12-25-2007

You are welcome mrkirkland. Thank you for your comments!
I hope somebody with experience in extending the core can help me on this.

 Signature 

Oh God… Why didn’t you show me CodeIgniter before?

Profile
 
 
Posted: 14 May 2008 03:09 PM   [ Ignore ]   [ # 11 ]  
Summer Student
Total Posts:  4
Joined  05-14-2008

I really think that client side caching is important, also read the php anthology link you provided and found it extremely useful. I’m looking forward to see some sort of CI implementation for this (maybe via a new cache lib?) smile

Profile
 
 
Posted: 14 May 2008 03:25 PM   [ Ignore ]   [ # 12 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  754
Joined  01-13-2008

Welcome to the Forums, deadcabbit.

 Signature 

Yonti - I am Currently looking for a business partner, to create the best developer hosting out there. If your interested PM me.

Fluxity Lighting - My other company.


I’m a Proud Supporter and Sponser of Tomorrows Web.

Profile
 
 
Posted: 21 May 2008 12:04 AM   [ Ignore ]   [ # 13 ]  
Grad Student
Rank
Total Posts:  41
Joined  07-22-2007

yeah, the caching is very important, as of now i use memcached to cache my data/content or everything i need to, plus it can be deleted if u want to by the ttl or by custom function .

Profile
 
 
   
 
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 819, on March 11, 2010 11:15 AM
Total Registered Members: 120442 Total Logged-in Users: 44
Total Topics: 126530 Total Anonymous Users: 6
Total Replies: 665324 Total Guests: 352
Total Posts: 791854    
Members ( View Memberlist )