*/ class Cache { const CACHE_VERSION = 1; // directory used for storing data public static $cacheDir = false; // prefix for the storing data 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 public static $forceRefresh = false; // specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up public static $gcLifetime = 604800; // array of already refreshed cache if $forceRefresh==='once' protected static $refreshed = []; /** * Constructor * * @param array $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 integer $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() ) { // filesystem global $wp_filesystem; // Initialize the WordPress filesystem, no more using file_put_contents function if ( empty( $wp_filesystem ) ) { require_once ABSPATH . '/wp-admin/includes/file.php'; WP_Filesystem(); } $c = $wp_filesystem->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 */ public function setCache( $operation, $what, $value, $options = [] ) { // filesystem global $wp_filesystem; // Initialize the WordPress filesystem, no more using file_put_contents function if ( empty( $wp_filesystem ) ) { require_once ABSPATH . '/wp-admin/includes/file.php'; WP_Filesystem(); } $fileCache = self::$cacheDir . self::cacheName( $operation, $what, $options ); $c = [ 'value' => $value ]; $c = serialize( $c ); $wp_filesystem->put_contents( $fileCache, $c, FS_CHMOD_FILE ); 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, '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 * * @throws \Exception */ public static function checkCacheDir() { self::$cacheDir = str_replace( '\\', '/', self::$cacheDir ); self::$cacheDir = rtrim( self::$cacheDir, '/' ) . '/'; if ( ! is_dir( self::$cacheDir ) ) { if ( ! wp_mkdir_p( self::$cacheDir ) ) { throw new Exception( 'Cache directory couldn\'t be created: ' . self::$cacheDir ); } } if ( ! is_writable( self::$cacheDir ) ) { throw new Exception( 'Cache directory isn\'t writable: ' . self::$cacheDir ); } } /** * Delete unused cached files */ 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 ); } } }