smarty_template_cached.php (13394B)
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: Uwe Tews 5 * Date: 04.12.2014 6 * Time: 06:08 7 */ 8 9 /** 10 * Smarty Resource Data Object 11 * Cache Data Container for Template Files 12 * 13 * @package Smarty 14 * @subpackage TemplateResources 15 * @author Rodney Rehm 16 */ 17 class Smarty_Template_Cached 18 { 19 /** 20 * Source Filepath 21 * 22 * @var string 23 */ 24 public $filepath = false; 25 26 /** 27 * Source Content 28 * 29 * @var string 30 */ 31 public $content = null; 32 33 /** 34 * Source Timestamp 35 * 36 * @var integer 37 */ 38 public $timestamp = false; 39 40 /** 41 * Source Existence 42 * 43 * @var boolean 44 */ 45 public $exists = false; 46 47 /** 48 * Cache Is Valid 49 * 50 * @var boolean 51 */ 52 public $valid = null; 53 54 /** 55 * Cache was processed 56 * 57 * @var boolean 58 */ 59 public $processed = false; 60 61 /** 62 * CacheResource Handler 63 * 64 * @var Smarty_CacheResource 65 */ 66 public $handler = null; 67 68 /** 69 * Template Compile Id (Smarty_Internal_Template::$compile_id) 70 * 71 * @var string 72 */ 73 public $compile_id = null; 74 75 /** 76 * Template Cache Id (Smarty_Internal_Template::$cache_id) 77 * 78 * @var string 79 */ 80 public $cache_id = null; 81 82 /** 83 * Id for cache locking 84 * 85 * @var string 86 */ 87 public $lock_id = null; 88 89 /** 90 * flag that cache is locked by this instance 91 * 92 * @var bool 93 */ 94 public $is_locked = false; 95 96 /** 97 * Source Object 98 * 99 * @var Smarty_Template_Source 100 */ 101 public $source = null; 102 103 /** 104 * create Cached Object container 105 * 106 * @param Smarty_Internal_Template $_template template object 107 */ 108 public function __construct(Smarty_Internal_Template $_template) 109 { 110 $this->compile_id = $_template->compile_id; 111 $this->cache_id = $_template->cache_id; 112 if (!isset($_template->source)) { 113 $_template->loadSource(); 114 } 115 $this->source = $_template->source; 116 if (!class_exists('Smarty_CacheResource', false)) { 117 require SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php'; 118 } 119 $this->handler = Smarty_CacheResource::load($_template->smarty); 120 } 121 122 /** 123 * @param Smarty_Internal_Template $_template 124 * 125 * @return Smarty_Template_Cached 126 */ 127 static function load(Smarty_Internal_Template $_template) 128 { 129 $_template->cached = $cached = new Smarty_Template_Cached($_template); 130 $cached->handler->populate($cached, $_template); 131 // caching enabled ? 132 if (!($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED) || $_template->source->recompiled) { 133 $cached->valid = false; 134 } 135 return $cached; 136 } 137 138 /** 139 * Check if cache is valid, lock cache if required 140 * 141 * @param \Smarty_Internal_Template $_template 142 * 143 * @return bool flag true if cache is valid 144 */ 145 public function isCached(Smarty_Internal_Template $_template) 146 { 147 if ($this->valid !== null) { 148 return $this->valid; 149 } 150 while (true) { 151 while (true) { 152 if ($this->exists === false || $_template->smarty->force_compile || $_template->smarty->force_cache) { 153 $this->valid = false; 154 } else { 155 $this->valid = true; 156 } 157 if ($this->valid && $_template->caching == Smarty::CACHING_LIFETIME_CURRENT && $_template->cache_lifetime >= 0 && time() > ($this->timestamp + $_template->cache_lifetime)) { 158 // lifetime expired 159 $this->valid = false; 160 } 161 if ($this->valid && $_template->source->timestamp > $this->timestamp) { 162 $this->valid = false; 163 } 164 if ($this->valid || !$_template->smarty->cache_locking) { 165 break; 166 } 167 if (!$this->handler->locked($_template->smarty, $this)) { 168 $this->handler->acquireLock($_template->smarty, $this); 169 break 2; 170 } 171 $this->handler->populate($this, $_template); 172 } 173 if ($this->valid) { 174 if (!$_template->smarty->cache_locking || $this->handler->locked($_template->smarty, $this) === null) { 175 // load cache file for the following checks 176 if ($_template->smarty->debugging) { 177 Smarty_Internal_Debug::start_cache($_template); 178 } 179 if ($this->handler->process($_template, $this) === false) { 180 $this->valid = false; 181 } else { 182 $this->processed = true; 183 } 184 if ($_template->smarty->debugging) { 185 Smarty_Internal_Debug::end_cache($_template); 186 } 187 } else { 188 $this->is_locked = true; 189 continue; 190 } 191 } else { 192 return $this->valid; 193 } 194 if ($this->valid && $_template->caching === Smarty::CACHING_LIFETIME_SAVED && $_template->properties['cache_lifetime'] >= 0 && (time() > ($_template->cached->timestamp + $_template->properties['cache_lifetime']))) { 195 $this->valid = false; 196 } 197 if ($_template->smarty->cache_locking) { 198 if (!$this->valid) { 199 $this->handler->acquireLock($_template->smarty, $this); 200 } elseif ($this->is_locked) { 201 $this->handler->releaseLock($_template->smarty, $this); 202 } 203 } 204 return $this->valid; 205 } 206 return $this->valid; 207 } 208 209 /** 210 * Process cached template 211 * 212 * @param Smarty_Internal_Template $_template template object 213 */ 214 public function process(Smarty_Internal_Template $_template) 215 { 216 if ($this->handler->process($_template, $this) === false) { 217 $this->valid = false; 218 } 219 if ($this->valid) { 220 $this->processed = true; 221 } else { 222 $this->processed = false; 223 } 224 } 225 226 /** 227 * Render cached template 228 * 229 * @param Smarty_Internal_Template $_template 230 * 231 * @return string 232 * @throws Exception 233 */ 234 public function render(Smarty_Internal_Template $_template) 235 { 236 if (!$this->processed) { 237 $this->process($_template); 238 } 239 return $_template->getRenderedTemplateCode(); 240 } 241 242 /** 243 * Write this cache object to handler 244 * 245 * @param Smarty_Internal_Template $_template template object 246 * @param string $content content to cache 247 * 248 * @return boolean success 249 */ 250 public function write(Smarty_Internal_Template $_template, $content) 251 { 252 if (!$_template->source->recompiled) { 253 if ($this->handler->writeCachedContent($_template, $content)) { 254 $this->content = null; 255 $this->timestamp = time(); 256 $this->exists = true; 257 $this->valid = true; 258 $this->processed = false; 259 if ($_template->smarty->cache_locking) { 260 $this->handler->releaseLock($_template->smarty, $this); 261 } 262 263 return true; 264 } 265 $this->content = null; 266 $this->timestamp = false; 267 $this->exists = false; 268 $this->valid = false; 269 $this->processed = false; 270 } 271 272 return false; 273 } 274 275 /** 276 * Read cache content from handler 277 * 278 * @param Smarty_Internal_Template $_template template object 279 * 280 * @return string content 281 */ 282 public function read(Smarty_Internal_Template $_template) 283 { 284 if (!$_template->source->recompiled) { 285 return $this->handler->readCachedContent($_template); 286 } 287 return false; 288 } 289 290 /** 291 * Sanitize content and write it to cache resource 292 * 293 * @param Smarty_Internal_Template $_template 294 * @param string $content 295 * @param bool $no_output_filter 296 * 297 * @throws SmartyException 298 */ 299 public function updateCache(Smarty_Internal_Template $_template, $content, $no_output_filter) 300 { 301 $_template->properties['has_nocache_code'] = false; 302 // get text between non-cached items 303 $cache_split = preg_split("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $content); 304 // get non-cached items 305 preg_match_all("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $content, $cache_parts); 306 $output = ''; 307 // loop over items, stitch back together 308 foreach ($cache_split as $curr_idx => $curr_split) { 309 // escape PHP tags in template content 310 $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>|<script\s+language\s*=\s*[\"\']?\s*php\s*[\"\']?\s*>)/', "<?php echo '\$1'; ?>\n", $curr_split); 311 if (isset($cache_parts[0][$curr_idx])) { 312 $_template->properties['has_nocache_code'] = true; 313 $output .= $cache_parts[1][$curr_idx]; 314 } 315 } 316 if (!$no_output_filter && !$_template->has_nocache_code && (isset($_template->smarty->autoload_filters['output']) || isset($_template->smarty->registered_filters['output']))) { 317 $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $_template); 318 } 319 // write cache file content 320 $this->writeCachedContent($_template, $output); 321 } 322 323 /** 324 * Writes the content to cache resource 325 * 326 * @param Smarty_Internal_Template $_template 327 * @param string $content 328 * 329 * @return bool 330 */ 331 public function writeCachedContent(Smarty_Internal_Template $_template, $content) 332 { 333 if ($_template->source->recompiled || !($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED)) { 334 // don't write cache file 335 return false; 336 } 337 $_template->properties['cache_lifetime'] = $_template->cache_lifetime; 338 $_template->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); 339 $content = Smarty_Internal_Extension_CodeFrame::create($_template, $content, true); 340 if (!empty($_template->properties['tpl_function'])) { 341 foreach ($_template->properties['tpl_function'] as $funcParam) { 342 if (is_file($funcParam['compiled_filepath'])) { 343 // read compiled file 344 $code = file_get_contents($funcParam['compiled_filepath']); 345 // grab template function 346 if (preg_match("/\/\* {$funcParam['call_name']} \*\/([\S\s]*?)\/\*\/ {$funcParam['call_name']} \*\//", $code, $match)) { 347 unset($code); 348 $content .= "<?php " . $match[0] . "?>\n"; 349 } 350 } 351 } 352 } 353 return $this->write($_template, $content); 354 } 355 356 /** 357 * check client side cache 358 * 359 * @param Smarty_Internal_Template $_template 360 * @param string $content 361 */ 362 public function cacheModifiedCheck(Smarty_Internal_Template $_template, $content) 363 { 364 $_isCached = $_template->isCached() && !$_template->has_nocache_code; 365 $_last_modified_date = @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); 366 if ($_isCached && $this->timestamp <= strtotime($_last_modified_date)) { 367 switch (PHP_SAPI) { 368 case 'cgi': // php-cgi < 5.3 369 case 'cgi-fcgi': // php-cgi >= 5.3 370 case 'fpm-fcgi': // php-fpm >= 5.3.3 371 header('Status: 304 Not Modified'); 372 break; 373 374 case 'cli': 375 if ( /* ^phpunit */ 376 !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ 377 ) { 378 $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified'; 379 } 380 break; 381 382 default: 383 header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); 384 break; 385 } 386 } else { 387 switch (PHP_SAPI) { 388 case 'cli': 389 if ( /* ^phpunit */ 390 !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ 391 ) { 392 $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $this->timestamp) . ' GMT'; 393 } 394 break; 395 396 default: 397 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $this->timestamp) . ' GMT'); 398 break; 399 } 400 echo $content; 401 } 402 } 403 }