mirror of
https://github.com/mrclay/minify.git
synced 2025-08-12 09:05:08 +02:00
Work on: Issue 120, Issue 170, Issue 152, Issue 125, Issue 134, Issue 143
Broke some tests
This commit is contained in:
10
README.txt
10
README.txt
@@ -16,12 +16,14 @@ See UPGRADING.txt for instructions.
|
|||||||
INSTALLATION AND USAGE:
|
INSTALLATION AND USAGE:
|
||||||
|
|
||||||
1. Place the /min/ directory as a child of your DOCUMENT_ROOT
|
1. Place the /min/ directory as a child of your DOCUMENT_ROOT
|
||||||
directory: i.e. you will have: /home/user/www/public_html/min
|
directory: i.e. you will have: /home/user/www/min
|
||||||
|
|
||||||
2. Open http://yourdomain/min/ in a web browser. This will forward
|
2. Open http://yourdomain/min/ in a web browser. This will forward
|
||||||
you to the Minify URI Builder application, which will help you
|
you to the Minify URI Builder application, which will help you
|
||||||
quickly start using Minify to serve content on your site.
|
quickly start using Minify to serve content on your site.
|
||||||
|
|
||||||
|
See the User Guide: http://code.google.com/p/minify/wiki/UserGuide
|
||||||
|
|
||||||
|
|
||||||
UNIT TESTING:
|
UNIT TESTING:
|
||||||
|
|
||||||
@@ -36,12 +38,6 @@ components with more verbose output.)
|
|||||||
3. Remove /min_unit_tests/ from your DOCUMENT_ROOT when you are done.
|
3. Remove /min_unit_tests/ from your DOCUMENT_ROOT when you are done.
|
||||||
|
|
||||||
|
|
||||||
EXTRAS:
|
|
||||||
|
|
||||||
The min_extras folder contains files for benchmarking using Apache ab on Windows
|
|
||||||
and a couple single-use tools. DO NOT place this on your production server.
|
|
||||||
|
|
||||||
|
|
||||||
FILE ENCODINGS
|
FILE ENCODINGS
|
||||||
|
|
||||||
Minify *should* work fine with files encoded in UTF-8 or other 8-bit
|
Minify *should* work fine with files encoded in UTF-8 or other 8-bit
|
||||||
|
@@ -1,4 +1,13 @@
|
|||||||
<IfModule mod_rewrite.c>
|
<IfModule mod_rewrite.c>
|
||||||
RewriteEngine on
|
RewriteEngine on
|
||||||
RewriteRule ^([a-z]=.*) index.php?$1 [L,NE]
|
|
||||||
|
# You may need RewriteBase on some servers
|
||||||
|
#RewriteBase /min
|
||||||
|
|
||||||
|
# rewrite URLs like "/min/f=..." to "/min/?f=..."
|
||||||
|
RewriteRule ^([bfg]=.*) index.php?$1 [L,NE]
|
||||||
|
</IfModule>
|
||||||
|
<IfModule mod_env.c>
|
||||||
|
# In case AddOutputFilterByType has been added
|
||||||
|
SetEnv no-gzip
|
||||||
</IfModule>
|
</IfModule>
|
@@ -66,9 +66,9 @@ to the /js and /themes/default directories, use:
|
|||||||
$min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default');
|
$min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default');
|
||||||
|
|
||||||
|
|
||||||
GROUPS: FASTER PERFORMANCE AND BETTER URLS
|
GROUPS: NICER URLS
|
||||||
|
|
||||||
For the best performance, edit groupsConfig.php to pre-specify groups of files
|
For nicer URLs, edit groupsConfig.php to pre-specify groups of files
|
||||||
to be combined under preset keys. E.g., here's an example configuration in
|
to be combined under preset keys. E.g., here's an example configuration in
|
||||||
groupsConfig.php:
|
groupsConfig.php:
|
||||||
|
|
||||||
|
@@ -202,7 +202,7 @@ var MUB = {
|
|||||||
$('#sources').html('');
|
$('#sources').html('');
|
||||||
$('#add button').click(MUB.addButtonClick);
|
$('#add button').click(MUB.addButtonClick);
|
||||||
// make easier to copy text out of
|
// make easier to copy text out of
|
||||||
$('#uriHtml, #groupConfig').click(function () {
|
$('#uriHtml, #groupConfig, #symlinkOpt').click(function () {
|
||||||
this.select();
|
this.select();
|
||||||
}).focus(function () {
|
}).focus(function () {
|
||||||
this.select();
|
this.select();
|
||||||
@@ -223,10 +223,9 @@ var MUB = {
|
|||||||
return false;
|
return false;
|
||||||
}).attr({title:'Add file +'});
|
}).attr({title:'Add file +'});
|
||||||
} else {
|
} else {
|
||||||
// copy bookmarklet code into href
|
// setup bookmarklet 1
|
||||||
var bmUri = location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1);
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url : '../?f=' + bmUri
|
url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1)
|
||||||
,success : function (code) {
|
,success : function (code) {
|
||||||
$('#bm')[0].href = code
|
$('#bm')[0].href = code
|
||||||
.replace('%BUILDER_URL%', location.href)
|
.replace('%BUILDER_URL%', location.href)
|
||||||
@@ -237,6 +236,14 @@ var MUB = {
|
|||||||
$.browser.msie && $('#getBm p:last').append(' Sorry, not supported in MSIE!');
|
$.browser.msie && $('#getBm p:last').append(' Sorry, not supported in MSIE!');
|
||||||
MUB.addButtonClick();
|
MUB.addButtonClick();
|
||||||
}
|
}
|
||||||
|
// setup bookmarklet 2
|
||||||
|
$.ajax({
|
||||||
|
url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm2.js').substr(1)
|
||||||
|
,success : function (code) {
|
||||||
|
$('#bm2')[0].href = code.replace(/\n/g, ' ');
|
||||||
|
}
|
||||||
|
,dataType : 'text'
|
||||||
|
});
|
||||||
MUB.checkRewrite();
|
MUB.checkRewrite();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
14
min/builder/bm2.js
Normal file
14
min/builder/bm2.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
javascript:(function(){
|
||||||
|
var d = document
|
||||||
|
,c = d.cookie
|
||||||
|
,m = c.match(/\bminDebug=([^; ]+)/)
|
||||||
|
,v = m ? decodeURIComponent(m[1]) : ''
|
||||||
|
,p = prompt('Debug Minify URIs on "' + location.hostname + '" \ncontaining: (empty to disable)', v)
|
||||||
|
;
|
||||||
|
if (p === null) return;
|
||||||
|
p = p.replace(/\s+/g, '');
|
||||||
|
v = (p === '')
|
||||||
|
? 'minDebug=; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/'
|
||||||
|
: 'minDebug=' + encodeURIComponent(p) + '; path=/';
|
||||||
|
d.cookie = v;
|
||||||
|
})();
|
@@ -8,6 +8,20 @@ if (phpversion() < 5) {
|
|||||||
$encodeOutput = (function_exists('gzdeflate')
|
$encodeOutput = (function_exists('gzdeflate')
|
||||||
&& !ini_get('zlib.output_compression'));
|
&& !ini_get('zlib.output_compression'));
|
||||||
|
|
||||||
|
// recommend $min_symlinks setting for Apache UserDir
|
||||||
|
$symlinkOption = '';
|
||||||
|
if (0 === strpos($_SERVER["SERVER_SOFTWARE"], 'Apache/')
|
||||||
|
&& preg_match('@^/\\~(\\w+)/@', $_SERVER['REQUEST_URI'], $m)
|
||||||
|
) {
|
||||||
|
$userDir = DIRECTORY_SEPARATOR . $m[1] . DIRECTORY_SEPARATOR;
|
||||||
|
if (false !== strpos(__FILE__, $userDir)) {
|
||||||
|
$sm = array();
|
||||||
|
$sm["//~{$m[1]}"] = dirname(dirname(__FILE__));
|
||||||
|
$array = str_replace('array (', 'array(', var_export($sm, 1));
|
||||||
|
$symlinkOption = "\$min_symlinks = $array;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
require dirname(__FILE__) . '/../config.php';
|
require dirname(__FILE__) . '/../config.php';
|
||||||
|
|
||||||
if (! $min_enableBuilder) {
|
if (! $min_enableBuilder) {
|
||||||
@@ -18,8 +32,8 @@ if (! $min_enableBuilder) {
|
|||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
|
|
||||||
<title>Minify URI Builder</title>
|
<title>Minify URI Builder</title>
|
||||||
|
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
body {margin:1em 60px;}
|
body {margin:1em 60px;}
|
||||||
h1, h2, h3 {margin-left:-25px; position:relative;}
|
h1, h2, h3 {margin-left:-25px; position:relative;}
|
||||||
@@ -39,14 +53,24 @@ b {color:#c00}
|
|||||||
.topWarning a {color:#fff;}
|
.topWarning a {color:#fff;}
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
|
<?php if ($symlinkOption): ?>
|
||||||
|
<div class=topNote><strong>Note:</strong> It looks like you're running Minify in a user
|
||||||
|
directory. You may need the following option in /min/config.php to have URIs
|
||||||
|
correctly rewritten in CSS output:
|
||||||
|
<br><textarea id=symlinkOpt rows=3 cols=80 readonly><?php echo htmlspecialchars($symlinkOption); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<p class=topWarning id=jsDidntLoad><strong>Uh Oh.</strong> Minify was unable to
|
<p class=topWarning id=jsDidntLoad><strong>Uh Oh.</strong> Minify was unable to
|
||||||
serve the Javascript for this app. <a href="http://code.google.com/p/minify/wiki/Debugging">Enable
|
serve the Javascript for this app. To troubleshoot this,
|
||||||
FirePHP debugging</a> and request the <a id=builderScriptSrc href=#>Minify URL</a> directly.
|
<a href="http://code.google.com/p/minify/wiki/Debugging">enable FirePHP debugging</a>
|
||||||
|
and request the <a id=builderScriptSrc href=#>Minify URL</a> directly. Hopefully the
|
||||||
|
FirePHP console will report the cause of the error.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<?php if (! isset($min_cachePath)): ?>
|
<?php if (! isset($min_cachePath)): ?>
|
||||||
<p class=topNote><strong>Note:</strong> Please set <code>$min_cachePath</code>
|
<p class=topNote><strong>Note:</strong> You can set <code>$min_cachePath</code>
|
||||||
in /min/config.php to improve performance.</p>
|
in /min/config.php to slightly improve performance.</p>
|
||||||
<?php endIf; ?>
|
<?php endIf; ?>
|
||||||
|
|
||||||
<p id=minRewriteFailed class="hide"><strong>Note:</strong> Your webserver does not seem to
|
<p id=minRewriteFailed class="hide"><strong>Note:</strong> Your webserver does not seem to
|
||||||
@@ -111,14 +135,21 @@ in your list, and move any others to the top of the first file in your list
|
|||||||
<p>If you desire, you can use Minify URIs in imports and they will not be touched
|
<p>If you desire, you can use Minify URIs in imports and they will not be touched
|
||||||
by Minify. E.g. <code>@import "<span class=minRoot>/min/?</span>g=css2";</code></p>
|
by Minify. E.g. <code>@import "<span class=minRoot>/min/?</span>g=css2";</code></p>
|
||||||
|
|
||||||
|
<h3>Debug Mode</h3>
|
||||||
|
<p>When /min/config.php has <code>$min_allowDebugFlag = <strong>true</strong>;</code>
|
||||||
|
you can get debug output by appending <code>&debug</code> to a Minify URL, or
|
||||||
|
by sending the cookie <code>minDebug=<match></code>, where <code>minDebug=<match></code>
|
||||||
|
should match the Minify URIs you'd like to debug. This bookmarklet will allow you to
|
||||||
|
set this cookie.</p>
|
||||||
|
<p><a id=bm2>Minify Debug</a> <small>(right-click, add to bookmarks)</small></p>
|
||||||
|
|
||||||
</div><!-- #app -->
|
</div><!-- #app -->
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<p>Need help? Search or post to the <a class=ext
|
<p>Need help? Check the <a href="http://code.google.com/p/minify/w/list?can=3">wiki</a>,
|
||||||
href="http://groups.google.com/group/minify">Minify discussion list</a>.</p>
|
or post to the <a class=ext href="http://groups.google.com/group/minify">discussion
|
||||||
<p><small>This app is minified :) <a class=ext
|
list</a>.</p>
|
||||||
href="http://code.google.com/p/minify/source/browse/trunk/min/builder/index.php">view
|
<p><small>This app is minified :)</small></p>
|
||||||
source</a></small></p>
|
|
||||||
|
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
|
src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
|
||||||
@@ -163,9 +194,22 @@ $(function () {
|
|||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<?php
|
<?php
|
||||||
|
$content = ob_get_clean();
|
||||||
|
|
||||||
$serveOpts = array(
|
// setup Minify
|
||||||
'content' => ob_get_contents()
|
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 : ''
|
||||||
|
,$min_cacheFileLocking
|
||||||
|
);
|
||||||
|
Minify::$uploaderHoursBehind = $min_uploaderHoursBehind;
|
||||||
|
|
||||||
|
Minify::serve('Page', array(
|
||||||
|
'content' => $content
|
||||||
,'id' => __FILE__
|
,'id' => __FILE__
|
||||||
,'lastModifiedTime' => max(
|
,'lastModifiedTime' => max(
|
||||||
// regenerate cache if either of these change
|
// regenerate cache if either of these change
|
||||||
@@ -174,17 +218,4 @@ $serveOpts = array(
|
|||||||
)
|
)
|
||||||
,'minifyAll' => true
|
,'minifyAll' => true
|
||||||
,'encodeOutput' => $encodeOutput
|
,'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);
|
|
||||||
|
@@ -7,16 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true to log messages to FirePHP (Firefox Firebug addon).
|
* Set to true to log messages to FirePHP (Firefox Firebug addon).
|
||||||
* Set to false for no error logging (Minify may be slightly faster).
|
* Set to false for no error logging (Minify may be slightly faster).
|
||||||
@@ -30,6 +20,21 @@ $min_allowDebugFlag = false;
|
|||||||
$min_errorLogger = false;
|
$min_errorLogger = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To allow debugging, 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;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow use of the Minify URI Builder app. If you no longer need
|
* Allow use of the Minify URI Builder app. If you no longer need
|
||||||
* this, set to false.
|
* this, set to false.
|
||||||
|
@@ -35,9 +35,16 @@ foreach ($min_symlinks as $uri => $target) {
|
|||||||
$min_serveOptions['minApp']['allowDirs'][] = $target;
|
$min_serveOptions['minApp']['allowDirs'][] = $target;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($min_allowDebugFlag && isset($_GET['debug'])) {
|
if ($min_allowDebugFlag) {
|
||||||
|
if (! empty($_COOKIE['minDebug'])
|
||||||
|
&& false !== strpos($_SERVER['REQUEST_URI'], $_COOKIE['minDebug'])) {
|
||||||
$min_serveOptions['debug'] = true;
|
$min_serveOptions['debug'] = true;
|
||||||
}
|
}
|
||||||
|
// allow GET to override
|
||||||
|
if (isset($_GET['debug'])) {
|
||||||
|
$min_serveOptions['debug'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($min_errorLogger) {
|
if ($min_errorLogger) {
|
||||||
require_once 'Minify/Logger.php';
|
require_once 'Minify/Logger.php';
|
||||||
|
@@ -75,9 +75,8 @@ class HTTP_ConditionalGet {
|
|||||||
/**
|
/**
|
||||||
* @param array $spec options
|
* @param array $spec options
|
||||||
*
|
*
|
||||||
* 'isPublic': (bool) if true, the Cache-Control header will contain
|
* 'isPublic': (bool) if false, the Cache-Control header will contain
|
||||||
* "public", allowing proxies to cache the content. Otherwise "private" will
|
* "private", allowing only browser caching. (default false)
|
||||||
* be sent, allowing only browser caching. (default false)
|
|
||||||
*
|
*
|
||||||
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
* 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
|
||||||
* will be sent with content. This is recommended.
|
* will be sent with content. This is recommended.
|
||||||
@@ -150,7 +149,10 @@ class HTTP_ConditionalGet {
|
|||||||
} elseif (isset($spec['contentHash'])) { // Use the hash as the ETag
|
} elseif (isset($spec['contentHash'])) { // Use the hash as the ETag
|
||||||
$this->_setEtag($spec['contentHash'] . $etagAppend, $scope);
|
$this->_setEtag($spec['contentHash'] . $etagAppend, $scope);
|
||||||
}
|
}
|
||||||
$this->_headers['Cache-Control'] = "max-age={$maxAge}, {$scope}";
|
$privacy = ($scope === 'private')
|
||||||
|
? ', private'
|
||||||
|
: '';
|
||||||
|
$this->_headers['Cache-Control'] = "max-age={$maxAge}{$privacy}";
|
||||||
// invalidate cache if disabled, otherwise check
|
// invalidate cache if disabled, otherwise check
|
||||||
$this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate'])
|
$this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate'])
|
||||||
? false
|
? false
|
||||||
@@ -332,11 +334,8 @@ class HTTP_ConditionalGet {
|
|||||||
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
// strip off IE's extra data (semicolon)
|
||||||
if (false !== ($semicolon = strrpos($ifModifiedSince, ';'))) {
|
list($ifModifiedSince) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE'], 2);
|
||||||
// IE has tacked on extra data to this header, strip it
|
|
||||||
$ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
|
|
||||||
}
|
|
||||||
if (strtotime($ifModifiedSince) >= $this->_lmTime) {
|
if (strtotime($ifModifiedSince) >= $this->_lmTime) {
|
||||||
// Apache 2.2's behavior. If there was no ETag match, send the
|
// Apache 2.2's behavior. If there was no ETag match, send the
|
||||||
// non-encoded version of the ETag value.
|
// non-encoded version of the ETag value.
|
||||||
|
@@ -171,7 +171,8 @@ class JSMin {
|
|||||||
}
|
}
|
||||||
if (ord($this->a) <= self::ORD_LF) {
|
if (ord($this->a) <= self::ORD_LF) {
|
||||||
throw new JSMin_UnterminatedStringException(
|
throw new JSMin_UnterminatedStringException(
|
||||||
"Unterminated String: {$str}");
|
"JSMin: Unterminated String at byte "
|
||||||
|
. $this->inputIndex . ": {$str}");
|
||||||
}
|
}
|
||||||
$str .= $this->a;
|
$str .= $this->a;
|
||||||
if ($this->a === '\\') {
|
if ($this->a === '\\') {
|
||||||
@@ -198,7 +199,8 @@ class JSMin {
|
|||||||
$pattern .= $this->a;
|
$pattern .= $this->a;
|
||||||
} elseif (ord($this->a) <= self::ORD_LF) {
|
} elseif (ord($this->a) <= self::ORD_LF) {
|
||||||
throw new JSMin_UnterminatedRegExpException(
|
throw new JSMin_UnterminatedRegExpException(
|
||||||
"Unterminated RegExp: {$pattern}");
|
"JSMin: Unterminated RegExp at byte "
|
||||||
|
. $this->inputIndex .": {$pattern}");
|
||||||
}
|
}
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
}
|
}
|
||||||
@@ -310,7 +312,9 @@ class JSMin {
|
|||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
} elseif ($get === null) {
|
} elseif ($get === null) {
|
||||||
throw new JSMin_UnterminatedCommentException("Unterminated Comment: /*{$comment}");
|
throw new JSMin_UnterminatedCommentException(
|
||||||
|
"JSMin: Unterminated comment at byte "
|
||||||
|
. $this->inputIndex . ": /*{$comment}");
|
||||||
}
|
}
|
||||||
$comment .= $get;
|
$comment .= $get;
|
||||||
}
|
}
|
||||||
|
@@ -227,6 +227,8 @@ class Minify {
|
|||||||
);
|
);
|
||||||
if (self::$_options['maxAge'] > 0) {
|
if (self::$_options['maxAge'] > 0) {
|
||||||
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
$cgOptions['maxAge'] = self::$_options['maxAge'];
|
||||||
|
} elseif (self::$_options['debug']) {
|
||||||
|
$cgOptions['invalidate'] = true;
|
||||||
}
|
}
|
||||||
$cg = new HTTP_ConditionalGet($cgOptions);
|
$cg = new HTTP_ConditionalGet($cgOptions);
|
||||||
if ($cg->cacheIsValid) {
|
if ($cg->cacheIsValid) {
|
||||||
@@ -267,7 +269,7 @@ class Minify {
|
|||||||
// the goal is to use only the cache methods to sniff the length and
|
// the goal is to use only the cache methods to sniff the length and
|
||||||
// output the content, as they do not require ever loading the file into
|
// output the content, as they do not require ever loading the file into
|
||||||
// memory.
|
// memory.
|
||||||
$cacheId = 'minify_' . self::_getCacheId();
|
$cacheId = self::_getCacheId();
|
||||||
$fullCacheId = (self::$_options['encodeMethod'])
|
$fullCacheId = (self::$_options['encodeMethod'])
|
||||||
? $cacheId . '.gz'
|
? $cacheId . '.gz'
|
||||||
: $cacheId;
|
: $cacheId;
|
||||||
@@ -489,7 +491,12 @@ class Minify {
|
|||||||
if ($minifier) {
|
if ($minifier) {
|
||||||
self::$_controller->loadMinifier($minifier);
|
self::$_controller->loadMinifier($minifier);
|
||||||
// get source content and minify it
|
// get source content and minify it
|
||||||
|
try {
|
||||||
$pieces[] = call_user_func($minifier, $source->getContent(), $options);
|
$pieces[] = call_user_func($minifier, $source->getContent(), $options);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new Exception("Exception in " . $source->getId() .
|
||||||
|
": " . $e->getMessage());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$pieces[] = $source->getContent();
|
$pieces[] = $source->getContent();
|
||||||
}
|
}
|
||||||
@@ -515,17 +522,23 @@ class Minify {
|
|||||||
*
|
*
|
||||||
* Any settings that could affect output are taken into consideration
|
* Any settings that could affect output are taken into consideration
|
||||||
*
|
*
|
||||||
|
* @param string $prefix
|
||||||
|
*
|
||||||
* @return string
|
* @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, 250 - 34 - strlen($prefix));
|
||||||
|
$md5 = md5(serialize(array(
|
||||||
Minify_Source::getDigest(self::$_controller->sources)
|
Minify_Source::getDigest(self::$_controller->sources)
|
||||||
,self::$_options['minifiers']
|
,self::$_options['minifiers']
|
||||||
,self::$_options['minifierOptions']
|
,self::$_options['minifierOptions']
|
||||||
,self::$_options['postprocessor']
|
,self::$_options['postprocessor']
|
||||||
,self::$_options['bubbleCssImports']
|
,self::$_options['bubbleCssImports']
|
||||||
)));
|
)));
|
||||||
|
return "{$prefix}_{$name}_{$md5}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -144,6 +144,15 @@ abstract class Minify_Controller_Base {
|
|||||||
*/
|
*/
|
||||||
public $sources = array();
|
public $sources = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 short name to place inside cache id
|
||||||
|
*/
|
||||||
|
public $selectionId = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mix in default controller options with user-given options
|
* Mix in default controller options with user-given options
|
||||||
*
|
*
|
||||||
|
@@ -41,6 +41,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->selectionId = "g=" . $_GET['g'];
|
||||||
$files = $cOptions['groups'][$_GET['g']];
|
$files = $cOptions['groups'][$_GET['g']];
|
||||||
// if $files is a single object, casting will break it
|
// if $files is a single object, casting will break it
|
||||||
if (is_object($files)) {
|
if (is_object($files)) {
|
||||||
@@ -70,7 +71,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
// respond to. Ideally there should be only one way to reference a file.
|
// respond to. Ideally there should be only one way to reference a file.
|
||||||
if (// verify at least one file, files are single comma separated,
|
if (// verify at least one file, files are single comma separated,
|
||||||
// and are all same extension
|
// and are all same extension
|
||||||
! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'])
|
! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m)
|
||||||
// no "//"
|
// no "//"
|
||||||
|| strpos($_GET['f'], '//') !== false
|
|| strpos($_GET['f'], '//') !== false
|
||||||
// no "\"
|
// no "\"
|
||||||
@@ -81,11 +82,13 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
$this->log("GET param 'f' invalid (see MinApp.php line 63)");
|
$this->log("GET param 'f' invalid (see MinApp.php line 63)");
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
$ext = ".{$m[1]}";
|
||||||
$files = explode(',', $_GET['f']);
|
$files = explode(',', $_GET['f']);
|
||||||
if ($files != array_unique($files)) {
|
if ($files != array_unique($files)) {
|
||||||
$this->log("Duplicate files specified");
|
$this->log("Duplicate files specified");
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['b'])) {
|
if (isset($_GET['b'])) {
|
||||||
// check for validity
|
// check for validity
|
||||||
if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b'])
|
if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b'])
|
||||||
@@ -104,6 +107,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
foreach ((array)$cOptions['allowDirs'] as $allowDir) {
|
foreach ((array)$cOptions['allowDirs'] as $allowDir) {
|
||||||
$allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir));
|
$allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir));
|
||||||
}
|
}
|
||||||
|
$basenames = array(); // just for cache id
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$path = $_SERVER['DOCUMENT_ROOT'] . $base . $file;
|
$path = $_SERVER['DOCUMENT_ROOT'] . $base . $file;
|
||||||
$file = realpath($path);
|
$file = realpath($path);
|
||||||
@@ -115,8 +119,10 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
return $options;
|
return $options;
|
||||||
} else {
|
} else {
|
||||||
$sources[] = $this->_getFileSource($file, $cOptions);
|
$sources[] = $this->_getFileSource($file, $cOptions);
|
||||||
|
$basenames[] = basename($file, $ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->selectionId = implode(',', $basenames) . $ext;
|
||||||
}
|
}
|
||||||
if ($sources) {
|
if ($sources) {
|
||||||
$this->sources = $sources;
|
$this->sources = $sources;
|
||||||
|
@@ -40,14 +40,19 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
|||||||
$sourceSpec = array(
|
$sourceSpec = array(
|
||||||
'filepath' => $options['file']
|
'filepath' => $options['file']
|
||||||
);
|
);
|
||||||
|
$f = $options['file'];
|
||||||
} else {
|
} else {
|
||||||
// strip controller options
|
// strip controller options
|
||||||
$sourceSpec = array(
|
$sourceSpec = array(
|
||||||
'content' => $options['content']
|
'content' => $options['content']
|
||||||
,'id' => $options['id']
|
,'id' => $options['id']
|
||||||
);
|
);
|
||||||
|
$f = $options['id'];
|
||||||
unset($options['content'], $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'])) {
|
if (isset($options['minifyAll'])) {
|
||||||
// this will be the 2nd argument passed to Minify_HTML::minify()
|
// this will be the 2nd argument passed to Minify_HTML::minify()
|
||||||
$sourceSpec['minifyOptions'] = array(
|
$sourceSpec['minifyOptions'] = array(
|
||||||
|
4
min_unit_tests/.htaccess
Normal file
4
min_unit_tests/.htaccess
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<IfModule mod_env.c>
|
||||||
|
# In case AddOutputFilterByType has been added
|
||||||
|
SetEnv no-gzip
|
||||||
|
</IfModule>
|
@@ -29,7 +29,7 @@ function test_Minify()
|
|||||||
'Vary' => 'Accept-Encoding',
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"pub{$lastModified}\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=1800, public',
|
'Cache-Control' => 'max-age=1800',
|
||||||
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -49,7 +49,7 @@ function test_Minify()
|
|||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
! class_exists('Minify_CSS', false)
|
! class_exists('Minify_CSS', false)
|
||||||
&& ! class_exists('Minify_Cache', false)
|
&& ! class_exists('Minify_Cache_File', false)
|
||||||
,'Minify : cache, and minifier classes aren\'t loaded for 304s'
|
,'Minify : cache, and minifier classes aren\'t loaded for 304s'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -70,11 +70,13 @@ function test_Minify()
|
|||||||
'Vary' => 'Accept-Encoding',
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"pub{$lastModified}\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=86400, public',
|
'Cache-Control' => 'max-age=86400',
|
||||||
'Content-Length' => strlen($content),
|
'Content-Length' => strlen($content),
|
||||||
'Content-Type' => 'application/x-javascript; charset=utf-8',
|
'Content-Type' => 'application/x-javascript; charset=utf-8',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
unset($_SERVER['HTTP_IF_NONE_MATCH']);
|
||||||
|
unset($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
'files' => array(
|
'files' => array(
|
||||||
$minifyTestPath . '/email.js'
|
$minifyTestPath . '/email.js'
|
||||||
@@ -185,7 +187,7 @@ function test_Minify()
|
|||||||
'Vary' => 'Accept-Encoding',
|
'Vary' => 'Accept-Encoding',
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"pub{$lastModified}\"",
|
'ETag' => "\"pub{$lastModified}\"",
|
||||||
'Cache-Control' => 'max-age=0, public',
|
'Cache-Control' => 'max-age=0',
|
||||||
'Content-Length' => strlen($expectedContent),
|
'Content-Length' => strlen($expectedContent),
|
||||||
'Content-Type' => 'text/css; charset=utf-8',
|
'Content-Type' => 'text/css; charset=utf-8',
|
||||||
)
|
)
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
//phpinfo(); exit();
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
// called directly
|
// called directly
|
||||||
if (isset($_GET['getOutputCompression'])) {
|
if (isset($_GET['getOutputCompression'])) {
|
||||||
@@ -9,6 +11,10 @@ if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
|||||||
if (isset($_GET['hello'])) {
|
if (isset($_GET['hello'])) {
|
||||||
// try to disable (may not work)
|
// try to disable (may not work)
|
||||||
ini_set('zlib.output_compression', '0');
|
ini_set('zlib.output_compression', '0');
|
||||||
|
$type = ($_GET['hello'] == 'js')
|
||||||
|
? 'application/x-javascript'
|
||||||
|
: "text/{$_GET['hello']}";
|
||||||
|
header("Content-Type: {$type}");
|
||||||
echo 'World!';
|
echo 'World!';
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -61,41 +67,72 @@ function test_environment()
|
|||||||
. " or .htaccess.\n";
|
. " or .htaccess.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$fp = fopen($thisUrl . '?hello=1', 'r', false, stream_context_create(array(
|
$testJs = _test_environment_getHello($thisUrl . '?hello=js');
|
||||||
|
$passed = assertTrue(
|
||||||
|
$testJs['length'] == 6
|
||||||
|
,'environment : PHP/server should not auto-encode application/x-javascript output'
|
||||||
|
);
|
||||||
|
|
||||||
|
$testCss = _test_environment_getHello($thisUrl . '?hello=css');
|
||||||
|
$passed = $passed && assertTrue(
|
||||||
|
$testCss['length'] == 6
|
||||||
|
,'environment : PHP/server should not auto-encode text/css output'
|
||||||
|
);
|
||||||
|
|
||||||
|
$testHtml = _test_environment_getHello($thisUrl . '?hello=html');
|
||||||
|
$passed = $passed && assertTrue(
|
||||||
|
$testHtml['length'] == 6
|
||||||
|
,'environment : PHP/server should not auto-encode text/html output'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $passed) {
|
||||||
|
$testFake = _test_environment_getHello($thisUrl . '?hello=faketype');
|
||||||
|
if ($testFake['length'] == 6) {
|
||||||
|
echo "!NOTE: environment : Server does not auto-encode arbitrary types. This\n"
|
||||||
|
. " may indicate that the auto-encoding is caused by Apache's \n"
|
||||||
|
. " AddOutputFilterByType.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _test_environment_getHello($url)
|
||||||
|
{
|
||||||
|
$fp = fopen($url, 'r', false, stream_context_create(array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
'method' => "GET",
|
'method' => "GET",
|
||||||
'header' => "Accept-Encoding: deflate, gzip\r\n"
|
'timeout' => '10',
|
||||||
|
'header' => "Accept-Encoding: deflate, gzip\r\n",
|
||||||
)
|
)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
$meta = stream_get_meta_data($fp);
|
$meta = stream_get_meta_data($fp);
|
||||||
|
$encoding = '';
|
||||||
$passed = true;
|
$length = 0;
|
||||||
foreach ($meta['wrapper_data'] as $i => $header) {
|
foreach ($meta['wrapper_data'] as $i => $header) {
|
||||||
if ((preg_match('@^Content-Length: (\\d+)$@i', $header, $m) && $m[1] !== '6')
|
if (preg_match('@^Content-Length:\\s*(\\d+)$@i', $header, $m)) {
|
||||||
|| preg_match('@^Content-Encoding:@i', $header, $m)
|
$length = $m[1];
|
||||||
) {
|
} elseif (preg_match('@^Content-Encoding:\\s*(\\S+)$@i', $header, $m)) {
|
||||||
$passed = false;
|
if ($m[1] !== 'identity') {
|
||||||
break;
|
$encoding = $m[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$streamContents = stream_get_contents($fp);
|
$streamContents = stream_get_contents($fp);
|
||||||
if ($passed && $streamContents !== 'World!') {
|
|
||||||
$passed = false;
|
|
||||||
}
|
|
||||||
assertTrue(
|
|
||||||
$passed
|
|
||||||
,'environment : PHP/server does not auto-HTTP-encode content'
|
|
||||||
);
|
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
|
||||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||||
if (! $passed) {
|
if ($length != 6) {
|
||||||
echo "\nReturned content should be 6 bytes and not HTTP encoded.\n"
|
echo "\nReturned content should be 6 bytes and not HTTP encoded.\n"
|
||||||
. "Headers returned by: {$thisUrl}?hello=1\n\n";
|
. "Headers returned by: {$url}\n\n";
|
||||||
var_export($meta['wrapper_data']);
|
var_export($meta['wrapper_data']);
|
||||||
}
|
echo "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'length' => $length
|
||||||
|
,'encoding' => $encoding
|
||||||
|
,'bytes' => $streamContents
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test_environment();
|
test_environment();
|
||||||
|
Reference in New Issue
Block a user