Newer
Older
Import / web / www.xiaofrog.com / wordpress / wp-content / plugins / wp-cache / wp-cache.php
<?php
/*
Plugin Name: wp-cache
Plugin URI: http://mnm.uib.es/gallir/wp-cache-2/
Description: Very fast cache module. It's composed of several modules, this plugin can configure and manage the whole system. Once enabled, go to "Options" and select "WP-Cache".
Version: 2.1.2
Author: Ricardo Galli Granada
Author URI: http://mnm.uib.es/gallir/
*/
/*  Copyright 2005-2006  Ricardo Galli Granada  (email : gallir@uib.es)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* Changelog
	2007-09-21
		- Version 2.1.2:
			- Add "Content-type" to "known header" because WP uses both (?).
			- Removed quotes from charset http headers, some clients get confused.

	2007-03-23
		- Version 2.1.1: Patch from Alex Concha: add control in admin pages to avoid 
		                possible XSS derived from CSRF attacks, if the users store
						the form with the "injected" bad values.
	2007-01-31
		- Version 2.1: modified and tested with WP 2.1, WP 2.0, WP 1.5 and PHP 4.3 and PHP 5.2.

	2007-01-14: 2.0.22
		- Corrected bug with meta object not marked as dynamic (introduce in 2.0.20 by http://dev.wp-plugins.org/ticket/517

	2006-12-31: 2.0.21
		- Added global definitien missing from http://dev.wp-plugins.org/ticket/517

	2006-12-31: 2.0.20
		- See http://mnm.uib.es/gallir/posts/2006/12/31/930/

	2006-11-06: 2.0.19
		- Added control of blog_id to delete only those cache files belonging to the same
		  virtual blog. $blog_id is tricky business, because the variable is not assigned yet
		  when wp-cache-phase1.php is called, so it cannot be used as part of the key.

	2006-11-04: 2.0.18 (beta)
		- Changed the use of REQUEST_URI to SCRIPT_URI for key generation. This
		  would solve problems in WP-MU.
		- Clean URI string in MetaCache object to avoid XSS attacks in the admin page.
		- Do not cache 404 pages.
	2005-10-23: 2.0.17
		- Commented out Content-Lenght negotiation, some site have strange problems with
		  ob_content_lenght and buffer length at OB shutdown. WP does not send it anyway.

	2005-10-20: 2.0.16
		- strlen($buffer) is a bug the that function, it's really not defined.
		
	2005-10-16: 2.0.15
		- Changed "Content-Size" to "Content-Length". Obvious bug.

	2005-09-12: 2.0.14
		- Add array() to headers to avoid PHP warnings

	2005-09-08: 2.0.13
			- Move request for Apache response headers to the shutdown callback
			  It seems some plugins do dirty things with headers... or php config?

	2005-07-26: 2.0.12
			- Patch from James (http://shreddies.org/) to delete individual cache files

	2005-07-21: 2.0.11
			- Check also for Last-Modified headers. Last WP version (1.5.3) does not 
			  it.
			- Move the previous check to the ob_callback, so the aditional headers 
			  can be sent also when cache still does not exist.

	2005-07-19: 2.0.10
			- Check also for feeds' closing tags
			  (patch from Daniel Westermann-Clark <dwc at ufl dot edu>)

	2005-07-19: 2.0.9
			- Better control of post_id and comment_id by refactoring the code
			  (inspired by a Brian Dupuis patch).
			- Avoid cleaning cache twice due to WP bugs that wrongly calls two actions.
			
	2005-07-12: 2.0.8
			- Add paranoic control to make sure it only caches files with
			  closing "body" and "html" tags.

	2005-06-23: 2.0.7
			- Add an extra control to make sure meta_mtime >= content_mtime
			  (it could serves incomplete html because other process is re-generating
			   content file and the meta file is the previous one).

	2005-06-23: 2.0.6
			- Delect cache _selectively_. If post_id is known
			  it deletes only that cache and the general (indexes) ones.
			  See: http://mnm.uib.es/gallir/wp-cache-2/#comment-4194
			- Delete cache files (all) also after moderation.

	2005-06-19: 2.0.5
			- Added "#anchors" to refresh cache files' list
			  (http://mnm.uib.es/gallir/wp-cache-2/#comment-4116)

	2005-06-09: 2.0.4
			- Avoid "fwrite() thrashing" at the begining of a connections storm
			- Send Content-Size header when generated dynamically too
			- Clean stats cache before deleting expired files
			- Optimized phase1, EVEN MORE! :-): 
				removed random and extrachecks that were not useful in the context 
				move checking for .meta at the begining

	2005-05-27: 2.0.3
			- Check for zero length of user agent and uri strings

	2005-05-24: 2.0.2a
			- As a workaround for buggy apache installations, create
			  Content-Type header if is not retrieved from Apache headers.
	2005-05-23: 2.0.2
			- Added mfunc sintax as in Staticize Reloaded 2.5,
			  also keep tags but take out function calls
			- Check of numbers are really numbers in web forms.
			- Remove header_list function verification, its result are not
			  the same.
			- wp-cache now verifies if gzipcompression is enabled
			
	2005-05-08: 2.0.1
			sanitize function names to aovid namespace collisions

	2005-05-08: 2.0-beta6
			ignore URI after #, it's sent by buggy clients
			print in red expired files's cache time
			if phase2 was compiled, reuse its function to remove files,
				it avoids race-conditions
			check html _and_ meta exist when listing/accesing files in cache

	2005-05-06: 2.0-beta5
			remove all expired files when one has expired
			POSTs are completely ignored
			only wordpress specific cookies are used for the md5 key

	2005-05-06: 2.0-beta4
			move wp_cache_microtime_diff to phase 2
			normalize functions' name in phase2
			workaround for nasty bug un PHP4(.3) that hits when cache fallbacks to flock()

	2005-05-06:	2.0-beta3
			include sample configuration file if the final one does not exist
			more verbose in errors
			change order of initial configuration to give better information
			stop if global cache is not enabled
			wp-cache-phase1 returns silently if no wp-cache-config.php is found
				
	2005-05-06:	2.0-beta2
			removed paranoic chmod's
			check for cache file consistency in Phase1 several times
			addded option to prevent cache based on user-agents
			added size in KB to every listed file in "cache listing"

*/

$wp_cache_config_file = ABSPATH . 'wp-content/wp-cache-config.php';
$wp_cache_config_file_sample = ABSPATH . 'wp-content/plugins/wp-cache/wp-cache-config-sample.php';
$wp_cache_link = ABSPATH . 'wp-content/advanced-cache.php';
$wp_cache_file = ABSPATH . 'wp-content/plugins/wp-cache/wp-cache-phase1.php';


if( !@include($wp_cache_config_file) ) {
	@include($wp_cache_config_file_sample);
}
include(ABSPATH . 'wp-content/plugins/wp-cache/wp-cache-base.php');

function wp_cache_add_pages() {
	add_options_page('WP-Cache Manager', 'WP-Cache', 5, __FILE__, 'wp_cache_manager');
}

function wp_cache_manager() {
	global $wp_cache_config_file, $valid_nonce;

	$valid_nonce = wp_verify_nonce($_REQUEST['_wpnonce'], 'wp-cache');
	
 	echo '<div class="wrap">';
	echo "<h2>WP-Cache Manager</h2>\n";
	if(isset($_REQUEST['wp_restore_config']) && $valid_nonce) {
		unlink($wp_cache_config_file);
		echo '<strong>Configuration file changed, some values might be wrong. Load the page again from the "Options" menu to reset them.</strong>';
	}

	echo '<a name="main"></a><fieldset class="options"><legend>Main options</legend>';
	if ( !wp_cache_check_link() ||
		!wp_cache_verify_config_file() ||
		!wp_cache_verify_cache_dir() ) {
		echo "<br>Cannot continue... fix previous problems and retry.<br />";
		echo "</fieldset></div>\n";
		return;
	}

	if (!wp_cache_check_global_config()) {
		echo "</fieldset></div>\n";
		return;
	}

	if ( $valid_nonce ) {
		if(isset($_REQUEST['wp_enable'])) {
			wp_cache_enable();
		} elseif (isset($_REQUEST['wp_disable'])) {
			wp_cache_disable();
		}
	}

	echo '<form name="wp_manager" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
 	if (wp_cache_is_enabled()) {
		echo '<strong>WP-Cache is Enabled</strong>';
		echo '<input type="hidden" name="wp_disable" />';
		echo '<div class="submit"><input type="submit"value="Disable it" /></div>';
	} else {
		echo '<strong>WP-Cache is Disabled</strong>';
		echo '<input type="hidden" name="wp_enable" />';
		echo '<div class="submit"><input type="submit" value="Enable it" /></div>';
	}
	wp_nonce_field('wp-cache');
	echo "</form>\n";

	wp_cache_edit_max_time();
	echo '</fieldset>';

	echo '<a name="files"></a><fieldset class="options"><legend>Accepted filenames, rejected URIs</legend>';
	wp_cache_edit_rejected();
	echo "<br />\n";
	wp_cache_edit_accepted();
	echo '</fieldset>';

	wp_cache_edit_rejected_ua();

	wp_cache_files();

	wp_cache_restore();

	echo "</div>\n";

}

function wp_cache_restore() {
	echo '<fieldset class="options"><legend>Configuration messed up?</legend>';
	echo '<form name="wp_restore" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
	echo '<input type="hidden" name="wp_restore_config" />';
	echo '<div class="submit"><input type="submit" id="deletepost" value="Restore default configuration" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";
	echo '</fieldset>';

}

function wp_cache_edit_max_time () {
	global $cache_max_time, $wp_cache_config_file, $valid_nonce;

	if(isset($_REQUEST['wp_max_time']) && $valid_nonce) {
		$max_time = (int)$_REQUEST['wp_max_time'];
		if ($max_time > 0) {
			$cache_max_time = $max_time;
			wp_cache_replace_line('^ *\$cache_max_time', "\$cache_max_time = $cache_max_time;", $wp_cache_config_file);
		}
	}
	echo '<form name="wp_edit_max_time" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
	echo '<label for="wp_max_time">Expire time (in seconds)</label>';
	echo "<input type=\"text\" name=\"wp_max_time\" value=\"$cache_max_time\" />";
	echo '<div class="submit"><input type="submit" value="Change expiration" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";


}

function wp_cache_sanitize_value($text, & $array) {
	$text = wp_specialchars(strip_tags($text));
	$array = preg_split("/[\s,]+/", chop($text));
	$text = var_export($array, true);
	$text = preg_replace('/[\s]+/', ' ', $text);
	return $text;
}

function wp_cache_edit_rejected_ua() {
	global $cache_rejected_user_agent, $wp_cache_config_file, $valid_nonce;

	if (!function_exists('apache_request_headers')) return;

	if(isset($_REQUEST['wp_rejected_user_agent']) && $valid_nonce) {
		$text = wp_cache_sanitize_value($_REQUEST['wp_rejected_user_agent'], $cache_rejected_user_agent);
		wp_cache_replace_line('^ *\$cache_rejected_user_agent', "\$cache_rejected_user_agent = $text;", $wp_cache_config_file);
	}


	echo '<a name="user-agents"></a><fieldset class="options"><legend>Rejected User Agents</legend>';
	echo "<p>Strings in the HTTP 'User Agent' header that prevent WP-Cache from 
		caching bot, spiders, and crawlers' requests.
		Note that cached files are still sent to these request if they already exists.</p>\n";
	echo '<form name="wp_edit_rejected_user_agent" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
	echo '<label for="wp_rejected_user_agent">Rejected UA strings</label>';
	echo '<textarea name="wp_rejected_user_agent" cols="40" rows="4" style="width: 70%; font-size: 12px;" class="code">';
	foreach ($cache_rejected_user_agent as $ua) {
		echo wp_specialchars($ua) . "\n";
	}
	echo '</textarea> ';
	echo '<div class="submit"><input type="submit" value="Save UA strings" /></div>';
	wp_nonce_field('wp-cache');
	echo '</form>';
	echo "</fieldset>\n";
}


function wp_cache_edit_rejected() {
	global $cache_acceptable_files, $cache_rejected_uri, $wp_cache_config_file, $valid_nonce;

	if(isset($_REQUEST['wp_rejected_uri']) && $valid_nonce) {
		$text = wp_cache_sanitize_value($_REQUEST['wp_rejected_uri'], $cache_rejected_uri);
		wp_cache_replace_line('^ *\$cache_rejected_uri', "\$cache_rejected_uri = $text;", $wp_cache_config_file);
	}


	echo "<p>Add here strings (not a filename) that forces a page not to be cached. For example, if your URLs include year and you dont want to cache last year posts, it's enough to specify the year, i.e. '/2004/'. WP-Cache will search if that string is part of the URI and if so, it will no cache that page.</p>\n";
	echo '<form name="wp_edit_rejected" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
	echo '<label for="wp_rejected_uri">Rejected URIs</label>';
	echo '<textarea name="wp_rejected_uri" cols="40" rows="4" style="width: 70%; font-size: 12px;" class="code">';
	foreach ($cache_rejected_uri as $file) {
		echo wp_specialchars($file) . "\n";
	}
	echo '</textarea> ';
	echo '<div class="submit"><input type="submit" value="Save strings" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";
}

function wp_cache_edit_accepted() {
	global $cache_acceptable_files, $cache_rejected_uri, $wp_cache_config_file, $valid_nonce;

	if(isset($_REQUEST['wp_accepted_files']) && $valid_nonce) {
		$text = wp_cache_sanitize_value($_REQUEST['wp_accepted_files'], $cache_acceptable_files);
		wp_cache_replace_line('^ *\$cache_acceptable_files', "\$cache_acceptable_files = $text;", $wp_cache_config_file);
	}


	echo "<p>Add here those filenames that can be cached, even if they match one of the rejected substring specified above.</p>\n";
	echo '<form name="wp_edit_accepted" action="'. $_SERVER["REQUEST_URI"] . '" method="post">';
	echo '<label for="wp_accepted_files">Accepted files</label>';
	echo '<textarea name="wp_accepted_files" cols="40" rows="8" style="width: 70%; font-size: 12px;" class="code">';
	foreach ($cache_acceptable_files as $file) {
		echo wp_specialchars($file) . "\n";
	}
	echo '</textarea> ';
	echo '<div class="submit"><input type="submit" value="Save files" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";
}

function wp_cache_enable() {
	global $wp_cache_config_file, $cache_enabled;

	if(get_settings('gzipcompression')) {
		echo "<b>Error: GZIP compression is enabled, disable it if you want to enable wp-cache.</b><br /><br />";
		return false;
	}
	if( wp_cache_replace_line('^ *\$cache_enabled', '$cache_enabled = true;', $wp_cache_config_file) ) {
		$cache_enabled = true;
	}
}

function wp_cache_disable() {
	global $wp_cache_config_file, $cache_enabled;

	if (wp_cache_replace_line('^ *\$cache_enabled', 
			'$cache_enabled = false;', $wp_cache_config_file)) {
		$cache_enabled = false;
	}
}

function wp_cache_is_enabled() {
	global $wp_cache_config_file;

	if(get_settings('gzipcompression')) {
		echo "<b>Warning</b>: GZIP compression is enabled in Wordpress, wp-cache will be bypassed until you disable gzip compression.<br />";
		return false;
	}
	$lines = file($wp_cache_config_file);
	foreach($lines as $line) {
	 	if (preg_match('/^ *\$cache_enabled *= *true *;/', $line))
			return true;
	}
	return false;
}


function wp_cache_replace_line($old, $new, $my_file) {
	if (!is_writable($my_file)) {
		echo "Error: file $my_file is not writeable.<br />\n";
		return false;
	}
	$found = false;
	$lines = file($my_file);
	foreach($lines as $line) {
	 	if ( preg_match("/$old/", $line)) {
			$found = true;
			break;
		}
	}
	if ($found) {
		$fd = fopen($my_file, 'w');
		foreach($lines as $line) {
			if ( !preg_match("/$old/", $line))
				fputs($fd, $line);
			else {
				fputs($fd, "$new //Added by WP-Cache Manager\n");
			}
		}
		fclose($fd);
		return true;
	}
	$fd = fopen($my_file, 'w');
	$done = false;
	foreach($lines as $line) {
		if ( $done || !preg_match('/^define|\$|\?>/', $line))
			fputs($fd, $line);
		else {
			fputs($fd, "$new //Added by WP-Cache Manager\n");
			fputs($fd, $line);
			$done = true;
		}
	}
	fclose($fd);
	return true;
/*
	copy($my_file, $my_file . "-prev");
	rename($my_file . '-new', $my_file);
*/
}

function wp_cache_verify_cache_dir() {
	global $cache_path;

	$dir = dirname($cache_path);
	if ( !file_exists($cache_path) ) {
		if ( !is_writable( $dir ) || !($dir = mkdir( $cache_path, 0777) ) ) {
				echo "<b>Error:</b> Your cache directory (<b>$cache_path</b>) did not exist and couldn't be created by the web server. <br /> Check  $dir permissions.";
				return false;
		}
	}
	if ( !is_writable($cache_path)) {
		echo "<b>Error:</b> Your cache directory (<b>$cache_path</b>) or <b>$dir</b> need to be writable for this plugin to work. <br /> Double-check it.";
		return false;
	}

	if ( '/' != substr($cache_path, -1)) {
		$cache_path .= '/';
	}
	return true;
}

function wp_cache_verify_config_file() {
	global $wp_cache_config_file, $wp_cache_config_file_sample;

	$new = false;
	$dir = dirname($wp_cache_config_file);

	if ( !is_writable($dir)) {
			echo "<b>Error:</b> wp-content directory (<b>$dir</b>) is not writable by the Web server.<br />Check its permissions.";
			return false;
	}
	if ( !file_exists($wp_cache_config_file) ) {
		if ( !file_exists($wp_cache_config_file_sample) ) {
			echo "<b>Error:</b> Sample WP-Cache config file (<b>$wp_cache_config_file_sample</b>) does not exist.<br />Verify you installation.";
			return false;
		}
		copy($wp_cache_config_file_sample, $wp_cache_config_file);
		$new = true;
	}
	if ( !is_writable($wp_cache_config_file)) {
		echo "<b>Error:</b> Your WP-Cache config file (<b>$wp_cache_config_file</b>) is not writable by the Web server.<br />Check its permissions.";
		return false;
	}
	require($wp_cache_config_file);
	return true;
}

function wp_cache_check_link() {
	global $wp_cache_link, $wp_cache_file;

	if ( basename(@readlink($wp_cache_link)) != basename($wp_cache_file)) {
		@unlink($wp_cache_link);
		if (!@symlink ($wp_cache_file, $wp_cache_link)) {
			echo "<code>advanced-cache.php</code> link does not exist<br />";
			echo "Create it by executing: <br /><code>ln -s $wp_cache_file $wp_cache_link</code><br /> in your server<br />";
			return false;
		}
	}
	return true;
}

function wp_cache_check_global_config() {

	$global = ABSPATH . 'wp-config.php';

	$lines = file($global);
	foreach($lines as $line) {
	 	if (preg_match('/^ *define *\( *\'WP_CACHE\' *, *true *\) *;/', $line)) {
			return true;
		}
	}
	$line = 'define(\'WP_CACHE\', true);';
	if (!is_writable($global) || !wp_cache_replace_line('define *\( *\'WP_CACHE\'', $line, $global) ) {
			echo "<b>Error: WP_CACHE is not enabled</b> in your <code>wp-config.php</code> file and I couldn't modified it.<br />";
			echo "Edit <code>$global</code> and add the following line: <br /><code>define('WP_CACHE', true);</code><br />Otherwise, <b>WP-Cache will not be executed</b> by Wordpress core. <br />";
			return false;
	} 
	return true;
}

function wp_cache_files() {
	global $cache_path, $file_prefix, $cache_max_time, $valid_nonce;

	if ( '/' != substr($cache_path, -1)) {
		$cache_path .= '/';
	}

	if ( $valid_nonce ) {
		if(isset($_REQUEST['wp_delete_cache'])) {
			wp_cache_clean_cache($file_prefix);
		}
		if(isset($_REQUEST['wp_delete_cache_file'])) {
			wp_cache_clean_cache($_REQUEST['wp_delete_cache_file']);
		}
		if(isset($_REQUEST['wp_delete_expired'])) {
			wp_cache_clean_expired($file_prefix);
		}
	}
	if(isset($_REQUEST['wp_list_cache'])) {
		$list_files = true;
		$list_mess = "Update list";
	} else 
		$list_mess = "List files";

	echo '<a name="list"></a><fieldset class="options"><legend>Cache contents</legend>';
	echo '<form name="wp_cache_content_list" action="'. $_SERVER["REQUEST_URI"] . '#list" method="post">';
	echo '<input type="hidden" name="wp_list_cache" />';
	echo '<div class="submit"><input type="submit" value="'.$list_mess.'" /></div>';
	echo "</form>\n";

	$count = 0;
	$expired = 0;
	$now = time();
	if ( ($handle = opendir( $cache_path )) ) { 
		if ($list_files) echo "<table cellspacing=\"0\" cellpadding=\"5\">";
		while ( false !== ($file = readdir($handle))) {
			if ( preg_match("/^$file_prefix.*\.meta/", $file) ) {
				$this_expired = false;
				$content_file = preg_replace("/meta$/", "html", $file);
				$mtime = filemtime($cache_path.$file);
				if ( ! ($fsize = @filesize($cache_path.$content_file)) ) 
					continue; // .meta does not exists
				$fsize = intval($fsize/1024);
				$age = $now - $mtime;
				if ( $age > $cache_max_time) {
					$expired++;
					$this_expired = true;
				}
				$count++;
				if ($list_files) {
					$meta = new CacheMeta;
					$meta = unserialize(file_get_contents($cache_path . $file));
					echo $flip ? '<tr style="background: #EAEAEA;">' : '<tr>';
					$flip = !$flip;
					echo '<td><a href="http://' . $meta->uri . '" target="_blank" >';
					echo $meta->uri . "</a></td>";
					if ($this_expired) echo "<td><span style='color:red'>$age secs</span></td>";
					else echo "<td>$age secs</td>";
					echo "<td>$fsize KB</td>";
					echo '<td><form name="wp_delete_cache_file" action="'. $_SERVER["REQUEST_URI"] . '#list" method="post">';
					echo '<input type="hidden" name="wp_list_cache" />';
					echo '<input type="hidden" name="wp_delete_cache_file" value="'.preg_replace("/^(.*)\.meta$/", "$1", $file).'" />';
					echo '<div class="submit"><input id="deletepost" type="submit" value="Remove" /></div>';
					wp_nonce_field('wp-cache');
					echo "</form></td></tr>\n";
				}
			}
		}
		closedir($handle);
		if ($list_files) echo "</table>";
	}
	echo "<P><b>$count cached pages</b></p>";
	echo "<P><b>$expired expired pages</b></p>";

	echo '<form name="wp_cache_content_expired" action="'. $_SERVER["REQUEST_URI"] . '#list" method="post">';
	echo '<input type="hidden" name="wp_delete_expired" />';
	echo '<input type="hidden" name="wp_list_cache" />';
	echo '<div class="submit"><input type="submit" value="Delete expired" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";


	echo '<form name="wp_cache_content_delete" action="'. $_SERVER["REQUEST_URI"] . '#list" method="post">';
	echo '<input type="hidden" name="wp_delete_cache" />';
	echo '<div class="submit"><input id="deletepost" type="submit" value="Delete cache" /></div>';
	wp_nonce_field('wp-cache');
	echo "</form>\n";

	echo '</fieldset>';
}

function wp_cache_clean_cache($file_prefix) {
	global $cache_path;

	// If phase2 was compiled, use its function to avoid race-conditions
	if(function_exists('wp_cache_phase2_clean_cache'))
		return wp_cache_phase2_clean_cache($file_prefix);

	$expr = "/^$file_prefix/";
	if ( ($handle = opendir( $cache_path )) ) { 
		while ( false !== ($file = readdir($handle))) {
			if ( preg_match($expr, $file) ) {
				unlink($cache_path . $file);
			}
		}
		closedir($handle);
	}
}

function wp_cache_clean_expired($file_prefix) {
	global $cache_path, $cache_max_time;

	// If phase2 was compiled, use its function to avoid race-conditions
	if(function_exists('wp_cache_phase2_clean_expired'))
		return wp_cache_phase2_clean_expired($file_prefix);

	$expr = "/^$file_prefix/";
	$now = time();
	if ( ($handle = opendir( $cache_path )) ) { 
		while ( false !== ($file = readdir($handle))) {
			if ( preg_match($expr, $file)  &&
				(filemtime($cache_path . $file) + $cache_max_time) <= $now) {
				unlink($cache_path . $file);
			}
		}
		closedir($handle);
	}
}

add_action('admin_menu', 'wp_cache_add_pages');
?>