library/smarty/libs/sysplugins/smarty_internal_cacheresource_file.php
changeset 46 f11c31f7fa3e
parent 45 a56e7f9a0463
child 47 03388ec805b4
equal deleted inserted replaced
45:a56e7f9a0463 46:f11c31f7fa3e
     1 <?php
       
     2 /**
       
     3  * Smarty Internal Plugin CacheResource File
       
     4  *
       
     5  * @package    Smarty
       
     6  * @subpackage Cacher
       
     7  * @author     Uwe Tews
       
     8  * @author     Rodney Rehm
       
     9  */
       
    10 
       
    11 /**
       
    12  * This class does contain all necessary methods for the HTML cache on file system
       
    13  * Implements the file system as resource for the HTML cache Version ussing nocache inserts.
       
    14  *
       
    15  * @package    Smarty
       
    16  * @subpackage Cacher
       
    17  */
       
    18 class Smarty_Internal_CacheResource_File extends Smarty_CacheResource {
       
    19     /**
       
    20      * populate Cached Object with meta data from Resource
       
    21      *
       
    22      * @param Smarty_Template_Cached $cached cached object
       
    23      * @param Smarty_Internal_Template $_template template object
       
    24      *
       
    25      * @return void
       
    26      */
       
    27     public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template) {
       
    28         $_source_file_path = str_replace(':', '.', $_template->source->filepath);
       
    29         $_cache_id = isset($_template->cache_id) ? preg_replace('![^\w\|]+!', '_', $_template->cache_id) : null;
       
    30         $_compile_id = isset($_template->compile_id) ? preg_replace('![^\w\|]+!', '_', $_template->compile_id) : null;
       
    31         $_filepath = $_template->source->uid;
       
    32         // if use_sub_dirs, break file into directories
       
    33         if ($_template->smarty->use_sub_dirs) {
       
    34             $_filepath = substr($_filepath, 0, 2) . DS
       
    35                 . substr($_filepath, 2, 2) . DS
       
    36                 . substr($_filepath, 4, 2) . DS
       
    37                 . $_filepath;
       
    38         }
       
    39         $_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';
       
    40         if (isset($_cache_id)) {
       
    41             $_cache_id = str_replace('|', $_compile_dir_sep, $_cache_id) . $_compile_dir_sep;
       
    42         } else {
       
    43             $_cache_id = '';
       
    44         }
       
    45         if (isset($_compile_id)) {
       
    46             $_compile_id = $_compile_id . $_compile_dir_sep;
       
    47         } else {
       
    48             $_compile_id = '';
       
    49         }
       
    50         $_cache_dir = $_template->smarty->getCacheDir();
       
    51         if ($_template->smarty->cache_locking) {
       
    52             // create locking file name
       
    53             // relative file name?
       
    54             if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_cache_dir)) {
       
    55                 $_lock_dir = rtrim(getcwd(), '/\\') . DS . $_cache_dir;
       
    56             } else {
       
    57                 $_lock_dir = $_cache_dir;
       
    58             }
       
    59             $cached->lock_id = $_lock_dir . sha1($_cache_id . $_compile_id . $_template->source->uid) . '.lock';
       
    60         }
       
    61         $cached->filepath = $_cache_dir . $_cache_id . $_compile_id . $_filepath . '.' . basename($_source_file_path) . '.php';
       
    62         $cached->timestamp = $cached->exists = is_file($cached->filepath);
       
    63         if ($cached->exists) {
       
    64             $cached->timestamp = filemtime($cached->filepath);
       
    65         }
       
    66     }
       
    67 
       
    68     /**
       
    69      * populate Cached Object with timestamp and exists from Resource
       
    70      *
       
    71      * @param Smarty_Template_Cached $cached cached object
       
    72      *
       
    73      * @return void
       
    74      */
       
    75     public function populateTimestamp(Smarty_Template_Cached $cached) {
       
    76         $cached->timestamp = $cached->exists = is_file($cached->filepath);
       
    77         if ($cached->exists) {
       
    78             $cached->timestamp = filemtime($cached->filepath);
       
    79         }
       
    80     }
       
    81 
       
    82     /**
       
    83      * Read the cached template and process its header
       
    84      *
       
    85      * @param Smarty_Internal_Template $_template template object
       
    86      * @param Smarty_Template_Cached $cached cached object
       
    87      *
       
    88      * @return booleantrue or false if the cached content does not exist
       
    89      */
       
    90     public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached = null) {
       
    91         /** @var Smarty_Internal_Template $_smarty_tpl
       
    92          * used in included file
       
    93          */
       
    94         $_smarty_tpl = $_template;
       
    95 
       
    96         return @include $_template->cached->filepath;
       
    97     }
       
    98 
       
    99     /**
       
   100      * Write the rendered template output to cache
       
   101      *
       
   102      * @param Smarty_Internal_Template $_template template object
       
   103      * @param string $content content to cache
       
   104      *
       
   105      * @return boolean success
       
   106      */
       
   107     public function writeCachedContent(Smarty_Internal_Template $_template, $content) {
       
   108         $obj = new Smarty_Internal_Write_File();
       
   109         if ($obj->writeFile($_template->cached->filepath, $content, $_template->smarty) === true) {
       
   110             $cached = $_template->cached;
       
   111             $cached->timestamp = $cached->exists = is_file($cached->filepath);
       
   112             if ($cached->exists) {
       
   113                 $cached->timestamp = filemtime($cached->filepath);
       
   114                 return true;
       
   115             }
       
   116         }
       
   117         return false;
       
   118     }
       
   119 
       
   120     /**
       
   121      * Read cached template from cache
       
   122      *
       
   123      * @param  Smarty_Internal_Template $_template template object
       
   124      *
       
   125      * @return string  content
       
   126      */
       
   127     public function readCachedContent(Smarty_Internal_Template $_template) {
       
   128         if (is_file($_template->cached->filepath)) {
       
   129             return file_get_contents($_template->cached->filepath);
       
   130         }
       
   131         return false;
       
   132     }
       
   133 
       
   134     /**
       
   135      * Empty cache
       
   136      *
       
   137      * @param Smarty $smarty
       
   138      * @param integer $exp_time expiration time (number of seconds, not timestamp)
       
   139      *
       
   140      * @return integer number of cache files deleted
       
   141      */
       
   142     public function clearAll(Smarty $smarty, $exp_time = null) {
       
   143         return $this->clear($smarty, null, null, null, $exp_time);
       
   144     }
       
   145 
       
   146     /**
       
   147      * Empty cache for a specific template
       
   148      *
       
   149      * @param Smarty $smarty
       
   150      * @param string $resource_name template name
       
   151      * @param string $cache_id cache id
       
   152      * @param string $compile_id compile id
       
   153      * @param integer $exp_time expiration time (number of seconds, not timestamp)
       
   154      *
       
   155      * @return integer number of cache files deleted
       
   156      */
       
   157     public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) {
       
   158         $_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null;
       
   159         $_compile_id = isset($compile_id) ? preg_replace('![^\w\|]+!', '_', $compile_id) : null;
       
   160         $_dir_sep = $smarty->use_sub_dirs ? '/' : '^';
       
   161         $_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0;
       
   162         $_dir = realpath($smarty->getCacheDir()) . '/';
       
   163         if ($_dir == '/') { //We should never want to delete this!
       
   164             return 0;
       
   165         }
       
   166         $_dir_length = strlen($_dir);
       
   167         if (isset($_cache_id)) {
       
   168             $_cache_id_parts = explode('|', $_cache_id);
       
   169             $_cache_id_parts_count = count($_cache_id_parts);
       
   170             if ($smarty->use_sub_dirs) {
       
   171                 foreach ($_cache_id_parts as $id_part) {
       
   172                     $_dir .= $id_part . DS;
       
   173                 }
       
   174             }
       
   175         }
       
   176         if (isset($resource_name)) {
       
   177             $_save_stat = $smarty->caching;
       
   178             $smarty->caching = true;
       
   179             $tpl = new $smarty->template_class($resource_name, $smarty);
       
   180             $smarty->caching = $_save_stat;
       
   181 
       
   182             // remove from template cache
       
   183             $tpl->source; // have the template registered before unset()
       
   184             if ($smarty->allow_ambiguous_resources) {
       
   185                 $_templateId = $tpl->source->unique_resource . $tpl->cache_id . $tpl->compile_id;
       
   186             } else {
       
   187                 $_templateId = $smarty->joined_template_dir . '#' . $resource_name . $tpl->cache_id . $tpl->compile_id;
       
   188             }
       
   189             if (isset($_templateId[150])) {
       
   190                 $_templateId = sha1($_templateId);
       
   191             }
       
   192             unset($smarty->template_objects[$_templateId]);
       
   193 
       
   194             if ($tpl->source->exists) {
       
   195                 $_resourcename_parts = basename(str_replace('^', '/', $tpl->cached->filepath));
       
   196             } else {
       
   197                 return 0;
       
   198             }
       
   199         }
       
   200         $_count = 0;
       
   201         $_time = time();
       
   202         if (file_exists($_dir)) {
       
   203             $_cacheDirs = new RecursiveDirectoryIterator($_dir);
       
   204             $_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST);
       
   205             foreach ($_cache as $_file) {
       
   206                 if (substr(basename($_file->getPathname()), 0, 1) == '.' || strpos($_file, '.svn') !== false) {
       
   207                     continue;
       
   208                 }
       
   209                 // directory ?
       
   210                 if ($_file->isDir()) {
       
   211                     if (!$_cache->isDot()) {
       
   212                         // delete folder if empty
       
   213                         @rmdir($_file->getPathname());
       
   214                     }
       
   215                 } else {
       
   216                     $_parts = explode($_dir_sep, str_replace('\\', '/', substr((string)$_file, $_dir_length)));
       
   217                     $_parts_count = count($_parts);
       
   218                     // check name
       
   219                     if (isset($resource_name)) {
       
   220                         if ($_parts[$_parts_count - 1] != $_resourcename_parts) {
       
   221                             continue;
       
   222                         }
       
   223                     }
       
   224                     // check compile id
       
   225                     if (isset($_compile_id) && (!isset($_parts[$_parts_count - 2 - $_compile_id_offset]) || $_parts[$_parts_count - 2 - $_compile_id_offset] != $_compile_id)) {
       
   226                         continue;
       
   227                     }
       
   228                     // check cache id
       
   229                     if (isset($_cache_id)) {
       
   230                         // count of cache id parts
       
   231                         $_parts_count = (isset($_compile_id)) ? $_parts_count - 2 - $_compile_id_offset : $_parts_count - 1 - $_compile_id_offset;
       
   232                         if ($_parts_count < $_cache_id_parts_count) {
       
   233                             continue;
       
   234                         }
       
   235                         for ($i = 0; $i < $_cache_id_parts_count; $i++) {
       
   236                             if ($_parts[$i] != $_cache_id_parts[$i]) {
       
   237                                 continue 2;
       
   238                             }
       
   239                         }
       
   240                     }
       
   241                     // expired ?
       
   242                     if (isset($exp_time)) {
       
   243                         if ($exp_time < 0) {
       
   244                             preg_match('#\'cache_lifetime\' =>\s*(\d*)#', file_get_contents($_file), $match);
       
   245                             if ($_time < (@filemtime($_file) + $match[1])) {
       
   246                                 continue;
       
   247                             }
       
   248                         } else {
       
   249                             if ($_time - @filemtime($_file) < $exp_time) {
       
   250                                 continue;
       
   251                             }
       
   252                         }
       
   253                     }
       
   254                     $_count += @unlink((string)$_file) ? 1 : 0;
       
   255                 }
       
   256             }
       
   257         }
       
   258 
       
   259         return $_count;
       
   260     }
       
   261 
       
   262     /**
       
   263      * Check is cache is locked for this template
       
   264      *
       
   265      * @param Smarty $smarty Smarty object
       
   266      * @param Smarty_Template_Cached $cached cached object
       
   267      *
       
   268      * @return boolean true or false if cache is locked
       
   269      */
       
   270     public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) {
       
   271         if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
       
   272             clearstatcache(true, $cached->lock_id);
       
   273         } else {
       
   274             clearstatcache();
       
   275         }
       
   276         if (is_file($cached->lock_id)) {
       
   277             $t = @filemtime($cached->lock_id);
       
   278             return $t && (time() - $t < $smarty->locking_timeout);
       
   279         } else {
       
   280             return false;
       
   281         }
       
   282     }
       
   283 
       
   284     /**
       
   285      * Lock cache for this template
       
   286      *
       
   287      * @param Smarty $smarty Smarty object
       
   288      * @param Smarty_Template_Cached $cached cached object
       
   289      *
       
   290      * @return bool|void
       
   291      */
       
   292     public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) {
       
   293         $cached->is_locked = true;
       
   294         touch($cached->lock_id);
       
   295     }
       
   296 
       
   297     /**
       
   298      * Unlock cache for this template
       
   299      *
       
   300      * @param Smarty $smarty Smarty object
       
   301      * @param Smarty_Template_Cached $cached cached object
       
   302      *
       
   303      * @return bool|void
       
   304      */
       
   305     public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) {
       
   306         $cached->is_locked = false;
       
   307         @unlink($cached->lock_id);
       
   308     }
       
   309 }