|
Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon. |
|
View previous topic :: View next topic |
Author |
Message |
dragon001 Smarty Rookie
Joined: 12 Feb 2005 Posts: 5
|
Posted: Sat Jan 13, 2007 12:09 pm Post subject: cache Handler for APC |
|
|
I was using eAccelarator as Cache Engine to now, but since i install php5 there was the apc package already included.
So I removed eaccelerator and utilized apc more then before.
But i didn't find an alternativ solution to the cache handler,
so here is the apc cache handler for Smarty:
Code: | <?php
/**
* Smarty Cache Handler<br>
* utilizing APC extension (http://apc.net/HomeUk)<br>
*
* @package Smarty
* @subpackage plugins
*/
/**
* Modifikations by
* Chris Westerfield
*/
/**
* Helper function for smarty_cache_APC()
* Clears a whole hierarchy of cache entries.
*
* @access private
* @param array $hierarchy hierarchical array of cache ids
* @return void
*
* @see smarty_cache_apc()
*/
function _APC_clear_cache(&$hierarchy) {
foreach ($hierarchy as $key => $value) {
if (is_array($value)) {
_APC_clear_cache($value);
}
else {
apc_delete($value);
}
}
}
/**
* Helper function for smarty_cache_apc()
* Checks whether a cached content has been expired by reading the content's header.
*
* @access private
* @param string $cache_content the cached content
* @return boolean TRUE if cache has been expired, FALSE otherwise
*
* @see smarty_cache_apc()
*/
function _apc_hasexpired(&$cache_content) {
$split = explode("\n", $cache_content, 2);
$attributes = unserialize($split[0]);
if ($attributes['expires'] > 0 && time() > $attributes['expires'])
return true;
else
return false;
}
/**
* Smarty Cache Handler<br>
* utilizing apc extension (http://apc.net/HomeUk)<br>
*
* Name: smarty_cache_apc<br>
* Type: Cache Handler<br>
* Purpose: Replacement for the file based cache handling of Smarty. smarty_cache_apc() is
* using Turck apc extension to minimize disk usage.
* File: cache.apc.php<br>
* Date: Dec 2, 2003<br>
*
* Usage Example<br>
* <pre>
* $smarty = new Smarty;
* $smarty->cache_handler_func = 'smarty_cache_apc';
* $smarty->caching = true;
* $smarty->display('index.tpl');
* </pre>
*
* @author André Rabold
* @version RC-1
*
* @param string $action Cache operation to perform ( read | write | clear )
* @param mixed $smarty Reference to an instance of Smarty
* @param string $cache_content Reference to cached contents
* @param string $tpl_file Template file name
* @param string $cache_id Cache identifier
* @param string $compile_id Compile identifier
* @param integer $exp_time Expiration time
* @return boolean TRUE on success, FALSE otherwise
*
* @link http://apc.net/HomeUk
* (apc homepage)
* @link http://smarty.php.net/manual/en/section.template.cache.handler.func.php
* (Smarty online manual)
*/
function smarty_cache_apc($action, &$smarty, &$cache_content, $tpl_file=null, $cache_id=null, $compile_id=null, $exp_time=null)
{
if(!function_exists("apc")) {
$smarty->trigger_error("cache_handler: PHP Extension \"apc\" (http://apc.net/HomeUk) not installed.");
return false;
}
// Create unique cache id:
// We are using smarty's internal functions here to be as compatible as possible.
$_auto_id = $smarty->_get_auto_id($cache_id, $compile_id);
$_cache_file = substr($smarty->_get_auto_filename(".", $tpl_file, $_auto_id),2);
$apc_id = "smarty_apc|".$_cache_file;
// The index contains all stored cache ids in a hierarchy and can be iterated later
$apc_index_id = "smarty_apc_index";
switch ($action) {
case 'read':
// read cache from shared memory
$cache_content = apc_get($apc_id);
if (!is_null($cache_content) && _apc_hasexpired($cache_content)) {
// Cache has been expired so we clear it now by calling ourself with another parameter :)
$cache_content = null;
smarty_cache_apc('clear', $smarty, $cache_content, $tpl_file, $cache_id, $compile_id);
}
$return = true;
break;
case 'write':
// save cache to shared memory
$current_time = time();
if (is_null($exp_time) || $exp_time < $current_time)
$ttl = 0;
else
$ttl = $exp_time - time();
// First run garbage collection
#apc_gc();
// Put content into cache
#apc_lock($apc_id);
apc_store($apc_id, $cache_content, $ttl);
// Create an index association
#apc_lock($apc_index_id);
$apc_index = apc_get($apc_index_id);
if (!is_array($apc_index))
$apc_index = array();
$indexes = explode(DIRECTORY_SEPARATOR, $_cache_file);
$_pointer =& $apc_index;
foreach ($indexes as $index) {
if (!isset($_pointer[$index]))
$_pointer[$index] = array();
$_pointer =& $_pointer[$index];
}
$_pointer = $apc_id;
apc_store($apc_index_id, $apc_index, 0);
#apc_unlock($apc_index_id);
#apc_unlock($apc_id);
break;
case 'clear':
// clear cache info
apc_lock($apc_index_id);
$apc_index = apc_get($apc_index_id);
if (is_array($apc_index)) {
if (empty($cache_id) && empty($compile_id) && empty($tpl_file)) {
// clear all cache
#apc_lock($apc_id);
_APC_clear_cache($apc_index);
#apc_unlock($apc_id);
$apc_index = array();
}
else {
// clear single file or cache group
$indexes = explode(DIRECTORY_SEPARATOR, $_cache_file);
if (is_null($tpl_file))
array_pop($indexes);
$_pointer =& $apc_index;
$_failed = false;
foreach ($indexes as $index) {
if (!isset($_pointer[$index])) {
$_failed = true;
break;
}
$_pointer =& $_pointer[$index];
}
if (!$_failed) {
if (is_array($_pointer)) {
// Clear cache group
_APC_clear_cache($_pointer);
}
else {
// Clear single file
#apc_lock($_pointer);
apc_delete($_pointer);
#apc_unlock($_pointer);
}
$_pointer = null;
}
}
}
apc_ store ($apc_index_id, $apc_index, 0);
#apc_unlock($apc_index_id);
$return = true;
break;
default:
// error, unknown action
$smarty->trigger_error("cache_handler: unknown action \"$action\"");
$return = false;
break;
}
return $return;
}
?>
|
I didn't test it jet, so be warned |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Sat Jan 13, 2007 8:01 pm Post subject: |
|
|
Ahh. Cool.
I've been meaning to do a port of this but haven't had the time. I'll have to test it to see how it goes.
Thanks! |
|
Back to top |
|
dragon001 Smarty Rookie
Joined: 12 Feb 2005 Posts: 5
|
Posted: Sat Jan 13, 2007 8:11 pm Post subject: |
|
|
it should work fine.
the only thing i recognized is,
that apc doesn't have a gc command to remove old scripts.
I removed them via # (but left them in the script).
storage and deleting functions where replaced by there corresponding funktions.
renamed also the eaccelerator in variables and function defnitions to keep the distanz between the handlers
^^
have fun
^^ |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Sat Jan 13, 2007 10:11 pm Post subject: |
|
|
btw: at one point, I considered creating a generalized cache handler using something like http://pear.php.net/package/System_SharedMemory (I'm not sure if I would use that package, but it contains the main idea). As I don't change the shared memory options on my servers that often, I never got around to it. |
|
Back to top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|