diff --git a/min/README.txt b/min/README.txt index 2aa9aa5..6b9f332 100644 --- a/min/README.txt +++ b/min/README.txt @@ -60,10 +60,10 @@ 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_allowDirs array in config.php. E.g. to limit to the /js and -/themes/default directories, use: +$min_serveOptions['minApp']['allowDirs'] array in config.php. E.g. to limit +to the /js and /themes/default directories, use: -$min_allowDirs = array('//js', '//themes/default'); +$min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default'); GROUPS: FASTER PERFORMANCE AND BETTER URLS diff --git a/min/config.php b/min/config.php index 6cd8cbc..d299410 100644 --- a/min/config.php +++ b/min/config.php @@ -5,6 +5,13 @@ */ +/** + * Path to Minify's lib folder. If you happen to move it, change + * this accordingly. + */ +$min_libPath = dirname(__FILE__) . '/lib'; + + /** * For best performance, specify your temp directory here. Otherwise * Minify will have to load extra code to guess. Commented out below @@ -15,6 +22,12 @@ //$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path()); +/** + * Cache file locking. Set to false if filesystem is NFS. + */ +$min_cacheFileLocking = true; + + /** * Allow use of the Minify URI Builder app. If you no longer need * this, set to false. @@ -22,6 +35,16 @@ $min_enableBuilder = true; +/** + * 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; + + /** * Maximum age of browser cache in seconds. After this period, * the browser will send another conditional GET. You might @@ -39,30 +62,18 @@ $min_serveOptions['maxAge'] = 1800; * * // = DOCUMENT_ROOT */ -//$min_allowDirs = array('//js', '//css'); - - -/** - * If you move Minify's lib folder, give the path to it here. - */ -//$min_libPath = dirname(__FILE__) . '/lib'; - +//$min_serveOptions['minApp']['allowDirs'] = array('//js', '//css'); /** * Set to true to disable the "f" GET parameter for specifying files. * Only the "g" parameter will be considered. */ -$min_groupsOnly = false; - +$min_serveOptions['minApp']['groupsOnly'] = false; /** - * 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 + * Maximum # of files that can be specified in the "f" GET parameter */ -$min_allowDebugFlag = false; +$min_serveOptions['minApp']['maxFiles'] = 10; /** diff --git a/min/index.php b/min/index.php index 864f757..9673d54 100644 --- a/min/index.php +++ b/min/index.php @@ -13,80 +13,39 @@ define('MINIFY_MIN_DIR', dirname(__FILE__)); require MINIFY_MIN_DIR . '/config.php'; // setup include path -if (!isset($min_libPath)) { - // default lib path is inside this directory - $min_libPath = MINIFY_MIN_DIR . '/lib'; -} set_include_path($min_libPath . PATH_SEPARATOR . get_include_path()); -// friendly error if lib wasn't in the include_path -if (! (include 'Minify.php')) { - trigger_error( - 'Minify: You must add Minify/lib to the include_path or set $min_libPath in config.php' - ,E_USER_ERROR - ); -} +require 'Minify.php'; + +Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; +Minify::setCache( + isset($min_cachePath) ? $min_cachePath : null + ,$min_cacheFileLocking +); if (0 === stripos(PHP_OS, 'win')) { Minify::setDocRoot(); // we may be on IIS } - if ($min_allowDebugFlag && isset($_GET['debug'])) { $min_serveOptions['debug'] = true; } - -Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; - if (isset($_GET['g'])) { - - Minify::setCache(isset($min_cachePath) ? $min_cachePath : null); - // Groups expects the group key as PATH_INFO - // we want to allow ?g=groupKey - $_SERVER['PATH_INFO'] = '/' . $_GET['g']; - $min_serveOptions['groups'] = (require MINIFY_MIN_DIR . '/groupsConfig.php'); + // well need groups config + $min_serveOptions['minApp']['groups'] = (require MINIFY_MIN_DIR . '/groupsConfig.php'); + // check for URI versioning if (preg_match('/&\\d/', $_SERVER['QUERY_STRING'])) { - // URI is versioned, send far off Expire $min_serveOptions['maxAge'] = 31536000; } - Minify::serve('Groups', $min_serveOptions); - -} elseif (!$min_groupsOnly && isset($_GET['f'])) { - - /** - * crude initial implementation hacked onto on Version1 controller - * @todo encapsulate this in a new controller - */ - - if (isset($min_cachePath)) { - define('MINIFY_CACHE_DIR', $min_cachePath); - } - if (isset($min_allowDirs)) { - foreach ((array)$min_allowDirs as $_allowDir) { - $min_serveOptions['allowDirs'][] = realpath( - $_SERVER['DOCUMENT_ROOT'] . substr($_allowDir, 1) - ); - } - } - // Version1 already does validation. All we want is to prepend "b" - // to each file if it looks right. - $min_base = (isset($_GET['b']) && preg_match('@^[^/.]+(?:/[^/.]+)*$@', $_GET['b'])) - ? '/' . $_GET['b'] . '/' - : '/'; - // Version1 expects ?files=/js/file1.js,/js/file2.js,/js/file3.js - // we want to allow ?f=js/file1.js,js/file2.js,js/file3.js - // or ?b=js&f=file1.js,file2.js,file3.js - $_GET['files'] = $min_base . str_replace(',', ',' . $min_base, $_GET['f']); - - Minify::serve('Version1', $min_serveOptions); +} +if (isset($_GET['f']) || isset($_GET['g'])) { + // serve! + Minify::serve('MinApp', $min_serveOptions); + } elseif ($min_enableBuilder) { - header('Location: builder/'); exit(); - } else { - header("Location: /"); exit(); - } diff --git a/min/lib/Minify/Cache/File.php b/min/lib/Minify/Cache/File.php index 6d1a6f2..fd4222a 100644 --- a/min/lib/Minify/Cache/File.php +++ b/min/lib/Minify/Cache/File.php @@ -35,7 +35,8 @@ class Minify_Cache_File { } if (! @file_put_contents($this->_path . '/' . $id, $data, $flag)) { return false; - } + } + // write control if ($data !== $this->fetch($id)) { @unlink($file); return false; diff --git a/min/lib/Minify/Controller/Base.php b/min/lib/Minify/Controller/Base.php index d3f5bb3..0d40c96 100644 --- a/min/lib/Minify/Controller/Base.php +++ b/min/lib/Minify/Controller/Base.php @@ -120,24 +120,19 @@ abstract class Minify_Controller_Base { { $pathOk = false; foreach ((array)$safeDirs as $safeDir) { - if (strpos($file, $safeDir) === 0 && file_exists($file)) { + if (strpos($file, $safeDir) === 0) { $pathOk = true; break; } } - if (! $pathOk) { - return false; - } $base = basename($file); - if ($base[0] === '.') { + if (! $pathOk || ! is_file($file) || $base[0] === '.') { return false; } list($revExt) = explode('.', strrev($base)); return in_array(strrev($revExt), array('js', 'css', 'html', 'txt')); } - /*public static function _haveSameExt - /** * @var array instances of Minify_Source, which provide content and * any individual minification needs. diff --git a/min/lib/Minify/Controller/MinApp.php b/min/lib/Minify/Controller/MinApp.php new file mode 100644 index 0000000..0e6d31d --- /dev/null +++ b/min/lib/Minify/Controller/MinApp.php @@ -0,0 +1,116 @@ + + */ +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 + $cOptions = array_merge( + array( + 'allowDirs' => '//' + ,'groupsOnly' => false + ,'groups' => array() + ,'maxFiles' => 10 + ) + ,(isset($options['minApp']) ? $options['minApp'] : array()) + ); + unset($options['minApp']); + $sources = array(); + if (isset($_GET['g'])) { + // try groups + if (! isset($cOptions['groups'][$_GET['g']])) { + return $options; + } + foreach ((array)$cOptions['groups'][$_GET['g']] 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 { + // file doesn't exist + return $options; + } + } + } elseif (! $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. + if (// verify at least one file, files are single comma separated, + // and are all same extension + ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f']) + // no "//" + || strpos($_GET['f'], '//') !== false + // no "\" + || strpos($_GET['f'], '\\') !== false + // no "./" + || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['f']) + ) { + return $options; + } + $files = explode(',', $_GET['f']); + if (count($files) > $cOptions['maxFiles'] || $files != array_unique($files)) { + // too many or duplicate files + return $options; + } + if (isset($_GET['b'])) { + // check for validity + if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) + && false === strpos($_GET['b'], '..') + && $_GET['b'] !== '.') { + // valid base + $base = "/{$_GET['b']}/"; + } else { + return $options; + } + } else { + $base = '/'; + } + $allowDirs = array(); + foreach ((array)$cOptions['allowDirs'] as $allowDir) { + $allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir)); + } + foreach ($files as $file) { + $file = realpath($_SERVER['DOCUMENT_ROOT'] . $base . $file); + // don't allow unsafe or duplicate files + if (parent::_fileIsSafe($file, $allowDirs)) { + $sources[] = new Minify_Source(array( + 'filepath' => $file + )); + } else { + // unsafe file + return $options; + } + } + } + if ($sources) { + $this->sources = $sources; + } + return $options; + } +} diff --git a/min_extras/ab_tests/results_summary.txt b/min_extras/ab_tests/results_summary.txt index b3abf4a..20657c7 100644 --- a/min_extras/ab_tests/results_summary.txt +++ b/min_extras/ab_tests/results_summary.txt @@ -1,41 +1,37 @@ -Document Path: /min_extras/ab_tests/ideal_php/before.php +Document Path: /_3rd_party/minify/min_extras/ab_tests/ideal_php/before.php Document Length: 15993 bytes - (Connect: 0, Length: 1, Exceptions: 0) -Requests per second: 385.54 [#/sec] (mean) +Requests per second: 354.57 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/v1.0/minify.php?files=before.js +Document Path: /_3rd_party/minify/min_extras/ab_tests/v1.0/minify.php?files=before.js Document Length: 54418 bytes -Requests per second: 276.46 [#/sec] (mean) +Requests per second: 261.76 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/minify/test_Files.php +Document Path: /_3rd_party/minify/min_extras/ab_tests/minify/test_Files.php Document Length: 15993 bytes - (Connect: 0, Length: 1, Exceptions: 0) -Requests per second: 233.15 [#/sec] (mean) +Requests per second: 203.82 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/minify/test_Files_Memcache.php +Document Path: /_3rd_party/minify/min_extras/ab_tests/minify/test_Files_Memcache.php Document Length: 15993 bytes - (Connect: 0, Length: 22, Exceptions: 0) -Requests per second: 183.64 [#/sec] (mean) + (Connect: 0, Length: 19, Exceptions: 0) +Requests per second: 156.86 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/minify/test_Groups.php/test +Document Path: /_3rd_party/minify/min_extras/ab_tests/minify/test_Groups.php/test Document Length: 15993 bytes - (Connect: 0, Length: 2, Exceptions: 0) Requests per second: 207.79 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/minify/test_Version1.php?files=before.js +Document Path: /_3rd_party/minify/min_extras/ab_tests/minify/test_Version1.php?files=before.js Document Length: 15993 bytes -Requests per second: 225.35 [#/sec] (mean) +Requests per second: 210.53 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min/?f=min_extras/ab_tests/minify/before.js +Document Path: /min/?f=_3rd_party/minify/min_extras/ab_tests/minify/before.js Document Length: 15993 bytes - (Connect: 0, Length: 1, Exceptions: 0) -Requests per second: 226.55 [#/sec] (mean) +Requests per second: 231.46 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/mod_deflate/before.js +Document Path: /_3rd_party/minify/min_extras/ab_tests/mod_deflate/before.js Document Length: 16053 bytes -Requests per second: 177.78 [#/sec] (mean) +Requests per second: 185.78 [#/sec] (mean) -------------------------------------------------------------------------------- -Document Path: /min_extras/ab_tests/type-map/before.js.var +Document Path: /_3rd_party/minify/min_extras/ab_tests/type-map/before.js.var Document Length: 15993 bytes -Requests per second: 334.20 [#/sec] (mean) +Requests per second: 472.32 [#/sec] (mean) -------------------------------------------------------------------------------- diff --git a/min_extras/config.php b/min_extras/config.php index ec9cc4f..6b4959a 100644 --- a/min_extras/config.php +++ b/min_extras/config.php @@ -4,10 +4,6 @@ require dirname(__FILE__) . '/../min/config.php'; -if (!isset($min_libPath)) { - // default lib path is inside min - $min_libPath = dirname(__FILE__) . '/../min/lib'; -} set_include_path($min_libPath . PATH_SEPARATOR . get_include_path()); $minifyCachePath = isset($min_cachePath) diff --git a/min_unit_tests/_inc.php b/min_unit_tests/_inc.php index f460a59..1f99017 100644 --- a/min_unit_tests/_inc.php +++ b/min_unit_tests/_inc.php @@ -2,10 +2,6 @@ require dirname(__FILE__) . '/../min/config.php'; -if (!isset($min_libPath)) { - // default lib path is inside min - $min_libPath = dirname(__FILE__) . '/../min/lib'; -} set_include_path($min_libPath . PATH_SEPARATOR . get_include_path()); $minifyCachePath = isset($min_cachePath)