Esempio n. 1
0
 /**
  * Execute lessphp on a .less file or a lessphp cache structure
  * 
  * The lessphp cache structure contains information about a specific
  * less file having been parsed. It can be used as a hint for future
  * calls to determine whether or not a rebuild is required.
  * 
  * The cache structure contains two important keys that may be used
  * externally:
  * 
  * compiled: The final compiled CSS
  * updated: The time (in seconds) the CSS was last compiled
  * 
  * The cache structure is a plain-ol' PHP associative array and can
  * be serialized and unserialized without a hitch.
  * 
  * @param mixed $in Input
  * @param bool $force Force rebuild?
  * @return array lessphp cache structure
  */
 public static function cexecute($in, $force = false)
 {
     // assume no root
     $root = null;
     if (is_string($in)) {
         $root = $in;
     } elseif (is_array($in) and isset($in['root'])) {
         if ($force or !isset($in['files'])) {
             // If we are forcing a recompile or if for some reason the
             // structure does not contain any file information we should
             // specify the root to trigger a rebuild.
             $root = $in['root'];
         } elseif (isset($in['files']) and is_array($in['files'])) {
             foreach ($in['files'] as $fname => $ftime) {
                 if (!file_exists($fname) or filemtime($fname) > $ftime) {
                     // One of the files we knew about previously has changed
                     // so we should look at our incoming root again.
                     $root = $in['root'];
                     break;
                 }
             }
         }
     } else {
         // TODO: Throw an exception? We got neither a string nor something
         // that looks like a compatible lessphp cache structure.
         return null;
     }
     if ($root !== null) {
         // If we have a root value which means we should rebuild.
         $less = new lessc($root);
         $out = array();
         $out['root'] = $root;
         $out['compiled'] = $less->parse();
         $out['files'] = $less->allParsedFiles();
         $out['updated'] = time();
         return $out;
     } else {
         // No changes, pass back the structure
         // we were given initially.
         return $in;
     }
 }
Esempio n. 2
0
 /**
  * Send a group of files to client (ie : JS or CSS files)
  * Provide coherent user caching infos (1 month) for files and allow gzip when possible
  *
  * @param array $files : array of files path to send to client (FS relative)
  * @param string $contentType : the content type to send to client (default : text/html)
  * @return void
  * @access public
  * @static
  */
 static function sendFiles($files, $contentType = 'text/html')
 {
     //check for the closest last modification date
     $lastdate = '';
     //check for included files in less files
     $includes = array();
     if ($contentType == 'text/css') {
         foreach ($files as $key => $file) {
             if (pathinfo($file, PATHINFO_EXTENSION) == 'less') {
                 $lessCache = new CMS_cache(md5($file), 'lessphp', 2592000, false);
                 if ($lessCache->exist()) {
                     $includes = array_merge($includes, $lessCache->load());
                 }
             }
         }
     }
     if ($includes) {
         foreach ($includes as $key => $file) {
             if (file_exists($file) && is_file($file)) {
                 $lastdate = filemtime($file) > $lastdate ? filemtime($file) : $lastdate;
             }
         }
     }
     foreach ($files as $key => $file) {
         if (file_exists($file) && is_file($file)) {
             $lastdate = filemtime($file) > $lastdate ? filemtime($file) : $lastdate;
         } else {
             CMS_grandFather::raiseError('Can\'t find file : ' . $file . ', skip it.');
             unset($files[$key]);
         }
     }
     if (file_exists($_SERVER['SCRIPT_FILENAME'])) {
         $lastdate = filemtime($_SERVER['SCRIPT_FILENAME']) > $lastdate ? filemtime($_SERVER['SCRIPT_FILENAME']) : $lastdate;
     }
     //check If-Modified-Since header if exists then return a 304 if needed
     if (isset($_SERVER['IF-MODIFIED-SINCE'])) {
         $ifModifiedSince = strtotime($_SERVER['IF-MODIFIED-SINCE']);
     } elseif (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
         $ifModifiedSince = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
     }
     if (isset($ifModifiedSince) && $lastdate <= $ifModifiedSince) {
         header('HTTP/1.1 304 Not Modified');
         header('Content-Type: ' . $contentType);
         header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastdate) . ' GMT');
         header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT');
         //30 days
         header("Cache-Control: must-revalidate");
         header("Pragma: public");
         exit;
     }
     $compress = 'ob_gzhandler' != ini_get('output_handler') && extension_loaded('zlib') && !ini_get('zlib.output_compression') && strpos(strtolower(@$_SERVER['HTTP_ACCEPT_ENCODING']), 'gzip') !== false;
     //create cache id from files, compression status and last time files access
     $id = md5(implode(',', $files) . '-' . $compress . '-' . $lastdate);
     //create cache object
     $cache = new CMS_cache($id, $contentType, 2592000, false);
     $datas = '';
     if (!$cache->exist() || !($datas = $cache->load())) {
         // datas cache missing so create it
         foreach ($files as $file) {
             $fileData = file_get_contents($file);
             //strip BOM from file if exists
             if (substr($fileData, 0, 3) === '') {
                 $fileData = substr($fileData, 3);
             }
             //append file origin comment
             if ($contentType == 'text/javascript') {
                 $fileData = '//<<' . "\n" . '//JS file: ' . str_replace(PATH_REALROOT_FS, '', $file) . '' . "\n" . '//!>>' . "\n" . $fileData;
             }
             //append file origin comment
             if ($contentType == 'text/css') {
                 //compile less files if needed
                 if (pathinfo($file, PATHINFO_EXTENSION) == 'less') {
                     $less = new lessc($file);
                     $fileData = $less->parse();
                     $lessIncludes = $less->allParsedFiles();
                     if (sizeof($lessIncludes) > 1) {
                         $lessCache = new CMS_cache(md5($file), 'lessphp', 2592000, false);
                         $lessCache->save(array_keys($lessIncludes), array('type' => 'lessphp'));
                     }
                 }
                 $fileData = '/*<<*/' . "\n" . '/* CSS file: ' . str_replace(PATH_REALROOT_FS, '', $file) . ' */' . "\n" . '/*!>>*/' . "\n" . $fileData;
             }
             $datas .= $fileData . "\n";
         }
         //minimize JS files if needed
         if (!SYSTEM_DEBUG && $contentType == 'text/javascript') {
             $datas = JSMin::minify($datas);
         }
         //minimize CSS files if needed
         if (!SYSTEM_DEBUG && $contentType == 'text/css') {
             $datas = cssmin::minify($datas);
         }
         //compres data if needed
         if ($compress) {
             $datas = gzencode($datas, 3);
         }
         if ($cache) {
             $cache->save($datas, array('type' => $contentType));
         }
     }
     //send headers
     header('Content-Type: ' . $contentType);
     header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastdate) . ' GMT');
     header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2592000) . ' GMT');
     //30 days
     header("Cache-Control: must-revalidate");
     header("Pragma: public");
     //send gzip header if needed
     if ($compress) {
         header('Vary: Accept-Encoding');
         // Handle proxies
         header("Content-Encoding: gzip");
     }
     //send content
     echo $datas;
     exit;
 }