From 4710509c689ee60288d51768193c2fbc86bca6f4 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sat, 27 Feb 2016 01:13:28 -0500 Subject: [PATCH] Large restructuring Moves all dependency building into App bootstrap.php returns an App instance The app loads config files as necessary Moves logging to Monolog Moves HTTP digest auth to packagist component Rely on sys_get_temp_dir Env hosts $_POST and allows defaults when reading HTML helper uses the App and can handle less files Source factory assumes strings are filenames Fixes JsClosureCompilerTest::test6 (API now handles ES5 by default) Exclude JsClosureCompilerTest due to API limitations config.php can now return a Minify\Config object Variables set in config.php are now moved to a `Minify\Config` object, allowing better static analysis. The `zlib.output_compression` set is moved into `Minify::serve`. --- HISTORY.md | 13 +- bootstrap.php | 6 +- builder/index.php | 66 ++----- builder/ocCheck.php | 8 +- composer.json | 5 +- config.php | 13 +- groupsConfig.php | 6 +- index.php | 126 +------------- lib/DooDigestAuth.php | 121 ------------- lib/Minify.php | 32 ++-- lib/Minify/App.php | 258 ++++++++++++++++++++++++++++ lib/Minify/Cache/File.php | 125 ++++++-------- lib/Minify/Config.php | 73 ++++++++ lib/Minify/Controller/Base.php | 19 +- lib/Minify/Controller/Files.php | 23 +-- lib/Minify/Controller/Groups.php | 2 +- lib/Minify/Controller/MinApp.php | 32 ++-- lib/Minify/ControllerInterface.php | 2 + lib/Minify/Env.php | 24 ++- lib/Minify/HTML/Helper.php | 50 ++++-- lib/Minify/Loader.php | 45 ----- lib/Minify/Logger.php | 47 ----- lib/Minify/Logger/LegacyHandler.php | 25 +++ lib/Minify/Source/Factory.php | 12 +- min_extras/tools/minifyTextarea.php | 41 +++-- min_extras/tools/minifyUrl.php | 29 ++-- min_extras/tools/testRewriteUri.php | 44 ++--- phpunit.xml | 1 + tests/JsClosureCompilerTest.php | 16 +- utils.php | 2 +- 30 files changed, 629 insertions(+), 637 deletions(-) delete mode 100644 lib/DooDigestAuth.php create mode 100644 lib/Minify/App.php create mode 100644 lib/Minify/Config.php delete mode 100644 lib/Minify/Loader.php delete mode 100644 lib/Minify/Logger.php create mode 100644 lib/Minify/Logger/LegacyHandler.php diff --git a/HISTORY.md b/HISTORY.md index 21c3691..90cc7ad 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,12 +1,15 @@ -## 3.0 progress -* Better CSS minification via Túbal Martín's CSSMin -* Docs overhaul -* New API incompatible with the 2.x versions +## Version 3.0.0 (unreleased) +* The project root is now what is deployed as `min` * Installation requires use of Composer to install dependencies +* Removes JSMin+ (unmaintained, high memory usage) +* Removes DooDigestAuth +* Removes Minify_Loader (uses Composer) +* Removes Minify_Logger (uses Monolog) +* The Minify, source, and controller components have changed APIs +* Better CSS minification via Túbal Martín's CSSMin * Add config option for simply concatenating files * Add config option for altering creation of Minify/MinApp objects * Missing spec no longer redirects, instead links to docs -* Removed JSMin+ (unmaintained, high memory usage) ## Version 2.2.1 (2014-10-30) * Builder styled with Bootstrap (thanks to help from acidvertigo) diff --git a/bootstrap.php b/bootstrap.php index a715ffa..d4dda6d 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,8 +1,6 @@ config; // recommend $min_symlinks setting for Apache UserDir $symlinkOption = ''; -if (0 === strpos($_SERVER["SERVER_SOFTWARE"], 'Apache/') - && preg_match('@^/\\~(\\w+)/@', $_SERVER['REQUEST_URI'], $m) +if (0 === strpos($app->env->server("SERVER_SOFTWARE"), 'Apache/') + && preg_match('@^/\\~(\\w+)/@', $app->env->server('REQUEST_URI'), $m) ) { $userDir = DIRECTORY_SEPARATOR . $m[1] . DIRECTORY_SEPARATOR; if (false !== strpos(__FILE__, $userDir)) { @@ -18,24 +19,19 @@ if (0 === strpos($_SERVER["SERVER_SOFTWARE"], 'Apache/') } } -require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/../config.php'; - -if (! $min_enableBuilder) { +if (!$config->enableBuilder) { header('Content-Type: text/plain'); die('This application is not enabled. See https://github.com/mrclay/minify/blob/master/docs/BuilderApp.wiki.md'); } -if (isset($min_builderPassword) - && is_string($min_builderPassword) - && $min_builderPassword !== '') { - DooDigestAuth::http_auth('Minify Builder', array('admin' => $min_builderPassword)); -} - -$cachePathCode = ''; -if (! isset($min_cachePath) && ! function_exists('sys_get_temp_dir')) { - $detectedTmp = Minify_Cache_File::tmp(); - $cachePathCode = "\$min_cachePath = " . var_export($detectedTmp, 1) . ';'; +if ($config->builderPassword && $config->builderPassword !== '') { + $auth = new Intervention\Httpauth\Httpauth(array( + 'username' => 'admin', + 'password' => $config->builderPassword, + 'type' => 'digest', + 'realm' => 'Minify Builder', + )); + $auth->secure(); } ob_start(); @@ -79,13 +75,6 @@ b {color:#c00} FirePHP console will report the cause of the error.

- -

Note: was discovered as a usable temp directory.
To - slightly improve performance you can hardcode this in /min/config.php: -

- -

Note: Your webserver does not seem to support mod_rewrite (used in /min/.htaccess). Your Minify URIs will contain "?", which

-

+

@@ -218,26 +207,8 @@ by Minify. E.g. @import "/min/?g=css2";< $min_uploaderHoursBehind, -)); - -$controller = new Minify_Controller_Page($env, $sourceFactory); - -$server = new Minify($cache); - -$server->serve($controller, array( +$controller = new Minify_Controller_Page($app->env, $app->sourceFactory); +$minify = $app->minify->serve($controller, array( 'content' => $content, 'id' => __FILE__, 'lastModifiedTime' => max( @@ -247,5 +218,4 @@ $server->serve($controller, array( filemtime(__DIR__ . '/../lib/Minify.php') ), 'minifyAll' => true, - 'encodeOutput' => $encodeOutput, )); diff --git a/builder/ocCheck.php b/builder/ocCheck.php index 799a632..9f8475c 100644 --- a/builder/ocCheck.php +++ b/builder/ocCheck.php @@ -5,18 +5,18 @@ * @package Minify */ -require __DIR__ . '/../bootstrap.php'; +$app = (require __DIR__ . '/../bootstrap.php'); +/* @var \Minify\App $app */ $_oc = ini_get('zlib.output_compression'); // allow access only if builder is enabled -require __DIR__ . '/../config.php'; -if (! $min_enableBuilder) { +if (!$app->config->enableBuilder) { header('Location: /'); exit; } -if (isset($_GET['hello'])) { +if ($app->env->get('hello')) { // echo 'World!' // try to prevent double encoding (may not have an effect) diff --git a/composer.json b/composer.json index 7842db1..8792065 100644 --- a/composer.json +++ b/composer.json @@ -23,10 +23,13 @@ "classmap": ["tests/TestCase.php"] }, "require": { + "php": ">=5.3.0", "ext-pcre": "*", "firephp/firephp-core": "~0.4.0", + "intervention/httpauth": "~2.0", + "monolog/monolog": "~1.1", "mrclay/jsmin-php": "~2", - "php": ">=5.3.0", + "mrclay/props-dic": "^2.2", "tubalmartin/cssmin": "~2.4.8" }, "require-dev": { diff --git a/config.php b/config.php index d731c6f..530a196 100644 --- a/config.php +++ b/config.php @@ -27,12 +27,8 @@ $min_builderPassword = 'admin'; /** - * Set to true to log messages to FirePHP (Firefox Firebug addon). + * Set to true to log messages to FirePHP (Firefox Firebug addon) and PHP's error_log * Set to false for no error logging (Minify may be slightly faster). - * @link http://www.firephp.org/ - * - * If you want to use a custom error logger, set this to your logger - * instance. Your object should have a method log(string $message). */ $min_errorLogger = false; @@ -193,9 +189,6 @@ $min_uploaderHoursBehind = 0; * * You can see the default implementations (and what gets passed in) in index.php. */ -//$min_factories['minify'] = ... a callable -//$min_factories['controller'] = ... a callable +//$min_factories['minify'] = ... a callable accepting a Minify\App object +//$min_factories['controller'] = ... a callable accepting a Minify\App object - -// try to disable output_compression (may not have an effect) -ini_set('zlib.output_compression', '0'); diff --git a/groupsConfig.php b/groupsConfig.php index c4cb4b0..cc80538 100644 --- a/groupsConfig.php +++ b/groupsConfig.php @@ -12,8 +12,8 @@ **/ return array( -// 'testJs' => array('//minify/min/quick-test.js'), -// 'testCss' => array('//minify/min/quick-test.css'), +// 'testJs' => array('//minify/quick-test.js'), +// 'testCss' => array('//minify/quick-test.css'), // 'js' => array('//js/file1.js', '//js/file2.js'), // 'css' => array('//css/file1.css', '//css/file2.css'), -); \ No newline at end of file +); diff --git a/index.php b/index.php index 938a49b..7b58bcc 100644 --- a/index.php +++ b/index.php @@ -7,127 +7,7 @@ * @package Minify */ -require __DIR__ . '/bootstrap.php'; +$app = (require __DIR__ . '/bootstrap.php'); +/* @var \Minify\App $app */ -// set config path defaults -$min_configPaths = array( - 'base' => __DIR__ . '/config.php', - 'test' => __DIR__ . '/config-test.php', - 'groups' => __DIR__ . '/groupsConfig.php', -); - -// check for custom config paths -if (!empty($min_customConfigPaths) && is_array($min_customConfigPaths)) { - $min_configPaths = array_merge($min_configPaths, $min_customConfigPaths); -} - -// load config -require $min_configPaths['base']; - -if (isset($_GET['test'])) { - include $min_configPaths['test']; -} - -// setup factories -$defaultFactories = array( - 'minify' => function (Minify_CacheInterface $cache) { - return new Minify($cache); - }, - 'controller' => function (Minify_Env $env, Minify_Source_Factory $sourceFactory) { - return new Minify_Controller_MinApp($env, $sourceFactory); - }, -); -if (!isset($min_factories)) { - $min_factories = array(); -} -$min_factories = array_merge($defaultFactories, $min_factories); - -// use an environment object to encapsulate all input -$server = $_SERVER; -if ($min_documentRoot) { - $server['DOCUMENT_ROOT'] = $min_documentRoot; -} -$env = new Minify_Env(array( - 'server' => $server, -)); - -// TODO probably should do this elsewhere... -$min_serveOptions['minifierOptions']['text/css']['docRoot'] = $env->getDocRoot(); -$min_serveOptions['minifierOptions']['text/css']['symlinks'] = $min_symlinks; -$min_serveOptions['minApp']['symlinks'] = $min_symlinks; -// auto-add targets to allowDirs -foreach ($min_symlinks as $uri => $target) { - $min_serveOptions['minApp']['allowDirs'][] = $target; -} - -if ($min_allowDebugFlag) { - // TODO get rid of static stuff - $min_serveOptions['debug'] = Minify_DebugDetector::shouldDebugRequest($env); -} - -if (!empty($min_concatOnly)) { - $min_serveOptions['concatOnly'] = true; -} - -if ($min_errorLogger) { - if (true === $min_errorLogger) { - $min_errorLogger = FirePHP::getInstance(true); - } - // TODO get rid of global state - Minify_Logger::setLogger($min_errorLogger); -} - -// check for URI versioning -if (null !== $env->get('v') || preg_match('/&\\d/', $env->server('QUERY_STRING'))) { - $min_serveOptions['maxAge'] = 31536000; -} - -// need groups config? -if (null !== $env->get('g')) { - // we need groups config - $min_serveOptions['minApp']['groups'] = (require $min_configPaths['groups']); -} - -// cache defaults -if (!isset($min_cachePath)) { - $min_cachePath = ''; -} -if (!isset($min_cacheFileLocking)) { - $min_cacheFileLocking = true; -} -if (is_string($min_cachePath)) { - $cache = new Minify_Cache_File($min_cachePath, $min_cacheFileLocking); -} else { - // assume it meets interface. - $cache = $min_cachePath; -} -/* @var Minify_CacheInterface $cache */ - -$minify = call_user_func($min_factories['minify'], $cache); -/* @var Minify $minify */ - -if (!$env->get('f') && $env->get('g') === null) { - // no spec given - $msg = '

No "f" or "g" parameters were detected.

'; - $url = 'https://github.com/mrclay/minify/blob/master/docs/CommonProblems.wiki.md#long-url-parameters-are-ignored'; - $defaults = $minify->getDefaultOptions(); - $minify->errorExit($defaults['badRequestHeader'], $url, $msg); -} - -$sourceFactoryOptions = array(); - -// translate legacy setting to option for source factory -if (isset($min_serveOptions['minApp']['noMinPattern'])) { - $sourceFactoryOptions['noMinPattern'] = $min_serveOptions['minApp']['noMinPattern']; -} - -if (isset($min_serveOptions['minApp']['allowDirs'])) { - $sourceFactoryOptions['allowDirs'] = $min_serveOptions['minApp']['allowDirs']; -} - -$sourceFactory = new Minify_Source_Factory($env, $sourceFactoryOptions, $cache); - -$controller = call_user_func($min_factories['controller'], $env, $sourceFactory); -/* @var Minify_ControllerInterface $controller */ - -$minify->serve($controller, $min_serveOptions); +$app->runServer(); diff --git a/lib/DooDigestAuth.php b/lib/DooDigestAuth.php deleted file mode 100644 index b979009..0000000 --- a/lib/DooDigestAuth.php +++ /dev/null @@ -1,121 +0,0 @@ - - * @link http://www.doophp.com/ - * @copyright Copyright © 2009 Leng Sheng Hong - * @license http://www.doophp.com/license - */ - -/** - * Handles HTTP digest authentication - * - *

HTTP digest authentication can be used with the URI router. - * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption. - * If you are running PHP on Apache in CGI/FastCGI mode, you would need to - * add the following line to your .htaccess for digest auth to work correctly.

- * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] - * - *

This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.

- * - * @author Leng Sheng Hong - * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 - * @package doo.auth - * @since 1.0 - */ -class DooDigestAuth{ - - /** - * Authenticate against a list of username and passwords. - * - *

HTTP Digest Authentication doesn't work with PHP in CGI mode, - * you have to add this into your .htaccess RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

- * - * @param string $realm Name of the authentication session - * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2') - * @param string $fail_msg Message to be displayed if the User cancel the login - * @param string $fail_url URL to be redirect if the User cancel the login - * @return string The username if login success. - */ - public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL) { - $realm = "Restricted area - $realm"; - - //user => password - //$users = array('admin' => '1234', 'guest' => 'guest'); - if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){ - $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; - } - - if (empty($_SERVER['PHP_AUTH_DIGEST'])) { - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - header('HTTP/1.1 401 Unauthorized'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // analyze the PHP_AUTH_DIGEST variable - if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){ - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - header('HTTP/1.1 401 Unauthorized'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // generate the valid response - $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); - $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); - $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); - - if ($data['response'] != $valid_response){ - header('HTTP/1.1 401 Unauthorized'); - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // ok, valid username & password - return $data['username']; - } - - /** - * Method to parse the http auth header, works with IE. - * - * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do. - * - * @param string $txt header string to parse - * @return array An assoc array of the digest auth session - */ - private static function http_digest_parse($txt) - { - $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match); - $data['username'] = (isset($match[1]))?$match[1]:null; - $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match); - $data['nonce'] = $match[1]; - $res = preg_match('/nc=([0-9]+)/i', $txt, $match); - $data['nc'] = $match[1]; - $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match); - $data['cnonce'] = $match[1]; - $res = preg_match('/qop=([^,]+)/i', $txt, $match); - $data['qop'] = str_replace('"','',$match[1]); - $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match); - $data['uri'] = $match[1]; - $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match); - $data['response'] = $match[1]; - - return $data; - } - -} diff --git a/lib/Minify.php b/lib/Minify.php index 8ecc4d8..4909dca 100644 --- a/lib/Minify.php +++ b/lib/Minify.php @@ -4,6 +4,8 @@ * @package Minify */ +use Psr\Log\LoggerInterface; + /** * Minify - Combines, minifies, and caches JavaScript and CSS files on demand. * @@ -64,10 +66,17 @@ class Minify { protected $options = null; /** - * @param Minify_CacheInterface $cache + * @var LoggerInterface|null */ - public function __construct(Minify_CacheInterface $cache) { + protected $logger = null; + + /** + * @param Minify_CacheInterface $cache + * @param LoggerInterface $logger + */ + public function __construct(Minify_CacheInterface $cache, LoggerInterface $logger = null) { $this->cache = $cache; + $this->logger = $logger; } /** @@ -209,6 +218,10 @@ class Minify { $this->selectionId = $config->getSelectionId(); $this->options = $this->analyzeSources($config->getOptions()); + if (!$this->options['quiet'] && !headers_sent()) { + ini_set('zlib.output_compression', '0'); + } + // check request validity if (!$this->sources) { // invalid request! @@ -321,7 +334,7 @@ class Minify { try { $content = $this->combineMinify(); } catch (Exception $e) { - $this->controller->log($e->getMessage()); + $this->logger && $this->logger->critical($e->getMessage()); if (! $this->options['quiet']) { $this->errorExit($this->options['errorHeader'], self::URL_DEBUG); } @@ -338,7 +351,7 @@ class Minify { try { $content = $this->combineMinify(); } catch (Exception $e) { - $this->controller->log($e->getMessage()); + $this->logger && $this->logger->critical($e->getMessage()); if (! $this->options['quiet']) { $this->errorExit($this->options['errorHeader'], self::URL_DEBUG); } @@ -413,7 +426,7 @@ class Minify { $sourceFactory = new Minify_Source_Factory($env, array( 'checkAllowDirs' => false, ), $this->cache); - $controller = new Minify_Controller_Files($env, $sourceFactory); + $controller = new Minify_Controller_Files($env, $sourceFactory, $this->logger); $options = array_merge($options, array( 'files' => (array)$sources, @@ -675,11 +688,10 @@ class Minify { if (!empty($options['contentType'])) { // just verify sources have null content type or match the options if ($sourceType !== null && $sourceType !== $options['contentType']) { - // TODO better logging - Minify_Logger::log('ContentType mismatch'); + + $this->logger && $this->logger->warning('ContentType mismatch'); $this->sources = array(); - return $options; } @@ -690,11 +702,9 @@ class Minify { $type = $sourceType; } elseif ($sourceType !== $type) { - // TODO better logging - Minify_Logger::log('ContentType mismatch'); + $this->logger && $this->logger->warning('ContentType mismatch'); $this->sources = array(); - return $options; } } diff --git a/lib/Minify/App.php b/lib/Minify/App.php new file mode 100644 index 0000000..f018460 --- /dev/null +++ b/lib/Minify/App.php @@ -0,0 +1,258 @@ +dir = rtrim($dir, '/\\'); + + $this->cache = function (App $app) use ($that) { + $config = $app->config; + + if ($config->cachePath instanceof \Minify_CacheInterface) { + return $config->cachePath; + } + + if (!$config->cachePath || is_string($config->cachePath)) { + return new \Minify_Cache_File($config->cachePath, $config->cacheFileLocking, $app->logger); + } + + $type = $that->typeOf($config->cachePath); + throw new \RuntimeException('$min_cachePath must be a path or implement Minify_CacheInterface.' + . " Given $type"); + }; + + $this->config = function (App $app) { + $config = (require $app->configPath); + + if ($config instanceof \Minify\Config) { + return $config; + } + + // copy from vars into properties + + $config = new \Minify\Config(); + + $propNames = array_keys(get_object_vars($config)); + + $varNames = array_map(function ($name) { + return "min_$name"; + }, $propNames); + + $vars = compact($varNames); + + foreach ($varNames as $varName) { + if (isset($vars[$varName])) { + $config->{substr($varName, 4)} = $vars[$varName]; + } + } + + return $config; + }; + + $this->configPath = "{$this->dir}/config.php"; + + $this->controller = function (App $app) use ($that) { + $config = $app->config; + + if (empty($config->factories['controller'])) { + $ctrl = new \Minify_Controller_MinApp($app->env, $app->sourceFactory, $app->logger); + } else { + $ctrl = call_user_func($config->factories['controller'], $app); + } + + if ($ctrl instanceof \Minify_ControllerInterface) { + return $ctrl; + } + + $type = $that->typeOf($ctrl); + throw new \RuntimeException('$min_factories["controller"] callable must return an implementation' + ." of Minify_CacheInterface. Returned $type"); + }; + + $this->docRoot = function (App $app) { + $config = $app->config; + if (empty($config->documentRoot)) { + return $app->env->getDocRoot(); + } + return rtrim($config->documentRoot, '/\\'); + }; + + $this->env = function (App $app) { + $config = $app->config; + $envArgs = empty($config->envArgs) ? array() : $config->envArgs; + return new \Minify_Env($envArgs); + }; + + $this->errorLogHandler = function (App $app) { + $format = "%channel%.%level_name%: %message% %context% %extra%"; + $handler = new \Monolog\Handler\ErrorLogHandler(); + $handler->setFormatter(new \Monolog\Formatter\LineFormatter($format)); + return $handler; + }; + + $this->groupsConfig = function (App $app) { + return (require $app->groupsConfigPath); + }; + + $this->groupsConfigPath = "{$this->dir}/groupsConfig.php"; + + $this->logger = function (App $app) use ($that) { + $value = $app->config->errorLogger; + + if ($value instanceof \Psr\Log\LoggerInterface) { + return $value; + } + + $logger = new \Monolog\Logger('minify'); + + if (!$value) { + return $logger; + } + + if ($value === true || $value instanceof \FirePHP) { + $logger->pushHandler($app->errorLogHandler); + $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); + return $logger; + } + + if ($value instanceof \Monolog\Handler\HandlerInterface) { + $logger->pushHandler($value); + return $logger; + } + + // BC + if (is_object($value) && is_callable(array($value, 'log'))) { + $handler = new \Minify\Logger\LegacyHandler($value); + $logger->pushHandler($handler); + return $logger; + } + + $type = $that->typeOf($value); + throw new \RuntimeException('If set, $min_errorLogger must be a PSR-3 logger or a Monolog handler.' + ." Given $type"); + }; + + $this->minify = function (App $app) use ($that) { + $config = $app->config; + + if (empty($config->factories['minify'])) { + return new \Minify($app->cache, $app->logger); + } + + $minify = call_user_func($config->factories['minify'], $app); + if ($minify instanceof \Minify) { + return $minify; + } + + $type = $that->typeOf($minify); + throw new \RuntimeException('$min_factories["minify"] callable must return a Minify object.' + ." Returned $type"); + }; + + $this->serveOptions = function (App $app) { + $config = $app->config; + $env = $app->env; + + $ret = $config->serveOptions; + + $ret['minifierOptions']['text/css']['docRoot'] = $app->docRoot; + $ret['minifierOptions']['text/css']['symlinks'] = $config->symlinks; + $ret['minApp']['symlinks'] = $config->symlinks; + + // auto-add targets to allowDirs + foreach ($config->symlinks as $uri => $target) { + $ret['minApp']['allowDirs'][] = $target; + } + + if ($config->allowDebugFlag) { + $ret['debug'] = \Minify_DebugDetector::shouldDebugRequest($env); + } + + if ($config->concatOnly) { + $ret['concatOnly'] = true; + } + + // check for URI versioning + if ($env->get('v') !== null || preg_match('/&\\d/', $app->env->server('QUERY_STRING'))) { + $ret['maxAge'] = 31536000; + } + + // need groups config? + if ($env->get('g') !== null) { + $ret['minApp']['groups'] = $app->groupsConfig; + } + + return $ret; + }; + + $this->sourceFactory = function (App $app) { + return new \Minify_Source_Factory($app->env, $app->sourceFactoryOptions, $app->cache); + }; + + $this->sourceFactoryOptions = function (App $app) { + $serveOptions = $app->serveOptions; + $ret = array(); + + // translate legacy setting to option for source factory + if (isset($serveOptions['minApp']['noMinPattern'])) { + $ret['noMinPattern'] = $serveOptions['minApp']['noMinPattern']; + } + + if (isset($serveOptions['minApp']['allowDirs'])) { + $ret['allowDirs'] = $serveOptions['minApp']['allowDirs']; + } + + if (is_numeric($app->config->uploaderHoursBehind)) { + $ret['uploaderHoursBehind'] = $app->config->uploaderHoursBehind; + } + + return $ret; + }; + } + + public function runServer() { + if (!$this->env->get('f') && $this->env->get('g') === null) { + // no spec given + $msg = '

No "f" or "g" parameters were detected.

'; + $url = 'https://github.com/mrclay/minify/blob/master/docs/CommonProblems.wiki.md#long-url-parameters-are-ignored'; + $defaults = $this->minify->getDefaultOptions(); + $this->minify->errorExit($defaults['badRequestHeader'], $url, $msg); + } + + $this->minify->serve($this->controller, $this->serveOptions); + } + + /** + * @param mixed $var + * @return string + */ + private function typeOf($var) { + $type = gettype($var); + return $type === 'object' ? get_class($var) : $type; + } +} diff --git a/lib/Minify/Cache/File.php b/lib/Minify/Cache/File.php index d4b6f42..cb3a082 100644 --- a/lib/Minify/Cache/File.php +++ b/lib/Minify/Cache/File.php @@ -4,15 +4,42 @@ * @package Minify */ +use Psr\Log\LoggerInterface; + class Minify_Cache_File implements Minify_CacheInterface { - public function __construct($path = '', $fileLocking = false) + /** + * @var string + */ + private $path; + + /** + * @var bool + */ + private $locking; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param string $path + * @param bool $fileLocking + * @param LoggerInterface $logger + */ + public function __construct($path = '', $fileLocking = false, LoggerInterface $logger = null) { if (! $path) { - $path = self::tmp(); + $path = sys_get_temp_dir(); } - $this->_locking = $fileLocking; - $this->_path = $path; + $this->locking = $fileLocking; + $this->path = $path; + + if (!$logger) { + $logger = new \Monolog\Logger('minify'); + } + $this->logger = $logger; } /** @@ -26,18 +53,17 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function store($id, $data) { - $flag = $this->_locking + $flag = $this->locking ? LOCK_EX : null; - $file = $this->_path . '/' . $id; + $file = $this->path . '/' . $id; if (! @file_put_contents($file, $data, $flag)) { - $this->_log("Minify_Cache_File: Write failed to '$file'"); + $this->logger->warning("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'"); - + $this->logger->warning("Minify_Cache_File: Post-write read failed for '$file'"); return false; } @@ -53,7 +79,7 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function getSize($id) { - return filesize($this->_path . '/' . $id); + return filesize($this->path . '/' . $id); } /** @@ -67,7 +93,7 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function isValid($id, $srcMtime) { - $file = $this->_path . '/' . $id; + $file = $this->path . '/' . $id; return (is_file($file) && (filemtime($file) >= $srcMtime)); } @@ -79,14 +105,14 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function display($id) { - if ($this->_locking) { - $fp = fopen($this->_path . '/' . $id, 'rb'); + if ($this->locking) { + $fp = fopen($this->path . '/' . $id, 'rb'); flock($fp, LOCK_SH); fpassthru($fp); flock($fp, LOCK_UN); fclose($fp); } else { - readfile($this->_path . '/' . $id); + readfile($this->path . '/' . $id); } } @@ -99,8 +125,8 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function fetch($id) { - if ($this->_locking) { - $fp = fopen($this->_path . '/' . $id, 'rb'); + if ($this->locking) { + $fp = fopen($this->path . '/' . $id, 'rb'); if (!$fp) { return false; } @@ -111,7 +137,7 @@ class Minify_Cache_File implements Minify_CacheInterface { return $ret; } else { - return file_get_contents($this->_path . '/' . $id); + return file_get_contents($this->path . '/' . $id); } } @@ -122,81 +148,30 @@ class Minify_Cache_File implements Minify_CacheInterface { */ public function getPath() { - return $this->_path; + 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 + * @deprecated */ 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'; + trigger_error(__METHOD__ . ' is deprecated in Minfy 3.0', E_USER_DEPRECATED); + return sys_get_temp_dir(); } /** * Send message to the Minify logger * @param string $msg * @return null + * @deprecated Use $this->logger */ protected function _log($msg) { - Minify_Logger::log($msg); + trigger_error(__METHOD__ . ' is deprecated in Minify 3.0.', E_USER_DEPRECATED); + $this->logger->warning($msg); } - - private $_path = null; - private $_locking = null; } diff --git a/lib/Minify/Config.php b/lib/Minify/Config.php new file mode 100644 index 0000000..9f1e8b8 --- /dev/null +++ b/lib/Minify/Config.php @@ -0,0 +1,73 @@ +env = $env; $this->sourceFactory = $sourceFactory; + if (!$logger) { + $logger = new Logger('minify'); + } + $this->logger = $logger; } /** @@ -49,9 +62,11 @@ abstract class Minify_Controller_Base implements Minify_ControllerInterface { * @param string $msg * * @return null + * @deprecated use $this->logger */ public function log($msg) { - Minify_Logger::log($msg); + trigger_error(__METHOD__ . ' is deprecated in Minify 3.0.', E_USER_DEPRECATED); + $this->logger->info($msg); } } diff --git a/lib/Minify/Controller/Files.php b/lib/Minify/Controller/Files.php index d687305..da22bd3 100644 --- a/lib/Minify/Controller/Files.php +++ b/lib/Minify/Controller/Files.php @@ -4,6 +4,9 @@ * @package Minify */ +use Psr\Log\LoggerInterface; +use Monolog\Logger; + /** * Controller class for minifying a set of files * @@ -28,16 +31,6 @@ */ class Minify_Controller_Files extends Minify_Controller_Base { - /** - * @param Minify_Env $env Environment - * @param Minify_Source_Factory $sourceFactory Source factory. If you need to serve files from any path, this - * component must have its "checkAllowDirs" option set to false. - */ - public function __construct(Minify_Env $env, Minify_Source_Factory $sourceFactory) - { - parent::__construct($env, $sourceFactory); - } - /** * Set up file sources * @@ -62,16 +55,10 @@ class Minify_Controller_Files extends Minify_Controller_Base { $sources = array(); foreach ($files as $file) { - if ($file instanceof Minify_SourceInterface) { - $sources[] = $file; - continue; - } try { - $sources[] = $this->sourceFactory->makeSource(array( - 'filepath' => $file, - )); + $sources[] = $this->sourceFactory->makeSource($file); } catch (Minify_Source_FactoryException $e) { - $this->log($e->getMessage()); + $this->logger->error($e->getMessage()); return new Minify_ServeConfiguration($options); } diff --git a/lib/Minify/Controller/Groups.php b/lib/Minify/Controller/Groups.php index e911b88..5c415e0 100644 --- a/lib/Minify/Controller/Groups.php +++ b/lib/Minify/Controller/Groups.php @@ -51,7 +51,7 @@ class Minify_Controller_Groups extends Minify_Controller_Files { ); if (false === $pathInfo || ! isset($groups[$pathInfo])) { // no PATH_INFO or not a valid group - $this->log("Missing PATH_INFO or no group set for \"$pathInfo\""); + $this->logger->info("Missing PATH_INFO or no group set for \"$pathInfo\""); return new Minify_ServeConfiguration($options); } diff --git a/lib/Minify/Controller/MinApp.php b/lib/Minify/Controller/MinApp.php index 6517e8a..9ce168c 100644 --- a/lib/Minify/Controller/MinApp.php +++ b/lib/Minify/Controller/MinApp.php @@ -58,13 +58,13 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { $selectionId .= 'g=' . $get['g']; $keys = explode(',', $get['g']); if ($keys != array_unique($keys)) { - $this->log("Duplicate group key found."); + $this->logger->info("Duplicate group key found."); return new Minify_ServeConfiguration($options); } foreach ($keys as $key) { if (! isset($localOptions['groups'][$key])) { - $this->log("A group configuration for \"{$key}\" was not found"); + $this->logger->info("A group configuration for \"{$key}\" was not found"); return new Minify_ServeConfiguration($options); } @@ -76,23 +76,17 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { $files = (array)$files; } foreach ($files as $file) { - if ($file instanceof Minify_SourceInterface) { - $sources[] = $file; - continue; - } try { - $source = $this->sourceFactory->makeSource(array( - 'filepath' => $file, - )); + $source = $this->sourceFactory->makeSource($file); $sources[] = $source; } catch (Minify_Source_FactoryException $e) { - $this->log($e->getMessage()); + $this->logger->error($e->getMessage()); if (null === $firstMissingResource) { $firstMissingResource = basename($file); continue; } else { $secondMissingResource = basename($file); - $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource'"); + $this->logger->info("More than one file was missing: '$firstMissingResource', '$secondMissingResource'"); return new Minify_ServeConfiguration($options); } @@ -112,14 +106,14 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { // no "\" || strpos($get['f'], '\\') !== false ) { - $this->log("GET param 'f' was invalid"); + $this->logger->info("GET param 'f' was invalid"); return new Minify_ServeConfiguration($options); } $ext = ".{$m[1]}"; $files = explode(',', $get['f']); if ($files != array_unique($files)) { - $this->log("Duplicate files were specified"); + $this->logger->info("Duplicate files were specified"); return new Minify_ServeConfiguration($options); } @@ -131,7 +125,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { // valid base $base = "/{$get['b']}/"; } else { - $this->log("GET param 'b' was invalid"); + $this->logger->info("GET param 'b' was invalid"); return new Minify_ServeConfiguration($options); } @@ -153,19 +147,17 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { } try { - $source = $this->sourceFactory->makeSource(array( - 'filepath' => $path, - )); + $source = $this->sourceFactory->makeSource($path); $sources[] = $source; $basenames[] = basename($path, $ext); } catch (Minify_Source_FactoryException $e) { - $this->log($e->getMessage()); + $this->logger->error($e->getMessage()); if (null === $firstMissingResource) { $firstMissingResource = $uri; continue; } else { $secondMissingResource = $uri; - $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'"); + $this->logger->info("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'"); return new Minify_ServeConfiguration($options); } @@ -178,7 +170,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { } if (!$sources) { - $this->log("No sources to serve"); + $this->logger->info("No sources to serve"); return new Minify_ServeConfiguration($options); } diff --git a/lib/Minify/ControllerInterface.php b/lib/Minify/ControllerInterface.php index 3ef1684..3828875 100644 --- a/lib/Minify/ControllerInterface.php +++ b/lib/Minify/ControllerInterface.php @@ -1,5 +1,7 @@ $_SERVER, 'get' => $_GET, + 'post' => $_POST, 'cookie' => $_COOKIE, ), $options); @@ -33,6 +34,7 @@ class Minify_Env { $this->server['DOCUMENT_ROOT'] = rtrim($this->server['DOCUMENT_ROOT'], '/\\'); } $this->get = $options['get']; + $this->post = $options['post']; $this->cookie = $options['cookie']; } @@ -47,30 +49,36 @@ class Minify_Env { : null; } - public function cookie($key = null) + public function cookie($key = null, $default = null) { if (null === $key) { return $this->cookie; } - return isset($this->cookie[$key]) - ? $this->cookie[$key] - : null; + return isset($this->cookie[$key]) ? $this->cookie[$key] : $default; } - public function get($key = null) + public function get($key = null, $default = null) { if (null === $key) { return $this->get; } - return isset($this->get[$key]) - ? $this->get[$key] - : null; + return isset($this->get[$key]) ? $this->get[$key] : $default; + } + + public function post($key = null, $default = null) + { + if (null === $key) { + return $this->post; + } + + return isset($this->post[$key]) ? $this->post[$key] : $default; } protected $server = null; protected $get = null; + protected $post = null; protected $cookie = null; /** diff --git a/lib/Minify/HTML/Helper.php b/lib/Minify/HTML/Helper.php index 5be4300..c67d891 100644 --- a/lib/Minify/HTML/Helper.php +++ b/lib/Minify/HTML/Helper.php @@ -31,17 +31,19 @@ class Minify_HTML_Helper { public static function getUri($keyOrFiles, $opts = array()) { $opts = array_merge(array( // default options - 'farExpires' => true - ,'debug' => false - ,'charset' => 'UTF-8' - ,'minAppUri' => '/min' - ,'rewriteWorks' => true - ,'groupsConfigFile' => '' + 'farExpires' => true, + 'debug' => false, + 'charset' => 'UTF-8', + 'minAppUri' => '/min', + 'rewriteWorks' => true, + 'groupsConfigFile' => self::app()->groupsConfigPath, ), $opts); + $h = new self; $h->minAppUri = $opts['minAppUri']; $h->rewriteWorks = $opts['rewriteWorks']; $h->groupsConfigFile = $opts['groupsConfigFile']; + if (is_array($keyOrFiles)) { $h->setFiles($keyOrFiles, $opts['farExpires']); } else { @@ -98,7 +100,7 @@ class Minify_HTML_Helper { $file = substr($file, 2); } elseif (0 === strpos($file, '/') || 1 === strpos($file, ':\\')) { - $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1); + $file = substr($file, strlen(self::app()->env->getDocRoot()) + 1); } $file = strtr($file, '\\', '/'); $files[$k] = $file; @@ -117,7 +119,7 @@ class Minify_HTML_Helper { $this->_groupKey = $key; if ($checkLastModified) { if (! $this->groupsConfigFile) { - $this->groupsConfigFile = dirname(dirname(dirname(__DIR__))) . '/groupsConfig.php'; + $this->groupsConfigFile = self::app()->groupsConfigPath; } if (is_file($this->groupsConfigFile)) { $gc = (require $this->groupsConfigFile); @@ -145,23 +147,35 @@ class Minify_HTML_Helper { public static function getLastModified($sources, $lastModified = 0) { $max = $lastModified; + $factory = self::app()->sourceFactory; + /** @var Minify_Source $source */ foreach ((array)$sources as $source) { - if ($source instanceof Minify_Source) { - $max = max($max, $source->getLastModified()); - } elseif (is_string($source)) { - if (0 === strpos($source, '//')) { - $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); - } - if (is_file($source)) { - $max = max($max, filemtime($source)); - } - } + $source = $factory->makeSource($source); + $max = max($max, $source->getLastModified()); } return $max; } + /** + * @param \Minify\App $app + * @return \Minify\App + * @internal + */ + public static function app(\Minify\App $app = null) + { + static $cached; + if ($app) { + $cached = $app; + return $app; + } + if ($cached === null) { + $cached = (require __DIR__ . '/../../../bootstrap.php'); + } + return $cached; + } + protected $_groupKey = null; // if present, URI will be like g=... protected $_filePaths = array(); protected $_lastModified = null; diff --git a/lib/Minify/Loader.php b/lib/Minify/Loader.php deleted file mode 100644 index b1df1fd..0000000 --- a/lib/Minify/Loader.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @deprecated Use Composer (/vendor/autoload.php) - */ -class Minify_Loader { - public function loadClass($class) - { - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR; - $file .= strtr($class, "\\_", DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) . '.php'; - if (is_readable($file)) { - require $file; - - return; - } - - $map = array( - 'JavascriptPacker' => 'class.JavaScriptPacker.php', - ); - - if (!isset($map[$class])) { - return; - } - - @include $map[$class]; - } - - public static function register() - { - $inst = new self(); - spl_autoload_register(array($inst, 'loadClass')); - - return $inst; - } -} - -return Minify_Loader::register(); diff --git a/lib/Minify/Logger.php b/lib/Minify/Logger.php deleted file mode 100644 index 5a9e931..0000000 --- a/lib/Minify/Logger.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * @todo lose this singleton! pass log object in Minify::serve and distribute to others - */ -class Minify_Logger { - - /** - * Set logger object. - * - * The object should have a method "log" that accepts a value as 1st argument and - * an optional string label as the 2nd. - * - * @param mixed $obj or a "falsey" value to disable - * @return null - */ - public static function setLogger($obj = null) { - self::$_logger = $obj - ? $obj - : null; - } - - /** - * Pass a message to the logger (if set) - * - * @param string $msg message to log - * @return null - */ - public static function log($msg, $label = 'Minify') { - if (! self::$_logger) return; - self::$_logger->log($msg, $label); - } - - /** - * @var mixed logger object (like FirePHP) or null (i.e. no logger available) - */ - private static $_logger = null; -} diff --git a/lib/Minify/Logger/LegacyHandler.php b/lib/Minify/Logger/LegacyHandler.php new file mode 100644 index 0000000..07f9991 --- /dev/null +++ b/lib/Minify/Logger/LegacyHandler.php @@ -0,0 +1,25 @@ +obj = $obj; + parent::__construct(); + } + + protected function write(array $record) + { + $this->obj->log((string)$record['formatted']); + } +} diff --git a/lib/Minify/Source/Factory.php b/lib/Minify/Source/Factory.php index c65ce6d..4e58b2d 100644 --- a/lib/Minify/Source/Factory.php +++ b/lib/Minify/Source/Factory.php @@ -133,12 +133,16 @@ class Minify_Source_Factory { */ public function makeSource($spec) { - $source = null; - - if ($spec instanceof Minify_SourceInterface) { - $source = $spec; + if (is_string($spec)) { + $spec = array( + 'filepath' => $spec, + ); + } elseif ($spec instanceof Minify_SourceInterface) { + return $spec; } + $source = null; + if (empty($spec['filepath'])) { // not much we can check return new Minify_Source($spec); diff --git a/min_extras/tools/minifyTextarea.php b/min_extras/tools/minifyTextarea.php index 8194fc8..fbdfcef 100644 --- a/min_extras/tools/minifyTextarea.php +++ b/min_extras/tools/minifyTextarea.php @@ -1,26 +1,29 @@ config->errorLogger) { + $app->config->errorLogger = true; } +$app->cache = new Minify_Cache_Null(); + +$env = $app->env; + function h($txt) { return htmlspecialchars($txt, ENT_QUOTES, 'UTF-8'); } -if (isset($_POST['textIn'])) { - require '../config.php'; - $textIn = str_replace("\r\n", "\n", getPost('textIn')); +if ($env->post('textIn')) { + $textIn = str_replace("\r\n", "\n", $env->post('textIn')); } -if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') { +if ($env->post('method') === 'Minify and serve') { - $base = trim(getPost('base')); + $base = trim($env->post('base')); if ($base) { $textIn = preg_replace( '@(]*>)@i' @@ -38,16 +41,12 @@ if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') { $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSSmin', 'minify'); } $source = new Minify_Source($sourceSpec); - Minify_Logger::setLogger(FirePHP::getInstance(true)); - - $env = new Minify_Env(); - $controller = new Minify_Controller_Files($env, new Minify_Source_Factory($env)); - $minify = new Minify(new Minify_Cache_Null()); + $controller = new Minify_Controller_Files($env, $app->sourceFactory, $app->logger); try { - $minify->serve($controller, array( - 'files' => $source - ,'contentType' => Minify::TYPE_HTML + $app->minify->serve($controller, array( + 'files' => $source, + 'contentType' => Minify::TYPE_HTML, )); } catch (Exception $e) { echo h($e->getMessage()); @@ -58,16 +57,16 @@ if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') { $tpl = array(); $tpl['classes'] = array('Minify_HTML', 'JSMin\\JSMin', 'Minify_CSS'); -if (isset($_POST['method']) && in_array($_POST['method'], $tpl['classes'])) { +if (in_array($env->post('method'), $tpl['classes'])) { $args = array($textIn); - if ($_POST['method'] === 'Minify_HTML') { + if ($env->post('method') === 'Minify_HTML') { $args[] = array( 'cssMinifier' => array('Minify_CSSmin', 'minify') ,'jsMinifier' => array('JSMin\\JSMin', 'minify') ); } - $func = array($_POST['method'], 'minify'); + $func = array($env->post('method'), 'minify'); $tpl['inBytes'] = strlen($textIn); $startTime = microtime(true); try { diff --git a/min_extras/tools/minifyUrl.php b/min_extras/tools/minifyUrl.php index 97f6319..a2629e6 100644 --- a/min_extras/tools/minifyUrl.php +++ b/min_extras/tools/minifyUrl.php @@ -5,7 +5,12 @@ die('Disabled: use this only for testing'); * Fetch and minify a URL (auto-detect HTML/JS/CSS) */ -require __DIR__ . '/../../bootstrap.php'; +$app = (require __DIR__ . '/../../bootstrap.php'); +/* @var \Minify\App $app */ + +$app->cache = new Minify_Cache_Null(); + +$env = $app->env; function getPost($key) { if (! isset($_POST[$key])) { @@ -47,9 +52,9 @@ if (isset($_POST['url'])) { require '../config.php'; - $url = trim(getPost('url')); - $ua = trim(getPost('ua')); - $cook = trim(getPost('cook')); + $url = trim($env->post('url')); + $ua = trim($env->post('ua')); + $cook = trim($env->post('cook')); if (! preg_match('@^https?://@', $url)) { die('HTTP(s) only.'); @@ -98,10 +103,10 @@ if (isset($_POST['url'])) { $sourceSpec['contentType'] = $type['minify']; if ($type['minify'] === 'text/html') { - if (isset($_POST['minJs'])) { + if ($env->post('minJs')) { $sourceSpec['minifyOptions']['jsMinifier'] = array('JSMin\\JSMin', 'minify'); } - if (isset($_POST['minCss'])) { + if ($env->post('minCss')) { $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSSmin', 'minify'); } } @@ -109,7 +114,7 @@ if (isset($_POST['url'])) { $source = new Minify_Source($sourceSpec); $sendType = 'text/plain'; - if ($type['minify'] === 'text/html' && ! isset($_POST['asText'])) { + if ($type['minify'] === 'text/html' && $env->post('asText') === null) { $sendType = $type['sent']; } if ($type['charset']) { @@ -119,10 +124,8 @@ if (isset($_POST['url'])) { // using combine instead of serve because it allows us to specify a // Content-Type like application/xhtml+xml IF we need to - $minify = new Minify(new Minify_Cache_Null()); - try { - echo $minify->combine(array($source)); + echo $app->minify->combine(array($source)); } catch (Exception $e) { header('Content-Type: text/html;charset=utf-8'); echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); @@ -132,9 +135,7 @@ if (isset($_POST['url'])) { header('Content-Type: text/html; charset=utf-8'); -$ua = get_magic_quotes_gpc() - ? stripslashes($_SERVER['HTTP_USER_AGENT']) - : $_SERVER['HTTP_USER_AGENT']; +$ua = $env->server('HTTP_USER_AGENT'); ?> Minify URL @@ -146,7 +147,7 @@ $ua = get_magic_quotes_gpc() The fetched resource Content-Type will determine the minifier used.

-

+

HTML options diff --git a/min_extras/tools/testRewriteUri.php b/min_extras/tools/testRewriteUri.php index 2d46b8c..f2f0011 100644 --- a/min_extras/tools/testRewriteUri.php +++ b/min_extras/tools/testRewriteUri.php @@ -1,51 +1,39 @@ env; header('Content-Type: text/html;charset=utf-8'); function h($str) { return htmlspecialchars($str, ENT_QUOTES); } -function getPost($name, $default = '') { return isset($_POST[$name]) ? $_POST[$name] : $default; } - function getInput($name, $default = '', $size = 50) { - $val = h(isset($_POST[$name]) ? $_POST[$name] : $default); - return ""; -} - -// validate user POST (no arrays and fix slashes) -if (! empty($_POST)) { - foreach ($_POST as $name => $val) { - if (! is_string($val)) { - unset($_POST[$name]); - continue; - } - if (get_magic_quotes_gpc()) { - $_POST[$name] = stripslashes($val); - } - } + global $env; + $val = $env->post($name, $default); + return ""; } $defaultCurrentDir = __DIR__; -$defaultDocRoot = realpath($_SERVER['DOCUMENT_ROOT']); +$defaultDocRoot = realpath($env->getDocRoot()); $defaultSymLink = '//symlinkPath'; $defaultSymTarget = ($defaultCurrentDir[0] === '/') ? '/tmp' : 'C:\\WINDOWS\\Temp'; $defaultCss = "url(hello.gif)\nurl(../hello.gif)\nurl(../../hello.gif)\nurl(up/hello.gif)"; $out = ''; -if (isset($_POST['css'])) { - require '../config.php'; +if ($env->post('css')) { $symlinks = array(); - if ('' !== ($target = getPost('symTarget'))) { - $symlinks[getPost('symLink')] = $target; + if ('' !== ($target = $env->post('symTarget'))) { + $symlinks[$env->post('symLink')] = $target; } $css = Minify_CSS_UriRewriter::rewrite( - getPost('css') - , getPost('currentDir') - , getPost('docRoot') - , $symlinks + $env->post('css'), + $env->post('currentDir'), + $env->post('docRoot'), + $symlinks ); $out = "
" . h($css) . '
'; } @@ -57,7 +45,7 @@ if (isset($_POST['css'])) {
-

+

diff --git a/phpunit.xml b/phpunit.xml index b11ab15..b6c77a5 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -16,6 +16,7 @@ tests + tests/JsClosureCompilerTest.php diff --git a/tests/JsClosureCompilerTest.php b/tests/JsClosureCompilerTest.php index 5b43964..380958f 100644 --- a/tests/JsClosureCompilerTest.php +++ b/tests/JsClosureCompilerTest.php @@ -51,7 +51,7 @@ class JsClosureCompilerTest extends PHPUnit_Framework_TestCase { $src = "(function(){})();"; $minOutput = $this->compile($src, array( - Minify_JS_ClosureCompiler::OPTION_MAX_BYTES => 0 + Minify_JS_ClosureCompiler::OPTION_MAX_BYTES => 0, )); $this->assertSame($src, $minOutput, 'With no limit set, it should compile properly'); @@ -65,7 +65,7 @@ class JsClosureCompilerTest extends PHPUnit_Framework_TestCase $e = null; try { $this->compile($src, array( - Minify_JS_ClosureCompiler::OPTION_MAX_BYTES => $allowedBytes + Minify_JS_ClosureCompiler::OPTION_MAX_BYTES => $allowedBytes, )); } catch (Minify_JS_ClosureCompiler_Exception $e) { } @@ -78,10 +78,14 @@ class JsClosureCompilerTest extends PHPUnit_Framework_TestCase // Test additional options passed to HTTP request public function test6() { - $ecmascript5 = "[1,].length;"; + $ecmascript3 = "[1,].length;"; $e = null; try { - $this->compile($ecmascript5); + $this->compile($ecmascript3, array( + Minify_JS_ClosureCompiler::OPTION_ADDITIONAL_OPTIONS => array( + 'language' => 'ECMASCRIPT3', + ), + )); } catch (Minify_JS_ClosureCompiler_Exception $e) { } $this->assertInstanceOf('Minify_JS_ClosureCompiler_Exception', $e, 'Throws Minify_JS_ClosureCompiler_Exception'); @@ -94,8 +98,8 @@ class JsClosureCompilerTest extends PHPUnit_Framework_TestCase $minExpected = '1;'; $minOutput = $this->compile($ecmascript5, array( Minify_JS_ClosureCompiler::OPTION_ADDITIONAL_OPTIONS => array( - 'language' => 'ECMASCRIPT5' - ) + 'language' => 'ECMASCRIPT5', + ), )); $this->assertSame($minExpected, $minOutput, 'Language option should make it compile'); } diff --git a/utils.php b/utils.php index d3b8023..46e29d7 100644 --- a/utils.php +++ b/utils.php @@ -56,7 +56,7 @@ function Minify_mtime($keysAndFiles, $groupsConfigFile = null) { $gc = null; if (! $groupsConfigFile) { - $groupsConfigFile = __DIR__ . '/groupsConfig.php'; + $groupsConfigFile = Minify_HTML_Helper::app()->groupsConfigPath; } $sources = array(); foreach ($keysAndFiles as $keyOrFile) {