0byt3m1n1
Path:
/
data
/
applications
/
aps
/
b2evolution
/
4.0.5-0
/
standard
/
htdocs
/
inc
/
_core
/
model
/
[
Home
]
File: _blockcache.class.php
<?php /** * This file implements the BlockCache class, which caches HTML blocks/snippets genereated by the app. * * This file is part of the evoCore framework - {@link http://evocore.net/} * See also {@link http://sourceforge.net/projects/evocms/}. * * @copyright (c)2003-2010 by Francois PLANQUE - {@link http://fplanque.net/} * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. * * {@internal License choice * - If you have received this file as part of a package, please find the license.txt file in * the same folder or the closest folder above for complete license terms. * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) * then you must choose one of the following licenses before using the file: * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php * }} * * {@internal Open Source relicensing agreement: * }} * * @package evocore * * @version $Id: _blockcache.class.php,v 1.17 2010/04/22 20:56:11 blueyed Exp $ }}} * */ if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); /** * Block Cache. * * @package evocore */ class BlockCache { var $type; var $keys; var $serialized_keys = ''; /** * After how many bytes should we output sth live while collecting cache content: */ var $output_chunk_size = 2000; /** * Progressively caching the content of the current page: */ var $cached_page_content = ''; /** * Are we currently recording cache contents */ var $is_collecting = false; /** * Constructor */ function BlockCache( $type, $keys ) { $this->type = $type; // Make sure keys are always in the same order: ksort( $keys ); $this->keys = $keys; $this->serialized_keys = $type; foreach( $keys as $key => $val ) { $this->serialized_keys .= '+'.$key.'='.$val; } // echo $this->serialized_keys; } /** * Invalidate a special key * * All we do is store the timestamp of teh invalidation * */ function invalidate_key( $key, $val ) { global $Debuglog, $servertimenow; $lastchanged_key_name = 'last_changed+'.$key.'='.$val; // Invalidate using the real time (seconds may have elapsed since $sertimenow) // Add 1 second because of teh granularity that's down to teh second // Worst case scenario: content will be collected/cahced several times for a whole second (as well as the first request after the end of that second) BlockCache::cacheproviderstore( $lastchanged_key_name, time()+1 ); $Debuglog->add( 'Invalidated: '.$lastchanged_key_name.' @ '.(time()+1), 'blockcache' ); } /** * Check if cache contents are available, otherwise start collecting output to be cached * * Basically we get all the invalidation dates we need, then we get the * data and then we check if some invalidation occured after the data was cached. * If an invalidation date is missing we consider the cache to be * obsolete but we generate a new invalidation date for next time we try to retrieve. * * @return true if we found and have echoed content from the cache */ function check() { global $Debuglog, $servertimenow; $missing_date = false; $most_recent_invalidation_ts = 0; $most_recent_invaliating_key = ''; foreach( $this->keys as $key => $val ) { $lastchanged_key_name = 'last_changed+'.$key.'='.$val; $last_changed_ts = $this->cacheproviderretrieve( $lastchanged_key_name, $success ); if( ! $success ) { // We have lost the key! Recreate and keep going for other keys: $Debuglog->add( 'Missing: '.$lastchanged_key_name, 'blockcache' ); $missing_date = true; $this->cacheproviderstore( $lastchanged_key_name, $servertimenow ); continue; } if( $last_changed_ts > $most_recent_invalidation_ts ) { // This is the new most recent invalidation date. $most_recent_invalidation_ts = $last_changed_ts; $most_recent_invaliating_key = $lastchanged_key_name; } } if( !$missing_date && $this->retrieve( $most_recent_invalidation_ts, $most_recent_invaliating_key ) ) { // cache was not invalidated yet and we could retrieve: return true; } $this->is_collecting = true; $Debuglog->add( 'Collecting: '.$this->serialized_keys, 'blockcache' ); ob_start( array( & $this, 'output_handler'), $this->output_chunk_size ); return false; } /** * Retrieve and output cache * * @param integer oldest acceptable timestamp * @return boolean true if we could retrieve */ function retrieve( $oldest_acceptable_ts = NULL, $most_recent_invaliating_key = '' ) { global $Debuglog; global $servertimenow; // return false; $content = $this->cacheproviderretrieve( $this->serialized_keys, $success ); if( ! $success ) { return false; } if( !is_null($oldest_acceptable_ts) ) { // We want to do timestamp checking: //if( ! preg_match( '/^([0-9]+) (.*)$/ms', $content, $matches ) ) if( ! $pos = strpos( $content, ' ' ) ) { // Could not find timestamp $Debuglog->add( 'MISSING TIMESTAMP on retrieval of: '.$this->serialized_keys, 'blockcache' ); return false; } // if( $matches[1] < $oldest_acceptable_ts ) if( ($cache_ts = substr( $content, 0, $pos )) < $oldest_acceptable_ts ) { // Timestamp too old (there has been an invalidation in between) $Debuglog->add( 'Retrieved INVALIDATED cached content: '.$this->serialized_keys .' (invalidated by '.$most_recent_invaliating_key.' - '.$cache_ts.' < '.$oldest_acceptable_ts.')', 'blockcache' ); return false; } // OK, we have content that is still valid: // $content = $matches[2]; $content = substr( $content, $pos+1 ); } $Debuglog->add( 'Retrieved: '.$this->serialized_keys, 'blockcache' ); // SEND CONTENT! echo $content; return true; } /** * This is called every x bytes to provide real time output */ function output_handler( $buffer ) { $this->cached_page_content .= $buffer; return $buffer; } /** * We are going to output personal data and we want to abort collecting the data for the cache. */ function abort_collect() { global $Debuglog; if( ! $this->is_collecting ) { // We are not collecting anyway return; } $Debuglog->add( 'Aborting cache data collection...', 'blockcache' ); ob_end_flush(); // We are no longer collecting... $this->is_collecting = false; } /** * End collecting output to be cached * * We just concatenate all the individual keys to have a single one * Then we store with the current timestamp */ function end_collect() { global $Debuglog, $servertimenow; if( ! $this->is_collecting ) { // We are not collecting return; } ob_end_flush(); // We use servertimenow because we may have used data that was loaded at the very start of this page $this->cacheproviderstore( $this->serialized_keys, $servertimenow.' '.$this->cached_page_content ); } /** * Store payload/data into the cache provider. * * @todo dh> This method should get removed from here, it's not limited to BlockCache. * @param mixed $key * @param mixed $payload * @param int Time to live in seconds (default: 86400; 0 means "as long as possible") */ function cacheproviderstore( $key, $payload, $ttl = 86400 ) { return set_to_mem_cache($key, $payload, $ttl); } /** * Fetch key from the cache provider. * * {@internal JFI: apc_fetch supports fetching an array of keys}} * * @todo dh> This method should get removed from here, it's not limited to BlockCache. * @todo dh> Add $default param, defaulting to NULL. This will be used on lookup failures. * @param mixed $key * @param boolean $success (by reference) */ function cacheproviderretrieve( $key, & $success ) { return get_from_mem_cache($key, $success); } } /* * $Log: _blockcache.class.php,v $ */ ?>