[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Smarty Internal Plugin 4 * 5 * @package Smarty 6 * @subpackage Cacher 7 */ 8 9 /** 10 * Smarty Cache Handler Base for Key/Value Storage Implementations 11 * 12 * This class implements the functionality required to use simple key/value stores 13 * for hierarchical cache groups. key/value stores like memcache or APC do not support 14 * wildcards in keys, therefore a cache group cannot be cleared like "a|*" - which 15 * is no problem to filesystem and RDBMS implementations. 16 * 17 * This implementation is based on the concept of invalidation. While one specific cache 18 * can be identified and cleared, any range of caches cannot be identified. For this reason 19 * each level of the cache group hierarchy can have its own value in the store. These values 20 * are nothing but microtimes, telling us when a particular cache group was cleared for the 21 * last time. These keys are evaluated for every cache read to determine if the cache has 22 * been invalidated since it was created and should hence be treated as inexistent. 23 * 24 * Although deep hierarchies are possible, they are not recommended. Try to keep your 25 * cache groups as shallow as possible. Anything up 3-5 parents should be ok. So 26 * »a|b|c« is a good depth where »a|b|c|d|e|f|g|h|i|j|k« isn't. Try to join correlating 27 * cache groups: if your cache groups look somewhat like »a|b|$page|$items|$whatever« 28 * consider using »a|b|c|$page-$items-$whatever« instead. 29 * 30 * @package Smarty 31 * @subpackage Cacher 32 * @author Rodney Rehm 33 */ 34 abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource { 35 36 /** 37 * cache for contents 38 * @var array 39 */ 40 protected $contents = array(); 41 /** 42 * cache for timestamps 43 * @var array 44 */ 45 protected $timestamps = array(); 46 47 /** 48 * populate Cached Object with meta data from Resource 49 * 50 * @param Smarty_Template_Cached $cached cached object 51 * @param Smarty_Internal_Template $_template template object 52 * @return void 53 */ 54 public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template) 55 { 56 $cached->filepath = $_template->source->uid 57 . '#' . $this->sanitize($cached->source->name) 58 . '#' . $this->sanitize($cached->cache_id) 59 . '#' . $this->sanitize($cached->compile_id); 60 61 $this->populateTimestamp($cached); 62 } 63 64 /** 65 * populate Cached Object with timestamp and exists from Resource 66 * 67 * @param Smarty_Template_Cached $cached cached object 68 * @return void 69 */ 70 public function populateTimestamp(Smarty_Template_Cached $cached) 71 { 72 if (!$this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $content, $timestamp, $cached->source->uid)) { 73 return; 74 } 75 $cached->content = $content; 76 $cached->timestamp = (int) $timestamp; 77 $cached->exists = $cached->timestamp; 78 } 79 80 /** 81 * Read the cached template and process the header 82 * 83 * @param Smarty_Internal_Template $_template template object 84 * @param Smarty_Template_Cached $cached cached object 85 * @return booelan true or false if the cached content does not exist 86 */ 87 public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null) 88 { 89 if (!$cached) { 90 $cached = $_template->cached; 91 } 92 $content = $cached->content ? $cached->content : null; 93 $timestamp = $cached->timestamp ? $cached->timestamp : null; 94 if ($content === null || !$timestamp) { 95 if (!$this->fetch($_template->cached->filepath, $_template->source->name, $_template->cache_id, $_template->compile_id, $content, $timestamp, $_template->source->uid)) { 96 return false; 97 } 98 } 99 if (isset($content)) { 100 $_smarty_tpl = $_template; 101 eval("?>" . $content); 102 return true; 103 } 104 return false; 105 } 106 107 /** 108 * Write the rendered template output to cache 109 * 110 * @param Smarty_Internal_Template $_template template object 111 * @param string $content content to cache 112 * @return boolean success 113 */ 114 public function writeCachedContent(Smarty_Internal_Template $_template, $content) 115 { 116 $this->addMetaTimestamp($content); 117 return $this->write(array($_template->cached->filepath => $content), $_template->properties['cache_lifetime']); 118 } 119 120 /** 121 * Empty cache 122 * 123 * {@internal the $exp_time argument is ignored altogether }} 124 * 125 * @param Smarty $smarty Smarty object 126 * @param integer $exp_time expiration time [being ignored] 127 * @return integer number of cache files deleted [always -1] 128 * @uses purge() to clear the whole store 129 * @uses invalidate() to mark everything outdated if purge() is inapplicable 130 */ 131 public function clearAll(Smarty $smarty, $exp_time=null) 132 { 133 if (!$this->purge()) { 134 $this->invalidate(null); 135 } 136 return -1; 137 } 138 139 /** 140 * Empty cache for a specific template 141 * 142 * {@internal the $exp_time argument is ignored altogether}} 143 * 144 * @param Smarty $smarty Smarty object 145 * @param string $resource_name template name 146 * @param string $cache_id cache id 147 * @param string $compile_id compile id 148 * @param integer $exp_time expiration time [being ignored] 149 * @return integer number of cache files deleted [always -1] 150 * @uses buildCachedFilepath() to generate the CacheID 151 * @uses invalidate() to mark CacheIDs parent chain as outdated 152 * @uses delete() to remove CacheID from cache 153 */ 154 public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) 155 { 156 $uid = $this->getTemplateUid($smarty, $resource_name, $cache_id, $compile_id); 157 $cid = $uid . '#' . $this->sanitize($resource_name) . '#' . $this->sanitize($cache_id) . '#' . $this->sanitize($compile_id); 158 $this->delete(array($cid)); 159 $this->invalidate($cid, $resource_name, $cache_id, $compile_id, $uid); 160 return -1; 161 } 162 /** 163 * Get template's unique ID 164 * 165 * @param Smarty $smarty Smarty object 166 * @param string $resource_name template name 167 * @param string $cache_id cache id 168 * @param string $compile_id compile id 169 * @return string filepath of cache file 170 */ 171 protected function getTemplateUid(Smarty $smarty, $resource_name, $cache_id, $compile_id) 172 { 173 $uid = ''; 174 if (isset($resource_name)) { 175 $tpl = new $smarty->template_class($resource_name, $smarty); 176 if ($tpl->source->exists) { 177 $uid = $tpl->source->uid; 178 } 179 180 // remove from template cache 181 if ($smarty->allow_ambiguous_resources) { 182 $_templateId = $tpl->source->unique_resource . $tpl->cache_id . $tpl->compile_id; 183 } else { 184 $_templateId = $smarty->joined_template_dir . '#' . $resource_name . $tpl->cache_id . $tpl->compile_id; 185 } 186 if (isset($_templateId[150])) { 187 $_templateId = sha1($_templateId); 188 } 189 unset($smarty->template_objects[$_templateId]); 190 } 191 return $uid; 192 } 193 194 /** 195 * Sanitize CacheID components 196 * 197 * @param string $string CacheID component to sanitize 198 * @return string sanitized CacheID component 199 */ 200 protected function sanitize($string) 201 { 202 // some poeple smoke bad weed 203 $string = trim($string, '|'); 204 if (!$string) { 205 return null; 206 } 207 return preg_replace('#[^\w\|]+#S', '_', $string); 208 } 209 210 /** 211 * Fetch and prepare a cache object. 212 * 213 * @param string $cid CacheID to fetch 214 * @param string $resource_name template name 215 * @param string $cache_id cache id 216 * @param string $compile_id compile id 217 * @param string $content cached content 218 * @param integer &$timestamp cached timestamp (epoch) 219 * @param string $resource_uid resource's uid 220 * @return boolean success 221 */ 222 protected function fetch($cid, $resource_name = null, $cache_id = null, $compile_id = null, &$content = null, &$timestamp = null, $resource_uid = null) 223 { 224 $t = $this->read(array($cid)); 225 $content = !empty($t[$cid]) ? $t[$cid] : null; 226 $timestamp = null; 227 228 if ($content && ($timestamp = $this->getMetaTimestamp($content))) { 229 $invalidated = $this->getLatestInvalidationTimestamp($cid, $resource_name, $cache_id, $compile_id, $resource_uid); 230 if ($invalidated > $timestamp) { 231 $timestamp = null; 232 $content = null; 233 } 234 } 235 236 return !!$content; 237 } 238 239 /** 240 * Add current microtime to the beginning of $cache_content 241 * 242 * {@internal the header uses 8 Bytes, the first 4 Bytes are the seconds, the second 4 Bytes are the microseconds}} 243 * 244 * @param string &$content the content to be cached 245 */ 246 protected function addMetaTimestamp(&$content) 247 { 248 $mt = explode(" ", microtime()); 249 $ts = pack("NN", $mt[1], (int) ($mt[0] * 100000000)); 250 $content = $ts . $content; 251 } 252 253 /** 254 * Extract the timestamp the $content was cached 255 * 256 * @param string &$content the cached content 257 * @return float the microtime the content was cached 258 */ 259 protected function getMetaTimestamp(&$content) 260 { 261 $s = unpack("N", substr($content, 0, 4)); 262 $m = unpack("N", substr($content, 4, 4)); 263 $content = substr($content, 8); 264 return $s[1] + ($m[1] / 100000000); 265 } 266 267 /** 268 * Invalidate CacheID 269 * 270 * @param string $cid CacheID 271 * @param string $resource_name template name 272 * @param string $cache_id cache id 273 * @param string $compile_id compile id 274 * @param string $resource_uid source's uid 275 * @return void 276 */ 277 protected function invalidate($cid = null, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null) 278 { 279 $now = microtime(true); 280 $key = null; 281 // invalidate everything 282 if (!$resource_name && !$cache_id && !$compile_id) { 283 $key = 'IVK#ALL'; 284 } 285 // invalidate all caches by template 286 else if ($resource_name && !$cache_id && !$compile_id) { 287 $key = 'IVK#TEMPLATE#' . $resource_uid . '#' . $this->sanitize($resource_name); 288 } 289 // invalidate all caches by cache group 290 else if (!$resource_name && $cache_id && !$compile_id) { 291 $key = 'IVK#CACHE#' . $this->sanitize($cache_id); 292 } 293 // invalidate all caches by compile id 294 else if (!$resource_name && !$cache_id && $compile_id) { 295 $key = 'IVK#COMPILE#' . $this->sanitize($compile_id); 296 } 297 // invalidate by combination 298 else { 299 $key = 'IVK#CID#' . $cid; 300 } 301 $this->write(array($key => $now)); 302 } 303 304 /** 305 * Determine the latest timestamp known to the invalidation chain 306 * 307 * @param string $cid CacheID to determine latest invalidation timestamp of 308 * @param string $resource_name template name 309 * @param string $cache_id cache id 310 * @param string $compile_id compile id 311 * @param string $resource_uid source's filepath 312 * @return float the microtime the CacheID was invalidated 313 */ 314 protected function getLatestInvalidationTimestamp($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null) 315 { 316 // abort if there is no CacheID 317 if (false && !$cid) { 318 return 0; 319 } 320 // abort if there are no InvalidationKeys to check 321 if (!($_cid = $this->listInvalidationKeys($cid, $resource_name, $cache_id, $compile_id, $resource_uid))) { 322 return 0; 323 } 324 325 // there are no InValidationKeys 326 if (!($values = $this->read($_cid))) { 327 return 0; 328 } 329 // make sure we're dealing with floats 330 $values = array_map('floatval', $values); 331 return max($values); 332 } 333 334 /** 335 * Translate a CacheID into the list of applicable InvalidationKeys. 336 * 337 * Splits "some|chain|into|an|array" into array( '#clearAll#', 'some', 'some|chain', 'some|chain|into', ... ) 338 * 339 * @param string $cid CacheID to translate 340 * @param string $resource_name template name 341 * @param string $cache_id cache id 342 * @param string $compile_id compile id 343 * @param string $resource_uid source's filepath 344 * @return array list of InvalidationKeys 345 * @uses $invalidationKeyPrefix to prepend to each InvalidationKey 346 */ 347 protected function listInvalidationKeys($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null) 348 { 349 $t = array('IVK#ALL'); 350 $_name = $_compile = '#'; 351 if ($resource_name) { 352 $_name .= $resource_uid . '#' . $this->sanitize($resource_name); 353 $t[] = 'IVK#TEMPLATE' . $_name; 354 } 355 if ($compile_id) { 356 $_compile .= $this->sanitize($compile_id); 357 $t[] = 'IVK#COMPILE' . $_compile; 358 } 359 $_name .= '#'; 360 // some poeple smoke bad weed 361 $cid = trim($cache_id, '|'); 362 if (!$cid) { 363 return $t; 364 } 365 $i = 0; 366 while (true) { 367 // determine next delimiter position 368 $i = strpos($cid, '|', $i); 369 // add complete CacheID if there are no more delimiters 370 if ($i === false) { 371 $t[] = 'IVK#CACHE#' . $cid; 372 $t[] = 'IVK#CID' . $_name . $cid . $_compile; 373 $t[] = 'IVK#CID' . $_name . $_compile; 374 break; 375 } 376 $part = substr($cid, 0, $i); 377 // add slice to list 378 $t[] = 'IVK#CACHE#' . $part; 379 $t[] = 'IVK#CID' . $_name . $part . $_compile; 380 // skip past delimiter position 381 $i++; 382 } 383 return $t; 384 } 385 386 /** 387 * Check is cache is locked for this template 388 * 389 * @param Smarty $smarty Smarty object 390 * @param Smarty_Template_Cached $cached cached object 391 * @return booelan true or false if cache is locked 392 */ 393 public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) 394 { 395 $key = 'LOCK#' . $cached->filepath; 396 $data = $this->read(array($key)); 397 return $data && time() - $data[$key] < $smarty->locking_timeout; 398 } 399 400 /** 401 * Lock cache for this template 402 * 403 * @param Smarty $smarty Smarty object 404 * @param Smarty_Template_Cached $cached cached object 405 */ 406 public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) 407 { 408 $cached->is_locked = true; 409 $key = 'LOCK#' . $cached->filepath; 410 $this->write(array($key => time()), $smarty->locking_timeout); 411 } 412 413 /** 414 * Unlock cache for this template 415 * 416 * @param Smarty $smarty Smarty object 417 * @param Smarty_Template_Cached $cached cached object 418 */ 419 public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) 420 { 421 $cached->is_locked = false; 422 $key = 'LOCK#' . $cached->filepath; 423 $this->delete(array($key)); 424 } 425 426 /** 427 * Read values for a set of keys from cache 428 * 429 * @param array $keys list of keys to fetch 430 * @return array list of values with the given keys used as indexes 431 */ 432 protected abstract function read(array $keys); 433 434 /** 435 * Save values for a set of keys to cache 436 * 437 * @param array $keys list of values to save 438 * @param int $expire expiration time 439 * @return boolean true on success, false on failure 440 */ 441 protected abstract function write(array $keys, $expire=null); 442 443 /** 444 * Remove values from cache 445 * 446 * @param array $keys list of keys to delete 447 * @return boolean true on success, false on failure 448 */ 449 protected abstract function delete(array $keys); 450 451 /** 452 * Remove *all* values from cache 453 * 454 * @return boolean true on success, false on failure 455 */ 456 protected function purge() 457 { 458 return false; 459 } 460 461 } 462 463 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |