'/']; } // generate name for compiled css file $hash = md5(json_encode($less_files)); $list_file = Less_Cache::$cache_dir.'lessphp_'.$hash.'.list'; // check cached content if (!isset($parser_options['use_cache']) || $parser_options['use_cache'] === TRUE) { if (file_exists($list_file)) { self::ListFiles($list_file, $list, $cached_name); $compiled_name = self::CompiledName($list); // if $cached_name != $compiled_name, we know we need to recompile if (!$cached_name || $cached_name === $compiled_name) { $output_file = self::OutputFile($compiled_name, $parser_options); if ($output_file && file_exists($output_file)) { @touch($list_file); return basename($output_file); // for backwards compatibility, we just return the name of the file } } } } $compiled = self::Cache($less_files, $parser_options); if (!$compiled) { return FALSE; } $compiled_name = self::CompiledName($less_files); $output_file = self::OutputFile($compiled_name, $parser_options); //save the file list $list = $less_files; $list[] = $compiled_name; $cache = implode("\n", $list); file_put_contents($list_file, $cache); //save the css file_put_contents($output_file, $compiled); //clean up self::CleanCache(); return basename($output_file); } public static function CheckCacheDir() { Less_Cache::$cache_dir = str_replace('\\', '/', Less_Cache::$cache_dir); Less_Cache::$cache_dir = rtrim(Less_Cache::$cache_dir, '/').'/'; if (!file_exists(Less_Cache::$cache_dir)) { if (!mkdir(Less_Cache::$cache_dir)) { throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir); } } else if (!is_dir(Less_Cache::$cache_dir)) { throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir); } else if (!is_writable(Less_Cache::$cache_dir)) { throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir); } } /** * Get the list of less files and generated css file from a list file * */ static function ListFiles($list_file, &$list, &$css_file_name) { $list = explode("\n", file_get_contents($list_file)); //pop the cached name that should match $compiled_name $css_file_name = array_pop($list); if (!preg_match('/^lessphp_[a-f0-9]+\.css$/', $css_file_name)) { $list[] = $css_file_name; $css_file_name = FALSE; } } private static function CompiledName($files) { //save the file list $temp = [Less_Version::cache_version]; foreach ($files as $file) { $temp[] = filemtime($file)."\t".filesize($file)."\t".$file; } return 'lessphp_'.sha1(json_encode($temp)).'.css'; } private static function OutputFile($compiled_name, $parser_options) { //custom output file if (!empty($parser_options['output'])) { //relative to cache directory? if (preg_match('#[\\\\/]#', $parser_options['output'])) { return $parser_options['output']; } return Less_Cache::$cache_dir.$parser_options['output']; } return Less_Cache::$cache_dir.$compiled_name; } public static function Cache(&$less_files, $parser_options = []) { // get less.php if it exists $file = __DIR__.'/Less.php'; if (file_exists($file) && !class_exists('Less_Parser')) { require_once($file); } $parser_options['cache_dir'] = Less_Cache::$cache_dir; $parser = new Less_Parser($parser_options); // combine files foreach ($less_files as $file_path => $uri_or_less) { //treat as less markup if there are newline characters if (strpos($uri_or_less, "\n") !== FALSE) { $parser->Parse($uri_or_less); continue; } $parser->ParseFile($file_path, $uri_or_less); } $compiled = $parser->getCss(); $less_files = $parser->allParsedFiles(); return $compiled; } /** * Delete unused less.php files * */ public static function CleanCache() { static $clean = FALSE; if ($clean) { return; } $files = scandir(Less_Cache::$cache_dir); if ($files) { $check_time = time() - self::$gc_lifetime; foreach ($files as $file) { // don't delete if the file wasn't created with less.php if (strpos($file, 'lessphp_') !== 0) { continue; } $full_path = Less_Cache::$cache_dir.'/'.$file; // make sure the file still exists // css files may have already been deleted if (!file_exists($full_path)) { continue; } $mtime = filemtime($full_path); // don't delete if it's a relatively new file if ($mtime > $check_time) { continue; } $parts = explode('.', $file); $type = array_pop($parts); // delete css files based on the list files if ($type === 'css') { continue; } // delete the list file and associated css file if ($type === 'list') { self::ListFiles($full_path, $list, $css_file_name); if ($css_file_name) { $css_file = Less_Cache::$cache_dir.'/'.$css_file_name; if (file_exists($css_file)) { unlink($css_file); } } } unlink($full_path); } } $clean = TRUE; } public static function SetCacheDir($dir) { Less_Cache::$cache_dir = $dir; } }