aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/scssphp/scssphp/src/Cache.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/scssphp/scssphp/src/Cache.php')
-rw-r--r--vendor/scssphp/scssphp/src/Cache.php272
1 files changed, 272 insertions, 0 deletions
diff --git a/vendor/scssphp/scssphp/src/Cache.php b/vendor/scssphp/scssphp/src/Cache.php
new file mode 100644
index 000000000..9731c60a7
--- /dev/null
+++ b/vendor/scssphp/scssphp/src/Cache.php
@@ -0,0 +1,272 @@
+<?php
+
+/**
+ * SCSSPHP
+ *
+ * @copyright 2012-2020 Leaf Corcoran
+ *
+ * @license http://opensource.org/licenses/MIT MIT
+ *
+ * @link http://scssphp.github.io/scssphp
+ */
+
+namespace ScssPhp\ScssPhp;
+
+use Exception;
+use ScssPhp\ScssPhp\Version;
+
+/**
+ * The scss cache manager.
+ *
+ * In short:
+ *
+ * allow to put in cache/get from cache a generic result from a known operation on a generic dataset,
+ * taking in account options that affects the result
+ *
+ * The cache manager is agnostic about data format and only the operation is expected to be described by string
+ */
+
+/**
+ * SCSS cache
+ *
+ * @author Cedric Morin <cedric@yterium.com>
+ *
+ * @internal
+ */
+class Cache
+{
+ const CACHE_VERSION = 1;
+
+ /**
+ * directory used for storing data
+ *
+ * @var string|false
+ */
+ public static $cacheDir = false;
+
+ /**
+ * prefix for the storing data
+ *
+ * @var string
+ */
+ public static $prefix = 'scssphp_';
+
+ /**
+ * force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
+ *
+ * @var bool|string
+ */
+ public static $forceRefresh = false;
+
+ /**
+ * specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
+ *
+ * @var int
+ */
+ public static $gcLifetime = 604800;
+
+ /**
+ * array of already refreshed cache if $forceRefresh==='once'
+ *
+ * @var array<string, bool>
+ */
+ protected static $refreshed = [];
+
+ /**
+ * Constructor
+ *
+ * @param array $options
+ *
+ * @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options
+ */
+ public function __construct($options)
+ {
+ // check $cacheDir
+ if (isset($options['cacheDir'])) {
+ self::$cacheDir = $options['cacheDir'];
+ }
+
+ if (empty(self::$cacheDir)) {
+ throw new Exception('cacheDir not set');
+ }
+
+ if (isset($options['prefix'])) {
+ self::$prefix = $options['prefix'];
+ }
+
+ if (empty(self::$prefix)) {
+ throw new Exception('prefix not set');
+ }
+
+ if (isset($options['forceRefresh'])) {
+ self::$forceRefresh = $options['forceRefresh'];
+ }
+
+ self::checkCacheDir();
+ }
+
+ /**
+ * Get the cached result of $operation on $what,
+ * which is known as dependant from the content of $options
+ *
+ * @param string $operation parse, compile...
+ * @param mixed $what content key (e.g., filename to be treated)
+ * @param array $options any option that affect the operation result on the content
+ * @param int|null $lastModified last modified timestamp
+ *
+ * @return mixed
+ *
+ * @throws \Exception
+ */
+ public function getCache($operation, $what, $options = [], $lastModified = null)
+ {
+ $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
+
+ if (
+ ((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
+ isset(self::$refreshed[$fileCache]))) && file_exists($fileCache)
+ ) {
+ $cacheTime = filemtime($fileCache);
+
+ if (
+ (\is_null($lastModified) || $cacheTime > $lastModified) &&
+ $cacheTime + self::$gcLifetime > time()
+ ) {
+ $c = file_get_contents($fileCache);
+ $c = unserialize($c);
+
+ if (\is_array($c) && isset($c['value'])) {
+ return $c['value'];
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Put in cache the result of $operation on $what,
+ * which is known as dependant from the content of $options
+ *
+ * @param string $operation
+ * @param mixed $what
+ * @param mixed $value
+ * @param array $options
+ *
+ * @return void
+ */
+ public function setCache($operation, $what, $value, $options = [])
+ {
+ $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
+
+ $c = ['value' => $value];
+ $c = serialize($c);
+
+ file_put_contents($fileCache, $c);
+
+ if (self::$forceRefresh === 'once') {
+ self::$refreshed[$fileCache] = true;
+ }
+ }
+
+ /**
+ * Get the cache name for the caching of $operation on $what,
+ * which is known as dependant from the content of $options
+ *
+ * @param string $operation
+ * @param mixed $what
+ * @param array $options
+ *
+ * @return string
+ */
+ private static function cacheName($operation, $what, $options = [])
+ {
+ $t = [
+ 'version' => self::CACHE_VERSION,
+ 'scssphpVersion' => Version::VERSION,
+ 'operation' => $operation,
+ 'what' => $what,
+ 'options' => $options
+ ];
+
+ $t = self::$prefix
+ . sha1(json_encode($t))
+ . ".$operation"
+ . ".scsscache";
+
+ return $t;
+ }
+
+ /**
+ * Check that the cache dir exists and is writeable
+ *
+ * @return void
+ *
+ * @throws \Exception
+ */
+ public static function checkCacheDir()
+ {
+ self::$cacheDir = str_replace('\\', '/', self::$cacheDir);
+ self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
+
+ if (! is_dir(self::$cacheDir)) {
+ throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir);
+ }
+
+ if (! is_writable(self::$cacheDir)) {
+ throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir);
+ }
+ }
+
+ /**
+ * Delete unused cached files
+ *
+ * @return void
+ */
+ public static function cleanCache()
+ {
+ static $clean = false;
+
+ if ($clean || empty(self::$cacheDir)) {
+ return;
+ }
+
+ $clean = true;
+
+ // only remove files with extensions created by SCSSPHP Cache
+ // css files removed based on the list files
+ $removeTypes = ['scsscache' => 1];
+
+ $files = scandir(self::$cacheDir);
+
+ if (! $files) {
+ return;
+ }
+
+ $checkTime = time() - self::$gcLifetime;
+
+ foreach ($files as $file) {
+ // don't delete if the file wasn't created with SCSSPHP Cache
+ if (strpos($file, self::$prefix) !== 0) {
+ continue;
+ }
+
+ $parts = explode('.', $file);
+ $type = array_pop($parts);
+
+ if (! isset($removeTypes[$type])) {
+ continue;
+ }
+
+ $fullPath = self::$cacheDir . $file;
+ $mtime = filemtime($fullPath);
+
+ // don't delete if it's a relatively new file
+ if ($mtime > $checkTime) {
+ continue;
+ }
+
+ unlink($fullPath);
+ }
+ }
+}