-
-
Save runion/3812913 to your computer and use it in GitHub Desktop.
<?php | |
class caching { | |
public $useCache = true; | |
public $hours_cache_remains_valid = 8; | |
private $curDirectory; | |
private $cacheFolder; // DOCUMENT_ROOT + this + $cacheFileName == cached_filename | |
private $serverFilename; | |
public $cacheFileName; // this is just the filename -- used to test if over 255 characters | |
public $cached_filename; // this includes the full path | |
public $saveCache; // boolean | |
private $ignore_directories = array( | |
"/administrator" | |
, "/translate" | |
, "/test" | |
, "/errors" | |
); | |
public function __construct() { | |
$this->serverFilename = $_SERVER['SCRIPT_FILENAME']; | |
if(!empty($this->serverFilename)) { | |
$this->curDirectory = dirname($this->serverFilename); | |
$this->cacheFolder = "/.cache".$this->curDirectory; | |
} | |
} | |
public function doCache() { | |
if( | |
$this->is_cpc_user() | |
|| sizeof(array_filter($this->ignore_directories, array($this, "ignore_directories_filter"))) | |
|| sizeof($_POST) > 0 | |
|| isset($_GET['bustcache']) | |
) { | |
$this->useCache = false; | |
} else { | |
if($this->valid_cache($this->get_cached_filename())) { | |
$this->saveCache = false; | |
} else { | |
$this->saveCache = true; | |
} | |
} | |
} | |
private function ignore_directories_filter($ignore_directory) { | |
# This function is used by array_filter directly above -- the $ignore_directory variable is one element | |
# passed by array_filter from the $this->ignore_directories array. | |
# We want to match on a substring so /test/subfolder will match and $this->useCache will be set to false, | |
# just the same as if we were in /test -- otherwise we could just do in_array | |
return strpos($this->curDirectory, $_SERVER['DOCUMENT_ROOT'].$ignore_directory) !== false; | |
} | |
public function valid_cache($cacheFile) { | |
if(!file_exists($cacheFile)) { return false; } | |
if(strlen($this->cacheFileName) > 250) { return false; } | |
$hours_cache_remains_valid = 8; | |
$max_cache_age = 60 * 60 * $hours_cache_remains_valid; | |
$cache_mtime = filemtime($cacheFile); | |
#echo $cacheFile."<br>"; | |
#echo $scriptFile."<br>"; | |
$script_mtime = filemtime($this->serverFilename); | |
# cache is valid if the file is less than $hours_cache_remains_valid old, and if the cache script was modified more recently than the generating script. | |
if($this->is_cache_expired($cache_mtime) || $this->is_cached_file_older_than_script($cache_mtime, $script_mtime)) { | |
unlink($cacheFile); | |
return false; | |
} | |
return true; | |
} | |
public function is_cache_expired($cache_mtime) { | |
$max_cache_age = 60 * 60 * $this->hours_cache_remains_valid; | |
return (time() - $max_cache_age > $cache_mtime); | |
} | |
public function is_cached_file_older_than_script($cache_mtime, $script_mtime) { | |
return ($cache_mtime < $script_mtime); | |
} | |
private function is_cpc_user() { | |
/* Determine if customer is a CPC customer. We show different contact info for paid search customers for tracking purposes. We could split off separate caches for this but it's easier to just generate the page... */ | |
if (isset($_COOKIE["__utmz"])) { | |
$AnalyticsCookie = array(); | |
foreach((array)preg_split('~([.|])(?=ut)~', $_COOKIE["__utmz"]) as $pair) { | |
if(strpos($pair, "=")) { | |
list($key, $value) = explode('=', $pair); | |
$AnalyticsCookie[$key] = $value; | |
} | |
} | |
if(isset($AnalyticsCookie['utmgclid']) && strlen($AnalyticsCookie['utmgclid']) > 0) { | |
return true; | |
} | |
} | |
if( | |
isset($_GET['gclid']) | |
|| isset($_GET['utm_nooverride']) | |
|| isset($_GET['utm_source']) | |
|| isset($_GET['utm_campaign']) | |
|| isset($_GET['utm_medium']) | |
) { | |
return true; | |
} | |
return false; | |
} | |
public function get_cached_filename() { | |
if(isset($this->cached_filename)) { return $this->cached_filename; } | |
GLOBAL $language; # we support multiple languages, a whole story in itself. | |
$this->create_cache_folder(); # make sure the folder exists first | |
$script_filename = $_SERVER['SCRIPT_FILENAME']; | |
$script_parts = explode("/", $script_filename); | |
$script = array_pop($script_parts); | |
$qs = ""; | |
ksort($_GET); # alphabetize get by keys | |
if(sizeof($_GET) > 0) { $qs = "?"; } | |
$qsArr = array(); | |
foreach($_GET as $key=>$value) { | |
array_push($qsArr, $key."=".$value); | |
} | |
$qsString = implode("+", $qsArr); # ampersands are a no-go but apparently equals signs in file names are fine | |
$qs .= $qsString; | |
$cacheFileNameTemp = str_replace(array("/", ",", "\\"), "", $script . "-" . $language . "-" . $hostTemp . "-" . $qs); # chomp / and , | |
$this->cacheFileName = str_replace(" ", "%20", $cacheFileNameTemp); # spaces to %20 -- as it should be | |
$cacheFileNameWithPath = $this->cacheFolder . "/" . $this->cacheFileName; | |
$this->cached_filename = $_SERVER['DOCUMENT_ROOT'].$cacheFileNameWithPath; | |
return $this->cached_filename; | |
} | |
private function create_cache_folder() { | |
if(!file_exists($_SERVER['DOCUMENT_ROOT'].$this->cacheFolder)) { | |
#echo "creating: ".$_SERVER['DOCUMENT_ROOT'].$this->cacheFolder."<br>"; | |
mkdir($_SERVER['DOCUMENT_ROOT'].$this->cacheFolder, 0777, true); | |
} | |
} | |
} | |
?> |
if(defined("SAVECACHE") && !defined("is_a_404_page")) {
/*
* this should be the last shutdown function run because we need to
* make sure the HTML has already been modified before we cache it
*/
ob_start('save_cache');
}
As referenced in the comment, I have other PHP shutdown functions that modify the HTML before it's sent out. The save_cache function, which saves the final HTML output, needs to run after the modifications are made.
And finally, the save_cache function:
function save_cache($buffer) {
$fp = fopen(SAVECACHE, "w");
fwrite($fp, $buffer);
fclose($fp);
return $buffer;
}
In my first comment there is a line
echo PHP_EOL.""
Inside the quotes is an html comment I put at the bottom of the page. That explains why it didn't show. This should show:
echo PHP_EOL . "get_cached_filename()))."--" . ">";
Third time's the charm:
echo PHP_EOL . "<" . "!-- cached on ".date('jS F Y H:i', filemtime($c->get_cached_filename()))."--" . ">";
darn it.
echo PHP_EOL . $html_comment_start . " cached on ".date('jS F Y H:i', filemtime($c->get_cached_filename())) . $html_comment_end;
Could you please explain how to set this up without the prepended option for a single PHP script?
On Line 53 I think you mean to say $this->hours_cache_remains_valid
so that the property of the object is used for anyone who modifies that expecting it to change the caching time. Also you could then remove Line 52!
@yazeed I think you would want to do a 'topcache' and 'bottomcache' page include method described like in this article
And then within the top and bottom you'd do what @runion is doing in his first two comments
I set the PHP variable auto_prepend to a file (say, "auto_prepend.php" in the root) that loads this like so:
I save the cache using a PHP shutdown function (next comment).