Mambo - Simple full site caching for dramatic speed gain

January 29th, 2007 by Marc

As I've described just a short while ago, I was working on speed issues with my Mambo (ver. 4.5.1) based site icq-4u.com. In addition to the caching of the site's download charts I've also thought about adding full site caching. Of course this step requires a fitting scenario since a full site cache freezes most of the dynamic content modules one might be using.

What I wanted was a pretty fast frontpage, but even with Mambo's native caching enabled it was still somewhat slow. The page generation time that I was displaying on my sites footer (which by the way is far from precise if you only include it in the template file) always stayed around the 0.7 mark which annoyed me. Of course 0.7 does not sound so slow, but considering that that specific duration wasn't accurate (try twice as much, when timing correctly prior to template initiation) and that caching was supposedly already enabled I was a litte bit disappointed.

Having looked into Mambo's caching function already I knew what was there and what was feasible, so I studied Mambo's index.php to find a fitting spot for a cache inclusion. These are the steps I did:

As you can see in step 1 , I've added cache activation pretty early and just after the user athentication. The modifcation will only apply for pages that are either the part of the remository component or the frontpage and only if the user's id is unspecified i.e. the user is unregistered. The cookie check is necessary to avoid sync issues with the SMF bridge for Mambo which I use. After that I start the caching with random identifier variables. And since we open an if here, we'll have to close it again. That's what the seconds code block in step 1 is about.

In step 2 we add functionality for a second caching method to Mambo's core. Mambo's caching component originally came from PEAR but only includes the call-function which allows caching of a function output, but not caching of a certain segment in the script which we intend to do. To be able to differ between both methods, we're adding the &getCacheAlt() function to the core. That's also the function which we call earlier in step 1.

Finally, in step 3 we add the additional PEAR function that is missing in Mambo.

Note: If you have Mambo's gzip function enabled, you might get a blank page upon the first page request and initial cache file generation. I use apache's gzip functionality which works great and also allows me to cache my CSS files.

  1. In index.php around line 250 add like this:

PHP:

  1. // marc 05.01.2007 22:37
  2. // cache activation
  3. // INSERT BEGINNING
  4. $maincache = &mosCache::getCacheAlt( 'com_main' );
  5. $cache_idle = true;
  6. if ((($option == 'com_frontpage') || ($option == 'com_remository')) && $my->id == 0 && !isset($_COOKIE['mbfcookie']) && !isset($_COOKIE['SMFCookie876'])) $cache_idle = false;
  7. if(!($maincache->start($my->id.'_'.$Itemid.'_'.$option.'_'.$task.'_'.$_SERVER[REQUEST_URI], 'com_main', $cache_idle)))    {
  8. // INSERT END
  9.  
  10. // gets template for page
  11. $cur_template = $mainframe->getTemplate();
  12. require_once( $configuration->rootPath().'/includes/frontend.php' );
  13. require_once( $configuration->rootPath().'/includes/mambo.php' );
  14. require_once ($configuration->rootPath().'/includes/mambofunc.php');
  15. require_once ($configuration->rootPath().'/includes/mamboHTML.php');
  16. ...

Now scroll all the way down and add these two lines:

PHP:

  1. ...
  2. // marc 05.01.2007 22:37
  3. // INSERT BEGIN
  4. $maincache->end($cache_idle);
  5. }
  6. // INSERT END
  7.  
  8. }
  9. // displays queries performed for page
  10. ...

  1. In include/core.clases.php find line ~2675 and right after the &getCache function add this additional function:

PHP:

  1. ...
  2. function &getCache(  $group=''  ) {
  3. $mosConfig_absolute_path = mamboCore::get('mosConfig_absolute_path');
  4. require_once($mosConfig_absolute_path.'/includes/Cache/Lite/Function.php');
  5. $path = mamboCore::get('mosConfig_cachepath');
  6. $caching = mamboCore::get('mosConfig_caching');
  7. $time = mamboCore::get('mosConfig_cachetime');
  8. $options = array(
  9. 'cacheDir' => "$path/",
  10. 'caching' => $caching,
  11. 'defaultGroup' => $group,
  12. 'lifeTime' => $time
  13. );
  14. $cache =& new Cache_Lite_Function( $options );
  15. return $cache;
  16. }
  17.  
  18. // marc 05.01.2007 22:37
  19. // INSERT BEGIN
  20. function &getCacheAlt(  $group=''  ) {
  21. $mosConfig_absolute_path = mamboCore::get('mosConfig_absolute_path');
  22. require_once($mosConfig_absolute_path.'/includes/Cache/Lite/Output.php');
  23. $path = mamboCore::get('mosConfig_cachepath');
  24. $caching = mamboCore::get('mosConfig_caching');
  25. $time = mamboCore::get('mosConfig_cachetime');
  26. $options = array(
  27. 'cacheDir' => "$path/",
  28. 'caching' => $caching,
  29. 'defaultGroup' => $group,
  30. 'lifeTime' => $time
  31. );
  32. $cache =& new Cache_Lite_Output( $options );
  33. return $cache;
  34. }
  35. // INSERT END
  36. ...

  1. Replace includes/Cache/Lite/Output.php with this

PHP:

  1. /**
  2. * This class extends Cache_Lite and uses output buffering to get the data to cache.
  3. *
  4. * There are some examples in the 'docs/examples' file
  5. * Technical choices are described in the 'docs/technical' file
  6. *
  7. * @package Cache_Lite
  8. * @version $Id: Output.php,v 1.1 2005/07/22 01:57:13 eddieajau Exp $
  9. * @author Fabien MARTY <fab@php.net>
  10. */
  11. /** ensure this file is being included by a parent file */
  12. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  13. require_once( $mosConfig_absolute_path . '/includes/Cache/Lite.php' );class Cache_Lite_Output extends Cache_Lite
  14. {
  15. // --- Public methods ---
  16. /**
  17. * Constructor
  18. *
  19. * $options is an assoc. To have a look at availables options,
  20. * see the constructor of the Cache_Lite class in 'Cache_Lite.php'
  21. *
  22. * @param array $options options
  23. * @access public
  24. */
  25. function Cache_Lite_Output($options)
  26. {
  27. $this->Cache_Lite($options);
  28. }
  29.  
  30. /**
  31. * Start the cache
  32. *
  33. * @param string $id cache id
  34. * @param string $group name of the cache group
  35. * @return boolean true if the cache is hit (false else)
  36. * @access public
  37. */
  38. function start($id, $group = 'default', $idle = true)
  39. {
  40. if($idle == false){
  41. $data = $this->get($id, $group);
  42. if ($data !== false) {
  43. echo($data);
  44. return true;
  45. } else {
  46. return false;
  47. }
  48. } return false;
  49. }
  50.  
  51. /**
  52. * Stop the cache
  53. *
  54. * @access public
  55. */
  56. function end($idle = true)
  57. {
  58. if($idle == false) {
  59. $data = ob_get_contents();
  60. $this->save($data, $this->_id, $this->_group);
  61. echo($data);
  62. }
  63. }
  64. }
  65. ?>

To be on the safe side you should always make backups before playing around with files ;-)

Since my remository and frontpage don't have a lot of dynamic content, I was able to set my cache time to one hour and have experienced a great gain of speed. Only one particular adsense adveritising block for which I serve user specific ads (location and language) had to be "oursourced" and is now being called via javascript.

Have fun!

Tags: , , , , , ,

Bookmark | del.icio.us | Digg it | Furl | RawSugar | Simpy | Spurl | Yahoo MyWeb

Posted in Mambo CMS, PHP |

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.