Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 3 /** 4 * SCSSPHP 5 * 6 * @copyright 2012-2020 Leaf Corcoran 7 * 8 * @license http://opensource.org/licenses/MIT MIT 9 * 10 * @link http://scssphp.github.io/scssphp 11 */ 12 13 namespace ScssPhp\ScssPhp; 14 15 use Exception; 16 use ScssPhp\ScssPhp\Version; 17 18 /** 19 * The scss cache manager. 20 * 21 * In short: 22 * 23 * allow to put in cache/get from cache a generic result from a known operation on a generic dataset, 24 * taking in account options that affects the result 25 * 26 * The cache manager is agnostic about data format and only the operation is expected to be described by string 27 */ 28 29 /** 30 * SCSS cache 31 * 32 * @author Cedric Morin <cedric@yterium.com> 33 */ 34 class Cache 35 { 36 const CACHE_VERSION = 1; 37 38 // directory used for storing data 39 public static $cacheDir = false; 40 41 // prefix for the storing data 42 public static $prefix = 'scssphp_'; 43 44 // force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit 45 public static $forceRefresh = false; 46 47 // specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up 48 public static $gcLifetime = 604800; 49 50 // array of already refreshed cache if $forceRefresh==='once' 51 protected static $refreshed = []; 52 53 /** 54 * Constructor 55 * 56 * @param array $options 57 */ 58 public function __construct($options) 59 { 60 // check $cacheDir 61 if (isset($options['cacheDir'])) { 62 self::$cacheDir = $options['cacheDir']; 63 } 64 65 if (empty(self::$cacheDir)) { 66 throw new Exception('cacheDir not set'); 67 } 68 69 if (isset($options['prefix'])) { 70 self::$prefix = $options['prefix']; 71 } 72 73 if (empty(self::$prefix)) { 74 throw new Exception('prefix not set'); 75 } 76 77 if (isset($options['forceRefresh'])) { 78 self::$forceRefresh = $options['forceRefresh']; 79 } 80 81 self::checkCacheDir(); 82 } 83 84 /** 85 * Get the cached result of $operation on $what, 86 * which is known as dependant from the content of $options 87 * 88 * @param string $operation parse, compile... 89 * @param mixed $what content key (e.g., filename to be treated) 90 * @param array $options any option that affect the operation result on the content 91 * @param integer $lastModified last modified timestamp 92 * 93 * @return mixed 94 * 95 * @throws \Exception 96 */ 97 public function getCache($operation, $what, $options = [], $lastModified = null) 98 { 99 $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); 100 101 if ( 102 ((self::$forceRefresh === false) || (self::$forceRefresh === 'once' && 103 isset(self::$refreshed[$fileCache]))) && file_exists($fileCache) 104 ) { 105 $cacheTime = filemtime($fileCache); 106 107 if ( 108 (\is_null($lastModified) || $cacheTime > $lastModified) && 109 $cacheTime + self::$gcLifetime > time() 110 ) { 111 $c = file_get_contents($fileCache); 112 $c = unserialize($c); 113 114 if (\is_array($c) && isset($c['value'])) { 115 return $c['value']; 116 } 117 } 118 } 119 120 return null; 121 } 122 123 /** 124 * Put in cache the result of $operation on $what, 125 * which is known as dependant from the content of $options 126 * 127 * @param string $operation 128 * @param mixed $what 129 * @param mixed $value 130 * @param array $options 131 */ 132 public function setCache($operation, $what, $value, $options = []) 133 { 134 $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); 135 136 $c = ['value' => $value]; 137 $c = serialize($c); 138 139 file_put_contents($fileCache, $c); 140 141 if (self::$forceRefresh === 'once') { 142 self::$refreshed[$fileCache] = true; 143 } 144 } 145 146 /** 147 * Get the cache name for the caching of $operation on $what, 148 * which is known as dependant from the content of $options 149 * 150 * @param string $operation 151 * @param mixed $what 152 * @param array $options 153 * 154 * @return string 155 */ 156 private static function cacheName($operation, $what, $options = []) 157 { 158 $t = [ 159 'version' => self::CACHE_VERSION, 160 'scssphpVersion' => Version::VERSION, 161 'operation' => $operation, 162 'what' => $what, 163 'options' => $options 164 ]; 165 166 $t = self::$prefix 167 . sha1(json_encode($t)) 168 . ".$operation" 169 . ".scsscache"; 170 171 return $t; 172 } 173 174 /** 175 * Check that the cache dir exists and is writeable 176 * 177 * @throws \Exception 178 */ 179 public static function checkCacheDir() 180 { 181 self::$cacheDir = str_replace('\\', '/', self::$cacheDir); 182 self::$cacheDir = rtrim(self::$cacheDir, '/') . '/'; 183 184 if (! is_dir(self::$cacheDir)) { 185 throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir); 186 } 187 188 if (! is_writable(self::$cacheDir)) { 189 throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir); 190 } 191 } 192 193 /** 194 * Delete unused cached files 195 */ 196 public static function cleanCache() 197 { 198 static $clean = false; 199 200 if ($clean || empty(self::$cacheDir)) { 201 return; 202 } 203 204 $clean = true; 205 206 // only remove files with extensions created by SCSSPHP Cache 207 // css files removed based on the list files 208 $removeTypes = ['scsscache' => 1]; 209 210 $files = scandir(self::$cacheDir); 211 212 if (! $files) { 213 return; 214 } 215 216 $checkTime = time() - self::$gcLifetime; 217 218 foreach ($files as $file) { 219 // don't delete if the file wasn't created with SCSSPHP Cache 220 if (strpos($file, self::$prefix) !== 0) { 221 continue; 222 } 223 224 $parts = explode('.', $file); 225 $type = array_pop($parts); 226 227 if (! isset($removeTypes[$type])) { 228 continue; 229 } 230 231 $fullPath = self::$cacheDir . $file; 232 $mtime = filemtime($fullPath); 233 234 // don't delete if it's a relatively new file 235 if ($mtime > $checkTime) { 236 continue; 237 } 238 239 unlink($fullPath); 240 } 241 } 242 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body