Page Cache - Benefits and How to
Written by MarketInSG in Tutorials on May 2, 2013 | 22 Comments
What is page caching? How can I improve my website’s loading speed? That would usually be the question that brought you here. In this quick tutorial, we will explain what is page caching and how we can achieve it using PHP. However, for this tutorial, we will not be providing a download at the end, unlike other tutorials we had written.
What is page caching?
If you render your web pages dynamically for relatively static pages such as your information pages on OpenCart or maybe even your homepage, you might wish to consider this. Page caching is done to help reduce the numerous request to your database. The fetched contents are captured and stored during the first load, and in the future loads, they are served instead.
In simpler explanation, imagine you are asked to find out about the history of the United States and share it with your friend. You did a search on the internet, tries to remember it, and go back to him with the details. Two hours later, another friend asked you the same question, you will be repeating the same process. Imagine hundreds of friends asking you the same question, you will be repeating it over and over. If you, instead, had written down the details, you won’t be repeating the process. So that’s what caching does. It stores the data fetched and just renders to the next guy who asked for the same thing.
What are the benefits?
Nowadays, most websites use cache to help reduce page load time. For sure, there are tons of benefits to page caching.
Caching your data can help to reduce page loading speed. With a faster website, it does somehow benefit your SEO rank. Who knows, your visitors might be happier too!
How to cache my page?
Alright, this should be the part all of you would be interested in. We will attempt to cache your web page on OpenCart. If we look into OpenCart’s structure, we will be able to understand that each normal page on OpenCart are rendered using
$this->response->setOutput($this->render());
Further looking into it, you will find the response file in system/library/response.php and that all pages are routed through the index.php file.
Now here’s what we will do. We will capture the HTML in the response.php file and store to serve to future requests.
We will need a simple script to do caching. We will create a script in system/library/pagecache.php and also an empty folder (system/cache/pagecache)
We will define the basics at the top of the script.
<?php define('CACHE_FOLDER', DIR_CACHE . 'pagecache/'); // Cache Folder define('CACHE_EXPIRE', '2400'); // Cache Expire in seconds define('SITE_LANGUAGE', 'en'); // Default website language define('SITE_CURRENCY', 'USD'); // Default website currency $skip_routes = array( // Skip routes to cache. We will not cache product/compare since it should be unique to all clients 'product/compare' );
Now, we will check if session had been started.
if (!session_id()) { ini_set('session.use_cookies', 'On'); ini_set('session.use_trans_sid', 'Off'); session_set_cookie_params(0, '/'); session_start(); }
Once the basics are ready, we will check for some conditions to ensure the user is not logged in or has items in their shopping cart.
if(!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' && (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off')) { if ((isset($_GET['route']) && !in_array($_GET['route'], $skip_routes)) || !isset($_GET['route'])) { if(empty($_SESSION['customer_id']) && empty($_SESSION['affiliate_id']) && empty($_GET['affiliate']) && empty($_SESSION['cart'])) {
Once we checked, we will start to build up the file path where the cache would be stored.
$domain = $_SERVER['HTTP_HOST']; $language = (empty($_SESSION['language']) || !is_string($_SESSION['language'])) ? SITE_LANGUAGE : $_SESSION['language']; $currency = (empty($_SESSION['currency']) || !is_string($_SESSION['currency'])) ? SITE_CURRENCY : $_SESSION['currency']; $url = http_build_query($_GET); $cacheFile = CACHE_FOLDER . $domain . '_' . $language . '_' . $currency . '_' . md5($url) . '.html'; define('CACHE_FILE', $cacheFile); $cacheTime = CACHE_EXPIRE;
Finally, we will check if the file exists, and output the file instead, followed by ending the whole script if the file exists.
if (file_exists($cacheFile) && time() - $cacheTime < filemtime($cacheFile)) { $file = gzopen($cacheFile, 'r'); $file = gzread($file, 1999999); echo $file; exit; } } } } ?>
That will be all for a simple script. Next, we will have to edit system/library/response.php to capture the file. We will do a quick search for the function that was always called for in all controller files.
public function setOutput($output) {
Inside the function, we will attempt to capture the data. We will first check if the cache file path has been defined.
if (defined('CACHE_FILE')) {
Then, we will start working on it. We will write the contents into the file.
$cacheFile = CACHE_FILE; $fp = gzopen($cacheFile, 'w9'); gzwrite($fp, $output); gzclose($fp); }
We are almost done now. I mentioned that every page is routed through the index.php file. We just have to do a simple ‘include’ in the index.php file to include the cache script we created. Do a quick search in index.php for the following line:
require_once('config.php');
and below it, just include your cache script.
require_once('system/library/pagecache.php');
You have now successfully created a script to cache your web pages! Below is how your page cache script should look like in the end.
<?php define('CACHE_FOLDER', DIR_CACHE . 'pagecache/'); // Cache Folder define('CACHE_EXPIRE', '2400'); // Cache Expire in seconds define('SITE_LANGUAGE', 'en'); // Default website language define('SITE_CURRENCY', 'USD'); // Default website currency $skip_routes = array( // Skip routes to cache 'product/compare' ); if (!session_id()) { ini_set('session.use_cookies', 'On'); ini_set('session.use_trans_sid', 'Off'); session_set_cookie_params(0, '/'); session_start(); } if(!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' && (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off')) { if ((isset($_GET['route']) && !in_array($_GET['route'], $skip_routes)) || !isset($_GET['route'])) { if(empty($_SESSION['customer_id']) && empty($_SESSION['affiliate_id']) && empty($_GET['affiliate']) && empty($_SESSION['cart'])) { $domain = $_SERVER['HTTP_HOST']; $language = (empty($_SESSION['language']) || !is_string($_SESSION['language'])) ? SITE_LANGUAGE : $_SESSION['language']; $currency = (empty($_SESSION['currency']) || !is_string($_SESSION['currency'])) ? SITE_CURRENCY : $_SESSION['currency']; $url = http_build_query($_GET); $cacheFile = CACHE_FOLDER . $domain . '_' . $language . '_' . $currency . '_' . md5($url) . '.html'; define('CACHE_FILE', $cacheFile); $cacheTime = CACHE_EXPIRE; if (file_exists($cacheFile) && time() - $cacheTime < filemtime($cacheFile)) { $file = gzopen($cacheFile, 'r'); $file = gzread($file, 1999999); echo $file; exit; } } } } ?>
There are also many tutorials on the internet that teaches about caching your web page using PHP. A quick search and you will find lots of them on the first page of Google. Most of them are for general websites, but this is specific to helping you kick start on OpenCart. You can definitely apply the same concepts learnt here on other PHP driven websites.
Page caching will help you in reducing page loading times, and in turn improve your SEO ranking and display higher up in search engines like Google and Bing. You can always consider purchasing other SEO tools for your OpenCart store. There are tons of SEO extensions out there for OpenCart, but always remember to pick one that achieves what you have in mind. We do offer one SEO pack, and you can look into it on our web store too.
22 Comments on "Page Cache - Benefits and How to"
Yes it works for 1.5.6, thanks a lot
Hi, seems a good job but it’s something that to me does not work. Please help me..
I did what you said but then can not get into the administration site (mysite.com/admin). When access mysite.com/admin page gives me a blank page. No errors can not see them because I dont access the management interface of the site.
I’m not sure if I added well in admin/index.php line require_once(‘system/library/pagecache.php’);
I added it so:
// Configuration
if (file_exists(‘config.php’)) {
require_once(‘config.php’);
require_once(‘system/library/pagecache.php’);
}
if I comment the line require_once(‘system/library/pagecache.php’); i.e.
// require_once(‘system/library/pagecache.php’); I have no blank page instead of the admin panel (mysite/admin)
Thx.
(O.C 1.5.5.1)
Is there any way to delete pages cache without entering in ftp and deleting manually ?
Hello
I did this and everything is working ok but what I’m wondering is right now I have only 300 product and since I added this page cache about 1 month ago I have about 30,000 pages in the pagecache folder, is this normal? Should I delete them sometime?
Regards
Cleo
Hello again
I went through the pagecache folder and found out that I have multiple copy of the same file! I compare them in notepad++ and they are exactly the same
Probably because I have 2 languages on my site?
and in the pagecache.php the language is “en” and currency “USD” but I also have language “fr” and currency “CAD”
Is it possible to put both of language and currency in the pagecache.php file?
Regards
Cleo
Hi
Ok just want to let you know that I found how to make it bilingual but finally I just deleted the page caching script because with it the affiliate link generator is not working, and maybe some other functions that I didn’t check yet but just in case it does I prefer not to use it.
Thanks
Cleo
Gee MarketInSG, it’s so beautiful one could cry… and I second R Rogerson all the way. We’re selling seasonal commodities so during that time I’m constantly adding new products and I would like to see the changes immediately. Will your trick work for me @sfk?
And MarketInSG! Thanks again. Stumbling over your tuts have been a very positive experience.
!!! WARNING !!!
For those that haven’t realised it - this is a time-based cache.
That means changes to products/categories may not appear “live” until the next caching occurs (the time elapses and a new cache-snapshot is taken).
The only solutions are;
1) You wait and let it happen (I think the 2400 = 40 minutes?)
2) You manually clear your page-cache(s) so the new ones are generates
3) You add in some code elsewhere to delete/create the cache on-change (such as when altering products/categories)
But, for a “quick fix”, this is still fantastic!
Fantastic job of a simple page cache!
I would say “I wonder why they don’t include this sort of thing by default”,
but after seeing how the owner and main Devs respond to people raising bugs etc., I’m not surprised such a simple, clever, useful and needed measure is Not included (they suck at implementing sensible ideas!).
All I can say is “thank you” and “more more more”
Hi,
I’m getting this error in admin panel:
Parse error: syntax error, unexpected ‘public’ (T_PUBLIC) in /home/zivaro/public_html/vqmod/vqcache/vq2-system_library_response.php on line 79
This is line 79:
}public function setOutput($output) {if (defined(‘CACHE_FILE’)) {$cacheFile = CACHE_FILE; $fp = gzopen($cacheFile, ‘w9′);gzwrite($fp, $output);gzclose($fp);}require_once(VQMod::modCheck(‘config.php’));require_once(VQMod::modCheck(‘system/library/pagecache.php’));
Sorry, it was my mistake, i fix it and now it works like a charm.
Thank you for share with us.
Respect,
Adi
http://www.ziva.ro
This is great! It reduce my site render time nearly 40% (from 17 mp 10 mp) ! But I must change .htaccess file and add to it this lines:
# Turn on Expires and set default to 0
ExpiresActive On
ExpiresDefault A0
# Set up caching on media files for 5 weeks
ExpiresDefault A3024000
Header append Cache-Control “public”
# Set up caching on media files for 5 weeks
ExpiresDefault A3024000
Header append Cache-Control “public”
# Set up 5 week caching on commonly updated files
ExpiresDefault A3024000
Header append Cache-Control “proxy-revalidate”
# Force no caching for dynamic files
ExpiresActive Off
Header set Cache-Control “private, no-cache, no-store, proxy-revalidate, no-transform”
Header set Pragma “no-cache”
Hi, a quick question. I following the instruction and am lost at this portion below. Where shall I include this part of the script? I put into the “public function setOutput($output) {” in the response.php and got an error.
peace, peter.
—————————————————————————————————————
Inside the function, we will attempt to capture the data. We will first check if the cache file path has been defined.
if (defined(‘CACHE_FILE’)) {
Then, we will start working on it. We will write the contents into the file.
$cacheFile = CACHE_FILE;
$fp = gzopen($cacheFile, ‘w9′);
gzwrite($fp, $output);
gzclose($fp);
}
————————————————————————————————-
Man you are our opencart Saviour…
Thank you so much buddy
Hello,
This script is one life saver. It worked very well.
One question I have is, how can this handle when you have an update to a page.
When you do price change or any instant changes to a page, it will pick up the
cache that is without any of the changes made. Is there a way to add a time stamp check
or something to verify the last modified from any of the tables….
Hope some one will get back with me on this…
Thanks,
I tried but get an error:
2013-09-11 13:35:15 - PHP Warning: Cannot modify header information - headers already sent by (output started at /var/sites/m/maycontainmutts.com/public_html/system/library/pagecache.php:1) in /var/sites/m/maycontainmutts.com/public_html/system/library/currency.php on line 45
using 1.5.51
OK - very strange using Filezilla FTP I had to set ASCII mode transfer and the error is fixed
Very nice, works great, except that my site is in Cyrillic with utf8, and when I write the cache files, the Cyrillic encoding goes bad. Should I encode $output, before write it into the file?
OK I found it by my self.
I change “gzwrite($fp, $output);”
to fwrite($fp, “\xEF\xBB\xBF” . $output);
and the magic works.
Thanks for the great work!
all versions.
This tutorial for Opencart 1551? or All version? Thank
Yes it works for 1.5.5.1. I guess it works for every version.
I have a shop with over 400 000 (yes 400K) categories and this helped a lot, though Opencart sucks at mysql queries, you can see that if you add many categories and products.