Source for file jMinifier.class.php

Documentation is available at jMinifier.class.php

  1. <?php
  2. /**
  3.  * @package    jelix
  4.  * @subpackage core
  5.  * @author     Brice Tence
  6.  * @copyright  2010 Brice Tence
  7.  *    Idea of this class was picked from the Minify project ( Minify 2.1.3, http://code.google.com/p/minify )
  8.  * @link       http://www.jelix.org
  9.  * @licence    GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  10.  */
  11.  
  12. define('MINIFY_MIN_DIR'LIB_PATH.'minify/min/');
  13.  
  14. // setup include path
  15. set_include_path(MINIFY_MIN_DIR.'/lib' PATH_SEPARATOR get_include_path());
  16.  
  17. require_once "Minify/Controller/MinApp.php";
  18. require_once 'Minify/Source.php';
  19. require_once 'Minify.php';
  20.  
  21. /**
  22.  * This object is responsible to concatenate and minify CSS or JS files.
  23.  * There is a cache system so that previously minified files are served directly.
  24.  * Otherwise, files ares concatenated, minified and stored in cache.
  25.  * We also check if cache is up to date and needs to be refreshed.
  26.  * @package  jelix
  27.  * @subpackage core
  28.  * @author     Brice Tence
  29.  * @copyright  2010 Brice Tence
  30.  * @licence    GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html .
  31.  */
  32. class jMinifier {
  33.  
  34.     /**
  35.      * @var Minify_Controller active controller for current request
  36.      */
  37.     protected static $_controller null;
  38.  
  39.     /**
  40.      * @var array options for current request
  41.      */
  42.     protected static $_options null;
  43.  
  44.     /**
  45.      * Cache file locking. Set to false of filesystem is NFS. On at least one
  46.      * NFS system flock-ing attempts stalled PHP for 30 seconds!
  47.      */
  48.     protected static $min_cacheFileLocking true;
  49.  
  50.     /**
  51.      * This is a static class, so private constructor
  52.      */
  53.     private function __construct(){
  54.     }
  55.  
  56.     /**
  57.      * @param    array   $fileList    Array of file URLs to include
  58.      * @return array of file path to minify's www cached file. A further improvment could be to output several files (size limit for iPhone). That's why this is an array.
  59.      */
  60.     public static function minify$fileList$fileType ){
  61.         global $gJConfig,$gJCoord;
  62.  
  63.         $cachePathCSS 'cache/minify/css/';
  64.         jFile::createDir(JELIX_APP_WWW_PATH.$cachePathCSS);
  65.         $cachePathJS 'cache/minify/js/';
  66.         jFile::createDir(JELIX_APP_WWW_PATH.$cachePathJS);
  67.  
  68.         $minifiedFiles array();
  69.  
  70.         $minAppMaxFiles count($fileList);
  71.  
  72.         //compute a hash of source files to manage cache
  73.         $sourcesHash md5(implode(';'$fileList));
  74.  
  75.         $options array();
  76.         $options['MinApp']['maxFiles'$minAppMaxFiles;
  77.         $cachePath '';
  78.         $cacheExt '';
  79.         switch ($fileType{
  80.         case 'js':
  81.             $options['contentType'Minify::TYPE_JS;
  82.             $cachePath $cachePathJS;
  83.             $cacheExt 'js';
  84.             break;
  85.         case 'css':
  86.             $options['contentType'Minify::TYPE_CSS;
  87.             $cachePath $cachePathCSS;
  88.             $cacheExt 'css';
  89.             break;
  90.         default:
  91.             return;
  92.         }
  93.  
  94.         $cacheFilepath $cachePath $sourcesHash '.' $cacheExt;
  95.  
  96.  
  97.         $cacheFilepathFilemtime null;
  98.         ifis_fileJELIX_APP_WWW_PATH.$cacheFilepath ) ) {
  99.             $cacheFilepathFilemtime filemtimeJELIX_APP_WWW_PATH.$cacheFilepath );
  100.         }
  101.  
  102.         //If we should not check filemtime of source files, let's see if we have the result in our cache
  103.         //We assume minifyCheckCacheFiletime is "on" if not set
  104.         ifisset($GLOBALS['gJConfig']->responseHtml&&
  105.             $GLOBALS['gJConfig']->responseHtml['minifyCheckCacheFiletime'=== false &&
  106.             $cacheFilepathFilemtime !== null {
  107.                 $minifiedFiles[$cacheFilepath;
  108.                 return $minifiedFiles;
  109.             }
  110.  
  111.  
  112.         $sources array();
  113.         //add source files
  114.         foreach ($fileList as $file{
  115.             $minifySource new Minify_Source(array(
  116.                 'filepath' => realpath($_SERVER['DOCUMENT_ROOT'$file)
  117.             ));
  118.             $sources[$minifySource;
  119.         }
  120.  
  121.         $controller new Minify_Controller_MinApp();
  122.         $controller->sources $sources;
  123.         $options $controller->analyzeSources($options);
  124.         $options $controller->mixInDefaultOptions($options);
  125.  
  126.         self::$_options $options;
  127.         self::$_controller $controller;
  128.  
  129.         if$cacheFilepathFilemtime === null ||
  130.             $cacheFilepathFilemtime self::$_options['lastModifiedTime'{
  131.                 //cache does not exist or is to old. Let's refresh it :
  132.  
  133.                 //rewrite URL in CSS files
  134.                 if (self::$_options['contentType'=== Minify::TYPE_CSS && self::$_options['rewriteCssUris']{
  135.                     reset($controller->sources);
  136.                     while (list($key$sourceeach(self::$_controller->sources)) {
  137.                         if ($source->filepath 
  138.                             && !isset($source->minifyOptions['currentDir'])
  139.                             && !isset($source->minifyOptions['prependRelativePath'])
  140.                         {
  141.                             $source->minifyOptions['currentDir'dirname($source->filepath);
  142.                         }
  143.                     }
  144.                 }
  145.  
  146.                 $cacheData self::combineAndMinify();
  147.  
  148.                 $flag self::$min_cacheFileLocking
  149.                     ? LOCK_EX
  150.                     : null;
  151.  
  152.                 if (is_file(JELIX_APP_WWW_PATH.$cacheFilepath)) {
  153.                     @unlink(JELIX_APP_WWW_PATH.$cacheFilepath);
  154.                 }
  155.  
  156.                 if (@file_put_contents(JELIX_APP_WWW_PATH.$cacheFilepath$cacheData$flag)) {
  157.                     return false;
  158.                 }
  159.             }
  160.  
  161.         $minifiedFiles[$cacheFilepath;
  162.  
  163.         return $minifiedFiles;
  164.     }
  165.  
  166.  
  167.  
  168.     /**
  169.      * Combines sources and minifies the result.
  170.      *
  171.      * @return string 
  172.      */
  173.     protected static function combineAndMinify()
  174.     {
  175.         $type self::$_options['contentType']// ease readability
  176.  
  177.         // when combining scripts, make sure all statements separated and
  178.         // trailing single line comment is terminated
  179.         $implodeSeparator ($type === Minify::TYPE_JS)
  180.             ? "\n;"
  181.             : '';
  182.         // allow the user to pass a particular array of options to each
  183.         // minifier (designated by type). source objects may still override
  184.         // these
  185.         $defaultOptions = isset(self::$_options['minifierOptions'][$type])
  186.             ? self::$_options['minifierOptions'][$type]
  187.             : array();
  188.         // if minifier not set, default is no minification. source objects
  189.         // may still override this
  190.         $defaultMinifier = isset(self::$_options['minifiers'][$type])
  191.             ? self::$_options['minifiers'][$type]
  192.             : false;
  193.  
  194.         if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
  195.             // all source have same options/minifier, better performance
  196.             // to combine, then minify once
  197.             foreach (self::$_controller->sources as $source{
  198.                 $pieces[$source->getContent();
  199.             }
  200.             $content implode($implodeSeparator$pieces);
  201.             if ($defaultMinifier{
  202.                 self::$_controller->loadMinifier($defaultMinifier);
  203.                 $content call_user_func($defaultMinifier$content$defaultOptions);    
  204.             }
  205.         else {
  206.             // minify each source with its own options and minifier, then combine
  207.             foreach (self::$_controller->sources as $source{
  208.                 // allow the source to override our minifier and options
  209.                 $minifier (null !== $source->minifier)
  210.                     ? $source->minifier
  211.                     : $defaultMinifier;
  212.                 $options (null !== $source->minifyOptions)
  213.                     ? array_merge($defaultOptions$source->minifyOptions)
  214.                     : $defaultOptions;
  215.                 if ($minifier{
  216.                     self::$_controller->loadMinifier($minifier);
  217.                     // get source content and minify it
  218.                     $pieces[call_user_func($minifier$source->getContent()$options);     
  219.                 else {
  220.                     $pieces[$source->getContent();     
  221.                 }
  222.             }
  223.             $content implode($implodeSeparator$pieces);
  224.         }
  225.  
  226.         if ($type === Minify::TYPE_CSS && false !== strpos($content'@import')) {
  227.             $content self::_handleCssImports($content);
  228.         }
  229.  
  230.         // do any post-processing (esp. for editing build URIs)
  231.         if (self::$_options['postprocessorRequire']{
  232.             require_once self::$_options['postprocessorRequire'];
  233.         }
  234.         if (self::$_options['postprocessor']{
  235.             $content call_user_func(self::$_options['postprocessor']$content$type);
  236.         }
  237.         return $content;
  238.     }
  239.  
  240.     /**
  241.      * Bubble CSS @imports to the top or prepend a warning if an
  242.      * @import is detected not at the top.
  243.      */
  244.     protected static function _handleCssImports($css)
  245.     {
  246.         if (self::$_options['bubbleCssImports']{
  247.             // bubble CSS imports
  248.             preg_match_all('/@import.*?;/'$css$imports);
  249.             $css implode(''$imports[0]preg_replace('/@import.*?;/'''$css);
  250.         else if ('' !== Minify::$importWarning{
  251.             // remove comments so we don't mistake { in a comment as a block
  252.             $noCommentCss preg_replace('@/\\*[\\s\\S]*?\\*/@'''$css);
  253.             $lastImportPos strrpos($noCommentCss'@import');
  254.             $firstBlockPos strpos($noCommentCss'{');
  255.             if (false !== $lastImportPos
  256.                 && false !== $firstBlockPos
  257.                 && $firstBlockPos $lastImportPos
  258.             {
  259.                 // { appears before @import : prepend warning
  260.                 $css Minify::$importWarning $css;
  261.             }
  262.         }
  263.         return $css;
  264.     }
  265.  
  266. }

Documentation generated on Thu, 19 Sep 2013 00:06:25 +0200 by phpDocumentor 1.4.3