PHP content caching script

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
dotsc
Forum Newbie
Posts: 14
Joined: Sun Jan 29, 2006 2:55 pm

PHP content caching script

Post by dotsc »

Hi to all :D

I found a great script on the net that caches content of rarely updated articles. When I have it integrated it greatly reduces load on my site because I'm not querying my database every time the page is accessed.

So as you can see in the code below i don't want to cache the header and footer info because it shows dynamic info based on the user and other factors.
It's almost perfect but there is one thing I need help to fix...
After my content gets cached the footer disappears!!

Is this a flaw in the output buffering? Is there an alternative way?
I'm running the script on php version 4.4.4

Any help is appreciated!

Code: Select all

<html>
<body>
<hr>
dynamic content header
<hr>
<?
// PHP Fast File Cache v0.1b
// Written by Åke Wallebom (ake at ake nu)
// Free to use for non-commercial purposes

	$cache_cacheDirectory = '/cache/';
	if (!isset($cache_refreshTime)) {
		$cache_refreshTime = 300; // seconds to keep a cached copy
	}

	/////
	// No configuration beyond this line
	/////

	function cache_fopen_exclusive($id) {
		if ($fp = fopen($id, "ab+")) {
			if (flock($fp, LOCK_EX | LOCK_NB)) {
				return $fp;
			} else {
				fclose($fp);
			}
		}
		
		return false;
	}
	
	function cache_fclose_exclusive($fp) {
		flock($fp, LOCK_UN);
		fclose($fp);
	}

	// Create cache file name
	if (isset($cache_parameters) && is_array($cache_parameters)) {
		$cache_id_param = '';
		foreach($cache_parameters as $value) {
			if (isset($_REQUEST[$value])) {
				$cache_id_param = $cache_id_param . '_' . $value . '=' . $_REQUEST[$value];
			}
		}
		
		$cache_id = md5($_SERVER['REQUEST_URI']) . '_' . md5($cache_id_param);
	} else {
		$cache_id = md5($_SERVER['REQUEST_URI']);
	}
	$cache_cacheFile = $cache_cacheDirectory . $cache_id . '.cache.html';

	$cache_FileExists = file_exists($cache_cacheFile);
	$cache_FileIsFresh = $cache_FileExists && (time() - filemtime($cache_cacheFile) < $cache_refreshTime);

	// Check if cache file is usable or not
	if ($cache_FileIsFresh) {
		$cache_UseCache = true;
	} else {
		$cache_UseCache = false;
		if ($cache_fp_lock = cache_fopen_exclusive($cache_cacheFile . '.lock')) {
			// We got the lock, create new cache
			$cache_UpdateCache = true;
		} else {
			// We didn't get the lock, use old file or regenerate
			$cache_UseCache = $cache_FileExists;
			$cache_UpdateCache = false;
		}
	}	

	// Output cached content
	if ($cache_UseCache) {
		// Display the cached file
		readfile($cache_cacheFile);
		exit;
	}
	
	// We will update the cache file and should not abort if the user cancels the request
	if ($cache_UpdateCache) {
		ignore_user_abort(true);
	}
	
	// We need to regenerate the page...
	ob_start();
?>

Hello World<br>
Here is the content that is needed to be cached.

<?
// PHP Fast File Cache v0.1b
// Written by Åke Wallebom (ake at ake nu)
// Free to use for non-commercial purposes

	// Get all output data and save to cache file
	if ($cache_UpdateCache) {
		if ($cache_fp = fopen($cache_cacheFile . '.new', "wb")) {
			$cache_data = ob_get_contents();
			fwrite($cache_fp, $cache_data, strlen($cache_data));
			fclose($cache_fp);
			rename($cache_cacheFile . '.new', $cache_cacheFile);
		}
		
		// Close and remove the lock-file
		cache_fclose_exclusive($cache_fp_lock);
		$cache_er_old = error_reporting(0);
		unlink($cache_cacheFile . '.lock');
		error_reporting($cache_er_old);

		// The script can now be aborted by the user without any problems		
		ignore_user_abort(false);
	} 
	
	ob_end_flush();
?>
<hr>
Footer dynamic content here
<hr>
</body>
</html>
[/b]
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Your code uses ob_get_contents() which is called nearly immediately after ob_start() is called. Nothing afterward will be cached. You need to move the ob_get_contents() calls to the very end of the file/script.

You probably also need to move the ob_start() to the very first thing that's run.
User avatar
Zoxive
Forum Regular
Posts: 974
Joined: Fri Apr 01, 2005 4:37 pm
Location: Bay City, Michigan

Post by Zoxive »

Code: Select all

if ($cache_UseCache) {
  // Display the cached file
  readfile($cache_cacheFile);
  exit; // EXITS So if you have a cached File, it will stop Execution right here, and not continue down to the footer.
}
That could be the reason there : p
dotsc
Forum Newbie
Posts: 14
Joined: Sun Jan 29, 2006 2:55 pm

Post by dotsc »

Thanks you for your response! I've removed the "exit" and footer shows up now. But now the issue i have is that the script is showing a queried mysql content + the cached content.

I've tried using:

Code: Select all

// Output cached content
	if ($cache_UseCache) {
		// Display the cached file
		readfile($cache_cacheFile);
		//exit;
	}
	else {
	// We need to regenerate the page...
	ob_start();
	}
I've also changed few lines towards the bottom with:

Code: Select all

if (!$cache_UseCache) 
{
	ob_end_flush();
}
But it still shows the cached content + the queried mysql content. What can I do, so it doesn't show the mysql queried content after the code has already created?
Post Reply