'/' ); } // generate name for compiled css file $hash = md5( json_encode( $less_files ) ); $list_file = Less_Cache::$cache_dir . Less_Cache::$prefix . $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, $hash ); // if $cached_name is the same as the $compiled name, don't regenerate 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, $hash ); $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 ); } /** * Force the compiler to regenerate the cached css file * * @param array $less_files Array of .less files to compile * @param array $parser_options Array of compiler options * @param array $modify_vars Array of variables * @return string Name of the css file */ public static function Regen( $less_files, $parser_options = array(), $modify_vars = array() ) { $parser_options['use_cache'] = false; return self::Get( $less_files, $parser_options, $modify_vars ); } public static function Cache( &$less_files, $parser_options = array() ) { // get less.php if it exists $file = dirname( __FILE__ ) . '/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; } 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; } private static function CompiledName( $files, $extrahash ) { // save the file list $temp = array( Less_Version::cache_version ); foreach ( $files as $file ) { $temp[] = filemtime( $file )."\t".filesize( $file )."\t".$file; } return Less_Cache::$prefix.sha1( json_encode( $temp ).$extrahash ).'.css'; } public static function SetCacheDir( $dir ) { Less_Cache::$cache_dir = $dir; self::CheckCacheDir(); } 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 ); } } elseif ( !is_dir( Less_Cache::$cache_dir ) ) { throw new Less_Exception_Parser( 'Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir ); } elseif ( !is_writable( Less_Cache::$cache_dir ) ) { throw new Less_Exception_Parser( 'Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir ); } } /** * Delete unused less.php files * */ public static function CleanCache() { static $clean = false; if ( $clean || empty( Less_Cache::$cache_dir ) ) { return; } $clean = true; // only remove files with extensions created by less.php // css files removed based on the list files $remove_types = array( 'lesscache' => 1,'list' => 1,'less' => 1,'map' => 1 ); $files = scandir( Less_Cache::$cache_dir ); if ( !$files ) { return; } $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, Less_Cache::$prefix ) !== 0 ) { continue; } $parts = explode( '.', $file ); $type = array_pop( $parts ); if ( !isset( $remove_types[$type] ) ) { continue; } $full_path = Less_Cache::$cache_dir . $file; $mtime = filemtime( $full_path ); // don't delete if it's a relatively new file if ( $mtime > $check_time ) { 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 ); } } /** * 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( '/^' . Less_Cache::$prefix . '[a-f0-9]+\.css$/', $css_file_name ) ) { $list[] = $css_file_name; $css_file_name = false; } } }