Every time a request hits your server, PHP has to do a lot of processing, all of your code has to be compiled & executed for every single visit. Even though the outcome of all this processing is often identical for both visitor 21600 and 21601. So why not save the flat HTML generated for visitor 21600, and serve that to 21601 as well? This will relieve resources of your web server and database server because less PHP often means less queries.
Cache_Lite
Now you could write such a performance system yourself but there’s a neat package in PEAR called Cache_Lite that can do this for us, benefits:
- it saves us the time of inventing the wheel
- it’s been thoroughly tested
- it’s easy to implement
- it’s got some cool features like lifetime, read/write control, etc.
Now you don’t need to cache entire pages, you can also just cache parts of pages if that’s easier to implement.
Install Cache_Lite
Installing is like taking candy from a baby. On Ubuntu I would use aptitude like this:
1 2 3 | |
And now that we have PEAR, i would use it to install the Cache_Lite extension:
1
| |
And we’re ready!
Implement Cache_Lite
So let’s see how we can implement Cache_Lite into our scripts. The basic idea is that we have a unique identifier for every page. You can make it up, get it from your database, or use the REQUEST_URI. Cache_Lite will see if it stored content for that identifier before, and if it’s fresh enough. If so, it will retrieve the stored HTML from disk and echo it right away. If not, we:
- turn on output buffereing so we can catch all following content
- we include the original PHP code
- catch the output buffer, and let Cache_Lite store it on disk for the next time.
- and then echo it
This is a PHP example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
In this example, the real, original php code is stored in realcontent.php
Let Cache Live in RAM
If your want, you can have all the static html files served from the server’s internal memory. Now this would really speedup things. Checkout my other article Create turbocharged storage using tmpfs to learn how.
More Cache_Lite
One thing I always like to do, is to automatically purge an article’s cache when a comment has been placed. You could for example place this before Cache_Lite checks if it’s got a cache page for a specific $id:
1 2 3 4 5 | |
Take some time to read the comments in the source code, it’s actually pretty easy.
Imported comments
These were imported from my old blog. Please use disqus below for new comments
ViserExcizer
on 2010-01-14 01:40:12
Hello, how do I install cache lite manually? If i am on a shared server?
steve shier
on 2009-05-06 06:14:02
Kevin:
Your article is good and clear. My cache file is being written but my cache is never hit, apparently because the filename changes. I am just trying to cache a string although later it will be an array of objects populated from a database. Everytime I try to retrieve it , instead of getting the cached data (which I can view in the cached file), it creates a new cache entry. Also, the cache filename seems to change each time. Is therre a way to fix it so it doesn't change and pulls from the cache?
Here's the code
In my main file which the user views (Contact.php) I have :
$quote=new QuoteBL();
$quotevalue=$quote-&
gt;GetNextQuote();
echo \&
quot;cache=\&
quot;.$quotevalue;
in QuoteBL I have:
class QuoteBL {
//constructor
public function QuoteBL(){
}
public function GetNextQuote(){
//tries to get quote from cache and if no cached data, retrieves data and saves to cache
$data=null;
$cacheid = 'quotearray';
$cache_options = array(
'cacheDir' =&
gt;'Cache/data/', //this is the temp directory of the cache files
'lifeTime' =&
gt;3600, //time, in seconds, of how long the cache will be valid
'fileNameProtection' =&
gt; true, //make sure filename is valid
'writeControl' =&
gt; 'true',
'readControl' =&
gt; 'true',
'readControlType' =&
gt; 'md5'
);
$cache=new Cache_Lite($cache_options);
if ($data = $cache-&
gt;get($cacheid)) {
// data is in our cache, access it through $data
echo \&
quot;got data from cache&
lt;BR&
gt;\&
quot;;
}
else { // Not found in cache, it needs to be added
$data=\&
quot;The quality of mercy is not strained\&
quot;;
$cache-&
gt;save($data,$cacheid,null);
echo \&
quot;cache empty, save new data in cache&
lt;BR&
gt;\&
quot;;
}
return $data;
}
}
TIA,
Steve Shier
Victor
on 2009-02-25 21:19:40
I think I got it. I was using the var $id for all block but for this one it didn't work. After I renamed it to some other name (say $ident) it worked.
Victor
on 2009-02-25 19:23:02
The code works but I can't get it to work fine with a php file that contains a msqyl query and is included in a parent file (e.g. template page). That template page contains about 4 cached block and all work fine, except this one that has mysql queries. The cache for that file rewrites with every refresh and I don't know why. If I remove the query it works just fine.
Dilli R. Maharjan
on 2008-06-18 08:15:04
Thanks Kevin, I was busy on other stuff. Thanks again for the suggestions.
Proea
on 2008-06-16 07:07:13
Thanks
Kevin
on 2008-05-31 12:37:08
@ Dilli R. Maharjan: You could do that yes, but Cache_Lite also provides methods to delete specific cached keys. You should review the (tiny) manual.
Dilli R. Maharjan
on 2008-05-27 08:21:54
Great article, It helped me a lot.
I searched for infromation regarding cache hit, cache miss and regarding cache stat and I did not find any. Someone please refer any URL regarding them. I am confused regarding how to flush my cache, simplying deleted cached directory work or not? Please help.
Kevin
on 2008-03-04 23:37:53
@ wireholic: maybe i'll write another article some day that diggs a little deeper. thanks for your remark and you're right, I'll update the article
wireholic
on 2008-03-04 21:03:15
Hey.
Good introduction to Cache_Lite.
However if you want to cache bigger sites than blogs,little portals etc. You should look deeper into Cache_Lite functionalities its really powerfull. Thereis a good article on the Sitepoint's page.
One more thing, if you dont want your data to duplicate at the first time the page is loaded add ob_end_clean() just after \&
quot;$Cache_Lite-&
gt;save($data, $id);\&
quot; line to clear output buffering data. That should be noticed.
Cheers.
Kevin
on 2007-11-23 17:52:59
@ Ashish: I've never used Smarty, but you should at least be able to implement it for caching entire pages. I would say play around with it a bit and see how flexibile Smarty really is.
Ashish
on 2007-11-23 16:12:46
Hi,
Thanks for this, do you have any idea on using this with Smarty?
Any tips?
seonet
on 2007-10-31 02:02:58
Thanks Kevin
:D
Kevin
on 2007-10-29 08:46:19
@ seonet: Hi, for example. If I wanted to cache this entire article, a logical $id would be: 'speedup_your_website_with_cache_lite' or maybe the internal article id like: 189 or something. If I only wanted to cache the comments section a logical id would be: 'speedup_your_website_with_cache_lite.comments'
See? You're totally free in what id to pick, just as long as it's unique and logically for you
seonet
on 2007-10-29 06:20:43
Hi Kevin,
I want to ask about how to assign $id
one $id for one cache file or what ?
So if I create template files in cache -&
gt;
I need assign one file with unique $id or how ?
I read in somewhere \&
quot;
$id = md5($strSQL);
if($cache-&
gt;get($id)){
//
$result = $cache-&
gt;get($id);
} else {
$result = getAll($strSQL)
$cache-&
gt;save($result, $id);
}
Hmm, what do you think about code ?
Kevin
on 2007-10-18 22:31:04
@ Moritz: I think you are not providing Cache_Lite with an $options array.
$Cache_Lite = new Cache_Lite($options);
You have to define some options in the options array just like in the example.
Moritz
on 2007-10-18 18:46:48
@Kevin
thanks for your help, but i guess i'm too stupid.
Now i get this error message:
Warning: Invalid argument supplied for foreach() in /….www/PEAR/Cache/Lite.php on line 282
Kevin
on 2007-10-14 12:52:10
@ Moritz: You've installed PEAR in /customers/zweiteherren.com/zweiteherren.com/httpd.www/PEAR and which is not in the include_path. PEAR should be in PHP's include_path so Cache_Lite can find all it's dependencies.
Moritz
on 2007-10-13 22:31:32
@Kevin
Thanks,
it works so far, but i still get this error message at the end of the page:
Warning: Cache_Lite::include_once(PEAR.php) [function.Cache-Lite-include-once]: failed to open stream: No such file or directory in /customers/zweiteherren.com/zweiteherren.com/httpd.www/PEAR/Cache/Lite.php on line 536
Warning: Cache_Lite::include_once() [function.include]: Failed opening 'PEAR.php' for inclusion (include_path='.:') in /customers/zweiteherren.com/zweiteherren.com/httpd.www/PEAR/Cache/Lite.php on line 536
Fatal error: Class 'PEAR' not found in /customers/zweiteherren.com/zweiteherren.com/httpd.www/PEAR/Cache/Lite.php on line 537
What's wrong with it?
Kevin
on 2007-10-12 11:38:49
@ Moritz: You're free to cache any page or part of a page you want. You could create a new index.php and rename your old one to real_content.php, you could also do this for a part of your page which isn't very dynamic but does require some heavy php &
amp; db operations. So in that case you keep your old index.php but you use the example code to only cache (for example) your sidebar. The original sidebar code goes moves to it's own: sidebar.php, and then that's the file you include instead of real_content.php
Moritz
on 2007-10-11 22:13:22
I really don't understand caching.
in which file di I include realcontent.php?
it's all explained half.
Kevin
on 2007-10-02 23:47:46
@ svetzal: You kan define the keys so that's up to the programmer I think. You can also have Cache_Lite use different directories.
@ Kon: Cache_Lite support some mechanisms to ensure a file has been successfully written to the filesystem. You will have to decide whether or not to use those based on the situation, because of course, every check that's implemented costs performance.
K
on 2007-09-08 22:47:48
What happens if two users view the same uncached page at the same time? Do you risk two PHP processes writing to the same file at the same time?
svetzal
on 2007-09-06 20:38:05
Be careful of Cache_Lite - if you have a large number of cache objects, you may get corrupted results back (I have assumed it's duplicate keys). Moved to memcached instead.
Kevin
on 2007-08-06 10:45:39
It means if a cached page is older than 3600 secs (1 hour), it should be removed. This way you automatically get fresh content every hour.
Preeti
on 2007-08-06 08:05:55
What does the 'lifeTime' =&
gt; 3600 in $options array do?