diff --git a/lib/minify/README.txt b/lib/minify/README.txt deleted file mode 100644 index 6f527a5f69f..00000000000 --- a/lib/minify/README.txt +++ /dev/null @@ -1,132 +0,0 @@ -The files in this directory represent the default Minify setup designed to ease -integration with your site. This app will combine and minify your Javascript or -CSS files and serve them with HTTP compression and cache headers. - - -RECOMMENDED - -It's recommended to edit config.php to set $min_cachePath to a writeable -(by PHP) directory on your system. This will improve performance. - - -GETTING STARTED - -The quickest way to get started is to use the Minify URI Builder application -on your website: http://example.com/min/builder/ - - -MINIFYING A SINGLE FILE - -Let's say you want to serve this file: - http://example.com/wp-content/themes/default/default.css - -Here's the "Minify URL" for this file: - http://example.com/min/?f=wp-content/themes/default/default.css - -In other words, the "f" argument is set to the file path from root without the -initial "/". As CSS files may contain relative URIs, Minify will automatically -"fix" these by rewriting them as root relative. - - -COMBINING MULTIPLE FILES IN ONE DOWNLOAD - -Separate the paths given to "f" with commas. - -Let's say you have CSS files at these URLs: - http://example.com/scripts/jquery-1.2.6.js - http://example.com/scripts/site.js - -You can combine these files through Minify by requesting this URL: - http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js - - -SIMPLIFYING URLS WITH A BASE PATH - -If you're combining files that share the same ancestor directory, you can use -the "b" argument to set the base directory for the "f" argument. Do not include -the leading or trailing "/" characters. - -E.g., the following URLs will serve the exact same content: - http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js,scripts/home.js - http://example.com/min/?b=scripts&f=jquery-1.2.6.js,site.js,home.js - - -MINIFY URLS IN HTML - -In (X)HTML files, don't forget to replace any "&" characters with "&". - - -SPECIFYING ALLOWED DIRECTORIES - -By default, Minify will serve any *.css/*.js files within the DOCUMENT_ROOT. If -you'd prefer to limit Minify's access to certain directories, set the -$min_serveOptions['minApp']['allowDirs'] array in config.php. E.g. to limit -to the /js and /themes/default directories, use: - -$min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default'); - - -GROUPS: FASTER PERFORMANCE AND BETTER URLS - -For the best performance, edit groupsConfig.php to pre-specify groups of files -to be combined under preset keys. E.g., here's an example configuration in -groupsConfig.php: - -return array( - 'js' => array('//js/Class.js', '//js/email.js') -); - -This pre-selects the following files to be combined under the key "js": - http://example.com/js/Class.js - http://example.com/js/email.js - -You can now serve these files with this simple URL: - http://example.com/min/?g=js - - -GROUPS: SPECIFYING FILES OUTSIDE THE DOC_ROOT - -In the groupsConfig.php array, the "//" in the file paths is a shortcut for -the DOCUMENT_ROOT, but you can also specify paths from the root of the filesystem -or relative to the DOC_ROOT: - -return array( - 'js' => array( - '//js/file.js' // file within DOC_ROOT - ,'//../file.js' // file in parent directory of DOC_ROOT - ,'C:/Users/Steve/file.js' // file anywhere on filesystem - ) -); - - -FAR-FUTURE EXPIRES HEADERS - -Minify can send far-future (one year) Expires headers. To enable this you must -add a number to the querystring (e.g. /min/?g=js&1234 or /min/f=file.js&1234) -and alter it whenever a source file is changed. If you have a build process you -can use a build/source control revision number. - -If you serve files as a group, you can use the utility function Minify_groupUri() -to get a "versioned" Minify URI for use in your HTML. E.g.: - -"; - - -DEBUG MODE - -In debug mode, instead of compressing files, Minify sends combined files with -comments prepended to each line to show the line number in the original source -file. To enable this, set $min_allowDebugFlag to true in config.php and append -"&debug=1" to your URIs. E.g. /min/?f=script1.js,script2.js&debug=1 - -Known issue: files with comment-like strings/regexps can cause problems in this mode. - - -QUESTIONS? - -http://groups.google.com/group/minify diff --git a/lib/minify/builder/_index.js b/lib/minify/builder/_index.js deleted file mode 100644 index c4b665546e8..00000000000 --- a/lib/minify/builder/_index.js +++ /dev/null @@ -1,242 +0,0 @@ -var MUB = { - _uid : 0 - ,_minRoot : '/min/?' - ,checkRewrite : function () { - var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1); - function fail() { - $('#minRewriteFailed')[0].className = 'topNote'; - }; - $.ajax({ - url : '../f=' + testUri + '&' + (new Date()).getTime() - ,success : function (data) { - if (data === '1') { - MUB._minRoot = '/min/'; - $('span.minRoot').html('/min/'); - } else - fail(); - } - ,error : fail - }); - } - /** - * Get markup for new source LI element - */ - ,newLi : function () { - return '
Found by bookmarklet: /' - + location.hash.substr(1).split(',').join(' | /') - + '
' - ); - $('#bmUris a').click(function () { - MUB.addButtonClick(); - $('#sources li:last input').val(this.innerHTML) - MUB.liUpdateTestLink.call($('#sources li:last')[0]); - $('#results').hide(); - return false; - }).attr({title:'Add file +'}); - } else { - // copy bookmarklet code into href - var bmUri = location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1); - $.ajax({ - url : '../?f=' + bmUri - ,success : function (code) { - $('#bm')[0].href = code - .replace('%BUILDER_URL%', location.href) - .replace(/\n/g, ' '); - } - ,dataType : 'text' - }); - $.browser.msie && $('#getBm p:last').append(' Sorry, not supported in MSIE!'); - MUB.addButtonClick(); - } - MUB.checkRewrite(); - } -}; -window.onload = MUB.init; diff --git a/lib/minify/builder/bm.js b/lib/minify/builder/bm.js deleted file mode 100644 index 703039ba724..00000000000 --- a/lib/minify/builder/bm.js +++ /dev/null @@ -1,36 +0,0 @@ -javascript:(function() { - var d = document - ,uris = [] - ,i = 0 - ,o - ,home = (location + '').split('/').splice(0, 3).join('/') + '/'; - function add(uri) { - return (0 === uri.indexOf(home)) - && (!/[\?&]/.test(uri)) - && uris.push(escape(uri.substr(home.length))); - }; - function sheet(ss) { - // we must check the domain with add() before accessing ss.cssRules - // otherwise a security exception will be thrown - if (ss.href && add(ss.href) && ss.cssRules) { - var i = 0, r; - while (r = ss.cssRules[i++]) - r.styleSheet && sheet(r.styleSheet); - } - }; - while (o = d.getElementsByTagName('script')[i++]) - o.src && !(o.type && /vbs/i.test(o.type)) && add(o.src); - i = 0; - while (o = d.styleSheets[i++]) - /* http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-DocumentStyle-styleSheets - document.styleSheet is a list property where [0] accesses the 1st element and - [outOfRange] returns null. In IE, styleSheets is a function, and also throws an - exception when you check the out of bounds index. (sigh) */ - sheet(o); - if (uris.length) - window.open('%BUILDER_URL%#' + uris.join(',')); - else - alert('No js/css files found with URLs within "' - + home.split('/')[2] - + '".\n(This tool is limited to URLs with the same domain.)'); -})(); diff --git a/lib/minify/builder/index.php b/lib/minify/builder/index.php deleted file mode 100644 index 1b209822202..00000000000 --- a/lib/minify/builder/index.php +++ /dev/null @@ -1,182 +0,0 @@ - - - - -Note: Please set $min_cachePath
-in /min/config.php to improve performance.
Note: Your webserver does not seem to - support mod_rewrite (used in /min/.htaccess). Your Minify URIs will contain "?", which -may reduce the benefit of proxy cache servers.
- -Create a list of Javascript or CSS files (or 1 is fine) you'd like to combine -and click [Update].
- -Place this URI in your HTML to serve the files above combined, minified, compressed and -with cache headers.
-| URI | /min (opens in new window) |
|---|---|
| HTML |
For the best performance you can serve these files as a pre-defined group with a URI
-like: /min/?g=keyName
To do this, add a line like this to /min/groupsConfig.php:
- -return array(
- ... your existing groups here ...
-
-);
-
-Make sure to replace keyName with a unique key for this group.
You can use the bookmarklet below to fetch all CSS & Javascript URIs from a page -on your site. When you active it, this page will open in a new window with a list of -available URIs to add.
- -Create Minify URIs (right-click, add to bookmarks)
-@importIf your CSS files contain @import declarations, Minify will not
-remove them. Therefore, you will want to remove those that point to files already
-in your list, and move any others to the top of the first file in your list
-(imports below any styles will be ignored by browsers as invalid).
If you desire, you can use Minify URIs in imports and they will not be touched
-by Minify. E.g. @import "/min/?g=css2";
Need help? Search or post to the Minify discussion list.
-This app is minified :) view -source
- - - - - - - ob_get_contents() - ,'id' => __FILE__ - ,'lastModifiedTime' => max( - // regenerate cache if either of these change - filemtime(__FILE__) - ,filemtime(dirname(__FILE__) . '/../config.php') - ) - ,'minifyAll' => true - ,'encodeOutput' => $encodeOutput -); -ob_end_clean(); - -set_include_path(dirname(__FILE__) . '/../lib' . PATH_SEPARATOR . get_include_path()); - -require 'Minify.php'; - -if (0 === stripos(PHP_OS, 'win')) { - Minify::setDocRoot(); // we may be on IIS -} -Minify::setCache(isset($min_cachePath) ? $min_cachePath : null); -Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; - -Minify::serve('Page', $serveOpts); diff --git a/lib/minify/builder/ocCheck.php b/lib/minify/builder/ocCheck.php deleted file mode 100644 index 8cc19af8b2a..00000000000 --- a/lib/minify/builder/ocCheck.php +++ /dev/null @@ -1,36 +0,0 @@ - 'World!' - ,'method' => 'deflate' - )); - $he->encode(); - $he->sendAll(); - -} else { - // echo status "0" or "1" - header('Content-Type: text/plain'); - echo (int)$_oc; -} diff --git a/lib/minify/builder/rewriteTest.js b/lib/minify/builder/rewriteTest.js deleted file mode 100644 index d00491fd7e5..00000000000 --- a/lib/minify/builder/rewriteTest.js +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/lib/minify/config.php b/lib/minify/config.php index 7e29c0b26e7..e2f709cea9f 100644 --- a/lib/minify/config.php +++ b/lib/minify/config.php @@ -1,19 +1,40 @@ tempdir; +$min_documentRoot = $CFG->dirroot.'/lib/minify'; +$min_cacheFileLocking = true; +$min_serveOptions['bubbleCssImports'] = false; +$min_serveOptions['maxAge'] = 1800; +$min_serveOptions['minApp']['groupsOnly'] = true; +$min_symlinks = array(); +$min_uploaderHoursBehind = 0; +$min_libPath = dirname(__FILE__) . '/lib'; +// do not change zlib compression or buffering here + +// TODO: locking setting, caching setting + +return; // end of moodle modification + /** - * In 'debug' mode, Minify can combine files with no minification and - * add comments to indicate line #s of the original files. - * - * To allow debugging, set this option to true and add "&debug=1" to - * a URI. E.g. /min/?f=script1.js,script2.js&debug=1 - */ -$min_allowDebugFlag = ($CFG->debug); + * Allow use of the Minify URI Builder app. Only set this to true while you need it. + **/ +$min_enableBuilder = true; /** @@ -23,24 +44,38 @@ $min_allowDebugFlag = ($CFG->debug); * * If you want to use a custom error logger, set this to your logger * instance. Your object should have a method log(string $message). - * - * @todo cache system does not have error logging yet. */ $min_errorLogger = false; /** - * Allow use of the Minify URI Builder app. If you no longer need - * this, set to false. - **/ -$min_enableBuilder = false; + * To allow debug mode output, you must set this option to true. + * + * Once true, you can send the cookie minDebug to request debug mode output. The + * cookie value should match the URIs you'd like to debug. E.g. to debug + * /min/f=file1.js send the cookie minDebug=file1.js + * You can manually enable debugging by appending "&debug" to a URI. + * E.g. /min/?f=script1.js,script2.js&debug + * + * In 'debug' mode, Minify combines files with no minification and adds comments + * to indicate line #s of the original files. + */ +$min_allowDebugFlag = false; /** * For best performance, specify your temp directory here. Otherwise Minify * will have to load extra code to guess. Some examples below: */ -$min_cachePath = $CFG->tempdir.''; +//$min_cachePath = 'c:\\WINDOWS\\Temp'; +//$min_cachePath = '/tmp'; +//$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path()); +/** + * To use APC/Memcache/ZendPlatform for cache storage, require the class and + * set $min_cachePath to an instance. Example below: + */ +//require dirname(__FILE__) . '/lib/Minify/Cache/APC.php'; +//$min_cachePath = new Minify_Cache_APC(); /** @@ -53,8 +88,8 @@ $min_cachePath = $CFG->tempdir.''; * If /min/ is directly inside your document root, just uncomment the * second line. The third line might work on some Apache servers. */ -$min_documentRoot = $CFG->dirroot.'/lib/minify'; -//$min_documentRoot = substr(__FILE__, 0, strlen(__FILE__) - 15); +$min_documentRoot = ''; +//$min_documentRoot = substr(__FILE__, 0, -15); //$min_documentRoot = $_SERVER['SUBDOMAIN_DOCUMENT_ROOT']; @@ -77,9 +112,9 @@ $min_serveOptions['bubbleCssImports'] = false; /** - * Maximum age of browser cache in seconds. After this period, the browser - * will send another conditional GET. Use a longer period for lower traffic - * but you may want to shorten this before making changes if it's crucial + * Cache-Control: max-age value sent to browser (in seconds). After this period, + * the browser will send another conditional GET. Use a longer period for lower + * traffic but you may want to shorten this before making changes if it's crucial * those changes are seen immediately. * * Note: Despite this setting, if you include a number at the end of the @@ -88,6 +123,18 @@ $min_serveOptions['bubbleCssImports'] = false; $min_serveOptions['maxAge'] = 1800; +/** + * To use Google's Closure Compiler API (falling back to JSMin on failure), + * uncomment the following lines: + */ +/*function closureCompiler($js) { + require_once 'Minify/JS/ClosureCompiler.php'; + return Minify_JS_ClosureCompiler::minify($js); +} +$min_serveOptions['minifiers']['application/x-javascript'] = 'closureCompiler'; +//*/ + + /** * If you'd like to restrict the "f" option to files within/below * particular directories below DOCUMENT_ROOT, set this here. @@ -102,12 +149,17 @@ $min_serveOptions['maxAge'] = 1800; * Set to true to disable the "f" GET parameter for specifying files. * Only the "g" parameter will be considered. */ -$min_serveOptions['minApp']['groupsOnly'] = true; +$min_serveOptions['minApp']['groupsOnly'] = false; + /** - * Maximum # of files that can be specified in the "f" GET parameter + * By default, Minify will not minify files with names containing .min or -min + * before the extension. E.g. myFile.min.js will not be processed by JSMin + * + * To minify all files, set this option to null. You could also specify your + * own pattern that is matched against the filename. */ -$min_serveOptions['minApp']['maxFiles'] = 10; +//$min_serveOptions['minApp']['noMinPattern'] = '@[-\\.]min\\.(?:js|css)$@i'; /** @@ -148,7 +200,7 @@ $min_uploaderHoursBehind = 0; * Path to Minify's lib folder. If you happen to move it, change * this accordingly. */ -$min_libPath = $CFG->libdir . '/minify/lib'; +$min_libPath = dirname(__FILE__) . '/lib'; // try to disable output_compression (may not have an effect) diff --git a/lib/minify/groupsConfig.php b/lib/minify/groupsConfig.php index 56398807283..c9007768381 100644 --- a/lib/minify/groupsConfig.php +++ b/lib/minify/groupsConfig.php @@ -7,28 +7,11 @@ /** * You may wish to use the Minify URI Builder app to suggest * changes. http://yourdomain/min/builder/ + * + * See http://code.google.com/p/minify/wiki/CustomSource for other ideas **/ return array( // 'js' => array('//js/file1.js', '//js/file2.js'), // 'css' => array('//css/file1.css', '//css/file2.css'), - - // custom source example - /*'js2' => array( - dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js', - // do NOT process this file - new Minify_Source(array( - 'filepath' => dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js', - 'minifier' => create_function('$a', 'return $a;') - )) - ),//*/ - - /*'js3' => array( - dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js', - // do NOT process this file - new Minify_Source(array( - 'filepath' => dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js', - 'minifier' => array('Minify_Packer', 'minify') - )) - ),//*/ -); +); \ No newline at end of file diff --git a/lib/minify/lib/FirePHP.php b/lib/minify/lib/FirePHP.php index d9d12106c82..d301a641abf 100644 --- a/lib/minify/lib/FirePHP.php +++ b/lib/minify/lib/FirePHP.php @@ -1065,7 +1065,7 @@ class FirePHP { * @author Brett StimmermanPlease see $url.
"; + exit(); + } + /** * Set up sources to use Minify_Lines * * @param array $sources Minify_Source instances - * - * @return null */ protected static function _setupDebug($sources) { @@ -439,21 +489,22 @@ class Minify { $defaultMinifier = isset(self::$_options['minifiers'][$type]) ? self::$_options['minifiers'][$type] : false; - - if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) { - // all source have same options/minifier, better performance - // to combine, then minify once - foreach (self::$_controller->sources as $source) { - $pieces[] = $source->getContent(); - } - $content = implode($implodeSeparator, $pieces); - if ($defaultMinifier) { - self::$_controller->loadMinifier($defaultMinifier); - $content = call_user_func($defaultMinifier, $content, $defaultOptions); - } - } else { - // minify each source with its own options and minifier, then combine - foreach (self::$_controller->sources as $source) { + + // process groups of sources with identical minifiers/options + $content = array(); + $i = 0; + $l = count(self::$_controller->sources); + $groupToProcessTogether = array(); + $lastMinifier = null; + $lastOptions = null; + do { + // get next source + $source = null; + if ($i < $l) { + $source = self::$_controller->sources[$i]; + /* @var Minify_Source $source */ + $sourceContent = $source->getContent(); + // allow the source to override our minifier and options $minifier = (null !== $source->minifier) ? $source->minifier @@ -461,16 +512,40 @@ class Minify { $options = (null !== $source->minifyOptions) ? array_merge($defaultOptions, $source->minifyOptions) : $defaultOptions; - if ($minifier) { - self::$_controller->loadMinifier($minifier); - // get source content and minify it - $pieces[] = call_user_func($minifier, $source->getContent(), $options); + } + // do we need to process our group right now? + if ($i > 0 // yes, we have at least the first group populated + && ( + ! $source // yes, we ran out of sources + || $type === self::TYPE_CSS // yes, to process CSS individually (avoiding PCRE bugs/limits) + || $minifier !== $lastMinifier // yes, minifier changed + || $options !== $lastOptions) // yes, options changed + ) + { + // minify previous sources with last settings + $imploded = implode($implodeSeparator, $groupToProcessTogether); + $groupToProcessTogether = array(); + if ($lastMinifier) { + self::$_controller->loadMinifier($lastMinifier); + try { + $content[] = call_user_func($lastMinifier, $imploded, $lastOptions); + } catch (Exception $e) { + throw new Exception("Exception in minifier: " . $e->getMessage()); + } } else { - $pieces[] = $source->getContent(); + $content[] = $imploded; } } - $content = implode($implodeSeparator, $pieces); - } + // add content to the group + if ($source) { + $groupToProcessTogether[] = $sourceContent; + $lastMinifier = $minifier; + $lastOptions = $options; + } + $i++; + } while ($source); + + $content = implode($implodeSeparator, $content); if ($type === self::TYPE_CSS && false !== strpos($content, '@import')) { $content = self::_handleCssImports($content); @@ -491,22 +566,32 @@ class Minify { * * Any settings that could affect output are taken into consideration * + * @param string $prefix + * * @return string */ - protected static function _getCacheId() + protected static function _getCacheId($prefix = 'minify') { - return md5(serialize(array( + $name = preg_replace('/[^a-zA-Z0-9\\.=_,]/', '', self::$_controller->selectionId); + $name = preg_replace('/\\.+/', '.', $name); + $name = substr($name, 0, 200 - 34 - strlen($prefix)); + $md5 = md5(serialize(array( Minify_Source::getDigest(self::$_controller->sources) ,self::$_options['minifiers'] ,self::$_options['minifierOptions'] ,self::$_options['postprocessor'] ,self::$_options['bubbleCssImports'] + ,self::VERSION ))); + return "{$prefix}_{$name}_{$md5}"; } /** - * Bubble CSS @imports to the top or prepend a warning if an - * @import is detected not at the top. + * Bubble CSS @imports to the top or prepend a warning if an import is detected not at the top. + * + * @param string $css + * + * @return string */ protected static function _handleCssImports($css) { diff --git a/lib/minify/lib/Minify/CSS.php b/lib/minify/lib/Minify/CSS.php index b2d8e0bf0b7..49882e9d2d5 100644 --- a/lib/minify/lib/Minify/CSS.php +++ b/lib/minify/lib/Minify/CSS.php @@ -1,83 +1,99 @@ - - * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) - */ -class Minify_CSS { - - /** - * Minify a CSS string - * - * @param string $css - * - * @param array $options available options: - * - * 'preserveComments': (default true) multi-line comments that begin - * with "/*!" will be preserved with newlines before and after to - * enhance readability. - * - * 'prependRelativePath': (default null) if given, this string will be - * prepended to all relative URIs in import/url declarations - * - * 'currentDir': (default null) if given, this is assumed to be the - * directory of the current CSS file. Using this, minify will rewrite - * all relative URIs in import/url declarations to correctly point to - * the desired files. For this to work, the files *must* exist and be - * visible by the PHP process. - * - * 'symlinks': (default = array()) If the CSS file is stored in - * a symlink-ed directory, provide an array of link paths to - * target paths, where the link paths are within the document root. Because - * paths need to be normalized for this to work, use "//" to substitute - * the doc root in the link paths (the array keys). E.g.: - *
- * array('//symlink' => '/real/target/path') // unix
- * array('//static' => 'D:\\staticStorage') // Windows
- *
- *
- * @return string
- */
- public static function minify($css, $options = array())
- {
- require_once 'Minify/CSS/Compressor.php';
- if (isset($options['preserveComments'])
- && !$options['preserveComments']) {
- $css = Minify_CSS_Compressor::process($css, $options);
- } else {
- require_once 'Minify/CommentPreserver.php';
- $css = Minify_CommentPreserver::process(
- $css
- ,array('Minify_CSS_Compressor', 'process')
- ,array($options)
- );
- }
- if (! isset($options['currentDir']) && ! isset($options['prependRelativePath'])) {
- return $css;
- }
- require_once 'Minify/CSS/UriRewriter.php';
- if (isset($options['currentDir'])) {
- return Minify_CSS_UriRewriter::rewrite(
- $css
- ,$options['currentDir']
- ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
- ,isset($options['symlinks']) ? $options['symlinks'] : array()
- );
- } else {
- return Minify_CSS_UriRewriter::prepend(
- $css
- ,$options['prependRelativePath']
- );
- }
- }
-}
+
+ * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
+ */
+class Minify_CSS {
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @param array $options available options:
+ *
+ * 'preserveComments': (default true) multi-line comments that begin
+ * with "/*!" will be preserved with newlines before and after to
+ * enhance readability.
+ *
+ * 'removeCharsets': (default true) remove all @charset at-rules
+ *
+ * 'prependRelativePath': (default null) if given, this string will be
+ * prepended to all relative URIs in import/url declarations
+ *
+ * 'currentDir': (default null) if given, this is assumed to be the
+ * directory of the current CSS file. Using this, minify will rewrite
+ * all relative URIs in import/url declarations to correctly point to
+ * the desired files. For this to work, the files *must* exist and be
+ * visible by the PHP process.
+ *
+ * 'symlinks': (default = array()) If the CSS file is stored in
+ * a symlink-ed directory, provide an array of link paths to
+ * target paths, where the link paths are within the document root. Because
+ * paths need to be normalized for this to work, use "//" to substitute
+ * the doc root in the link paths (the array keys). E.g.:
+ *
+ * array('//symlink' => '/real/target/path') // unix
+ * array('//static' => 'D:\\staticStorage') // Windows
+ *
+ *
+ * 'docRoot': (default = $_SERVER['DOCUMENT_ROOT'])
+ * see Minify_CSS_UriRewriter::rewrite
+ *
+ * @return string
+ */
+ public static function minify($css, $options = array())
+ {
+ $options = array_merge(array(
+ 'removeCharsets' => true,
+ 'preserveComments' => true,
+ 'currentDir' => null,
+ 'docRoot' => $_SERVER['DOCUMENT_ROOT'],
+ 'prependRelativePath' => null,
+ 'symlinks' => array(),
+ ), $options);
+
+ if ($options['removeCharsets']) {
+ $css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
+ }
+ require_once 'Minify/CSS/Compressor.php';
+ if (! $options['preserveComments']) {
+ $css = Minify_CSS_Compressor::process($css, $options);
+ } else {
+ require_once 'Minify/CommentPreserver.php';
+ $css = Minify_CommentPreserver::process(
+ $css
+ ,array('Minify_CSS_Compressor', 'process')
+ ,array($options)
+ );
+ }
+ if (! $options['currentDir'] && ! $options['prependRelativePath']) {
+ return $css;
+ }
+ require_once 'Minify/CSS/UriRewriter.php';
+ if ($options['currentDir']) {
+ return Minify_CSS_UriRewriter::rewrite(
+ $css
+ ,$options['currentDir']
+ ,$options['docRoot']
+ ,$options['symlinks']
+ );
+ } else {
+ return Minify_CSS_UriRewriter::prepend(
+ $css
+ ,$options['prependRelativePath']
+ );
+ }
+ }
+}
diff --git a/lib/minify/lib/Minify/CSS/Compressor.php b/lib/minify/lib/Minify/CSS/Compressor.php
index dad700a9c4e..c6cdd8b7a6d 100644
--- a/lib/minify/lib/Minify/CSS/Compressor.php
+++ b/lib/minify/lib/Minify/CSS/Compressor.php
@@ -1,251 +1,249 @@
-
- * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
- */
-class Minify_CSS_Compressor {
-
- /**
- * Minify a CSS string
- *
- * @param string $css
- *
- * @param array $options (currently ignored)
- *
- * @return string
- */
- public static function process($css, $options = array())
- {
- $obj = new Minify_CSS_Compressor($options);
- return $obj->_process($css);
- }
-
- /**
- * @var array options
- */
- protected $_options = null;
-
- /**
- * @var bool Are we "in" a hack?
- *
- * I.e. are some browsers targetted until the next comment?
- */
- protected $_inHack = false;
-
-
- /**
- * Constructor
- *
- * @param array $options (currently ignored)
- *
- * @return null
- */
- private function __construct($options) {
- $this->_options = $options;
- }
-
- /**
- * Minify a CSS string
- *
- * @param string $css
- *
- * @return string
- */
- protected function _process($css)
- {
- $css = str_replace("\r\n", "\n", $css);
-
- // preserve empty comment after '>'
- // http://www.webdevout.net/css-hacks#in_css-selectors
- $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
-
- // preserve empty comment between property and value
- // http://css-discuss.incutio.com/?page=BoxModelHack
- $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
- $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
-
- // apply callback to all valid comments (and strip out surrounding ws
- $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
- ,array($this, '_commentCB'), $css);
-
- // remove ws around { } and last semicolon in declaration block
- $css = preg_replace('/\\s*{\\s*/', '{', $css);
- $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
-
- // remove ws surrounding semicolons
- $css = preg_replace('/\\s*;\\s*/', ';', $css);
-
- // remove ws around urls
- $css = preg_replace('/
- url\\( # url(
- \\s*
- ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
- \\s*
- \\) # )
- /x', 'url($1)', $css);
-
- // remove ws between rules and colons
- $css = preg_replace('/
- \\s*
- ([{;]) # 1 = beginning of block or rule separator
- \\s*
- ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
- \\s*
- :
- \\s*
- (\\b|[#\'"]) # 3 = first character of a value
- /x', '$1$2:$3', $css);
-
- // remove ws in selectors
- $css = preg_replace_callback('/
- (?: # non-capture
- \\s*
- [^~>+,\\s]+ # selector part
- \\s*
- [,>+~] # combinators
- )+
- \\s*
- [^~>+,\\s]+ # selector part
- { # open declaration block
- /x'
- ,array($this, '_selectorsCB'), $css);
-
- // minimize hex colors
- $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
- , '$1#$2$3$4$5', $css);
-
- // remove spaces between font families
- $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
- ,array($this, '_fontFamilyCB'), $css);
-
- $css = preg_replace('/@import\\s+url/', '@import url', $css);
-
- // replace any ws involving newlines with a single newline
- $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
-
- // separate common descendent selectors w/ newlines (to limit line lengths)
- $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
-
- // Use newline after 1st numeric value (to limit line lengths).
- $css = preg_replace('/
- ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
- \\s+
- /x'
- ,"$1\n", $css);
-
- // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
- $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
-
- return trim($css);
- }
-
- /**
- * Replace what looks like a set of selectors
- *
- * @param array $m regex matches
- *
- * @return string
- */
- protected function _selectorsCB($m)
- {
- // remove ws around the combinators
- return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
- }
-
- /**
- * Process a comment and return a replacement
- *
- * @param array $m regex matches
- *
- * @return string
- */
- protected function _commentCB($m)
- {
- $hasSurroundingWs = (trim($m[0]) !== $m[1]);
- $m = $m[1];
- // $m is the comment content w/o the surrounding tokens,
- // but the return value will replace the entire comment.
- if ($m === 'keep') {
- return '/**/';
- }
- if ($m === '" "') {
- // component of http://tantek.com/CSS/Examples/midpass.html
- return '/*" "*/';
- }
- if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
- // component of http://tantek.com/CSS/Examples/midpass.html
- return '/*";}}/* */';
- }
- if ($this->_inHack) {
- // inversion: feeding only to one browser
- if (preg_match('@
- ^/ # comment started like /*/
- \\s*
- (\\S[\\s\\S]+?) # has at least some non-ws content
- \\s*
- /\\* # ends like /*/ or /**/
- @x', $m, $n)) {
- // end hack mode after this comment, but preserve the hack and comment content
- $this->_inHack = false;
- return "/*/{$n[1]}/**/";
- }
- }
- if (substr($m, -1) === '\\') { // comment ends like \*/
- // begin hack mode and preserve hack
- $this->_inHack = true;
- return '/*\\*/';
- }
- if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
- // begin hack mode and preserve hack
- $this->_inHack = true;
- return '/*/*/';
- }
- if ($this->_inHack) {
- // a regular comment ends hack mode but should be preserved
- $this->_inHack = false;
- return '/**/';
- }
- // Issue 107: if there's any surrounding whitespace, it may be important, so
- // replace the comment with a single space
- return $hasSurroundingWs // remove all other comments
- ? ' '
- : '';
- }
-
- /**
- * Process a font-family listing and return a replacement
- *
- * @param array $m regex matches
- *
- * @return string
- */
- protected function _fontFamilyCB($m)
- {
- // Issue 210: must not eliminate WS between words in unquoted families
- $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
- $out = 'font-family:';
- while (null !== ($piece = array_shift($pieces))) {
- if ($piece[0] !== '"' && $piece[0] !== "'") {
- $piece = preg_replace('/\\s+/', ' ', $piece);
- $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
- }
- $out .= $piece;
- }
- return $out . $m[2];
- }
-}
+
+ * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
+ */
+class Minify_CSS_Compressor {
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @param array $options (currently ignored)
+ *
+ * @return string
+ */
+ public static function process($css, $options = array())
+ {
+ $obj = new Minify_CSS_Compressor($options);
+ return $obj->_process($css);
+ }
+
+ /**
+ * @var array
+ */
+ protected $_options = null;
+
+ /**
+ * Are we "in" a hack? I.e. are some browsers targetted until the next comment?
+ *
+ * @var bool
+ */
+ protected $_inHack = false;
+
+
+ /**
+ * Constructor
+ *
+ * @param array $options (currently ignored)
+ */
+ private function __construct($options) {
+ $this->_options = $options;
+ }
+
+ /**
+ * Minify a CSS string
+ *
+ * @param string $css
+ *
+ * @return string
+ */
+ protected function _process($css)
+ {
+ $css = str_replace("\r\n", "\n", $css);
+
+ // preserve empty comment after '>'
+ // http://www.webdevout.net/css-hacks#in_css-selectors
+ $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
+
+ // preserve empty comment between property and value
+ // http://css-discuss.incutio.com/?page=BoxModelHack
+ $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
+ $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
+
+ // apply callback to all valid comments (and strip out surrounding ws
+ $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
+ ,array($this, '_commentCB'), $css);
+
+ // remove ws around { } and last semicolon in declaration block
+ $css = preg_replace('/\\s*{\\s*/', '{', $css);
+ $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
+
+ // remove ws surrounding semicolons
+ $css = preg_replace('/\\s*;\\s*/', ';', $css);
+
+ // remove ws around urls
+ $css = preg_replace('/
+ url\\( # url(
+ \\s*
+ ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
+ \\s*
+ \\) # )
+ /x', 'url($1)', $css);
+
+ // remove ws between rules and colons
+ $css = preg_replace('/
+ \\s*
+ ([{;]) # 1 = beginning of block or rule separator
+ \\s*
+ ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
+ \\s*
+ :
+ \\s*
+ (\\b|[#\'"-]) # 3 = first character of a value
+ /x', '$1$2:$3', $css);
+
+ // remove ws in selectors
+ $css = preg_replace_callback('/
+ (?: # non-capture
+ \\s*
+ [^~>+,\\s]+ # selector part
+ \\s*
+ [,>+~] # combinators
+ )+
+ \\s*
+ [^~>+,\\s]+ # selector part
+ { # open declaration block
+ /x'
+ ,array($this, '_selectorsCB'), $css);
+
+ // minimize hex colors
+ $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
+ , '$1#$2$3$4$5', $css);
+
+ // remove spaces between font families
+ $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
+ ,array($this, '_fontFamilyCB'), $css);
+
+ $css = preg_replace('/@import\\s+url/', '@import url', $css);
+
+ // replace any ws involving newlines with a single newline
+ $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
+
+ // separate common descendent selectors w/ newlines (to limit line lengths)
+ $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
+
+ // Use newline after 1st numeric value (to limit line lengths).
+ $css = preg_replace('/
+ ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
+ \\s+
+ /x'
+ ,"$1\n", $css);
+
+ // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
+ $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
+
+ return trim($css);
+ }
+
+ /**
+ * Replace what looks like a set of selectors
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _selectorsCB($m)
+ {
+ // remove ws around the combinators
+ return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
+ }
+
+ /**
+ * Process a comment and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _commentCB($m)
+ {
+ $hasSurroundingWs = (trim($m[0]) !== $m[1]);
+ $m = $m[1];
+ // $m is the comment content w/o the surrounding tokens,
+ // but the return value will replace the entire comment.
+ if ($m === 'keep') {
+ return '/**/';
+ }
+ if ($m === '" "') {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*" "*/';
+ }
+ if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
+ // component of http://tantek.com/CSS/Examples/midpass.html
+ return '/*";}}/* */';
+ }
+ if ($this->_inHack) {
+ // inversion: feeding only to one browser
+ if (preg_match('@
+ ^/ # comment started like /*/
+ \\s*
+ (\\S[\\s\\S]+?) # has at least some non-ws content
+ \\s*
+ /\\* # ends like /*/ or /**/
+ @x', $m, $n)) {
+ // end hack mode after this comment, but preserve the hack and comment content
+ $this->_inHack = false;
+ return "/*/{$n[1]}/**/";
+ }
+ }
+ if (substr($m, -1) === '\\') { // comment ends like \*/
+ // begin hack mode and preserve hack
+ $this->_inHack = true;
+ return '/*\\*/';
+ }
+ if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
+ // begin hack mode and preserve hack
+ $this->_inHack = true;
+ return '/*/*/';
+ }
+ if ($this->_inHack) {
+ // a regular comment ends hack mode but should be preserved
+ $this->_inHack = false;
+ return '/**/';
+ }
+ // Issue 107: if there's any surrounding whitespace, it may be important, so
+ // replace the comment with a single space
+ return $hasSurroundingWs // remove all other comments
+ ? ' '
+ : '';
+ }
+
+ /**
+ * Process a font-family listing and return a replacement
+ *
+ * @param array $m regex matches
+ *
+ * @return string
+ */
+ protected function _fontFamilyCB($m)
+ {
+ // Issue 210: must not eliminate WS between words in unquoted families
+ $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $out = 'font-family:';
+ while (null !== ($piece = array_shift($pieces))) {
+ if ($piece[0] !== '"' && $piece[0] !== "'") {
+ $piece = preg_replace('/\\s+/', ' ', $piece);
+ $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
+ }
+ $out .= $piece;
+ }
+ return $out . $m[2];
+ }
+}
diff --git a/lib/minify/lib/Minify/CSS/UriRewriter.php b/lib/minify/lib/Minify/CSS/UriRewriter.php
index 2b47cfc1d07..8845f1561f5 100644
--- a/lib/minify/lib/Minify/CSS/UriRewriter.php
+++ b/lib/minify/lib/Minify/CSS/UriRewriter.php
@@ -12,21 +12,15 @@
*/
class Minify_CSS_UriRewriter {
- /**
- * Defines which class to call as part of callbacks, change this
- * if you extend Minify_CSS_UriRewriter
- * @var string
- */
- protected static $className = 'Minify_CSS_UriRewriter';
-
/**
* rewrite() and rewriteRelative() append debugging information here
+ *
* @var string
*/
public static $debugText = '';
/**
- * Rewrite file relative URIs as root relative in CSS files
+ * In CSS content, rewrite file relative URIs as root relative
*
* @param string $css
*
@@ -83,7 +77,7 @@ class Minify_CSS_UriRewriter {
}
/**
- * Prepend a path to relative URIs in CSS files
+ * In CSS content, prepend a path to relative URIs
*
* @param string $css
*
@@ -107,73 +101,8 @@ class Minify_CSS_UriRewriter {
return $css;
}
-
/**
- * @var string directory of this stylesheet
- */
- private static $_currentDir = '';
-
- /**
- * @var string DOC_ROOT
- */
- private static $_docRoot = '';
-
- /**
- * @var array directory replacements to map symlink targets back to their
- * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
- */
- private static $_symlinks = array();
-
- /**
- * @var string path to prepend
- */
- private static $_prependPath = null;
-
- private static function _trimUrls($css)
- {
- return preg_replace('/
- url\\( # url(
- \\s*
- ([^\\)]+?) # 1 = URI (assuming does not contain ")")
- \\s*
- \\) # )
- /x', 'url($1)', $css);
- }
-
- private static function _processUriCB($m)
- {
- // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
- $isImport = ($m[0][0] === '@');
- // determine URI and the quote character (if any)
- if ($isImport) {
- $quoteChar = $m[1];
- $uri = $m[2];
- } else {
- // $m[1] is either quoted or not
- $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
- ? $m[1][0]
- : '';
- $uri = ($quoteChar === '')
- ? $m[1]
- : substr($m[1], 1, strlen($m[1]) - 2);
- }
- // analyze URI
- if ('/' !== $uri[0] // root-relative
- && false === strpos($uri, '//') // protocol (non-data)
- && 0 !== strpos($uri, 'data:') // data protocol
- ) {
- // URI is file-relative: rewrite depending on options
- $uri = (self::$_prependPath !== null)
- ? (self::$_prependPath . $uri)
- : self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
- }
- return $isImport
- ? "@import {$quoteChar}{$uri}{$quoteChar}"
- : "url({$quoteChar}{$uri}{$quoteChar})";
- }
-
- /**
- * Rewrite a file relative URI as root relative
+ * Get a root relative URI from a file relative URI
*
*
* Minify_CSS_UriRewriter::rewriteRelative(
@@ -236,21 +165,39 @@ class Minify_CSS_UriRewriter {
self::$debugText .= "docroot stripped : {$path}\n";
// fix to root-relative URI
-
$uri = strtr($path, '/\\', '//');
-
- // remove /./ and /../ where possible
- $uri = str_replace('/./', '/', $uri);
- // inspired by patch from Oleg Cherniy
- do {
- $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
- } while ($changed);
+ $uri = self::removeDots($uri);
self::$debugText .= "traversals removed : {$uri}\n\n";
return $uri;
}
+
+ /**
+ * Remove instances of "./" and "../" where possible from a root-relative URI
+ *
+ * @param string $uri
+ *
+ * @return string
+ */
+ public static function removeDots($uri)
+ {
+ $uri = str_replace('/./', '/', $uri);
+ // inspired by patch from Oleg Cherniy
+ do {
+ $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
+ } while ($changed);
+ return $uri;
+ }
+ /**
+ * Defines which class to call as part of callbacks, change this
+ * if you extend Minify_CSS_UriRewriter
+ *
+ * @var string
+ */
+ protected static $className = 'Minify_CSS_UriRewriter';
+
/**
* Get realpath with any trailing slash removed. If realpath() fails,
* just remove the trailing slash.
@@ -267,4 +214,97 @@ class Minify_CSS_UriRewriter {
}
return rtrim($path, '/\\');
}
+
+ /**
+ * Directory of this stylesheet
+ *
+ * @var string
+ */
+ private static $_currentDir = '';
+
+ /**
+ * DOC_ROOT
+ *
+ * @var string
+ */
+ private static $_docRoot = '';
+
+ /**
+ * directory replacements to map symlink targets back to their
+ * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
+ *
+ * @var array
+ */
+ private static $_symlinks = array();
+
+ /**
+ * Path to prepend
+ *
+ * @var string
+ */
+ private static $_prependPath = null;
+
+ /**
+ * @param string $css
+ *
+ * @return string
+ */
+ private static function _trimUrls($css)
+ {
+ return preg_replace('/
+ url\\( # url(
+ \\s*
+ ([^\\)]+?) # 1 = URI (assuming does not contain ")")
+ \\s*
+ \\) # )
+ /x', 'url($1)', $css);
+ }
+
+ /**
+ * @param array $m
+ *
+ * @return string
+ */
+ private static function _processUriCB($m)
+ {
+ // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
+ $isImport = ($m[0][0] === '@');
+ // determine URI and the quote character (if any)
+ if ($isImport) {
+ $quoteChar = $m[1];
+ $uri = $m[2];
+ } else {
+ // $m[1] is either quoted or not
+ $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
+ ? $m[1][0]
+ : '';
+ $uri = ($quoteChar === '')
+ ? $m[1]
+ : substr($m[1], 1, strlen($m[1]) - 2);
+ }
+ // analyze URI
+ if ('/' !== $uri[0] // root-relative
+ && false === strpos($uri, '//') // protocol (non-data)
+ && 0 !== strpos($uri, 'data:') // data protocol
+ ) {
+ // URI is file-relative: rewrite depending on options
+ if (self::$_prependPath === null) {
+ $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
+ } else {
+ $uri = self::$_prependPath . $uri;
+ if ($uri[0] === '/') {
+ $root = '';
+ $rootRelative = $uri;
+ $uri = $root . self::removeDots($rootRelative);
+ } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) {
+ $root = $m[1];
+ $rootRelative = substr($uri, strlen($root));
+ $uri = $root . self::removeDots($rootRelative);
+ }
+ }
+ }
+ return $isImport
+ ? "@import {$quoteChar}{$uri}{$quoteChar}"
+ : "url({$quoteChar}{$uri}{$quoteChar})";
+ }
}
diff --git a/lib/minify/lib/Minify/Cache/APC.php b/lib/minify/lib/Minify/Cache/APC.php
index ca84d299871..24ab0462052 100644
--- a/lib/minify/lib/Minify/Cache/APC.php
+++ b/lib/minify/lib/Minify/Cache/APC.php
@@ -54,9 +54,12 @@ class Minify_Cache_APC {
*/
public function getSize($id)
{
- return $this->_fetch($id)
- ? strlen($this->_data)
- : false;
+ if (! $this->_fetch($id)) {
+ return false;
+ }
+ return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
+ ? mb_strlen($this->_data, '8bit')
+ : strlen($this->_data);
}
/**
diff --git a/lib/minify/lib/Minify/Cache/File.php b/lib/minify/lib/Minify/Cache/File.php
index 2753e6b8e90..3fa6b18fcb2 100644
--- a/lib/minify/lib/Minify/Cache/File.php
+++ b/lib/minify/lib/Minify/Cache/File.php
@@ -9,13 +9,12 @@ class Minify_Cache_File {
public function __construct($path = '', $fileLocking = false)
{
if (! $path) {
- require_once 'Solar/Dir.php';
- $path = rtrim(Solar_Dir::tmp(), DIRECTORY_SEPARATOR);
+ $path = self::tmp();
}
$this->_locking = $fileLocking;
$this->_path = $path;
}
-
+
/**
* Write data to cache.
*
@@ -30,15 +29,14 @@ class Minify_Cache_File {
$flag = $this->_locking
? LOCK_EX
: null;
- if (is_file($this->_path . '/' . $id)) {
- @unlink($this->_path . '/' . $id);
- }
- if (! @file_put_contents($this->_path . '/' . $id, $data, $flag)) {
- return false;
+ $file = $this->_path . '/' . $id;
+ if (! @file_put_contents($file, $data, $flag)) {
+ $this->_log("Minify_Cache_File: Write failed to '$file'");
}
// write control
if ($data !== $this->fetch($id)) {
@unlink($file);
+ $this->_log("Minify_Cache_File: Post-write read failed for '$file'");
return false;
}
return true;
@@ -119,6 +117,78 @@ class Minify_Cache_File {
{
return $this->_path;
}
+
+ /**
+ * Get a usable temp directory
+ *
+ * Adapted from Solar/Dir.php
+ * @author Paul M. Jones
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php
+ *
+ * @return string
+ */
+ public static function tmp()
+ {
+ static $tmp = null;
+ if (! $tmp) {
+ $tmp = function_exists('sys_get_temp_dir')
+ ? sys_get_temp_dir()
+ : self::_tmp();
+ $tmp = rtrim($tmp, DIRECTORY_SEPARATOR);
+ }
+ return $tmp;
+ }
+
+ /**
+ * Returns the OS-specific directory for temporary files
+ *
+ * @author Paul M. Jones
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php
+ *
+ * @return string
+ */
+ protected static function _tmp()
+ {
+ // non-Windows system?
+ if (strtolower(substr(PHP_OS, 0, 3)) != 'win') {
+ $tmp = empty($_ENV['TMPDIR']) ? getenv('TMPDIR') : $_ENV['TMPDIR'];
+ if ($tmp) {
+ return $tmp;
+ } else {
+ return '/tmp';
+ }
+ }
+ // Windows 'TEMP'
+ $tmp = empty($_ENV['TEMP']) ? getenv('TEMP') : $_ENV['TEMP'];
+ if ($tmp) {
+ return $tmp;
+ }
+ // Windows 'TMP'
+ $tmp = empty($_ENV['TMP']) ? getenv('TMP') : $_ENV['TMP'];
+ if ($tmp) {
+ return $tmp;
+ }
+ // Windows 'windir'
+ $tmp = empty($_ENV['windir']) ? getenv('windir') : $_ENV['windir'];
+ if ($tmp) {
+ return $tmp;
+ }
+ // final fallback for Windows
+ return getenv('SystemRoot') . '\\temp';
+ }
+
+ /**
+ * Send message to the Minify logger
+ * @param string $msg
+ * @return null
+ */
+ protected function _log($msg)
+ {
+ require_once 'Minify/Logger.php';
+ Minify_Logger::log($msg);
+ }
private $_path = null;
private $_locking = null;
diff --git a/lib/minify/lib/Minify/Cache/Memcache.php b/lib/minify/lib/Minify/Cache/Memcache.php
index 2b81e7a3294..72bf454b93a 100644
--- a/lib/minify/lib/Minify/Cache/Memcache.php
+++ b/lib/minify/lib/Minify/Cache/Memcache.php
@@ -60,9 +60,12 @@ class Minify_Cache_Memcache {
*/
public function getSize($id)
{
- return $this->_fetch($id)
- ? strlen($this->_data)
- : false;
+ if (! $this->_fetch($id)) {
+ return false;
+ }
+ return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
+ ? mb_strlen($this->_data, '8bit')
+ : strlen($this->_data);
}
/**
diff --git a/lib/minify/lib/Minify/Cache/ZendPlatform.php b/lib/minify/lib/Minify/Cache/ZendPlatform.php
new file mode 100644
index 00000000000..3130d69a7b5
--- /dev/null
+++ b/lib/minify/lib/Minify/Cache/ZendPlatform.php
@@ -0,0 +1,142 @@
+
+ * Minify::setCache(new Minify_Cache_ZendPlatform());
+ *
+ *
+ * @package Minify
+ * @author Patrick van Dissel
+ */
+class Minify_Cache_ZendPlatform {
+
+
+ /**
+ * Create a Minify_Cache_ZendPlatform object, to be passed to
+ * Minify::setCache().
+ *
+ * @param int $expire seconds until expiration (default = 0
+ * meaning the item will not get an expiration date)
+ *
+ * @return null
+ */
+ public function __construct($expire = 0)
+ {
+ $this->_exp = $expire;
+ }
+
+
+ /**
+ * Write data to cache.
+ *
+ * @param string $id cache id
+ *
+ * @param string $data
+ *
+ * @return bool success
+ */
+ public function store($id, $data)
+ {
+ return output_cache_put($id, "{$_SERVER['REQUEST_TIME']}|{$data}");
+ }
+
+
+ /**
+ * Get the size of a cache entry
+ *
+ * @param string $id cache id
+ *
+ * @return int size in bytes
+ */
+ public function getSize($id)
+ {
+ return $this->_fetch($id)
+ ? strlen($this->_data)
+ : false;
+ }
+
+
+ /**
+ * Does a valid cache entry exist?
+ *
+ * @param string $id cache id
+ *
+ * @param int $srcMtime mtime of the original source file(s)
+ *
+ * @return bool exists
+ */
+ public function isValid($id, $srcMtime)
+ {
+ $ret = ($this->_fetch($id) && ($this->_lm >= $srcMtime));
+ return $ret;
+ }
+
+
+ /**
+ * Send the cached content to output
+ *
+ * @param string $id cache id
+ */
+ public function display($id)
+ {
+ echo $this->_fetch($id)
+ ? $this->_data
+ : '';
+ }
+
+
+ /**
+ * Fetch the cached content
+ *
+ * @param string $id cache id
+ *
+ * @return string
+ */
+ public function fetch($id)
+ {
+ return $this->_fetch($id)
+ ? $this->_data
+ : '';
+ }
+
+
+ private $_exp = null;
+
+
+ // cache of most recently fetched id
+ private $_lm = null;
+ private $_data = null;
+ private $_id = null;
+
+
+ /**
+ * Fetch data and timestamp from ZendPlatform, store in instance
+ *
+ * @param string $id
+ *
+ * @return bool success
+ */
+ private function _fetch($id)
+ {
+ if ($this->_id === $id) {
+ return true;
+ }
+ $ret = output_cache_get($id, $this->_exp);
+ if (false === $ret) {
+ $this->_id = null;
+ return false;
+ }
+ list($this->_lm, $this->_data) = explode('|', $ret, 2);
+ $this->_id = $id;
+ return true;
+ }
+}
diff --git a/lib/minify/lib/Minify/CommentPreserver.php b/lib/minify/lib/Minify/CommentPreserver.php
index f56eb3461c3..7a359bf9bb5 100644
--- a/lib/minify/lib/Minify/CommentPreserver.php
+++ b/lib/minify/lib/Minify/CommentPreserver.php
@@ -30,8 +30,7 @@ class Minify_CommentPreserver {
* Process a string outside of C-style comments that begin with "/*!"
*
* On each non-empty string outside these comments, the given processor
- * function will be called. The first "!" will be removed from the
- * preserved comments, and the comments will be surrounded by
+ * function will be called. The comments will be surrounded by
* Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
*
* @param string $content
@@ -65,7 +64,7 @@ class Minify_CommentPreserver {
* @param string $in input
*
* @return array 3 elements are returned. If a YUI comment is found, the
- * 2nd element is the comment and the 1st and 2nd are the surrounding
+ * 2nd element is the comment and the 1st and 3rd are the surrounding
* strings. If no comment is found, the entire string is returned as the
* 1st element and the other two are false.
*/
@@ -79,7 +78,7 @@ class Minify_CommentPreserver {
}
$ret = array(
substr($in, 0, $start)
- ,self::$prepend . '/*' . substr($in, $start + 3, $end - $start - 1) . self::$append
+ ,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append
);
$endChars = (strlen($in) - $end - 2);
$ret[] = (0 === $endChars)
diff --git a/lib/minify/lib/Minify/Controller/Base.php b/lib/minify/lib/Minify/Controller/Base.php
index 84889b3f0c5..240b54495b8 100644
--- a/lib/minify/lib/Minify/Controller/Base.php
+++ b/lib/minify/lib/Minify/Controller/Base.php
@@ -27,7 +27,7 @@ abstract class Minify_Controller_Base {
*
* @param array $options controller and Minify options
*
- * return array $options Minify::serve options
+ * @return array $options Minify::serve options
*/
abstract public function setupSources($options);
@@ -52,9 +52,10 @@ abstract class Minify_Controller_Base {
,'quiet' => false // serve() will send headers and output
,'debug' => false
- // if you override this, the response code MUST be directly after
+ // if you override these, the response codes MUST be directly after
// the first space.
,'badRequestHeader' => 'HTTP/1.0 400 Bad Request'
+ ,'errorHeader' => 'HTTP/1.0 500 Internal Server Error'
// callback function to see/modify content of all sources
,'postprocessor' => null
@@ -117,6 +118,8 @@ abstract class Minify_Controller_Base {
* be in subdirectories of these directories.
*
* @return bool file is safe
+ *
+ * @deprecated use checkAllowDirs, checkNotHidden instead
*/
public static function _fileIsSafe($file, $safeDirs)
{
@@ -134,15 +137,58 @@ abstract class Minify_Controller_Base {
list($revExt) = explode('.', strrev($base));
return in_array(strrev($revExt), array('js', 'css', 'html', 'txt'));
}
-
+
/**
- * @var array instances of Minify_Source, which provide content and
- * any individual minification needs.
+ * @param string $file
+ * @param array $allowDirs
+ * @param string $uri
+ * @return bool
+ * @throws Exception
+ */
+ public static function checkAllowDirs($file, $allowDirs, $uri)
+ {
+ foreach ((array)$allowDirs as $allowDir) {
+ if (strpos($file, $allowDir) === 0) {
+ return true;
+ }
+ }
+ throw new Exception("File '$file' is outside \$allowDirs. If the path is"
+ . " resolved via an alias/symlink, look into the \$min_symlinks option."
+ . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';");
+ }
+
+ /**
+ * @param string $file
+ * @throws Exception
+ */
+ public static function checkNotHidden($file)
+ {
+ $b = basename($file);
+ if (0 === strpos($b, '.')) {
+ throw new Exception("Filename '$b' starts with period (may be hidden)");
+ }
+ }
+
+ /**
+ * instances of Minify_Source, which provide content and any individual minification needs.
+ *
+ * @var array
*
* @see Minify_Source
*/
public $sources = array();
+ /**
+ * Short name to place inside cache id
+ *
+ * The setupSources() method may choose to set this, making it easier to
+ * recognize a particular set of sources/settings in the cache folder. It
+ * will be filtered and truncated to make the final cache id <= 250 bytes.
+ *
+ * @var string
+ */
+ public $selectionId = '';
+
/**
* Mix in default controller options with user-given options
*
@@ -192,10 +238,12 @@ abstract class Minify_Controller_Base {
/**
* Send message to the Minify logger
+ *
* @param string $msg
+ *
* @return null
*/
- protected function log($msg) {
+ public function log($msg) {
require_once 'Minify/Logger.php';
Minify_Logger::log($msg);
}
diff --git a/lib/minify/lib/Minify/Controller/Groups.php b/lib/minify/lib/Minify/Controller/Groups.php
index 1ac57703ad8..2d4e43b2f7b 100644
--- a/lib/minify/lib/Minify/Controller/Groups.php
+++ b/lib/minify/lib/Minify/Controller/Groups.php
@@ -34,12 +34,11 @@ class Minify_Controller_Groups extends Minify_Controller_Base {
* Set up groups of files as sources
*
* @param array $options controller and Minify options
- * @return array Minify options
- *
- * Controller options:
- *
+ *
* 'groups': (required) array mapping PATH_INFO strings to arrays
- * of complete file paths. @see Minify_Controller_Groups
+ * of complete file paths. @see Minify_Controller_Groups
+ *
+ * @return array Minify options
*/
public function setupSources($options) {
// strip controller options
diff --git a/lib/minify/lib/Minify/Controller/MinApp.php b/lib/minify/lib/Minify/Controller/MinApp.php
index 9582d292caa..d47c60d9f78 100644
--- a/lib/minify/lib/Minify/Controller/MinApp.php
+++ b/lib/minify/lib/Minify/Controller/MinApp.php
@@ -18,8 +18,8 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
* Set up groups of files as sources
*
* @param array $options controller and Minify options
+ *
* @return array Minify options
- *
*/
public function setupSources($options) {
// filter controller options
@@ -28,64 +28,94 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
'allowDirs' => '//'
,'groupsOnly' => false
,'groups' => array()
- ,'maxFiles' => 10
+ ,'noMinPattern' => '@[-\\.]min\\.(?:js|css)$@i' // matched against basename
)
,(isset($options['minApp']) ? $options['minApp'] : array())
);
unset($options['minApp']);
$sources = array();
+ $this->selectionId = '';
+ $firstMissingResource = null;
+
if (isset($_GET['g'])) {
- // try groups
- if (! isset($cOptions['groups'][$_GET['g']])) {
- $this->log("A group configuration for \"{$_GET['g']}\" was not set");
+ // add group(s)
+ $this->selectionId .= 'g=' . $_GET['g'];
+ $keys = explode(',', $_GET['g']);
+ if ($keys != array_unique($keys)) {
+ $this->log("Duplicate group key found.");
return $options;
}
-
- $files = $cOptions['groups'][$_GET['g']];
- // if $files is a single object, casting will break it
- if (is_object($files)) {
- $files = array($files);
- } elseif (! is_array($files)) {
- $files = (array)$files;
- }
- foreach ($files as $file) {
- if ($file instanceof Minify_Source) {
- $sources[] = $file;
- continue;
- }
- if (0 === strpos($file, '//')) {
- $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
- }
- $file = realpath($file);
- if (is_file($file)) {
- $sources[] = new Minify_Source(array(
- 'filepath' => $file
- ));
- } else {
- $this->log("The path \"{$file}\" could not be found (or was not a file)");
+ $keys = explode(',', $_GET['g']);
+ foreach ($keys as $key) {
+ if (! isset($cOptions['groups'][$key])) {
+ $this->log("A group configuration for \"{$key}\" was not found");
return $options;
}
+ $files = $cOptions['groups'][$key];
+ // if $files is a single object, casting will break it
+ if (is_object($files)) {
+ $files = array($files);
+ } elseif (! is_array($files)) {
+ $files = (array)$files;
+ }
+ foreach ($files as $file) {
+ if ($file instanceof Minify_Source) {
+ $sources[] = $file;
+ continue;
+ }
+ if (0 === strpos($file, '//')) {
+ $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1);
+ }
+ $realpath = realpath($file);
+ if ($realpath && is_file($realpath)) {
+ $sources[] = $this->_getFileSource($realpath, $cOptions);
+ } else {
+ $this->log("The path \"{$file}\" (realpath \"{$realpath}\") could not be found (or was not a file)");
+ if (null === $firstMissingResource) {
+ $firstMissingResource = basename($file);
+ continue;
+ } else {
+ $secondMissingResource = basename($file);
+ $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource'");
+ return $options;
+ }
+ }
+ }
+ if ($sources) {
+ try {
+ $this->checkType($sources[0]);
+ } catch (Exception $e) {
+ $this->log($e->getMessage());
+ return $options;
+ }
+ }
}
- } elseif (! $cOptions['groupsOnly'] && isset($_GET['f'])) {
+ }
+ if (! $cOptions['groupsOnly'] && isset($_GET['f'])) {
// try user files
// The following restrictions are to limit the URLs that minify will
- // respond to. Ideally there should be only one way to reference a file.
+ // respond to.
if (// verify at least one file, files are single comma separated,
// and are all same extension
- ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'])
+ ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m)
// no "//"
|| strpos($_GET['f'], '//') !== false
// no "\"
|| strpos($_GET['f'], '\\') !== false
- // no "./"
- || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['f'])
) {
- $this->log("GET param 'f' invalid (see MinApp.php line 63)");
+ $this->log("GET param 'f' was invalid");
+ return $options;
+ }
+ $ext = ".{$m[1]}";
+ try {
+ $this->checkType($m[1]);
+ } catch (Exception $e) {
+ $this->log($e->getMessage());
return $options;
}
$files = explode(',', $_GET['f']);
- if (count($files) > $cOptions['maxFiles'] || $files != array_unique($files)) {
- $this->log("Too many or duplicate files specified");
+ if ($files != array_unique($files)) {
+ $this->log("Duplicate files were specified");
return $options;
}
if (isset($_GET['b'])) {
@@ -96,7 +126,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
// valid base
$base = "/{$_GET['b']}/";
} else {
- $this->log("GET param 'b' invalid (see MinApp.php line 84)");
+ $this->log("GET param 'b' was invalid");
return $options;
}
} else {
@@ -106,27 +136,96 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
foreach ((array)$cOptions['allowDirs'] as $allowDir) {
$allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir));
}
+ $basenames = array(); // just for cache id
foreach ($files as $file) {
- $path = $_SERVER['DOCUMENT_ROOT'] . $base . $file;
- $file = realpath($path);
- if (false === $file) {
- $this->log("Path \"{$path}\" failed realpath()");
- return $options;
- } elseif (! parent::_fileIsSafe($file, $allowDirs)) {
- $this->log("Path \"{$path}\" failed Minify_Controller_Base::_fileIsSafe()");
- return $options;
- } else {
- $sources[] = new Minify_Source(array(
- 'filepath' => $file
- ));
+ $uri = $base . $file;
+ $path = $_SERVER['DOCUMENT_ROOT'] . $uri;
+ $realpath = realpath($path);
+ if (false === $realpath || ! is_file($realpath)) {
+ $this->log("The path \"{$path}\" (realpath \"{$realpath}\") could not be found (or was not a file)");
+ if (null === $firstMissingResource) {
+ $firstMissingResource = $uri;
+ continue;
+ } else {
+ $secondMissingResource = $uri;
+ $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'");
+ return $options;
+ }
}
+ try {
+ parent::checkNotHidden($realpath);
+ parent::checkAllowDirs($realpath, $allowDirs, $uri);
+ } catch (Exception $e) {
+ $this->log($e->getMessage());
+ return $options;
+ }
+ $sources[] = $this->_getFileSource($realpath, $cOptions);
+ $basenames[] = basename($realpath, $ext);
}
+ if ($this->selectionId) {
+ $this->selectionId .= '_f=';
+ }
+ $this->selectionId .= implode(',', $basenames) . $ext;
}
if ($sources) {
+ if (null !== $firstMissingResource) {
+ array_unshift($sources, new Minify_Source(array(
+ 'id' => 'missingFile'
+ // should not cause cache invalidation
+ ,'lastModified' => 0
+ // due to caching, filename is unreliable.
+ ,'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n"
+ ,'minifier' => ''
+ )));
+ }
$this->sources = $sources;
} else {
$this->log("No sources to serve");
}
return $options;
}
+
+ /**
+ * @param string $file
+ *
+ * @param array $cOptions
+ *
+ * @return Minify_Source
+ */
+ protected function _getFileSource($file, $cOptions)
+ {
+ $spec['filepath'] = $file;
+ if ($cOptions['noMinPattern']
+ && preg_match($cOptions['noMinPattern'], basename($file))) {
+ $spec['minifier'] = '';
+ }
+ return new Minify_Source($spec);
+ }
+
+ protected $_type = null;
+
+ /**
+ * Make sure that only source files of a single type are registered
+ *
+ * @param string $sourceOrExt
+ *
+ * @throws Exception
+ */
+ public function checkType($sourceOrExt)
+ {
+ if ($sourceOrExt === 'js') {
+ $type = Minify::TYPE_JS;
+ } elseif ($sourceOrExt === 'css') {
+ $type = Minify::TYPE_CSS;
+ } elseif ($sourceOrExt->contentType !== null) {
+ $type = $sourceOrExt->contentType;
+ } else {
+ return;
+ }
+ if ($this->_type === null) {
+ $this->_type = $type;
+ } elseif ($this->_type !== $type) {
+ throw new Exception('Content-Type mismatch');
+ }
+ }
}
diff --git a/lib/minify/lib/Minify/Controller/Page.php b/lib/minify/lib/Minify/Controller/Page.php
index fa4599abd9e..de471e1248e 100644
--- a/lib/minify/lib/Minify/Controller/Page.php
+++ b/lib/minify/lib/Minify/Controller/Page.php
@@ -40,14 +40,19 @@ class Minify_Controller_Page extends Minify_Controller_Base {
$sourceSpec = array(
'filepath' => $options['file']
);
+ $f = $options['file'];
} else {
// strip controller options
$sourceSpec = array(
'content' => $options['content']
,'id' => $options['id']
);
+ $f = $options['id'];
unset($options['content'], $options['id']);
}
+ // something like "builder,index.php" or "directory,file.html"
+ $this->selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,');
+
if (isset($options['minifyAll'])) {
// this will be the 2nd argument passed to Minify_HTML::minify()
$sourceSpec['minifyOptions'] = array(
diff --git a/lib/minify/lib/Minify/Controller/Version1.php b/lib/minify/lib/Minify/Controller/Version1.php
index 1861aabc11e..5279d36dd1a 100644
--- a/lib/minify/lib/Minify/Controller/Version1.php
+++ b/lib/minify/lib/Minify/Controller/Version1.php
@@ -7,7 +7,7 @@
require_once 'Minify/Controller/Base.php';
/**
- * Controller class for emulating version 1 of minify.php
+ * Controller class for emulating version 1 of minify.php (mostly a proof-of-concept)
*
*
* Minify::serve('Version1');
diff --git a/lib/minify/lib/Minify/DebugDetector.php b/lib/minify/lib/Minify/DebugDetector.php
new file mode 100644
index 00000000000..1def97484fc
--- /dev/null
+++ b/lib/minify/lib/Minify/DebugDetector.php
@@ -0,0 +1,26 @@
+
+ */
+class Minify_DebugDetector {
+ public static function shouldDebugRequest($cookie, $get, $requestUri)
+ {
+ if (isset($get['debug'])) {
+ return true;
+ }
+ if (! empty($cookie['minifyDebug'])) {
+ foreach (preg_split('/\\s+/', $cookie['minifyDebug']) as $debugUri) {
+ $pattern = '@' . preg_quote($debugUri, '@') . '@i';
+ $pattern = str_replace(array('\\*', '\\?'), array('.*', '.'), $pattern);
+ if (preg_match($pattern, $requestUri)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/lib/minify/lib/Minify/HTML.php b/lib/minify/lib/Minify/HTML.php
index fb5c1e98291..e9453ffb419 100644
--- a/lib/minify/lib/Minify/HTML.php
+++ b/lib/minify/lib/Minify/HTML.php
@@ -1,245 +1,246 @@
-
- */
-class Minify_HTML {
-
- /**
- * "Minify" an HTML page
- *
- * @param string $html
- *
- * @param array $options
- *
- * 'cssMinifier' : (optional) callback function to process content of STYLE
- * elements.
- *
- * 'jsMinifier' : (optional) callback function to process content of SCRIPT
- * elements. Note: the type attribute is ignored.
- *
- * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
- * unset, minify will sniff for an XHTML doctype.
- *
- * @return string
- */
- public static function minify($html, $options = array()) {
- $min = new Minify_HTML($html, $options);
- return $min->process();
- }
-
-
- /**
- * Create a minifier object
- *
- * @param string $html
- *
- * @param array $options
- *
- * 'cssMinifier' : (optional) callback function to process content of STYLE
- * elements.
- *
- * 'jsMinifier' : (optional) callback function to process content of SCRIPT
- * elements. Note: the type attribute is ignored.
- *
- * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
- * unset, minify will sniff for an XHTML doctype.
- *
- * @return null
- */
- public function __construct($html, $options = array())
- {
- $this->_html = str_replace("\r\n", "\n", trim($html));
- if (isset($options['xhtml'])) {
- $this->_isXhtml = (bool)$options['xhtml'];
- }
- if (isset($options['cssMinifier'])) {
- $this->_cssMinifier = $options['cssMinifier'];
- }
- if (isset($options['jsMinifier'])) {
- $this->_jsMinifier = $options['jsMinifier'];
- }
- }
-
-
- /**
- * Minify the markeup given in the constructor
- *
- * @return string
- */
- public function process()
- {
- if ($this->_isXhtml === null) {
- $this->_isXhtml = (false !== strpos($this->_html, '_html);
-
- // fill placeholders
- $this->_html = str_replace(
- array_keys($this->_placeholders)
- ,array_values($this->_placeholders)
- ,$this->_html
- );
- return $this->_html;
- }
-
- protected function _commentCB($m)
- {
- return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%';
- $this->_placeholders[$placeholder] = $content;
- return $placeholder;
- }
-
- protected $_isXhtml = null;
- protected $_replacementHash = null;
- protected $_placeholders = array();
- protected $_cssMinifier = null;
- protected $_jsMinifier = null;
-
- protected function _outsideTagCB($m)
- {
- return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
- }
-
- protected function _removePreCB($m)
- {
- return $this->_reservePlace($m[1]);
- }
-
- protected function _removeTextareaCB($m)
- {
- return $this->_reservePlace($m[1]);
- }
-
- protected function _removeStyleCB($m)
- {
- $openStyle = $m[1];
- $css = $m[2];
- // remove HTML comments
- $css = preg_replace('/(?:^\\s*\\s*$)/', '', $css);
-
- // remove CDATA section markers
- $css = $this->_removeCdata($css);
-
- // minify
- $minifier = $this->_cssMinifier
- ? $this->_cssMinifier
- : 'trim';
- $css = call_user_func($minifier, $css);
-
- return $this->_reservePlace($this->_needsCdata($css)
- ? "{$openStyle}/**/"
- : "{$openStyle}{$css}"
- );
- }
-
- protected function _removeScriptCB($m)
- {
- $openScript = $m[2];
- $js = $m[3];
-
- // whitespace surrounding? preserve at least one space
- $ws1 = ($m[1] === '') ? '' : ' ';
- $ws2 = ($m[4] === '') ? '' : ' ';
-
- // remove HTML comments (and ending "//" if present)
- $js = preg_replace('/(?:^\\s*\\s*$)/', '', $js);
-
- // remove CDATA section markers
- $js = $this->_removeCdata($js);
-
- // minify
- $minifier = $this->_jsMinifier
- ? $this->_jsMinifier
- : 'trim';
- $js = call_user_func($minifier, $js);
-
- return $this->_reservePlace($this->_needsCdata($js)
- ? "{$ws1}{$openScript}/**/{$ws2}"
- : "{$ws1}{$openScript}{$js}{$ws2}"
- );
- }
-
- protected function _removeCdata($str)
- {
- return (false !== strpos($str, ''), '', $str)
- : $str;
- }
-
- protected function _needsCdata($str)
- {
- return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
- }
-}
+
+ */
+class Minify_HTML {
+
+ /**
+ * "Minify" an HTML page
+ *
+ * @param string $html
+ *
+ * @param array $options
+ *
+ * 'cssMinifier' : (optional) callback function to process content of STYLE
+ * elements.
+ *
+ * 'jsMinifier' : (optional) callback function to process content of SCRIPT
+ * elements. Note: the type attribute is ignored.
+ *
+ * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
+ * unset, minify will sniff for an XHTML doctype.
+ *
+ * @return string
+ */
+ public static function minify($html, $options = array()) {
+ $min = new Minify_HTML($html, $options);
+ return $min->process();
+ }
+
+
+ /**
+ * Create a minifier object
+ *
+ * @param string $html
+ *
+ * @param array $options
+ *
+ * 'cssMinifier' : (optional) callback function to process content of STYLE
+ * elements.
+ *
+ * 'jsMinifier' : (optional) callback function to process content of SCRIPT
+ * elements. Note: the type attribute is ignored.
+ *
+ * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
+ * unset, minify will sniff for an XHTML doctype.
+ *
+ * @return null
+ */
+ public function __construct($html, $options = array())
+ {
+ $this->_html = str_replace("\r\n", "\n", trim($html));
+ if (isset($options['xhtml'])) {
+ $this->_isXhtml = (bool)$options['xhtml'];
+ }
+ if (isset($options['cssMinifier'])) {
+ $this->_cssMinifier = $options['cssMinifier'];
+ }
+ if (isset($options['jsMinifier'])) {
+ $this->_jsMinifier = $options['jsMinifier'];
+ }
+ }
+
+
+ /**
+ * Minify the markeup given in the constructor
+ *
+ * @return string
+ */
+ public function process()
+ {
+ if ($this->_isXhtml === null) {
+ $this->_isXhtml = (false !== strpos($this->_html, '_html);
+
+ // fill placeholders
+ $this->_html = str_replace(
+ array_keys($this->_placeholders)
+ ,array_values($this->_placeholders)
+ ,$this->_html
+ );
+ // issue 229: multi-pass to catch scripts that didn't get replaced in textareas
+ $this->_html = str_replace(
+ array_keys($this->_placeholders)
+ ,array_values($this->_placeholders)
+ ,$this->_html
+ );
+ return $this->_html;
+ }
+
+ protected function _commentCB($m)
+ {
+ return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%';
+ $this->_placeholders[$placeholder] = $content;
+ return $placeholder;
+ }
+
+ protected $_isXhtml = null;
+ protected $_replacementHash = null;
+ protected $_placeholders = array();
+ protected $_cssMinifier = null;
+ protected $_jsMinifier = null;
+
+ protected function _removePreCB($m)
+ {
+ return $this->_reservePlace("_reservePlace("
*
- * If you do not want ampersands as HTML entities, set Minify_Build::$ampersand = "&"
- * before using this function.
- *
- * @param string $group a key from groupsConfig.php
- * @param boolean $forceAmpersand (default false) Set to true if the RewriteRule
- * directives in .htaccess are functional. This will remove the "?" from URIs, making them
- * more cacheable by proxies.
+ * @param mixed $keyOrFiles a group key or array of file paths/URIs
+ * @param array $opts options:
+ * 'farExpires' : (default true) append a modified timestamp for cache revving
+ * 'debug' : (default false) append debug flag
+ * 'charset' : (default 'UTF-8') for htmlspecialchars
+ * 'minAppUri' : (default '/min') URI of min directory
+ * 'rewriteWorks' : (default true) does mod_rewrite work in min app?
+ * 'groupsConfigFile' : specify if different
* @return string
- */
-function Minify_groupUri($group, $forceAmpersand = false)
-{
- $path = $forceAmpersand
- ? "/g={$group}"
- : "/?g={$group}";
- return _Minify_getBuild($group)->uri(
- '/' . basename(dirname(__FILE__)) . $path
- ,$forceAmpersand
- );
-}
-
-
-/**
- * Get the last modification time of the source js/css files used by Minify to
- * build the page.
- *
- * If you're caching the output of Minify_groupUri(), you'll want to rebuild
- * the cache if it's older than this timestamp.
- *
- *
- * // simplistic HTML cache system
- * $file = '/path/to/cache/file';
- * if (! file_exists($file) || filemtime($file) < Minify_groupsMtime(array('js', 'css'))) {
- * // (re)build cache
- * $page = buildPage(); // this calls Minify_groupUri() for js and css
- * file_put_contents($file, $page);
- * echo $page;
- * exit();
- * }
- * readfile($file);
- *
- *
- * @param array $groups an array of keys from groupsConfig.php
- * @return int Unix timestamp of the latest modification
- */
-function Minify_groupsMtime($groups)
-{
- $max = 0;
- foreach ((array)$groups as $group) {
- $max = max($max, _Minify_getBuild($group)->lastModified);
- }
- return $max;
-}
-
-/**
- * @param string $group a key from groupsConfig.php
- * @return Minify_Build
- * @private
*/
-function _Minify_getBuild($group)
+function Minify_getUri($keyOrFiles, $opts = array())
{
- static $builds = array();
- static $gc = false;
- if (false === $gc) {
- $gc = (require dirname(__FILE__) . '/groupsConfig.php');
+ return Minify_HTML_Helper::getUri($keyOrFiles, $opts);
+}
+
+
+/**
+ * Get the last modification time of several source js/css files. If you're
+ * caching the output of Minify_getUri(), you might want to know if one of the
+ * dependent source files has changed so you can update the HTML.
+ *
+ * Since this makes a bunch of stat() calls, you might not want to check this
+ * on every request.
+ *
+ * @param array $keysAndFiles group keys and/or file paths/URIs.
+ * @return int latest modification time of all given keys/files
+ */
+function Minify_mtime($keysAndFiles, $groupsConfigFile = null)
+{
+ $gc = null;
+ if (! $groupsConfigFile) {
+ $groupsConfigFile = dirname(__FILE__) . '/groupsConfig.php';
}
- if (! isset($builds[$group])) {
- $builds[$group] = new Minify_Build($gc[$group]);
+ $sources = array();
+ foreach ($keysAndFiles as $keyOrFile) {
+ if (is_object($keyOrFile)
+ || 0 === strpos($keyOrFile, '/')
+ || 1 === strpos($keyOrFile, ':\\')) {
+ // a file/source obj
+ $sources[] = $keyOrFile;
+ } else {
+ if (! $gc) {
+ $gc = (require $groupsConfigFile);
+ }
+ foreach ($gc[$keyOrFile] as $source) {
+ $sources[] = $source;
+ }
+ }
}
- return $builds[$group];
+ return Minify_HTML_Helper::getLastModified($sources);
}
diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml
index f706bdeab89..9c98bbc3193 100644
--- a/lib/thirdpartylibs.xml
+++ b/lib/thirdpartylibs.xml
@@ -81,7 +81,7 @@