1
0
mirror of https://github.com/mrclay/minify.git synced 2025-01-29 19:27:45 +01:00

Added/improved ab tests. Prepended "minify_" to cache filenames.

This commit is contained in:
Steve Clay 2008-06-09 20:30:11 +00:00
parent 8cde22b934
commit 4c85da1fb3
14 changed files with 765 additions and 220 deletions

View File

@ -196,7 +196,7 @@ class Minify {
// the goal is to use only the cache methods to sniff the length and
// output the content, as they do not require ever loading the file into
// memory.
$cacheId = self::_getCacheId();
$cacheId = 'minify_' . self::_getCacheId();
$encodingExtension = self::$_options['encodeMethod']
? ('deflate' === self::$_options['encodeMethod']
? '.zd'

10
web/ab_tests/README.txt Normal file
View File

@ -0,0 +1,10 @@
This is a little AB testing setup for Windows. Before committing any non-trivial
change, these tests should be run so "results_summary.txt" will be an up-to-date
document of each revision's performance.
Before testing make sure all cache locations are correct.
Double-click "test_all.bat" to run the tests. At the end, "results_summary.txt"
will be opened in notepad. For more details see "results.txt".
Delete "results.txt" before committing. We don't need this much info in svn.

3
web/ab_tests/_delimiter Normal file
View File

@ -0,0 +1,3 @@
--------------------------------------------------------------------------------

View File

@ -1,4 +0,0 @@
C:\xampp\apache\bin\ab -c 100 -n 2000 -H "Accept-Encoding: deflate, gzip" http://mc.dev/_3rd_party/minify/web/ab_tests/ideal_php/before.php > results_ideal_php.txt
C:\xampp\apache\bin\ab -c 100 -n 2000 -H "Accept-Encoding: deflate, gzip" http://mc.dev/_3rd_party/minify/web/ab_tests/minify/before.js.php > results_minify.txt
C:\xampp\apache\bin\ab -c 100 -n 2000 -H "Accept-Encoding: deflate, gzip" http://mc.dev/_3rd_party/minify/web/ab_tests/mod_deflate/before.js > results_deflate.txt
C:\xampp\apache\bin\ab -c 100 -n 2000 -H "Accept-Encoding: deflate, gzip" http://mc.dev/_3rd_party/minify/web/ab_tests/type-map/before.js.var > results_type-map.txt

View File

@ -0,0 +1,15 @@
<?php
ini_set('include_path',
dirname(__FILE__) . '/../../../lib'
. PATH_SEPARATOR . ini_get('include_path')
);
define('MINIFY_BASE_DIR', realpath(
dirname(__FILE__) . '/../minify'
));
define('MINIFY_CACHE_DIR', 'C:/xampp/tmp');
require 'Minify.php';
Minify::serve('Version1');

204
web/ab_tests/results.txt Normal file
View File

@ -0,0 +1,204 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/ideal_php/before.php
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 3.234395 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32794000 bytes
HTML transferred: 31986000 bytes
Requests per second: 618.35 [#/sec] (mean)
Time per request: 161.720 [ms] (mean)
Time per request: 1.617 [ms] (mean, across all concurrent requests)
Transfer rate: 9901.39 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 15
Processing: 46 155 656
Total: 46 155 671
--------------------------------------------------------------------------------
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/v1.0/minify.php?files=before.js
Document Length: 54159 bytes
Concurrency Level: 100
Time taken for tests: 3.968775 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 108996000 bytes
HTML transferred: 108318000 bytes
Requests per second: 503.93 [#/sec] (mean)
Time per request: 198.439 [ms] (mean)
Time per request: 1.984 [ms] (mean, across all concurrent requests)
Transfer rate: 26819.61 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 15
Processing: 78 191 297
Total: 78 191 312
--------------------------------------------------------------------------------
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/minify/test_Files.php
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 4.875031 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32764000 bytes
HTML transferred: 31986000 bytes
Requests per second: 410.25 [#/sec] (mean)
Time per request: 243.752 [ms] (mean)
Time per request: 2.438 [ms] (mean, across all concurrent requests)
Transfer rate: 6563.24 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 15
Processing: 46 236 328
Total: 46 236 343
--------------------------------------------------------------------------------
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/minify/test_Version1.php?files=before.js
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 5.609411 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32872000 bytes
HTML transferred: 31986000 bytes
Requests per second: 356.54 [#/sec] (mean)
Time per request: 280.471 [ms] (mean)
Time per request: 2.805 [ms] (mean, across all concurrent requests)
Transfer rate: 5722.70 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 15
Processing: 46 272 891
Total: 46 272 906
--------------------------------------------------------------------------------
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/mod_deflate/before.js
Document Length: 16053 bytes
Concurrency Level: 100
Time taken for tests: 11.328198 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32994000 bytes
HTML transferred: 32106000 bytes
Requests per second: 176.55 [#/sec] (mean)
Time per request: 566.410 [ms] (mean)
Time per request: 5.664 [ms] (mean, across all concurrent requests)
Transfer rate: 2844.23 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 93
Processing: 62 547 1266
Total: 62 547 1359
--------------------------------------------------------------------------------
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.2.8
Server Hostname: localhost
Server Port: 80
Document Path: /minify/web/ab_tests/type-map/before.js.var
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 4.500029 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32990000 bytes
HTML transferred: 31986000 bytes
Requests per second: 444.44 [#/sec] (mean)
Time per request: 225.001 [ms] (mean)
Time per request: 2.250 [ms] (mean, across all concurrent requests)
Transfer rate: 7159.06 [Kbytes/sec] received
Connection Times (ms)
min avg max
Connect: 0 0 15
Processing: 62 216 297
Total: 62 216 312
--------------------------------------------------------------------------------

View File

@ -1,43 +0,0 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking mc.dev (be patient)
Server Software: Apache/2.2.4
Server Hostname: mc.dev
Server Port: 80
Document Path: /_3rd_party/minify/web/ab_tests/mod_deflate/before.js
Document Length: 16053 bytes
Concurrency Level: 100
Time taken for tests: 10.734375 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 33048000 bytes
HTML transferred: 32106000 bytes
Requests per second: 186.32 [#/sec] (mean)
Time per request: 536.719 [ms] (mean)
Time per request: 5.367 [ms] (mean, across all concurrent requests)
Transfer rate: 3006.51 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 9.5 0 187
Processing: 15 531 179.0 531 1000
Waiting: 0 412 191.3 453 937
Total: 15 533 179.3 546 1000
Percentage of the requests served within a certain time (ms)
50% 546
66% 546
75% 593
80% 640
90% 750
95% 875
98% 953
99% 1000
100% 1000 (longest request)

View File

@ -1,43 +0,0 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking mc.dev (be patient)
Server Software: Apache/2.2.4
Server Hostname: mc.dev
Server Port: 80
Document Path: /_3rd_party/minify/web/ab_tests/ideal_php/before.php
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 4.437500 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32848000 bytes
HTML transferred: 31986000 bytes
Requests per second: 450.70 [#/sec] (mean)
Time per request: 221.875 [ms] (mean)
Time per request: 2.219 [ms] (mean, across all concurrent requests)
Transfer rate: 7228.85 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.6 0 15
Processing: 31 214 37.5 218 359
Waiting: 31 209 32.7 218 281
Total: 31 215 37.5 218 359
Percentage of the requests served within a certain time (ms)
50% 218
66% 218
75% 234
80% 234
90% 234
95% 250
98% 296
99% 343
100% 359 (longest request)

View File

@ -1,43 +0,0 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking mc.dev (be patient)
Server Software: Apache/2.2.4
Server Hostname: mc.dev
Server Port: 80
Document Path: /_3rd_party/minify/web/ab_tests/minify/before.js.php
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 17.312500 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32736000 bytes
HTML transferred: 31986000 bytes
Requests per second: 115.52 [#/sec] (mean)
Time per request: 865.625 [ms] (mean)
Time per request: 8.656 [ms] (mean, across all concurrent requests)
Transfer rate: 1846.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.1 0 15
Processing: 125 853 150.1 844 1296
Waiting: 125 852 150.1 843 1281
Total: 125 854 150.1 859 1296
Percentage of the requests served within a certain time (ms)
50% 859
66% 906
75% 953
80% 984
90% 1046
95% 1109
98% 1156
99% 1187
100% 1296 (longest request)

View File

@ -1,43 +0,0 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking mc.dev (be patient)
Server Software: Apache/2.2.4
Server Hostname: mc.dev
Server Port: 80
Document Path: /_3rd_party/minify/web/ab_tests/minify/before.js.php
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 6.468750 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 32818000 bytes
HTML transferred: 31986000 bytes
Requests per second: 309.18 [#/sec] (mean)
Time per request: 323.438 [ms] (mean)
Time per request: 3.234 [ms] (mean, across all concurrent requests)
Transfer rate: 4954.28 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.5 0 31
Processing: 31 313 74.8 312 828
Waiting: 31 309 70.0 312 796
Total: 31 314 74.7 312 828
Percentage of the requests served within a certain time (ms)
50% 312
66% 312
75% 328
80% 328
90% 328
95% 343
98% 578
99% 640
100% 828 (longest request)

View File

@ -1,43 +0,0 @@
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking mc.dev (be patient)
Server Software: Apache/2.2.4
Server Hostname: mc.dev
Server Port: 80
Document Path: /_3rd_party/minify/web/ab_tests/type-map/before.js.var
Document Length: 15993 bytes
Concurrency Level: 100
Time taken for tests: 4.171875 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 33044000 bytes
HTML transferred: 31986000 bytes
Requests per second: 479.40 [#/sec] (mean)
Time per request: 208.594 [ms] (mean)
Time per request: 2.086 [ms] (mean, across all concurrent requests)
Transfer rate: 7734.89 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.9 0 31
Processing: 31 202 53.4 203 453
Waiting: 15 195 52.1 203 453
Total: 31 202 53.4 203 453
Percentage of the requests served within a certain time (ms)
50% 203
66% 218
75% 218
80% 218
90% 250
95% 312
98% 343
99% 343
100% 453 (longest request)

33
web/ab_tests/test_all.bat Normal file
View File

@ -0,0 +1,33 @@
@SET PATH=%PATH%;C:\xampp\apache\bin
@SET ABCALL=ab -d -S -c 100 -n 2000 -H "Accept-Encoding: deflate, gzip" http://localhost
@SET DELIM=TYPE _delimiter
DEL results.txt
@REM baseline PHP
%ABCALL%/minify/web/ab_tests/ideal_php/before.php >> results.txt
%DELIM% >> results.txt
@REM 1.0 release
%ABCALL%/minify/web/ab_tests/v1.0/minify.php?files=before.js >> results.txt
%DELIM% >> results.txt
@REM Files controller
%ABCALL%/minify/web/ab_tests/minify/test_Files.php >> results.txt
%DELIM% >> results.txt
@REM Version1 controller
%ABCALL%/minify/web/ab_tests/minify/test_Version1.php?files=before.js >> results.txt
%DELIM% >> results.txt
@REM mod_deflate
%ABCALL%/minify/web/ab_tests/mod_deflate/before.js >> results.txt
%DELIM% >> results.txt
@REM type-map
%ABCALL%/minify/web/ab_tests/type-map/before.js.var >> results.txt
%DELIM% >> results.txt
FINDSTR "Path: Length: Requests --" results.txt > results_summary.txt
notepad results_summary.txt

View File

@ -0,0 +1,499 @@
<?php
// ab test of Minify 1.0, mostly to see how fast it can serve server-cached files.
define('MINIFY_BASE_DIR', realpath(
dirname(__FILE__) . '/../minify'
));
define('MINIFY_CACHE_DIR', 'C:/xampp/tmp');
/**
* Minify - Combines, minifies, and caches JavaScript and CSS files on demand.
*
* See http://code.google.com/p/minify/ for usage instructions.
*
* This library was inspired by jscsscomp by Maxim Martynyuk <flashkot@mail.ru>
* and by the article "Supercharged JavaScript" by Patrick Hunlock
* <wb@hunlock.com>.
*
* JSMin was originally written by Douglas Crockford <douglas@crockford.com>.
*
* Requires PHP 5.2.1+.
*
* @package Minify
* @author Ryan Grove <ryan@wonko.com>
* @copyright 2007 Ryan Grove. All rights reserved.
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version 1.1.0 (?)
* @link http://code.google.com/p/minify/
*/
if (!defined('MINIFY_BASE_DIR')) {
/**
* Base path from which all relative file paths should be resolved. By default
* this is set to the document root.
*/
define('MINIFY_BASE_DIR', realpath($_SERVER['DOCUMENT_ROOT']));
}
if (!defined('MINIFY_CACHE_DIR')) {
/** Directory where compressed files will be cached. */
define('MINIFY_CACHE_DIR', sys_get_temp_dir());
}
if (!defined('MINIFY_ENCODING')) {
/** Character set to use when outputting the minified files. */
define('MINIFY_ENCODING', 'utf-8');
}
if (!defined('MINIFY_MAX_FILES')) {
/** Maximum number of files to combine in one request. */
define('MINIFY_MAX_FILES', 16);
}
if (!defined('MINIFY_REWRITE_CSS_URLS')) {
/**
* Whether or not Minify should attempt to rewrite relative URLs used in CSS
* files so that they continue to point to the correct location after the file
* is combined and minified.
*
* Minify is pretty good at getting this right, but occasionally it can make
* mistakes. If you find that URL rewriting results in problems, you should
* disable it.
*/
define('MINIFY_REWRITE_CSS_URLS', true);
}
if (!defined('MINIFY_USE_CACHE')) {
/**
* Whether or not Minify should use a disk-based cache to increase
* performance.
*/
define('MINIFY_USE_CACHE', true);
}
/**
* Minify is a library for combining, minifying, and caching JavaScript and CSS
* files on demand before sending them to a web browser.
*
* @package Minify
* @author Ryan Grove <ryan@wonko.com>
* @copyright 2007 Ryan Grove. All rights reserved.
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version 1.1.0 (?)
* @link http://code.google.com/p/minify/
*/
class Minify {
const TYPE_CSS = 'text/css';
const TYPE_HTML = 'text/html';
const TYPE_JS = 'text/javascript';
protected $files = array();
protected $type = self::TYPE_JS;
// -- Public Static Methods --------------------------------------------------
/**
* Combines, minifies, and outputs the requested files.
*
* Inspects the $_GET array for a 'files' entry containing a comma-separated
* list and uses this as the set of files to be combined and minified.
*/
public static function handleRequest() {
// 404 if no files were requested.
if (!isset($_GET['files'])) {
header('HTTP/1.0 404 Not Found');
exit;
}
$files = array_map('trim', explode(',', $_GET['files'], MINIFY_MAX_FILES));
// 404 if the $files array is empty for some weird reason.
if (!count($files)) {
header('HTTP/1.0 404 Not Found');
exit;
}
// Determine the content type based on the extension of the first file
// requested.
if (preg_match('/\.js$/iD', $files[0])) {
$type = self::TYPE_JS;
} else if (preg_match('/\.css$/iD', $files[0])) {
$type = self::TYPE_CSS;
} else {
$type = self::TYPE_HTML;
}
// Minify and spit out the result.
try {
$minify = new Minify($type, $files);
header("Content-Type: $type;charset=".MINIFY_ENCODING);
$minify->browserCache();
echo $minify->combine();
exit;
}
catch (MinifyException $e) {
header('HTTP/1.0 404 Not Found');
echo htmlentities($e->getMessage());
exit;
}
}
/**
* Minifies the specified string and returns it.
*
* @param string $string JavaScript, CSS, or HTML string to minify
* @param string $type content type of the string (Minify::TYPE_CSS,
* Minify::TYPE_HTML, or Minify::TYPE_JS)
* @return string minified string
*/
public static function min($string, $type = self::TYPE_JS) {
switch ($type) {
case self::TYPE_CSS:
return self::minifyCSS($string);
break;
case self::TYPE_HTML:
return self::minifyHTML($string);
break;
case self::TYPE_JS:
return self::minifyJS($string);
break;
}
return $string;
}
// -- Protected Static Methods -----------------------------------------------
/**
* Minifies the specified CSS string and returns it.
*
* @param string $css CSS string
* @return string minified string
* @see minify()
* @see minifyJS()
*/
protected static function minifyCSS($css) {
// Compress whitespace.
$css = preg_replace('/\s+/', ' ', $css);
// Remove comments.
$css = preg_replace('/\/\*.*?\*\//', '', $css);
return trim($css);
}
protected static function minifyHTML($html) {
require_once dirname(__FILE__).'/lib/htmlmin.php';
return HTMLMin::minify($html);
}
/**
* Minifies the specified JavaScript string and returns it.
*
* @param string $js JavaScript string
* @return string minified string
* @see minify()
* @see minifyCSS()
*/
protected static function minifyJS($js) {
require_once dirname(__FILE__).'/../../../lib/JSMin.php';
return JSMin::minify($js);
}
/**
* Rewrites relative URLs in the specified CSS string to point to the correct
* location. URLs are assumed to be relative to the absolute path specified in
* the $path parameter.
*
* @param string $css CSS string
* @param string $path absolute path to which URLs are relative (should be a
* directory, not a file)
* @return string CSS string with rewritten URLs
*/
protected static function rewriteCSSUrls($css, $path) {
/*
Parentheses, commas, whitespace chars, single quotes, and double quotes are
escaped with a backslash as described in the CSS spec:
http://www.w3.org/TR/REC-CSS1#url
*/
$relativePath = preg_replace('/([\(\),\s\'"])/', '\\\$1',
str_replace(MINIFY_BASE_DIR, '', $path));
return preg_replace('/url\(\s*[\'"]?\/?(.+?)[\'"]?\s*\)/i', 'url('.
$relativePath.'/$1)', $css);
}
// -- Public Instance Methods ------------------------------------------------
/**
* Instantiates a new Minify object. A filename can be in the form of a
* relative path or a URL that resolves to the same site that hosts Minify.
*
* @param string $type content type of the specified files (either
* Minify::TYPE_CSS or Minify::TYPE_JS)
* @param array|string $files filename or array of filenames to be minified
*/
public function __construct($type = self::TYPE_JS, $files = array()) {
if ($type !== self::TYPE_JS && $type !== self::TYPE_CSS) {
throw new MinifyInvalidArgumentException('Invalid argument ($type): '.
$type);
}
$this->type = $type;
if (count((array) $files)) {
$this->addFile($files);
}
}
/**
* Adds the specified filename or array of filenames to the list of files to
* be minified. A filename can be in the form of a relative path or a URL
* that resolves to the same site that hosts Minify.
*
* @param array|string $files filename or array of filenames
* @see getFiles()
* @see removeFile()
*/
public function addFile($files) {
$files = @array_map(array($this, 'resolveFilePath'), (array) $files);
$this->files = array_unique(array_merge($this->files, $files));
}
/**
* Attempts to serve the combined, minified files from the cache if possible.
*
* This method first checks the ETag value and If-Modified-Since timestamp
* sent by the browser and exits with an HTTP "304 Not Modified" response if
* the requested files haven't changed since they were last sent to the
* client.
*
* If the browser hasn't cached the content, we check to see if it's been
* cached on the server and, if so, we send the cached content and exit.
*
* If neither the client nor the server has the content in its cache, we don't
* do anything.
*
* @return bool
*/
public function browserCache() {
$hash = $this->getHash();
$lastModified = $this->getLastModified();
$lastModifiedGMT = gmdate('D, d M Y H:i:s', $lastModified).' GMT';
// Check/set the ETag.
$etag = $hash.'_'.$lastModified;
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
if (strpos($_SERVER['HTTP_IF_NONE_MATCH'], $etag) !== false) {
header("Last-Modified: $lastModifiedGMT", true, 304);
exit;
}
}
header('ETag: "'.$etag.'"');
// Check If-Modified-Since.
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
if ($lastModified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
header("Last-Modified: $lastModifiedGMT", true, 304);
exit;
}
}
header("Last-Modified: $lastModifiedGMT");
return false;
}
/**
* Combines and returns the contents of all files that have been added with
* addFile() or via this class's constructor.
*
* If MINIFY_USE_CACHE is true, the content will be returned from the server's
* cache if the cache is up to date; otherwise the new content will be saved
* to the cache for future use.
*
* @param bool $minify minify the combined contents before returning them
* @return string combined file contents
*/
public function combine($minify = true) {
// Return contents from server cache if possible.
if (MINIFY_USE_CACHE) {
if ($cacheResult = $this->serverCache(true)) {
return $cacheResult;
}
}
// Combine contents.
$combined = array();
foreach($this->files as $file) {
if ($this->type === self::TYPE_CSS && MINIFY_REWRITE_CSS_URLS) {
// Rewrite relative CSS URLs.
$combined[] = self::rewriteCSSUrls(file_get_contents($file),
dirname($file));
}
else {
$combined[] = file_get_contents($file);
}
}
$combined = $minify ? self::min(implode("\n", $combined), $this->type) :
implode("\n", $combined);
// Save combined contents to the cache.
if (MINIFY_USE_CACHE) {
$cacheFile = MINIFY_CACHE_DIR.'/minify_'.$this->getHash();
@file_put_contents($cacheFile, $combined, LOCK_EX);
}
return $combined;
}
/**
* Gets an array of absolute pathnames of all files that have been added with
* addFile() or via this class's constructor.
*
* @return array array of absolute pathnames
* @see addFile()
* @see removeFile()
*/
public function getFiles() {
return $this->files;
}
/**
* Gets the MD5 hash of the concatenated filenames from the list of files to
* be minified.
*/
public function getHash() {
return hash('md5', implode('', $this->files));
}
/**
* Gets the timestamp of the most recently modified file.
*
* @return int timestamp
*/
public function getLastModified() {
$lastModified = 0;
// Get the timestamp of the most recently modified file.
foreach($this->files as $file) {
$modified = filemtime($file);
if ($modified !== false && $modified > $lastModified) {
$lastModified = $modified;
}
}
return $lastModified;
}
/**
* Removes the specified filename or array of filenames from the list of files
* to be minified.
*
* @param array|string $files filename or array of filenames
* @see addFile()
* @see getFiles()
*/
public function removeFile($files) {
$files = @array_map(array($this, 'resolveFilePath'), (array) $files);
$this->files = array_diff($this->files, $files);
}
/**
* Attempts to serve the combined, minified files from the server's disk-based
* cache if possible.
*
* @param bool $return return cached content as a string instead of outputting
* it to the client
* @return bool|string
*/
public function serverCache($return = false) {
$cacheFile = MINIFY_CACHE_DIR.'/minify_'.$this->getHash();
$lastModified = $this->getLastModified();
if (is_file($cacheFile) && $lastModified <= filemtime($cacheFile)) {
if ($return) {
return file_get_contents($cacheFile);
}
else {
echo file_get_contents($cacheFile);
exit;
}
}
return false;
}
// -- Protected Instance Methods ---------------------------------------------
/**
* Returns the canonicalized absolute pathname to the specified file or local
* URL.
*
* @param string $file relative file path
* @return string canonicalized absolute pathname
*/
protected function resolveFilePath($file) {
// Is this a URL?
if (preg_match('/^https?:\/\//i', $file)) {
if (!$parsedUrl = parse_url($file)) {
throw new MinifyInvalidUrlException("Invalid URL: $file");
}
// Does the server name match the local server name?
if (!isset($parsedUrl['host']) ||
$parsedUrl['host'] != $_SERVER['SERVER_NAME']) {
throw new MinifyInvalidUrlException('Non-local URL not supported: '.
$file);
}
// Get the file's absolute path.
$filepath = realpath(MINIFY_BASE_DIR.$parsedUrl['path']);
}
else {
// Get the file's absolute path.
$filepath = realpath(MINIFY_BASE_DIR.'/'.$file);
}
// Ensure that the file exists, that the path is under the base directory,
// that the file's extension is either '.css' or '.js', and that the file is
// actually readable.
if (!$filepath ||
!is_file($filepath) ||
!is_readable($filepath) ||
!preg_match('/^'.preg_quote(MINIFY_BASE_DIR, '/').'/', $filepath) ||
!preg_match('/\.(?:css|js)$/iD', $filepath)) {
// Even when the file exists, we still throw a
// MinifyFileNotFoundException in order to try to prevent an information
// disclosure vulnerability.
throw new MinifyFileNotFoundException("File not found: $file");
}
return $filepath;
}
}
// -- Exception Classes --------------------------------------------------------
class MinifyException extends Exception {}
class MinifyFileNotFoundException extends MinifyException {}
class MinifyInvalidArgumentException extends MinifyException {}
class MinifyInvalidUrlException extends MinifyException {}
// -- Global Scope -------------------------------------------------------------
if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
Minify::handleRequest();
}
?>