1
0
mirror of https://github.com/mrclay/minify.git synced 2025-01-17 21:28:14 +01:00

Minify.php : moved logging to Logger.php

Controller/Base.php : + log()
Changed controllers to use $this->log()
HTML.php : Issue 83 (preserve some WS around scripts)
CSS.php : + symlinks option to correct some rewritten URIs
min/config.php : + $min_symlinks
min/index.php : normalize symlinks and use Logger.php
min_unit_tests/_inc.php : default FirePHP logging, start output buffering
This commit is contained in:
Steve Clay 2009-01-28 20:02:25 +00:00
parent 7ca31ba2b2
commit 4c1fe68ab6
14 changed files with 153 additions and 66 deletions

View File

@ -100,6 +100,21 @@ $min_serveOptions['minApp']['groupsOnly'] = false;
$min_serveOptions['minApp']['maxFiles'] = 10;
/**
* If you minify CSS files stored in symlink-ed directories, the URI rewriting
* algorithm can fail. To prevent this, provide an array of link paths to
* target paths, where the link paths are within the document root.
*
* Because paths need to be normalized for this to work, use "//" to substitute
* the doc root in the link paths (the array keys). E.g.:
* <code>
* array('//symlink' => '/real/target/path') // unix
* array('//static' => 'D:\\staticStorage') // Windows
* </code>
*/
$min_symlinks = array();
/**
* If you upload files from Windows to a non-Windows server, Windows may report
* incorrect mtimes for the files. This may cause Minify to keep serving stale

View File

@ -29,15 +29,27 @@ if ($min_documentRoot) {
Minify::setDocRoot(); // IIS may need help
}
// normalize paths in symlinks
foreach ($min_symlinks as $link => $target) {
$link = str_replace('//', realpath($SERVER['DOCUMENT_ROOT']), $link);
$link = strtr($link, '/', DIRECTORY_SEPARATOR);
$min_serveOptions['minifierOptions']['text/css']['symlinks'][$link] = realpath($target);
}
if ($min_allowDebugFlag && isset($_GET['debug'])) {
$min_serveOptions['debug'] = true;
}
if (true === $min_errorLogger) {
require_once 'FirePHP.php';
Minify::setLogger(FirePHP::getInstance(true));
} elseif ($min_errorLogger) {
Minify::setLogger($min_errorLogger);
if ($min_errorLogger) {
require_once 'Minify/Logger.php';
if (true === $min_errorLogger) {
require_once 'FirePHP.php';
Minify_Logger::setLogger(FirePHP::getInstance(true));
} else {
Minify_Logger::setLogger($min_errorLogger);
}
}
// check for URI versioning
if (preg_match('/&\\d/', $_SERVER['QUERY_STRING'])) {
$min_serveOptions['maxAge'] = 31536000;

View File

@ -358,41 +358,11 @@ class Minify {
if ($unsetPathInfo) {
unset($_SERVER['PATH_INFO']);
}
Minify::logError("setDocRoot() set DOCUMENT_ROOT to \"{$_SERVER['DOCUMENT_ROOT']}\"");
require_once 'Minify/Logger.php';
Minify_Logger::log("setDocRoot() set DOCUMENT_ROOT to \"{$_SERVER['DOCUMENT_ROOT']}\"");
}
}
/**
* Set error 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;
}
/**
* Send message to the error log (if set)
*
* @param string $msg message to log
* @return null
*/
public static function logError($msg) {
if (! self::$_logger) return;
self::$_logger->log($msg, 'Minify');
}
/**
* @var mixed logger object (like FirePHP) or null (i.e. no logging enabled)
*/
private static $_logger = null;
/**
* @var mixed Minify_Cache_* object or null (i.e. no server cache is used)
*/

View File

@ -163,7 +163,10 @@ class Minify_CSS {
self::$_tempPrepend = $options['prependRelativePath'];
$rewrite = true;
} elseif (isset($options['currentDir'])) {
self::$_tempCurrentDir = $options['currentDir'];
self::$_tempCurrentDir = realpath($options['currentDir']);
if (isset($options['symlinks'])) {
self::$_tempSymlinks = $options['symlinks'];
}
$rewrite = true;
}
if ($rewrite) {
@ -172,7 +175,9 @@ class Minify_CSS {
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
,array(self::$className, '_urlCB'), $css);
}
// cleanup statics
self::$_tempPrepend = self::$_tempCurrentDir = '';
self::$_tempSymlinks = array();
return trim($css);
}
@ -190,28 +195,34 @@ class Minify_CSS {
}
/**
* @var bool Are we "in" a hack?
* @var bool Are we "in" a hack?
*
* I.e. are some browsers targetted until the next comment?
* I.e. are some browsers targetted until the next comment?
*/
protected static $_inHack = false;
/**
* @var string string to be prepended to relative URIs
* @var string string to be prepended to relative URIs
*/
protected static $_tempPrepend = '';
/**
* @var string directory of this stylesheet for rewriting purposes
* @var string directory of this stylesheet for rewriting purposes
*/
protected static $_tempCurrentDir = '';
/**
* @var array directory replacements to map symlink targets back to their
* source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
*/
protected static $_tempSymlinks = array();
/**
* Process a comment and return a replacement
*
* @param array $m regex matches
*
* @return string
* @return string
*/
protected static function _commentCB($m)
{
@ -291,6 +302,14 @@ class Minify_CSS {
// prepend path with current dir separator (OS-independent)
$path = self::$_tempCurrentDir
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
// "unresolve" a symlink back to doc root
foreach (self::$_tempSymlinks as $link => $target) {
if (0 === strpos($path, $target)) {
// replace $target with $link
$path = $link . substr($path, strlen($target));
break;
}
}
// strip doc root
$path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT'])));
// fix to absolute URL

View File

@ -188,4 +188,14 @@ abstract class Minify_Controller_Base {
}
return $options;
}
/**
* Send message to the Minify logger
* @param string $msg
* @return null
*/
protected function log($msg) {
require_once 'Minify/Logger.php';
Minify_Logger::log($msg);
}
}

View File

@ -58,7 +58,7 @@ class Minify_Controller_Files extends Minify_Controller_Base {
'filepath' => $realPath
));
} else {
Minify::logError("The path \"{$file}\" could not be found (or was not a file)");
$this->log("The path \"{$file}\" could not be found (or was not a file)");
return $options;
}
}

View File

@ -55,7 +55,7 @@ class Minify_Controller_Groups extends Minify_Controller_Base {
);
if (false === $pi || ! isset($groups[$pi])) {
// no PATH_INFO or not a valid group
Minify::logError("Missing PATH_INFO or no group set for \"$pi\"");
$this->log("Missing PATH_INFO or no group set for \"$pi\"");
return $options;
}
$sources = array();
@ -73,7 +73,7 @@ class Minify_Controller_Groups extends Minify_Controller_Base {
'filepath' => $realPath
));
} else {
Minify::logError("The path \"{$file}\" could not be found (or was not a file)");
$this->log("The path \"{$file}\" could not be found (or was not a file)");
return $options;
}
}

View File

@ -37,7 +37,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
if (isset($_GET['g'])) {
// try groups
if (! isset($cOptions['groups'][$_GET['g']])) {
Minify::logError("A group configuration for \"{$_GET['g']}\" was not set");
$this->log("A group configuration for \"{$_GET['g']}\" was not set");
return $options;
}
foreach ((array)$cOptions['groups'][$_GET['g']] as $file) {
@ -54,7 +54,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
'filepath' => $file
));
} else {
Minify::logError("The path \"{$file}\" could not be found (or was not a file)");
$this->log("The path \"{$file}\" could not be found (or was not a file)");
return $options;
}
}
@ -72,12 +72,12 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
// no "./"
|| preg_match('/(?:^|[^\\.])\\.\\//', $_GET['f'])
) {
Minify::logError("GET param 'f' invalid (see MinApp.php line 63)");
$this->log("GET param 'f' invalid (see MinApp.php line 63)");
return $options;
}
$files = explode(',', $_GET['f']);
if (count($files) > $cOptions['maxFiles'] || $files != array_unique($files)) {
Minify::logError("Too many or duplicate files specified");
$this->log("Too many or duplicate files specified");
return $options;
}
if (isset($_GET['b'])) {
@ -88,7 +88,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
// valid base
$base = "/{$_GET['b']}/";
} else {
Minify::logError("GET param 'b' invalid (see MinApp.php line 84)");
$this->log("GET param 'b' invalid (see MinApp.php line 84)");
return $options;
}
} else {
@ -102,10 +102,10 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
$path = $_SERVER['DOCUMENT_ROOT'] . $base . $file;
$file = realpath($path);
if (false === $file) {
Minify::logError("Path \"{$path}\" failed realpath()");
$this->log("Path \"{$path}\" failed realpath()");
return $options;
} elseif (! parent::_fileIsSafe($file, $allowDirs)) {
Minify::logError("Path \"{$path}\" failed Minify_Controller_Base::_fileIsSafe()");
$this->log("Path \"{$path}\" failed Minify_Controller_Base::_fileIsSafe()");
return $options;
} else {
$sources[] = new Minify_Source(array(
@ -117,7 +117,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
if ($sources) {
$this->sources = $sources;
} else {
Minify::logError("No sources to serve");
$this->log("No sources to serve");
}
return $options;
}

View File

@ -65,7 +65,7 @@ class Minify_HTML {
// replace SCRIPTs (and minify) with placeholders
$html = preg_replace_callback(
'/\\s*(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>\\s*/i'
'/(\\s*)(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
,array(self::$className, '_removeScriptCB')
,$html);
@ -183,9 +183,13 @@ class Minify_HTML {
protected static function _removeScriptCB($m)
{
$openScript = $m[1];
$js = $m[2];
$openScript = $m[2];
$js = $m[3];
// whitespace surrounding? preserve at least one space
$ws1 = ($m[1] === '') ? '' : ' ';
$ws2 = ($m[4] === '') ? '' : ' ';
// remove HTML comments (and ending "//" if present)
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
@ -199,8 +203,8 @@ class Minify_HTML {
$js = call_user_func($minifier, $js);
return self::_reservePlace(self::_needsCdata($js)
? "{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>"
: "{$openScript}{$js}</script>"
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
);
}

45
min/lib/Minify/Logger.php Normal file
View File

@ -0,0 +1,45 @@
<?php
/**
* Class Minify_Logger
* @package Minify
*/
/**
* Message logging class
*
* @package Minify
* @author Stephen Clay <steve@mrclay.org>
*/
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;
}

View File

@ -12,6 +12,15 @@ if ($min_documentRoot) {
$_SERVER['DOCUMENT_ROOT'] = $min_documentRoot;
}
// default log to FirePHP
require_once 'Minify/Logger.php';
if ($min_errorLogger && true !== $min_errorLogger) { // custom logger
Minify_Logger::setLogger($min_errorLogger);
} else {
require_once 'FirePHP.php';
Minify_Logger::setLogger(FirePHP::getInstance(true));
}
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
@ -37,3 +46,5 @@ function assertTrue($test, $message)
return (bool)$test;
}
ob_start();

View File

@ -4,10 +4,10 @@ http-equiv="content-type" content="text/html; charset=iso-8859-1" /><meta
name="author" content="Dave Shea" /><meta
name="keywords" content="design, css, cascading, style, sheets, xhtml, graphic design, w3c, web standards, visual, display" /><meta
name="description" content="A demonstration of what can be accomplished visually through CSS-based design." /><meta
name="robots" content="all" /><title>css Zen Garden: The Beauty in CSS Design</title><script type="text/javascript">var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
name="robots" content="all" /><title>css Zen Garden: The Beauty in CSS Design</title> <script type="text/javascript">var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}</script><script type="text/javascript">/*<![CDATA[*/var i=0;while(++i<10)
{}/*]]>*/</script><script type="text/javascript">i=1;</script><script type="text/javascript">/*<![CDATA[*/(i<1);/*]]>*/</script><!--[if IE 6]><style type="text/css">/*<![CDATA[*/
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}</script> <script type="text/javascript">/*<![CDATA[*/var i=0;while(++i<10)
{}/*]]>*/</script> <script type="text/javascript">i=1;</script> <script type="text/javascript">/*<![CDATA[*/(i<1);/*]]>*/</script> <!--[if IE 6]><style type="text/css">/*<![CDATA[*/
/* copyright: you'll need CDATA for this < & */
body{background:white}/*]]>*/</style><![endif]--><style type="text/css" title="currentStyle" media="screen">@import "/001/001.css";/*\*/css
hack{}/**//*/*/css

View File

@ -89,6 +89,7 @@ Design</span></h2>
<textarea name="comment" id="comment" rows="6" class="maxwidth" cols="80">66666
1234567890</textarea>
Preserve at least 1 char of whitespace near <script type="text/javascript"></script>scripts in case of document.write().
</div>
</body>
</html>

View File

@ -4,10 +4,10 @@ http-equiv="content-type" content="text/html; charset=iso-8859-1"><meta
name="author" content="Dave Shea"><meta
name="keywords" content="design, css, cascading, style, sheets, xhtml, graphic design, w3c, web standards, visual, display"><meta
name="description" content="A demonstration of what can be accomplished visually through CSS-based design."><meta
name="robots" content="all"><title>css Zen Garden: The Beauty in CSS Design</title><script type="text/javascript">var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
name="robots" content="all"><title>css Zen Garden: The Beauty in CSS Design</title> <script type="text/javascript">var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}</script><script type="text/javascript">var i=0;while(++i<10)
{}</script><script type="text/javascript">i=1;</script><script type="text/javascript">(i<1);</script><!--[if IE 6]><style type="text/css">
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}</script> <script type="text/javascript">var i=0;while(++i<10)
{}</script> <script type="text/javascript">i=1;</script> <script type="text/javascript">(i<1);</script> <!--[if IE 6]><style type="text/css">
/* copyright: you'll need CDATA for this < & */
body{background:white}</style><![endif]--><style type="text/css" title="currentStyle" media="screen">@import "/001/001.css";/*\*/css
hack{}/**//*/*/css
@ -33,4 +33,4 @@ class="p2"><span>Download the sample <a
href="/zengarden-sample.html" title="This page's source HTML code, not to be modified.">html file</a> and <a
href="/zengarden-sample.css" title="This page's sample CSS, the file you may modify.">css file</a></span></p></div><textarea name="comment" id="comment" rows="6" class="maxwidth" cols="80">66666
1234567890</textarea></div></body></html>
1234567890</textarea>Preserve at least 1 char of whitespace near <script type="text/javascript"></script>scripts in case of document.write().</div></body></html>