2008-08-29 22:56:34 +00:00
< ? php
/**
* Class Minify
* @ package Minify
*/
/**
* Minify_Source
*/
require_once 'Minify/Source.php' ;
/**
* Minify - Combines , minifies , and caches JavaScript and CSS files on demand .
*
* See README for usage instructions ( for now ) .
*
* This library was inspired by { @ link mailto : flashkot @ mail . ru jscsscomp by Maxim Martynyuk }
* and by the article { @ link http :// www . hunlock . com / blogs / Supercharged_Javascript " Supercharged JavaScript " by Patrick Hunlock } .
*
* Requires PHP 5.1 . 0.
* Tested on PHP 5.1 . 6.
*
* @ package Minify
* @ author Ryan Grove < ryan @ wonko . com >
* @ author Stephen Clay < steve @ mrclay . org >
* @ copyright 2008 Ryan Grove , Stephen Clay . All rights reserved .
* @ license http :// opensource . org / licenses / bsd - license . php New BSD License
* @ link http :// code . google . com / p / minify /
*/
class Minify {
2009-04-21 20:53:29 +00:00
2010-05-16 01:27:33 +00:00
const VERSION = '2.1.4' ;
2008-08-29 22:56:34 +00:00
const TYPE_CSS = 'text/css' ;
const TYPE_HTML = 'text/html' ;
// there is some debate over the ideal JS Content-Type, but this is the
// Apache default and what Yahoo! uses..
const TYPE_JS = 'application/x-javascript' ;
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
const URL_DEBUG = 'http://code.google.com/p/minify/wiki/Debugging' ;
2008-08-29 22:56:34 +00:00
/**
* How many hours behind are the file modification times of uploaded files ?
*
2008-08-24 00:30:30 +00:00
* If you upload files from Windows to a non - Windows server , Windows may report
* incorrect mtimes for the files . Immediately after modifying and uploading a
* file , use the touch command to update the mtime on the server . If the mtime
* jumps ahead by a number of hours , set this variable to that number . If the mtime
2008-08-29 22:56:34 +00:00
* moves back , this should not be needed .
*
* @ var int $uploaderHoursBehind
*/
public static $uploaderHoursBehind = 0 ;
2009-02-26 17:06:31 +00:00
/**
* If this string is not empty AND the serve () option 'bubbleCssImports' is
* NOT set , then serve () will check CSS files for @ import declarations that
* appear too late in the combined stylesheet . If found , serve () will prepend
* the output with this warning .
*
* @ var string $importWarning
*/
2009-03-19 16:33:38 +00:00
public static $importWarning = " /* See http://code.google.com/p/minify/wiki/CommonProblems#@imports_can_appear_in_invalid_locations_in_combined_CSS_files */ \n " ;
2011-09-03 20:39:25 -04:00
/**
* Has the DOCUMENT_ROOT been set in user code ?
*
* @ var bool
*/
public static $isDocRootSet = false ;
2008-08-29 22:56:34 +00:00
/**
* Specify a cache object ( with identical interface as Minify_Cache_File ) or
* a path to use with Minify_Cache_File .
*
* If not called , Minify will not use a cache and , for each 200 response , will
* need to recombine files , minify and encode the output .
*
* @ param mixed $cache object with identical interface as Minify_Cache_File or
2009-01-06 16:32:28 +00:00
* a directory path , or null to disable caching . ( default = '' )
2008-12-16 17:13:58 +00:00
*
* @ param bool $fileLocking ( default = true ) This only applies if the first
2008-09-05 20:50:58 +00:00
* parameter is a string .
2008-08-29 22:56:34 +00:00
*
* @ return null
*/
2008-09-05 20:50:58 +00:00
public static function setCache ( $cache = '' , $fileLocking = true )
2008-08-29 22:56:34 +00:00
{
if ( is_string ( $cache )) {
require_once 'Minify/Cache/File.php' ;
2008-09-05 20:50:58 +00:00
self :: $_cache = new Minify_Cache_File ( $cache , $fileLocking );
2008-08-29 22:56:34 +00:00
} else {
self :: $_cache = $cache ;
}
}
/**
* Serve a request for a minified file .
*
* Here are the available options and defaults in the base controller :
*
* 'isPublic' : send " public " instead of " private " in Cache - Control
* headers , allowing shared caches to cache the output . ( default true )
*
* 'quiet' : set to true to have serve () return an array rather than sending
* any headers / output ( default false )
*
2009-03-30 01:47:40 +00:00
* 'encodeOutput' : set to false to disable content encoding , and not send
* the Vary header ( default true )
2008-08-29 22:56:34 +00:00
*
* 'encodeMethod' : generally you should let this be determined by
* HTTP_Encoder ( leave null ), but you can force a particular encoding
2009-06-30 19:44:55 +00:00
* to be returned , by setting this to 'gzip' or '' ( no encoding )
2008-08-29 22:56:34 +00:00
*
* 'encodeLevel' : level of encoding compression ( 0 to 9 , default 9 )
*
* 'contentTypeCharset' : appended to the Content - Type header sent . Set to a falsey
2009-05-01 17:11:44 +00:00
* value to remove . ( default 'utf-8' )
2008-08-29 22:56:34 +00:00
*
* 'maxAge' : set this to the number of seconds the client should use its cache
* before revalidating with the server . This sets Cache - Control : max - age and the
* Expires header . Unlike the old 'setExpires' setting , this setting will NOT
* prevent conditional GETs . Note this has nothing to do with server - side caching .
2008-08-18 23:38:39 +00:00
*
* 'rewriteCssUris' : If true , serve () will automatically set the 'currentDir'
* minifier option to enable URI rewriting in CSS files ( default true )
2008-08-29 22:56:34 +00:00
*
2009-02-26 17:06:31 +00:00
* 'bubbleCssImports' : If true , all @ import declarations in combined CSS
* files will be move to the top . Note this may alter effective CSS values
* due to a change in order . ( default false )
*
2008-08-29 22:56:34 +00:00
* 'debug' : set to true to minify all sources with the 'Lines' controller , which
* eases the debugging of combined files . This also prevents 304 responses .
* @ see Minify_Lines :: minify ()
*
* 'minifiers' : to override Minify ' s default choice of minifier function for
* a particular content - type , specify your callback under the key of the
* content - type :
* < code >
* // call customCssMinifier($css) for all CSS minification
* $options [ 'minifiers' ][ Minify :: TYPE_CSS ] = 'customCssMinifier' ;
*
* // don't minify Javascript at all
* $options [ 'minifiers' ][ Minify :: TYPE_JS ] = '' ;
* </ code >
*
* 'minifierOptions' : to send options to the minifier function , specify your options
* under the key of the content - type . E . g . To send the CSS minifier an option :
* < code >
* // give CSS minifier array('optionName' => 'optionValue') as 2nd argument
* $options [ 'minifierOptions' ][ Minify :: TYPE_CSS ][ 'optionName' ] = 'optionValue' ;
* </ code >
*
* 'contentType' : ( optional ) this is only needed if your file extension is not
* js / css / html . The given content - type will be sent regardless of source file
* extension , so this should not be used in a Groups config with other
* Javascript / CSS files .
*
* Any controller options are documented in that controller ' s setupSources () method .
*
* @ param mixed instance of subclass of Minify_Controller_Base or string name of
* controller . E . g . 'Files'
*
* @ param array $options controller / serve options
*
* @ return mixed null , or , if the 'quiet' option is set to true , an array
* with keys " success " ( bool ), " statusCode " ( int ), " content " ( string ), and
* " headers " ( array ) .
*/
2009-04-21 20:53:29 +00:00
public static function serve ( $controller , $options = array ())
{
2011-09-03 20:39:25 -04:00
if ( ! self :: $isDocRootSet && 0 === stripos ( PHP_OS , 'win' )) {
self :: setDocRoot ();
}
2008-08-29 22:56:34 +00:00
if ( is_string ( $controller )) {
// make $controller into object
$class = 'Minify_Controller_' . $controller ;
if ( ! class_exists ( $class , false )) {
require_once " Minify/Controller/ "
. str_replace ( '_' , '/' , $controller ) . " .php " ;
}
$controller = new $class ();
}
// set up controller sources and mix remaining options with
// controller defaults
$options = $controller -> setupSources ( $options );
$options = $controller -> analyzeSources ( $options );
self :: $_options = $controller -> mixInDefaultOptions ( $options );
// check request validity
if ( ! $controller -> sources ) {
// invalid request!
if ( ! self :: $_options [ 'quiet' ]) {
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
self :: _errorExit ( self :: $_options [ 'badRequestHeader' ], self :: URL_DEBUG );
2008-08-29 22:56:34 +00:00
} else {
list (, $statusCode ) = explode ( ' ' , self :: $_options [ 'badRequestHeader' ]);
return array (
'success' => false
, 'statusCode' => ( int ) $statusCode
, 'content' => ''
, 'headers' => array ()
);
}
}
self :: $_controller = $controller ;
if ( self :: $_options [ 'debug' ]) {
self :: _setupDebug ( $controller -> sources );
self :: $_options [ 'maxAge' ] = 0 ;
}
2009-03-30 01:47:40 +00:00
// determine encoding
if ( self :: $_options [ 'encodeOutput' ]) {
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
$sendVary = true ;
2009-03-30 01:47:40 +00:00
if ( self :: $_options [ 'encodeMethod' ] !== null ) {
// controller specifically requested this
$contentEncoding = self :: $_options [ 'encodeMethod' ];
} else {
// sniff request header
require_once 'HTTP/Encoder.php' ;
// depending on what the client accepts, $contentEncoding may be
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
2009-06-30 19:44:55 +00:00
// getAcceptedEncoding(false, false) leaves out compress and deflate as options.
list ( self :: $_options [ 'encodeMethod' ], $contentEncoding ) = HTTP_Encoder :: getAcceptedEncoding ( false , false );
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
$sendVary = ! HTTP_Encoder :: isBuggyIe ();
2009-03-30 01:47:40 +00:00
}
} else {
self :: $_options [ 'encodeMethod' ] = '' ; // identity (no encoding)
}
2008-08-29 22:56:34 +00:00
// check client cache
require_once 'HTTP/ConditionalGet.php' ;
$cgOptions = array (
2009-01-06 16:32:28 +00:00
'lastModifiedTime' => self :: $_options [ 'lastModifiedTime' ]
2008-08-29 22:56:34 +00:00
, 'isPublic' => self :: $_options [ 'isPublic' ]
2009-03-30 01:47:40 +00:00
, 'encoding' => self :: $_options [ 'encodeMethod' ]
2008-08-29 22:56:34 +00:00
);
if ( self :: $_options [ 'maxAge' ] > 0 ) {
$cgOptions [ 'maxAge' ] = self :: $_options [ 'maxAge' ];
2010-05-10 07:44:40 +00:00
} elseif ( self :: $_options [ 'debug' ]) {
$cgOptions [ 'invalidate' ] = true ;
2008-08-29 22:56:34 +00:00
}
$cg = new HTTP_ConditionalGet ( $cgOptions );
if ( $cg -> cacheIsValid ) {
// client's cache is valid
if ( ! self :: $_options [ 'quiet' ]) {
$cg -> sendHeaders ();
return ;
} else {
return array (
'success' => true
2009-01-06 16:32:28 +00:00
, 'statusCode' => 304
2008-08-29 22:56:34 +00:00
, 'content' => ''
, 'headers' => $cg -> getHeaders ()
);
}
} else {
// client will need output
$headers = $cg -> getHeaders ();
unset ( $cg );
}
2008-08-18 23:38:39 +00:00
if ( self :: $_options [ 'contentType' ] === self :: TYPE_CSS
&& self :: $_options [ 'rewriteCssUris' ]) {
2011-06-23 19:38:04 +00:00
foreach ( $controller -> sources as $key => $source ) {
2008-08-18 23:38:39 +00:00
if ( $source -> filepath
&& ! isset ( $source -> minifyOptions [ 'currentDir' ])
&& ! isset ( $source -> minifyOptions [ 'prependRelativePath' ])
) {
$source -> minifyOptions [ 'currentDir' ] = dirname ( $source -> filepath );
}
}
}
2008-08-29 22:56:34 +00:00
// check server cache
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
if ( null !== self :: $_cache && ! self :: $_options [ 'debug' ]) {
2008-08-29 22:56:34 +00:00
// using cache
// the goal is to use only the cache methods to sniff the length and
// output the content, as they do not require ever loading the file into
// memory.
2010-05-10 07:44:40 +00:00
$cacheId = self :: _getCacheId ();
2009-06-30 19:44:55 +00:00
$fullCacheId = ( self :: $_options [ 'encodeMethod' ])
? $cacheId . '.gz'
: $cacheId ;
2008-08-29 22:56:34 +00:00
// check cache for valid entry
$cacheIsReady = self :: $_cache -> isValid ( $fullCacheId , self :: $_options [ 'lastModifiedTime' ]);
if ( $cacheIsReady ) {
$cacheContentLength = self :: $_cache -> getSize ( $fullCacheId );
} else {
// generate & cache content
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
try {
$content = self :: _combineMinify ();
} catch ( Exception $e ) {
self :: $_controller -> log ( $e -> getMessage ());
if ( ! self :: $_options [ 'quiet' ]) {
self :: _errorExit ( self :: $_options [ 'errorHeader' ], self :: URL_DEBUG );
}
throw $e ;
}
2008-08-29 22:56:34 +00:00
self :: $_cache -> store ( $cacheId , $content );
2009-06-30 19:44:55 +00:00
if ( function_exists ( 'gzencode' )) {
self :: $_cache -> store ( $cacheId . '.gz' , gzencode ( $content , self :: $_options [ 'encodeLevel' ]));
2008-10-08 14:20:34 +00:00
}
2008-08-29 22:56:34 +00:00
}
} else {
// no cache
$cacheIsReady = false ;
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
try {
$content = self :: _combineMinify ();
} catch ( Exception $e ) {
self :: $_controller -> log ( $e -> getMessage ());
if ( ! self :: $_options [ 'quiet' ]) {
self :: _errorExit ( self :: $_options [ 'errorHeader' ], self :: URL_DEBUG );
}
throw $e ;
}
2008-08-29 22:56:34 +00:00
}
if ( ! $cacheIsReady && self :: $_options [ 'encodeMethod' ]) {
// still need to encode
2009-06-30 19:44:55 +00:00
$content = gzencode ( $content , self :: $_options [ 'encodeLevel' ]);
2008-08-29 22:56:34 +00:00
}
// add headers
$headers [ 'Content-Length' ] = $cacheIsReady
? $cacheContentLength
2010-05-16 01:27:33 +00:00
: (( function_exists ( 'mb_strlen' ) && (( int ) ini_get ( 'mbstring.func_overload' ) & 2 ))
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
? mb_strlen ( $content , '8bit' )
: strlen ( $content )
);
2008-08-29 22:56:34 +00:00
$headers [ 'Content-Type' ] = self :: $_options [ 'contentTypeCharset' ]
? self :: $_options [ 'contentType' ] . '; charset=' . self :: $_options [ 'contentTypeCharset' ]
: self :: $_options [ 'contentType' ];
if ( self :: $_options [ 'encodeMethod' ] !== '' ) {
$headers [ 'Content-Encoding' ] = $contentEncoding ;
2009-03-30 01:47:40 +00:00
}
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
if ( self :: $_options [ 'encodeOutput' ] && $sendVary ) {
2008-08-29 22:56:34 +00:00
$headers [ 'Vary' ] = 'Accept-Encoding' ;
}
if ( ! self :: $_options [ 'quiet' ]) {
// output headers & content
foreach ( $headers as $name => $val ) {
header ( $name . ': ' . $val );
}
if ( $cacheIsReady ) {
self :: $_cache -> display ( $fullCacheId );
} else {
echo $content ;
}
} else {
return array (
'success' => true
, 'statusCode' => 200
, 'content' => $cacheIsReady
? self :: $_cache -> fetch ( $fullCacheId )
: $content
2009-01-06 16:32:28 +00:00
, 'headers' => $headers
2008-08-29 22:56:34 +00:00
);
}
}
2008-09-04 00:38:08 +00:00
/**
* Return combined minified content for a set of sources
*
* No internal caching will be used and the content will not be HTTP encoded .
*
* @ param array $sources array of filepaths and / or Minify_Source objects
*
2009-02-26 17:06:31 +00:00
* @ param array $options ( optional ) array of options for serve . By default
* these are already set : quiet = true , encodeMethod = '' , lastModifiedTime = 0.
*
2008-09-04 00:38:08 +00:00
* @ return string
*/
2009-02-26 17:06:31 +00:00
public static function combine ( $sources , $options = array ())
2008-09-04 00:38:08 +00:00
{
$cache = self :: $_cache ;
self :: $_cache = null ;
2009-02-26 17:06:31 +00:00
$options = array_merge ( array (
2008-09-04 00:38:08 +00:00
'files' => ( array ) $sources
, 'quiet' => true
, 'encodeMethod' => ''
, 'lastModifiedTime' => 0
2009-02-26 17:06:31 +00:00
), $options );
$out = self :: serve ( 'Files' , $options );
2008-09-04 00:38:08 +00:00
self :: $_cache = $cache ;
return $out [ 'content' ];
}
2008-09-03 19:42:41 +00:00
/**
* On IIS , create $_SERVER [ 'DOCUMENT_ROOT' ]
*
* @ param bool $unsetPathInfo ( default false ) if true , $_SERVER [ 'PATH_INFO' ]
* will be unset ( it is inconsistent with Apache ' s setting )
*
* @ return null
*/
public static function setDocRoot ( $unsetPathInfo = false )
{
2008-12-16 17:13:58 +00:00
if ( isset ( $_SERVER [ 'SERVER_SOFTWARE' ])
&& 0 === strpos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'Microsoft-IIS/' )
) {
2009-06-30 19:44:55 +00:00
$_SERVER [ 'DOCUMENT_ROOT' ] = rtrim ( substr (
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
$_SERVER [ 'SCRIPT_FILENAME' ]
2008-12-16 17:13:58 +00:00
, 0
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
, strlen ( $_SERVER [ 'SCRIPT_FILENAME' ]) - strlen ( $_SERVER [ 'SCRIPT_NAME' ])
2009-06-30 19:44:55 +00:00
), '\\' );
2008-12-16 17:13:58 +00:00
if ( $unsetPathInfo ) {
2008-09-03 19:42:41 +00:00
unset ( $_SERVER [ 'PATH_INFO' ]);
2008-12-16 17:13:58 +00:00
}
2009-01-28 20:02:25 +00:00
require_once 'Minify/Logger.php' ;
Minify_Logger :: log ( " setDocRoot() set DOCUMENT_ROOT to \" { $_SERVER [ 'DOCUMENT_ROOT' ] } \" " );
2008-09-03 19:42:41 +00:00
}
2011-09-03 20:39:25 -04:00
self :: $isDocRootSet = true ;
2008-09-03 19:42:41 +00:00
}
2008-09-05 04:22:57 +00:00
/**
* @ var mixed Minify_Cache_ * object or null ( i . e . no server cache is used )
*/
private static $_cache = null ;
2008-08-29 22:56:34 +00:00
/**
* @ var Minify_Controller active controller for current request
*/
protected static $_controller = null ;
/**
* @ var array options for current request
*/
protected static $_options = null ;
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
protected static function _errorExit ( $header , $url )
{
$url = htmlspecialchars ( $url , ENT_QUOTES );
list (, $h1 ) = explode ( ' ' , $header , 2 );
$h1 = htmlspecialchars ( $h1 );
2010-07-25 05:11:41 +00:00
// FastCGI environments require 3rd arg to header() to be set
list (, $code ) = explode ( ' ' , $header , 3 );
header ( $header , true , $code );
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
header ( 'Content-Type: text/html; charset=utf-8' );
echo " <h1> $h1 </h1> " ;
echo " <p>Please see <a href=' $url '> $url </a>.</p> " ;
exit ();
}
2008-08-29 22:56:34 +00:00
/**
* Set up sources to use Minify_Lines
*
* @ param array $sources Minify_Source instances
*
* @ return null
*/
protected static function _setupDebug ( $sources )
{
foreach ( $sources as $source ) {
$source -> minifier = array ( 'Minify_Lines' , 'minify' );
$id = $source -> getId ();
$source -> minifyOptions = array (
'id' => ( is_file ( $id ) ? basename ( $id ) : $id )
);
}
}
/**
* Combines sources and minifies the result .
*
* @ return string
*/
2009-04-21 20:53:29 +00:00
protected static function _combineMinify ()
{
2008-08-29 22:56:34 +00:00
$type = self :: $_options [ 'contentType' ]; // ease readability
2009-01-06 16:32:28 +00:00
// when combining scripts, make sure all statements separated and
// trailing single line comment is terminated
2008-08-29 22:56:34 +00:00
$implodeSeparator = ( $type === self :: TYPE_JS )
2009-01-06 16:32:28 +00:00
? " \n ; "
2008-08-29 22:56:34 +00:00
: '' ;
// allow the user to pass a particular array of options to each
// minifier (designated by type). source objects may still override
// these
$defaultOptions = isset ( self :: $_options [ 'minifierOptions' ][ $type ])
? self :: $_options [ 'minifierOptions' ][ $type ]
: array ();
// if minifier not set, default is no minification. source objects
// may still override this
$defaultMinifier = isset ( self :: $_options [ 'minifiers' ][ $type ])
? self :: $_options [ 'minifiers' ][ $type ]
: false ;
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
// minify each source with its own options and minifier, then combine.
// Here we used to combine all first but this was probably
// bad for PCRE performance, esp. in CSS.
foreach ( self :: $_controller -> sources as $source ) {
// allow the source to override our minifier and options
$minifier = ( null !== $source -> minifier )
? $source -> minifier
: $defaultMinifier ;
$options = ( null !== $source -> minifyOptions )
? array_merge ( $defaultOptions , $source -> minifyOptions )
: $defaultOptions ;
if ( $minifier ) {
self :: $_controller -> loadMinifier ( $minifier );
// get source content and minify it
2010-05-10 07:44:40 +00:00
try {
$pieces [] = call_user_func ( $minifier , $source -> getContent (), $options );
} catch ( Exception $e ) {
throw new Exception ( " Exception in " . $source -> getId () .
" : " . $e -> getMessage ());
}
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
} else {
2008-08-29 22:56:34 +00:00
$pieces [] = $source -> getContent ();
}
}
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
$content = implode ( $implodeSeparator , $pieces );
2008-08-29 22:56:34 +00:00
2009-02-26 17:06:31 +00:00
if ( $type === self :: TYPE_CSS && false !== strpos ( $content , '@import' )) {
$content = self :: _handleCssImports ( $content );
}
2008-08-29 22:56:34 +00:00
// do any post-processing (esp. for editing build URIs)
if ( self :: $_options [ 'postprocessorRequire' ]) {
require_once self :: $_options [ 'postprocessorRequire' ];
}
if ( self :: $_options [ 'postprocessor' ]) {
$content = call_user_func ( self :: $_options [ 'postprocessor' ], $content , $type );
}
return $content ;
}
/**
* Make a unique cache id for for this request .
*
* Any settings that could affect output are taken into consideration
*
2010-05-10 07:44:40 +00:00
* @ param string $prefix
*
2008-08-29 22:56:34 +00:00
* @ return string
*/
2010-05-10 07:44:40 +00:00
protected static function _getCacheId ( $prefix = 'minify' )
2009-04-21 20:53:29 +00:00
{
2010-05-10 07:44:40 +00:00
$name = preg_replace ( '/[^a-zA-Z0-9\\.=_,]/' , '' , self :: $_controller -> selectionId );
$name = preg_replace ( '/\\.+/' , '.' , $name );
2010-10-29 04:10:39 +00:00
$name = substr ( $name , 0 , 200 - 34 - strlen ( $prefix ));
2010-05-10 07:44:40 +00:00
$md5 = md5 ( serialize ( array (
2008-08-29 22:56:34 +00:00
Minify_Source :: getDigest ( self :: $_controller -> sources )
, self :: $_options [ 'minifiers' ]
2008-08-16 22:13:28 +00:00
, self :: $_options [ 'minifierOptions' ]
2008-08-29 22:56:34 +00:00
, self :: $_options [ 'postprocessor' ]
2009-02-26 17:06:31 +00:00
, self :: $_options [ 'bubbleCssImports' ]
2008-08-29 22:56:34 +00:00
)));
2010-05-10 07:44:40 +00:00
return " { $prefix } _ { $name } _ { $md5 } " ;
2009-01-06 16:32:28 +00:00
}
2009-02-26 17:06:31 +00:00
/**
* Bubble CSS @ imports to the top or prepend a warning if an
* @ import is detected not at the top .
*/
2009-04-21 20:53:29 +00:00
protected static function _handleCssImports ( $css )
{
2009-02-26 17:06:31 +00:00
if ( self :: $_options [ 'bubbleCssImports' ]) {
// bubble CSS imports
Work on: Issue 125, Issue 126, Issue 132, Issue 134, Issue 138, Issue 139, Issue 147, Issue 149, Issue 151, Issue 162, Issue 166
2010-05-09 16:43:47 +00:00
preg_match_all ( '/@import.*?;/' , $css , $imports );
2009-02-26 17:06:31 +00:00
$css = implode ( '' , $imports [ 0 ]) . preg_replace ( '/@import.*?;/' , '' , $css );
} else if ( '' !== self :: $importWarning ) {
// remove comments so we don't mistake { in a comment as a block
$noCommentCss = preg_replace ( '@/\\*[\\s\\S]*?\\*/@' , '' , $css );
$lastImportPos = strrpos ( $noCommentCss , '@import' );
$firstBlockPos = strpos ( $noCommentCss , '{' );
if ( false !== $lastImportPos
&& false !== $firstBlockPos
&& $firstBlockPos < $lastImportPos
) {
// { appears before @import : prepend warning
$css = self :: $importWarning . $css ;
}
}
return $css ;
}
2008-08-29 22:56:34 +00:00
}