Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/minify/lib/Minify.php
Go to the documentation of this file.
00001 <?php
00010 require_once 'Minify/Source.php';
00011  
00030 class Minify {
00031     
00032     const VERSION = '2.1.3';
00033     const TYPE_CSS = 'text/css';
00034     const TYPE_HTML = 'text/html';
00035     // there is some debate over the ideal JS Content-Type, but this is the
00036     // Apache default and what Yahoo! uses..
00037     const TYPE_JS = 'application/x-javascript';
00038     
00050     public static $uploaderHoursBehind = 0;
00051     
00060     public static $importWarning = "/* See http://code.google.com/p/minify/wiki/CommonProblems#@imports_can_appear_in_invalid_locations_in_combined_CSS_files */\n";
00061     
00077     public static function setCache($cache = '', $fileLocking = true)
00078     {
00079         if (is_string($cache)) {
00080             require_once 'Minify/Cache/File.php';
00081             self::$_cache = new Minify_Cache_File($cache, $fileLocking);
00082         } else {
00083             self::$_cache = $cache;
00084         }
00085     }
00086     
00160     public static function serve($controller, $options = array())
00161     {
00162         if (is_string($controller)) {
00163             // make $controller into object
00164             $class = 'Minify_Controller_' . $controller;
00165             if (! class_exists($class, false)) {
00166                 require_once "Minify/Controller/" 
00167                     . str_replace('_', '/', $controller) . ".php";    
00168             }
00169             $controller = new $class();
00170         }
00171         
00172         // set up controller sources and mix remaining options with
00173         // controller defaults
00174         $options = $controller->setupSources($options);
00175         $options = $controller->analyzeSources($options);
00176         self::$_options = $controller->mixInDefaultOptions($options);
00177         
00178         // check request validity
00179         if (! $controller->sources) {
00180             // invalid request!
00181             if (! self::$_options['quiet']) {
00182                 header(self::$_options['badRequestHeader']);
00183                 echo self::$_options['badRequestHeader'];
00184                 return;
00185             } else {
00186                 list(,$statusCode) = explode(' ', self::$_options['badRequestHeader']);
00187                 return array(
00188                     'success' => false
00189                     ,'statusCode' => (int)$statusCode
00190                     ,'content' => ''
00191                     ,'headers' => array()
00192                 );
00193             }
00194         }
00195         
00196         self::$_controller = $controller;
00197         
00198         if (self::$_options['debug']) {
00199             self::_setupDebug($controller->sources);
00200             self::$_options['maxAge'] = 0;
00201         }
00202         
00203         // determine encoding
00204         if (self::$_options['encodeOutput']) {
00205             if (self::$_options['encodeMethod'] !== null) {
00206                 // controller specifically requested this
00207                 $contentEncoding = self::$_options['encodeMethod'];
00208             } else {
00209                 // sniff request header
00210                 require_once 'HTTP/Encoder.php';
00211                 // depending on what the client accepts, $contentEncoding may be 
00212                 // 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
00213                 // getAcceptedEncoding(false, false) leaves out compress and deflate as options.
00214                 list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false, false);
00215             }
00216         } else {
00217             self::$_options['encodeMethod'] = ''; // identity (no encoding)
00218         }
00219         
00220         // check client cache
00221         require_once 'HTTP/ConditionalGet.php';
00222         $cgOptions = array(
00223             'lastModifiedTime' => self::$_options['lastModifiedTime']
00224             ,'isPublic' => self::$_options['isPublic']
00225             ,'encoding' => self::$_options['encodeMethod']
00226         );
00227         if (self::$_options['maxAge'] > 0) {
00228             $cgOptions['maxAge'] = self::$_options['maxAge'];
00229         }
00230         $cg = new HTTP_ConditionalGet($cgOptions);
00231         if ($cg->cacheIsValid) {
00232             // client's cache is valid
00233             if (! self::$_options['quiet']) {
00234                 $cg->sendHeaders();
00235                 return;
00236             } else {
00237                 return array(
00238                     'success' => true
00239                     ,'statusCode' => 304
00240                     ,'content' => ''
00241                     ,'headers' => $cg->getHeaders()
00242                 );
00243             }
00244         } else {
00245             // client will need output
00246             $headers = $cg->getHeaders();
00247             unset($cg);
00248         }
00249         
00250         if (self::$_options['contentType'] === self::TYPE_CSS
00251             && self::$_options['rewriteCssUris']) {
00252             reset($controller->sources);
00253             while (list($key, $source) = each($controller->sources)) {
00254                 if ($source->filepath 
00255                     && !isset($source->minifyOptions['currentDir'])
00256                     && !isset($source->minifyOptions['prependRelativePath'])
00257                 ) {
00258                     $source->minifyOptions['currentDir'] = dirname($source->filepath);
00259                 }
00260             }
00261         }
00262         
00263         // check server cache
00264         if (null !== self::$_cache) {
00265             // using cache
00266             // the goal is to use only the cache methods to sniff the length and 
00267             // output the content, as they do not require ever loading the file into
00268             // memory.
00269             $cacheId = 'minify_' . self::_getCacheId();
00270             $fullCacheId = (self::$_options['encodeMethod'])
00271                 ? $cacheId . '.gz'
00272                 : $cacheId;
00273             // check cache for valid entry
00274             $cacheIsReady = self::$_cache->isValid($fullCacheId, self::$_options['lastModifiedTime']); 
00275             if ($cacheIsReady) {
00276                 $cacheContentLength = self::$_cache->getSize($fullCacheId);    
00277             } else {
00278                 // generate & cache content
00279                 $content = self::_combineMinify();
00280                 self::$_cache->store($cacheId, $content);
00281                 if (function_exists('gzencode')) {
00282                     self::$_cache->store($cacheId . '.gz', gzencode($content, self::$_options['encodeLevel']));
00283                 }
00284             }
00285         } else {
00286             // no cache
00287             $cacheIsReady = false;
00288             $content = self::_combineMinify();
00289         }
00290         if (! $cacheIsReady && self::$_options['encodeMethod']) {
00291             // still need to encode
00292             $content = gzencode($content, self::$_options['encodeLevel']);
00293         }
00294         
00295         // add headers
00296         $headers['Content-Length'] = $cacheIsReady
00297             ? $cacheContentLength
00298             : strlen($content);
00299         $headers['Content-Type'] = self::$_options['contentTypeCharset']
00300             ? self::$_options['contentType'] . '; charset=' . self::$_options['contentTypeCharset']
00301             : self::$_options['contentType'];
00302         if (self::$_options['encodeMethod'] !== '') {
00303             $headers['Content-Encoding'] = $contentEncoding;
00304         }
00305         if (self::$_options['encodeOutput']) {
00306             $headers['Vary'] = 'Accept-Encoding';
00307         }
00308 
00309         if (! self::$_options['quiet']) {
00310             // output headers & content
00311             foreach ($headers as $name => $val) {
00312                 header($name . ': ' . $val);
00313             }
00314             if ($cacheIsReady) {
00315                 self::$_cache->display($fullCacheId);
00316             } else {
00317                 echo $content;
00318             }
00319         } else {
00320             return array(
00321                 'success' => true
00322                 ,'statusCode' => 200
00323                 ,'content' => $cacheIsReady
00324                     ? self::$_cache->fetch($fullCacheId)
00325                     : $content
00326                 ,'headers' => $headers
00327             );
00328         }
00329     }
00330     
00343     public static function combine($sources, $options = array())
00344     {
00345         $cache = self::$_cache;
00346         self::$_cache = null;
00347         $options = array_merge(array(
00348             'files' => (array)$sources
00349             ,'quiet' => true
00350             ,'encodeMethod' => ''
00351             ,'lastModifiedTime' => 0
00352         ), $options);
00353         $out = self::serve('Files', $options);
00354         self::$_cache = $cache;
00355         return $out['content'];
00356     }
00357     
00366     public static function setDocRoot($unsetPathInfo = false)
00367     {
00368         if (isset($_SERVER['SERVER_SOFTWARE'])
00369             && 0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/')
00370         ) {
00371             $_SERVER['DOCUMENT_ROOT'] = rtrim(substr(
00372                 $_SERVER['PATH_TRANSLATED']
00373                 ,0
00374                 ,strlen($_SERVER['PATH_TRANSLATED']) - strlen($_SERVER['SCRIPT_NAME'])
00375             ), '\\');
00376             if ($unsetPathInfo) {
00377                 unset($_SERVER['PATH_INFO']);
00378             }
00379             require_once 'Minify/Logger.php';
00380             Minify_Logger::log("setDocRoot() set DOCUMENT_ROOT to \"{$_SERVER['DOCUMENT_ROOT']}\"");
00381         }
00382     }
00383     
00387     private static $_cache = null;
00388     
00392     protected static $_controller = null;
00393     
00397     protected static $_options = null;
00398     
00406     protected static function _setupDebug($sources)
00407     {
00408         foreach ($sources as $source) {
00409             $source->minifier = array('Minify_Lines', 'minify');
00410             $id = $source->getId();
00411             $source->minifyOptions = array(
00412                 'id' => (is_file($id) ? basename($id) : $id)
00413             );
00414         }
00415     }
00416     
00422     protected static function _combineMinify()
00423     {
00424         $type = self::$_options['contentType']; // ease readability
00425         
00426         // when combining scripts, make sure all statements separated and
00427         // trailing single line comment is terminated
00428         $implodeSeparator = ($type === self::TYPE_JS)
00429             ? "\n;"
00430             : '';
00431         // allow the user to pass a particular array of options to each
00432         // minifier (designated by type). source objects may still override
00433         // these
00434         $defaultOptions = isset(self::$_options['minifierOptions'][$type])
00435             ? self::$_options['minifierOptions'][$type]
00436             : array();
00437         // if minifier not set, default is no minification. source objects
00438         // may still override this
00439         $defaultMinifier = isset(self::$_options['minifiers'][$type])
00440             ? self::$_options['minifiers'][$type]
00441             : false;
00442        
00443         if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
00444             // all source have same options/minifier, better performance
00445             // to combine, then minify once
00446             foreach (self::$_controller->sources as $source) {
00447                 $pieces[] = $source->getContent();
00448             }
00449             $content = implode($implodeSeparator, $pieces);
00450             if ($defaultMinifier) {
00451                 self::$_controller->loadMinifier($defaultMinifier);
00452                 $content = call_user_func($defaultMinifier, $content, $defaultOptions);    
00453             }
00454         } else {
00455             // minify each source with its own options and minifier, then combine
00456             foreach (self::$_controller->sources as $source) {
00457                 // allow the source to override our minifier and options
00458                 $minifier = (null !== $source->minifier)
00459                     ? $source->minifier
00460                     : $defaultMinifier;
00461                 $options = (null !== $source->minifyOptions)
00462                     ? array_merge($defaultOptions, $source->minifyOptions)
00463                     : $defaultOptions;
00464                 if ($minifier) {
00465                     self::$_controller->loadMinifier($minifier);
00466                     // get source content and minify it
00467                     $pieces[] = call_user_func($minifier, $source->getContent(), $options);     
00468                 } else {
00469                     $pieces[] = $source->getContent();     
00470                 }
00471             }
00472             $content = implode($implodeSeparator, $pieces);
00473         }
00474         
00475         if ($type === self::TYPE_CSS && false !== strpos($content, '@import')) {
00476             $content = self::_handleCssImports($content);
00477         }
00478         
00479         // do any post-processing (esp. for editing build URIs)
00480         if (self::$_options['postprocessorRequire']) {
00481             require_once self::$_options['postprocessorRequire'];
00482         }
00483         if (self::$_options['postprocessor']) {
00484             $content = call_user_func(self::$_options['postprocessor'], $content, $type);
00485         }
00486         return $content;
00487     }
00488     
00496     protected static function _getCacheId()
00497     {
00498         return md5(serialize(array(
00499             Minify_Source::getDigest(self::$_controller->sources)
00500             ,self::$_options['minifiers'] 
00501             ,self::$_options['minifierOptions']
00502             ,self::$_options['postprocessor']
00503             ,self::$_options['bubbleCssImports']
00504         )));
00505     }
00506     
00511     protected static function _handleCssImports($css)
00512     {
00513         if (self::$_options['bubbleCssImports']) {
00514             // bubble CSS imports
00515             preg_match_all('/@import.*?;/', $css, $imports);
00516             $css = implode('', $imports[0]) . preg_replace('/@import.*?;/', '', $css);
00517         } else if ('' !== self::$importWarning) {
00518             // remove comments so we don't mistake { in a comment as a block
00519             $noCommentCss = preg_replace('@/\\*[\\s\\S]*?\\*/@', '', $css);
00520             $lastImportPos = strrpos($noCommentCss, '@import');
00521             $firstBlockPos = strpos($noCommentCss, '{');
00522             if (false !== $lastImportPos
00523                 && false !== $firstBlockPos
00524                 && $firstBlockPos < $lastImportPos
00525             ) {
00526                 // { appears before @import : prepend warning
00527                 $css = self::$importWarning . $css;
00528             }
00529         }
00530         return $css;
00531     }
00532 }
 All Data Structures Namespaces Files Functions Variables Enumerations