1
0

Cache.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. require_once( dirname(__FILE__).'/Version.php');
  3. /**
  4. * Utility for handling the generation and caching of css files
  5. *
  6. * @package Less
  7. * @subpackage cache
  8. *
  9. */
  10. class Less_Cache{
  11. public static $cache_dir = false; // directory less.php can use for storing data
  12. /**
  13. * Save and reuse the results of compiled less files.
  14. * The first call to Get() will generate css and save it.
  15. * Subsequent calls to Get() with the same arguments will return the same css filename
  16. *
  17. * @param array $less_files Array of .less files to compile
  18. * @param array $parser_options Array of compiler options
  19. * @param array $modify_vars Array of variables
  20. * @return string Name of the css file
  21. */
  22. public static function Get( $less_files, $parser_options = array(), $modify_vars = array() ){
  23. //check $cache_dir
  24. if( isset($parser_options['cache_dir']) ){
  25. Less_Cache::$cache_dir = $parser_options['cache_dir'];
  26. }
  27. if( empty(Less_Cache::$cache_dir) ){
  28. throw new Exception('cache_dir not set');
  29. }
  30. self::CheckCacheDir();
  31. $less_files = (array)$less_files;
  32. //create a file for variables
  33. if( !empty($modify_vars) ){
  34. $lessvars = Less_Parser::serializeVars($modify_vars);
  35. $vars_file = Less_Cache::$cache_dir.'lessphpvars_' . sha1($lessvars) . '.less';
  36. if( !file_exists($vars_file) ){
  37. file_put_contents($vars_file, $lessvars);
  38. }
  39. $less_files += array($vars_file => '/');
  40. }
  41. // generate name for compiled css file
  42. $hash = md5(json_encode($less_files));
  43. $list_file = Less_Cache::$cache_dir.'lessphp_'.$hash.'.list';
  44. // check cached content
  45. if( !isset($parser_options['use_cache']) || $parser_options['use_cache'] === true ){
  46. if( file_exists($list_file) ){
  47. $list = explode("\n",file_get_contents($list_file));
  48. //pop the cached name that should match $compiled_name
  49. $cached_name = array_pop($list);
  50. if( !preg_match('/^lessphp_[a-f0-9]+\.css$/',$cached_name) ){
  51. $list[] = $cached_name;
  52. $cached_name = false;
  53. }
  54. $compiled_name = self::CompiledName($list);
  55. // if $cached_name != $compiled_name, we know we need to recompile
  56. if( !$cached_name || $cached_name === $compiled_name ){
  57. $output_file = self::OutputFile($compiled_name, $parser_options );
  58. if( $output_file && file_exists($output_file) ){
  59. @touch($list_file);
  60. @touch($output_file);
  61. return basename($output_file); // for backwards compatibility, we just return the name of the file
  62. }
  63. }
  64. }
  65. }
  66. $compiled = self::Cache( $less_files, $parser_options );
  67. if( !$compiled ){
  68. return false;
  69. }
  70. $compiled_name = self::CompiledName( $less_files );
  71. $output_file = self::OutputFile($compiled_name, $parser_options );
  72. //save the file list
  73. $list = $less_files;
  74. $list[] = $compiled_name;
  75. $cache = implode("\n",$list);
  76. file_put_contents( $list_file, $cache );
  77. //save the css
  78. file_put_contents( $output_file, $compiled );
  79. //clean up
  80. self::CleanCache();
  81. return basename($output_file);
  82. }
  83. /**
  84. * Force the compiler to regenerate the cached css file
  85. *
  86. * @param array $less_files Array of .less files to compile
  87. * @param array $parser_options Array of compiler options
  88. * @param array $modify_vars Array of variables
  89. * @return string Name of the css file
  90. */
  91. public static function Regen( $less_files, $parser_options = array(), $modify_vars = array() ){
  92. $parser_options['use_cache'] = false;
  93. return self::Get( $less_files, $parser_options, $modify_vars );
  94. }
  95. public static function Cache( &$less_files, $parser_options = array() ){
  96. // get less.php if it exists
  97. $file = dirname(__FILE__) . '/Less.php';
  98. if( file_exists($file) && !class_exists('Less_Parser') ){
  99. require_once($file);
  100. }
  101. $parser_options['cache_dir'] = Less_Cache::$cache_dir;
  102. $parser = new Less_Parser($parser_options);
  103. // combine files
  104. foreach($less_files as $file_path => $uri_or_less ){
  105. //treat as less markup if there are newline characters
  106. if( strpos($uri_or_less,"\n") !== false ){
  107. $parser->Parse( $uri_or_less );
  108. continue;
  109. }
  110. $parser->ParseFile( $file_path, $uri_or_less );
  111. }
  112. $compiled = $parser->getCss();
  113. $less_files = $parser->allParsedFiles();
  114. return $compiled;
  115. }
  116. private static function OutputFile( $compiled_name, $parser_options ){
  117. //custom output file
  118. if( !empty($parser_options['output']) ){
  119. //relative to cache directory?
  120. if( preg_match('#[\\\\/]#',$parser_options['output']) ){
  121. return $parser_options['output'];
  122. }
  123. return Less_Cache::$cache_dir.$parser_options['output'];
  124. }
  125. return Less_Cache::$cache_dir.$compiled_name;
  126. }
  127. private static function CompiledName( $files ){
  128. //save the file list
  129. $temp = array(Less_Version::cache_version);
  130. foreach($files as $file){
  131. $temp[] = filemtime($file)."\t".filesize($file)."\t".$file;
  132. }
  133. return 'lessphp_'.sha1(json_encode($temp)).'.css';
  134. }
  135. public static function SetCacheDir( $dir ){
  136. Less_Cache::$cache_dir = $dir;
  137. }
  138. public static function CheckCacheDir(){
  139. Less_Cache::$cache_dir = str_replace('\\','/',Less_Cache::$cache_dir);
  140. Less_Cache::$cache_dir = rtrim(Less_Cache::$cache_dir,'/').'/';
  141. if( !file_exists(Less_Cache::$cache_dir) ){
  142. if( !mkdir(Less_Cache::$cache_dir) ){
  143. throw new Less_Exception_Parser('Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir);
  144. }
  145. }elseif( !is_dir(Less_Cache::$cache_dir) ){
  146. throw new Less_Exception_Parser('Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir);
  147. }elseif( !is_writable(Less_Cache::$cache_dir) ){
  148. throw new Less_Exception_Parser('Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir);
  149. }
  150. }
  151. public static function CleanCache(){
  152. static $clean = false;
  153. if( $clean ){
  154. return;
  155. }
  156. $files = scandir(Less_Cache::$cache_dir);
  157. if( $files ){
  158. $check_time = time() - 604800;
  159. foreach($files as $file){
  160. if( strpos($file,'lessphp_') !== 0 ){
  161. continue;
  162. }
  163. $full_path = Less_Cache::$cache_dir.'/'.$file;
  164. if( filemtime($full_path) > $check_time ){
  165. continue;
  166. }
  167. unlink($full_path);
  168. }
  169. }
  170. $clean = true;
  171. }
  172. }