Recent Topics

1 Jul 25, 2008 12:41    

We in http://www.lahaine.org have the same problems as http://forums.b2evolution.net/viewtopic.php?t=15895 (lots of visits and complains of our server), and because we are preparing the upgrade to 2.4.2, we made this very simple hack, based mostly on Hyper Cache: http://www.satollo.com/english/wordpress/hyper-cache, whith ideas from Simple Cache Hack v0.3: http://forums.b2evolution.net/viewtopic.php?p=25724#25724 and 1 Blog Cacher: http://1blogcacher.com/features-and-download.

The hack starts up just after a user requests a page, and just before b2evo starts to send queries to the database. If the page requested is already in cache, it sends the content back and stop; otherwise it creates the page. There is no expiration time for cached files, we just run delete_cache() every time something is updated/created/deleted (as in Cache Hack v0.3).

It works quite OK in our local Apache with b2evo 2.4.2 (31 000 posts), we haven't upload yet to the remote server, but html is html. As URLĀ“s we use Explicit param on index.php and Use param: post ID, so the hack is made based on those parameters. It is a very basic job, but it works, and can give ideas.

The first thing is to fill the config parameters, just put in conf/_advanced.php (or other config file):

$my_cache_enabled = true;
$my_cachedir = $basepath.'mycache';

You have to create the directory whith permissions to read and write.

Then in index.php, just after
require_once $inc_path.'_main.inc.php';

put

my_cache_exists();

Then, if you haven't created a conf/hacks.php file before, create a dummy (empty) conf/hacks.php, and add the following lines:

<?php
/////////////////////////////////////////////////////////////////////////
// Very simple Page Caching Hack
//
// Based mostly on Hyper Cache: http://www.satollo.com/english/wordpress/hyper-cache
// whith ideas from Simple Cache Hack v0.3: http://forums.b2evolution.net/viewtopic.php?p=25724#25724
// and 1 Blog Cacher: http://1blogcacher.com/features-and-download
//
// By: www.lahaine.org
//
/////////////////////////////////////////////////////////////////////////

// Caching routine, if everything is ok
function my_cache_exists()
{
 	global $preview, $my_file, $my_cache_enabled, $my_cachedir;

	// Config values and check if dir has been created
	if( !$my_cache_enabled || !$my_cachedir || ( !is_dir($my_cachedir) ) )
	{
		return false;
	}

 	// The server itself requested that page. (create, update... don't use caching)
 	if( strcmp( $_SERVER[ 'SERVER_ADDR' ], $_SERVER[ 'REMOTE_ADDR' ] ) == 0 )
	{
		return false;
	}
	elseif( $preview )
	{ // We don't cache previews
		return false;
	}

	// Reject User Agents in order to avoid over-caching from search engines
	if( !defined('OBC_REJECTED_USER_AGENTS') )
		define( "OBC_REJECTED_USER_AGENTS", "bot, ia_archive, slurp, crawl, spider" );
	$user_agent = strtolower( $_SERVER["HTTP_USER_AGENT"] );
	$obc_rejected_user_agents = explode( ",", OBC_REJECTED_USER_AGENTS );
	$obc_rejected_user_agents = array_filter( $obc_rejected_user_agents );
	if( count($obc_rejected_user_agents ))
	{
		foreach( $obc_rejected_user_agents as $x=>$rejected_user_agent )
		{
			$rejected_user_agent = trim( strtolower( $rejected_user_agent ));
			if( strpos( $user_agent,$rejected_user_agent ) !== false )
			{
				return false;
			}
		}
	}

	// Do not cache post request (comments, plugins and so on)
	if( $_SERVER["REQUEST_METHOD"] == 'POST' )
	{
		return false;
	}

/////////////////////////////////////////////////////////////////////////

	// We are going to use the cached file, if exists
	get_filename(); // Get name of the file

	if( is_file($my_file) )
	{ // File exists, then display it
		$hyper_data = unserialize( file_get_contents($my_file) );
	
		if( $hyper_data != null && $hyper_data['html'] != '' )
		{
			// $Hit->log(); // We don't use it, but it should be here
			echo $hyper_data['html'];
			echo '<!-- hyper cache -->';
			flush();
			die();
 		}
		else
		{ //ERROR, problems in the cache file
			return false;
		}
	}

	// The cache file doesn't exists. Now we start the caching
	ob_start('hyper_cache_callback');
}

/////////////////////////////////////////////////////////////////////////
function hyper_cache_callback( $buffer )
{
	global $my_file;
	get_filename(); // Get name of the file

	$data['uri'] = $_SERVER['REQUEST_URI'];
	$data['referer'] = $_SERVER['HTTP_REFERER'];
	$data['time'] = time();
	$data['mime'] = 'text/html;charset=UTF-8';
	$data['html'] = $buffer;

	// Write the file and return
	$file = fopen($my_file, 'w');
	fwrite($file, serialize($data));
	fclose($file);

	return $buffer;
}

/////////////////////////////////////////////////////////////////////////
// Get name of the file
// We use index.html for the homepage file and 999.html for the post files
function get_filename()
{
	global $my_cachedir, $my_file, $baseurl, $baseurlroot;
	$sPathRU = $_SERVER['REQUEST_URI'];
	$my_urlbase = substr( $baseurl, strlen( $baseurlroot ) );
	$my_urlind = $my_urlbase.'index.php';
	$p_exists_1 = explode( "?p=", $sPathRU ); // The actual URI uses ?p=
	$p_exists_2 = explode( "&p=", $sPathRU ); // The actual URI uses &p=

	if( ( $sPathRU == $my_urlbase ) || ( $sPathRU == $my_urlind ) )
	{ // the request comes from the homepage
		$my_file = $my_cachedir.'/index.html';
	}
	elseif( !empty($p_exists_1[1]) )
	{ // the request comes from  a posts page
		$my_file = $my_cachedir.'/'.$p_exists_1[1].'.html';
	}
	elseif( !empty($p_exists_2[1]) )
	{ // the request comes from  a posts page
		$my_file = $my_cachedir.'/'.$p_exists_2[1].'.html';
	}
	else
	{	// Any other request. We just want to use the caching system in those two cases
		// (homepage and posts with p=), you can add other cases
		return false;
	}
	return $my_file;
}

/////////////////////////////////////////////////////////////////////////
// Delete all files in cache dir or just what you select, you decide where and when to call it, 
// depending on the frecuency of your post creation/updating, the volume of comments, etc.
function delete_cache( $del_what )
{
	global $my_cachedir;
	if ($handle = opendir($my_cachedir))
	{
		if( $del_what == 'all' )
		{
			while ($file = readdir($handle))
			{
				if ($file != '.' && $file != '..')
					unlink($my_cachedir . '/' . $file);
			}
		}
		else
		{ // delete only $del_what
			unlink($my_cachedir . '/' . $del_what . '.html');
		}
	}
}
?>

2 Aug 29, 2008 13:29

Hi, this sounds like a nice solution to server overload.

I'm testing now in my development server, bu I have a question for you: how would you go about knowing whether this is really taking some load off the server?

I see your site is quite fast (firebug reports in the order on 1 - 2 seconds to load every page). Did you already implemented this hack in your production server?

3 Sep 01, 2008 17:51

Cool! Let's make a plugin of it ;)

4 Sep 01, 2008 18:29

I'm already working on turning this into a plugin. If anyone else is working on it, it would be nice to day it now, so I don't waste time in duplicating effort.

5 Sep 01, 2008 19:53

Not duplicating effort here ;)

6 Sep 02, 2008 14:18

To austriaco: We don't know "scientifically" if the server load goes down, other than looking, just like you, at firebug on busy days (and maybe asking our server). If anyone knows a better method, is welcomed.
We didn't implement this in production yet, we are still working on other adaptations of 2.4.2, our plan is to start in production in the middle of October. Now if our actual system goes fast (especially in summer months) is because we modified b2evo motor, so that it doesn't read table postcats (40 000 plus records) when you ask for the homepage or for a posts ($p) page, the most visited pages.
And we think is great that you are working on turning this into a plugin.


Form is loading...