1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-08 07:06:49 +02:00

builder/index.php : fix Issue 67

Minify.php : allow minifier = ''
Minify/CSS.php : more extensible (Issue 64)
Minify/HTML.php : more extensible
Minify/Lines.php : fix Issue 55
Minify/Packer.php : usability
test_environment.php : test DOCUMENT_ROOT
test_Minify_Lines.php : test Issue 55
This commit is contained in:
Steve Clay
2008-12-16 17:13:58 +00:00
parent 3d2076148c
commit f9abe0a730
11 changed files with 421 additions and 350 deletions

View File

@@ -1,7 +1,8 @@
<?php <?php
// check for auto-encoding // check for auto-encoding
$encodeOutput = ! ini_get('zlib.output_compression'); $encodeOutput = (function_exists('gzdeflate')
&& !ini_get('zlib.output_compression'));
require dirname(__FILE__) . '/../config.php'; require dirname(__FILE__) . '/../config.php';

View File

@@ -12,4 +12,23 @@
return array( return array(
// 'js' => array('//js/file1.js', '//js/file2.js'), // 'js' => array('//js/file1.js', '//js/file2.js'),
// 'css' => array('//css/file1.css', '//css/file2.css'), // 'css' => array('//css/file1.css', '//css/file2.css'),
// custom source example
/*'js2' => array(
dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js',
// do NOT process this file
new Minify_Source(array(
'filepath' => dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js',
'minifier' => create_function('$a', 'return $a;')
))
),//*/
/*'js3' => array(
dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js',
// do NOT process this file
new Minify_Source(array(
'filepath' => dirname(__FILE__) . '/../min_unit_tests/_test_files/js/before.js',
'minifier' => array('Minify_Packer', 'minify')
))
),//*/
); );

View File

@@ -56,9 +56,9 @@ class Minify {
* need to recombine files, minify and encode the output. * need to recombine files, minify and encode the output.
* *
* @param mixed $cache object with identical interface as Minify_Cache_File or * @param mixed $cache object with identical interface as Minify_Cache_File or
* a directory path. (default = '') * a directory path. (default = '')
* *
* @param bool $fileLocking (default = true) This only applies if the first * @param bool $fileLocking (default = true) This only applies if the first
* parameter is a string. * parameter is a string.
* *
* @return null * @return null
@@ -347,17 +347,17 @@ class Minify {
*/ */
public static function setDocRoot($unsetPathInfo = false) public static function setDocRoot($unsetPathInfo = false)
{ {
if (isset($_SERVER['SERVER_SOFTWARE']) if (isset($_SERVER['SERVER_SOFTWARE'])
&& 0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/') && 0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/')
) { ) {
$_SERVER['DOCUMENT_ROOT'] = substr( $_SERVER['DOCUMENT_ROOT'] = substr(
$_SERVER['PATH_TRANSLATED'] $_SERVER['PATH_TRANSLATED']
,0 ,0
,strlen($_SERVER['PATH_TRANSLATED']) - strlen($_SERVER['SCRIPT_NAME']) ,strlen($_SERVER['PATH_TRANSLATED']) - strlen($_SERVER['SCRIPT_NAME'])
); );
if ($unsetPathInfo) { if ($unsetPathInfo) {
unset($_SERVER['PATH_INFO']); unset($_SERVER['PATH_INFO']);
} }
} }
} }
@@ -439,7 +439,7 @@ class Minify {
$options = (null !== $source->minifyOptions) $options = (null !== $source->minifyOptions)
? array_merge($defaultOptions, $source->minifyOptions) ? array_merge($defaultOptions, $source->minifyOptions)
: $defaultOptions; : $defaultOptions;
if ($defaultMinifier) { if ($minifier) {
self::$_controller->loadMinifier($minifier); self::$_controller->loadMinifier($minifier);
// get source content and minify it // get source content and minify it
$pieces[] = call_user_func($minifier, $source->getContent(), $options); $pieces[] = call_user_func($minifier, $source->getContent(), $options);

View File

@@ -1,322 +1,330 @@
<?php <?php
/** /**
* Class Minify_CSS * Class Minify_CSS
* @package Minify * @package Minify
*/ */
/** /**
* Compress CSS * Compress CSS
* *
* This is a heavy regex-based removal of whitespace, unnecessary * This is a heavy regex-based removal of whitespace, unnecessary
* comments and tokens, and some CSS value minimization, where practical. * comments and tokens, and some CSS value minimization, where practical.
* Many steps have been taken to avoid breaking comment-based hacks, * Many steps have been taken to avoid breaking comment-based hacks,
* including the ie5/mac filter (and its inversion), but expect tricky * including the ie5/mac filter (and its inversion), but expect tricky
* hacks involving comment tokens in 'content' value strings to break * hacks involving comment tokens in 'content' value strings to break
* minimization badly. A test suite is available. * minimization badly. A test suite is available.
* *
* @package Minify * @package Minify
* @author Stephen Clay <steve@mrclay.org> * @author Stephen Clay <steve@mrclay.org>
*/ * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
class Minify_CSS { */
class Minify_CSS {
/**
* Minify a CSS string /**
* * Defines which class to call as part of callbacks, change this
* @param string $css * if you extend Minify_CSS
* * @var string
* @param array $options available options: */
* protected static $className = 'Minify_CSS';
* 'preserveComments': (default true) multi-line comments that begin
* with "/*!" will be preserved with newlines before and after to /**
* enhance readability. * Minify a CSS string
* *
* 'prependRelativePath': (default null) if given, this string will be * @param string $css
* prepended to all relative URIs in import/url declarations *
* * @param array $options available options:
* 'currentDir': (default null) if given, this is assumed to be the *
* directory of the current CSS file. Using this, minify will rewrite * 'preserveComments': (default true) multi-line comments that begin
* all relative URIs in import/url declarations to correctly point to * with "/*!" will be preserved with newlines before and after to
* the desired files. For this to work, the files *must* exist and be * enhance readability.
* visible by the PHP process. *
* * 'prependRelativePath': (default null) if given, this string will be
* @return string * prepended to all relative URIs in import/url declarations
*/ *
public static function minify($css, $options = array()) * 'currentDir': (default null) if given, this is assumed to be the
{ * directory of the current CSS file. Using this, minify will rewrite
if (isset($options['preserveComments']) * all relative URIs in import/url declarations to correctly point to
&& !$options['preserveComments']) { * the desired files. For this to work, the files *must* exist and be
return self::_minify($css, $options); * visible by the PHP process.
} *
require_once 'Minify/CommentPreserver.php'; * @return string
// recursive calls don't preserve comments */
$options['preserveComments'] = false; public static function minify($css, $options = array())
return Minify_CommentPreserver::process( {
$css if (isset($options['preserveComments'])
,array('Minify_CSS', 'minify') && !$options['preserveComments']) {
,array($options) return self::_minify($css, $options);
); }
} require_once 'Minify/CommentPreserver.php';
// recursive calls don't preserve comments
/** $options['preserveComments'] = false;
* Minify a CSS string return Minify_CommentPreserver::process(
* $css
* @param string $css ,array(self::$className, 'minify')
* ,array($options)
* @param array $options To enable URL rewriting, set the value );
* for key 'prependRelativePath'. }
*
* @return string /**
*/ * Minify a CSS string
protected static function _minify($css, $options) *
{ * @param string $css
$css = str_replace("\r\n", "\n", $css); *
* @param array $options To enable URL rewriting, set the value
// preserve empty comment after '>' * for key 'prependRelativePath'.
// http://www.webdevout.net/css-hacks#in_css-selectors *
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css); * @return string
*/
// preserve empty comment between property and value protected static function _minify($css, $options)
// http://css-discuss.incutio.com/?page=BoxModelHack {
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css); $css = str_replace("\r\n", "\n", $css);
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
// preserve empty comment after '>'
// apply callback to all valid comments (and strip out surrounding ws // http://www.webdevout.net/css-hacks#in_css-selectors
self::$_inHack = false; $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
,array('Minify_CSS', '_commentCB'), $css); // preserve empty comment between property and value
// http://css-discuss.incutio.com/?page=BoxModelHack
// remove ws around { } and last semicolon in declaration block $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
$css = preg_replace('/\\s*{\\s*/', '{', $css); $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
// apply callback to all valid comments (and strip out surrounding ws
// remove ws surrounding semicolons self::$_inHack = false;
$css = preg_replace('/\\s*;\\s*/', ';', $css); $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
,array(self::$className, '_commentCB'), $css);
// remove ws around urls
$css = preg_replace('/ // remove ws around { } and last semicolon in declaration block
url\\( # url( $css = preg_replace('/\\s*{\\s*/', '{', $css);
\\s* $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
\\s* // remove ws surrounding semicolons
\\) # ) $css = preg_replace('/\\s*;\\s*/', ';', $css);
/x', 'url($1)', $css);
// remove ws around urls
// remove ws between rules and colons $css = preg_replace('/
$css = preg_replace('/ url\\( # url(
\\s* \\s*
([{;]) # 1 = beginning of block or rule separator ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
\\s* \\s*
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter) \\) # )
\\s* /x', 'url($1)', $css);
:
\\s* // remove ws between rules and colons
(\\b|[#\'"]) # 3 = first character of a value $css = preg_replace('/
/x', '$1$2:$3', $css); \\s*
([{;]) # 1 = beginning of block or rule separator
// remove ws in selectors \\s*
$css = preg_replace_callback('/ ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
(?: # non-capture \\s*
\\s* :
[^~>+,\\s]+ # selector part \\s*
\\s* (\\b|[#\'"]) # 3 = first character of a value
[,>+~] # combinators /x', '$1$2:$3', $css);
)+
\\s* // remove ws in selectors
[^~>+,\\s]+ # selector part $css = preg_replace_callback('/
{ # open declaration block (?: # non-capture
/x' \\s*
,array('Minify_CSS', '_selectorsCB'), $css); [^~>+,\\s]+ # selector part
\\s*
// minimize hex colors [,>+~] # combinators
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i' )+
, '$1#$2$3$4$5', $css); \\s*
[^~>+,\\s]+ # selector part
// remove spaces between font families { # open declaration block
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/' /x'
,array('Minify_CSS', '_fontFamilyCB'), $css); ,array(self::$className, '_selectorsCB'), $css);
$css = preg_replace('/@import\\s+url/', '@import url', $css); // minimize hex colors
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
// replace any ws involving newlines with a single newline , '$1#$2$3$4$5', $css);
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
// remove spaces between font families
// separate common descendent selectors w/ newlines (to limit line lengths) $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css); ,array(self::$className, '_fontFamilyCB'), $css);
// Use newline after 1st numeric value (to limit line lengths). $css = preg_replace('/@import\\s+url/', '@import url', $css);
$css = preg_replace('/
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value // replace any ws involving newlines with a single newline
\\s+ $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
/x'
,"$1\n", $css); // separate common descendent selectors w/ newlines (to limit line lengths)
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
$rewrite = false;
if (isset($options['prependRelativePath'])) { // Use newline after 1st numeric value (to limit line lengths).
self::$_tempPrepend = $options['prependRelativePath']; $css = preg_replace('/
$rewrite = true; ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
} elseif (isset($options['currentDir'])) { \\s+
self::$_tempCurrentDir = $options['currentDir']; /x'
$rewrite = true; ,"$1\n", $css);
}
if ($rewrite) { $rewrite = false;
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' if (isset($options['prependRelativePath'])) {
,array('Minify_CSS', '_urlCB'), $css); self::$_tempPrepend = $options['prependRelativePath'];
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/' $rewrite = true;
,array('Minify_CSS', '_urlCB'), $css); } elseif (isset($options['currentDir'])) {
} self::$_tempCurrentDir = $options['currentDir'];
self::$_tempPrepend = self::$_tempCurrentDir = ''; $rewrite = true;
return trim($css); }
} if ($rewrite) {
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
/** ,array(self::$className, '_urlCB'), $css);
* Replace what looks like a set of selectors $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
* ,array(self::$className, '_urlCB'), $css);
* @param array $m regex matches }
* self::$_tempPrepend = self::$_tempCurrentDir = '';
* @return string return trim($css);
*/ }
protected static function _selectorsCB($m)
{ /**
// remove ws around the combinators * Replace what looks like a set of selectors
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]); *
} * @param array $m regex matches
*
/** * @return string
* @var bool Are we "in" a hack? */
* protected static function _selectorsCB($m)
* I.e. are some browsers targetted until the next comment? {
*/ // remove ws around the combinators
protected static $_inHack = false; return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
}
/**
* @var string string to be prepended to relative URIs /**
*/ * @var bool Are we "in" a hack?
protected static $_tempPrepend = ''; *
* I.e. are some browsers targetted until the next comment?
/** */
* @var string directory of this stylesheet for rewriting purposes protected static $_inHack = false;
*/
protected static $_tempCurrentDir = ''; /**
* @var string string to be prepended to relative URIs
/** */
* Process a comment and return a replacement protected static $_tempPrepend = '';
*
* @param array $m regex matches /**
* * @var string directory of this stylesheet for rewriting purposes
* @return string */
*/ protected static $_tempCurrentDir = '';
protected static function _commentCB($m)
{ /**
$m = $m[1]; * Process a comment and return a replacement
// $m is the comment content w/o the surrounding tokens, *
// but the return value will replace the entire comment. * @param array $m regex matches
if ($m === 'keep') { *
return '/**/'; * @return string
} */
if ($m === '" "') { protected static function _commentCB($m)
// component of http://tantek.com/CSS/Examples/midpass.html {
return '/*" "*/'; $m = $m[1];
} // $m is the comment content w/o the surrounding tokens,
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) { // but the return value will replace the entire comment.
// component of http://tantek.com/CSS/Examples/midpass.html if ($m === 'keep') {
return '/*";}}/* */'; return '/**/';
} }
if (self::$_inHack) { if ($m === '" "') {
// inversion: feeding only to one browser // component of http://tantek.com/CSS/Examples/midpass.html
if (preg_match('@ return '/*" "*/';
^/ # comment started like /*/ }
\\s* if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
(\\S[\\s\\S]+?) # has at least some non-ws content // component of http://tantek.com/CSS/Examples/midpass.html
\\s* return '/*";}}/* */';
/\\* # ends like /*/ or /**/ }
@x', $m, $n)) { if (self::$_inHack) {
// end hack mode after this comment, but preserve the hack and comment content // inversion: feeding only to one browser
self::$_inHack = false; if (preg_match('@
return "/*/{$n[1]}/**/"; ^/ # comment started like /*/
} \\s*
} (\\S[\\s\\S]+?) # has at least some non-ws content
if (substr($m, -1) === '\\') { // comment ends like \*/ \\s*
// begin hack mode and preserve hack /\\* # ends like /*/ or /**/
self::$_inHack = true; @x', $m, $n)) {
return '/*\\*/'; // end hack mode after this comment, but preserve the hack and comment content
} self::$_inHack = false;
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */ return "/*/{$n[1]}/**/";
// begin hack mode and preserve hack }
self::$_inHack = true; }
return '/*/*/'; if (substr($m, -1) === '\\') { // comment ends like \*/
} // begin hack mode and preserve hack
if (self::$_inHack) { self::$_inHack = true;
// a regular comment ends hack mode but should be preserved return '/*\\*/';
self::$_inHack = false; }
return '/**/'; if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
} // begin hack mode and preserve hack
return ''; // remove all other comments self::$_inHack = true;
} return '/*/*/';
}
protected static function _urlCB($m) if (self::$_inHack) {
{ // a regular comment ends hack mode but should be preserved
$isImport = (0 === strpos($m[0], '@import')); self::$_inHack = false;
if ($isImport) { return '/**/';
$quote = $m[1]; }
$url = $m[2]; return ''; // remove all other comments
} else { }
// is url()
// $m[1] is either quoted or not protected static function _urlCB($m)
$quote = ($m[1][0] === "'" || $m[1][0] === '"') {
? $m[1][0] $isImport = (0 === strpos($m[0], '@import'));
: ''; if ($isImport) {
$url = ($quote === '') $quote = $m[1];
? $m[1] $url = $m[2];
: substr($m[1], 1, strlen($m[1]) - 2); } else {
} // is url()
if ('/' !== $url[0]) { // $m[1] is either quoted or not
if (strpos($url, '//') > 0) { $quote = ($m[1][0] === "'" || $m[1][0] === '"')
// probably starts with protocol, do not alter ? $m[1][0]
} else { : '';
// relative URI, rewrite! $url = ($quote === '')
if (self::$_tempPrepend) { ? $m[1]
$url = self::$_tempPrepend . $url; : substr($m[1], 1, strlen($m[1]) - 2);
} else { }
// rewrite absolute url from scratch! if ('/' !== $url[0]) {
// prepend path with current dir separator (OS-independent) if (strpos($url, '//') > 0) {
$path = self::$_tempCurrentDir // probably starts with protocol, do not alter
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR); } else {
// strip doc root // relative URI, rewrite!
$path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT']))); if (self::$_tempPrepend) {
// fix to absolute URL $url = self::$_tempPrepend . $url;
$url = strtr($path, DIRECTORY_SEPARATOR, '/'); } else {
// remove /./ and /../ where possible // rewrite absolute url from scratch!
$url = str_replace('/./', '/', $url); // prepend path with current dir separator (OS-independent)
// inspired by patch from Oleg Cherniy $path = self::$_tempCurrentDir
do { . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
$url = preg_replace('@/[^/]+/\\.\\./@', '/', $url, -1, $changed); // strip doc root
} while ($changed); $path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT'])));
} // fix to absolute URL
} $url = strtr($path, DIRECTORY_SEPARATOR, '/');
} // remove /./ and /../ where possible
return $isImport $url = str_replace('/./', '/', $url);
? "@import {$quote}{$url}{$quote}" // inspired by patch from Oleg Cherniy
: "url({$quote}{$url}{$quote})"; do {
} $url = preg_replace('@/[^/]+/\\.\\./@', '/', $url, -1, $changed);
} while ($changed);
/** }
* Process a font-family listing and return a replacement }
* }
* @param array $m regex matches return $isImport
* ? "@import {$quote}{$url}{$quote}"
* @return string : "url({$quote}{$url}{$quote})";
*/ }
protected static function _fontFamilyCB($m)
{ /**
$m[1] = preg_replace('/ * Process a font-family listing and return a replacement
\\s* *
( * @param array $m regex matches
"[^"]+" # 1 = family in double qutoes *
|\'[^\']+\' # or 1 = family in single quotes * @return string
|[\\w\\-]+ # or 1 = unquoted family */
) protected static function _fontFamilyCB($m)
\\s* {
/x', '$1', $m[1]); $m[1] = preg_replace('/
return 'font-family:' . $m[1] . $m[2]; \\s*
} (
} "[^"]+" # 1 = family in double qutoes
|\'[^\']+\' # or 1 = family in single quotes
|[\\w\\-]+ # or 1 = unquoted family
)
\\s*
/x', '$1', $m[1]);
return 'font-family:' . $m[1] . $m[2];
}
}

View File

@@ -17,7 +17,14 @@
* @author Stephen Clay <steve@mrclay.org> * @author Stephen Clay <steve@mrclay.org>
*/ */
class Minify_HTML { class Minify_HTML {
/**
* Defines which class to call as part of callbacks, change this
* if you extend Minify_HTML
* @var string
*/
protected static $className = 'Minify_HTML';
/** /**
* "Minify" an HTML page * "Minify" an HTML page
* *
@@ -59,30 +66,30 @@ class Minify_HTML {
// replace SCRIPTs (and minify) with placeholders // replace SCRIPTs (and minify) with placeholders
$html = preg_replace_callback( $html = preg_replace_callback(
'/\\s*(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>\\s*/i' '/\\s*(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>\\s*/i'
,array('Minify_HTML', '_removeScriptCB') ,array(self::$className, '_removeScriptCB')
,$html); ,$html);
// replace STYLEs (and minify) with placeholders // replace STYLEs (and minify) with placeholders
$html = preg_replace_callback( $html = preg_replace_callback(
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i' '/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
,array('Minify_HTML', '_removeStyleCB') ,array(self::$className, '_removeStyleCB')
,$html); ,$html);
// remove HTML comments (not containing IE conditional comments). // remove HTML comments (not containing IE conditional comments).
$html = preg_replace_callback( $html = preg_replace_callback(
'/<!--([\\s\\S]*?)-->/' '/<!--([\\s\\S]*?)-->/'
,array('Minify_HTML', '_commentCB') ,array(self::$className, '_commentCB')
,$html); ,$html);
// replace PREs with placeholders // replace PREs with placeholders
$html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i' $html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
,array('Minify_HTML', '_removePreCB') ,array(self::$className, '_removePreCB')
, $html); , $html);
// replace TEXTAREAs with placeholders // replace TEXTAREAs with placeholders
$html = preg_replace_callback( $html = preg_replace_callback(
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i' '/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
,array('Minify_HTML', '_removeTaCB') ,array(self::$className, '_removeTaCB')
, $html); , $html);
// trim each line. // trim each line.
@@ -99,7 +106,7 @@ class Minify_HTML {
// remove ws outside of all elements // remove ws outside of all elements
$html = preg_replace_callback( $html = preg_replace_callback(
'/>([^<]+)</' '/>([^<]+)</'
,array('Minify_HTML', '_outsideTagCB') ,array(self::$className, '_outsideTagCB')
,$html); ,$html);
// use newlines before 1st attribute in open tags (to limit line lengths) // use newlines before 1st attribute in open tags (to limit line lengths)

View File

@@ -9,6 +9,7 @@
* *
* @package Minify * @package Minify
* @author Stephen Clay <steve@mrclay.org> * @author Stephen Clay <steve@mrclay.org>
* @author Adam Pedersen (Issue 55 fix)
*/ */
class Minify_Lines { class Minify_Lines {
@@ -71,7 +72,13 @@ class Minify_Lines {
if (false === $pos) { if (false === $pos) {
return $inComment; return $inComment;
} else { } else {
$inComment = ! $inComment; if ($pos == 0
|| ($inComment
? substr($line, $pos, 3)
: substr($line, $pos-1, 3)) != '*/*')
{
$inComment = ! $inComment;
}
$line = substr($line, $pos + 2); $line = substr($line, $pos + 2);
} }
} }

View File

@@ -14,7 +14,13 @@
* @package Minify * @package Minify
*/ */
require 'class.JavaScriptPacker.php'; if (false === (@include 'class.JavaScriptPacker.php')) {
trigger_error(
'The script "class.JavaScriptPacker.php" is required. Please see: http:'
.'//code.google.com/p/minify/source/browse/trunk/min/lib/Minify/Packer.php'
,E_USER_ERROR
);
}
/** /**
* Minify Javascript using Dean Edward's Packer * Minify Javascript using Dean Edward's Packer

View File

@@ -0,0 +1,2 @@
var triggerBug = {_default: "*/*"};
var essentialFunctionality = true;

View File

@@ -26,6 +26,12 @@
/* 23 */ }; /* 23 */ };
/* 24 */ })(); /* 24 */ })();
; ;
/* lines_bugs.js */
/* 1 */ var triggerBug = {_default: "*/*"};
/* 2 */ var essentialFunctionality = true;
/* 3 */
;
/* QueryString.js */ /* QueryString.js */
/* 1 */ var MrClay = window.MrClay || {}; /* 1 */ var MrClay = window.MrClay || {};

View File

@@ -15,6 +15,7 @@ function test_Lines()
,'encodeOutput' => false ,'encodeOutput' => false
,'files' => array( ,'files' => array(
"{$thisDir}/_test_files/minify/email.js" "{$thisDir}/_test_files/minify/email.js"
,"{$thisDir}/_test_files/minify/lines_bugs.js"
,"{$thisDir}/_test_files/minify/QueryString.js" ,"{$thisDir}/_test_files/minify/QueryString.js"
,"{$thisDir}/_test_files/js/before.js" ,"{$thisDir}/_test_files/js/before.js"
) )

View File

@@ -19,8 +19,22 @@ require_once '_inc.php';
function test_environment() function test_environment()
{ {
global $thisDir; global $thisDir;
$thisUrl = 'http://' // check DOCROOT
$noSlash = assertTrue(
0 === preg_match('@[\\\\/]$@', $_SERVER['DOCUMENT_ROOT'])
,'environment : DOCUMENT_ROOT should not end in trailing slash'
);
$goodRoot = assertTrue(
0 === strpos(realpath(__FILE__), realpath($_SERVER['DOCUMENT_ROOT']))
,'environment : DOCUMENT_ROOT should be real path and contain this test file'
);
if (! $noSlash || ! $goodRoot) {
echo "!NOTE: If you cannot modify DOCUMENT_ROOT, see this comment for a workaround:"
,"\n http://code.google.com/p/minify/issues/detail?id=68#c6\n";
}
$thisUrl = 'http://'
. $_SERVER['HTTP_HOST'] // avoid redirects when SERVER_NAME doesn't match . $_SERVER['HTTP_HOST'] // avoid redirects when SERVER_NAME doesn't match
. ('80' === $_SERVER['SERVER_PORT'] ? '' : ":{$_SERVER['SERVER_PORT']}") . ('80' === $_SERVER['SERVER_PORT'] ? '' : ":{$_SERVER['SERVER_PORT']}")
. dirname($_SERVER['REQUEST_URI']) . dirname($_SERVER['REQUEST_URI'])
@@ -37,9 +51,9 @@ function test_environment()
} }
$fp = fopen($thisUrl . '?hello=1', 'r', false, stream_context_create(array( $fp = fopen($thisUrl . '?hello=1', 'r', false, stream_context_create(array(
'http' => array( 'http' => array(
'method' => "GET", 'method' => "GET",
'header' => "Accept-Encoding: deflate, gzip\r\n" 'header' => "Accept-Encoding: deflate, gzip\r\n"
) )
))); )));