From 79b7027c2ae1f9934cb7ff2f4fdd5be08692a8fa Mon Sep 17 00:00:00 2001 From: Andrew Podner Date: Tue, 25 Dec 2012 12:04:01 -0500 Subject: issue #2092 : Improve/Revise JS and CSS minify method --- system/core/Output.php | 71 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/system/core/Output.php b/system/core/Output.php index 9367e3b43..6f250b110 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -802,7 +802,16 @@ class CI_Output { * the string initially and saved without stripping whitespace to preserve * the tags and any associated properties if tags are present * - * @param string $output Output to minify + * Minification logic/workflow is similar to methods used by Douglas Crockford + * in JSMIN. http://www.crockford.com/javascript/jsmin.html + * + * KNOWN ISSUE: ending a line with a closing parenthesis ')' and no semicolon + * where there should be one will break the Javascript. New lines after a + * closing parenthesis are not recognized by the script. For best results + * be sure to terminate lines with a semicolon when appropriate. + * + * + * @param string $output Output to minify * @param bool $has_tags Specify if the output has style or script tags * @return string Minified output */ @@ -812,7 +821,7 @@ class CI_Output { if ($has_tags === TRUE) { // Remove opening tag and save for later - $pos = strpos($output, '>'); + $pos = strpos($output, '>') + 1; $open_tag = substr($output, 0, $pos); $output = substr_replace($output, '', 0, $pos); @@ -830,8 +839,18 @@ class CI_Output { // semi-colons, parenthesis, commas $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!i', '$1', $output); - // Remove spaces - $in_string = $in_dstring = FALSE; + // Replace tabs with spaces + $output = preg_replace('/\t/', ' ', $output); + + // Replace carriage returns with new line + $output = preg_replace('/\r/', "\n", $output); + + // Replace multiple new line with single new line + // and trim any leading or trailing whitespace + $output = trim(preg_replace('/\n+/', "\n", $output)); + + // Remove spaces when safe to do so. + $in_string = $in_dstring = $prev = FALSE; $array_output = str_split($output); foreach ($array_output as $key => $value) { @@ -839,7 +858,26 @@ class CI_Output { { if ($value === ' ') { - unset($array_output[$key]); + // Get the next element in the array for comparisons + $next = $array_output[$key + 1]; + + // Strip spaces preceded/followed by a non-ASCII character + // or not preceded/followed by an alphanumeric + // or not preceded/followed \ $ and _ + if ((preg_match('/^[\x20-\x7f]*$/D', $next) + || preg_match('/^[\x20-\x7f]*$/D', $prev)) + && ( ! ctype_alnum($next) || ! ctype_alnum($prev)) + && ( ! in_array($next, array('\\', '_', '$')) + && ! in_array($prev, array('\\', '_', '$')))) + { + unset($array_output[$key]); + } + } + else + { + // Save this value as previous for the next iteration + // if it is not a blank space + $prev = $value; } } @@ -853,8 +891,27 @@ class CI_Output { } } - // Remove breaklines and tabs - $output = preg_replace('/[\r\n\t]/', '', implode($array_output)); + // Put the string back together after spaces have been stripped + $output = implode($array_output); + + // Remove new line characters unless previous or next character is + // printable or Non-ASCII + preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE); + foreach ($lf as $feed_position) + { + foreach($feed_position as $position) + { + $next_char = substr($output, $position[1] + 1, 1); + $prev_char = substr($output, $position[1] - 1, 1); + if ( ! ctype_print($next_char) + && ! ctype_print($prev_char) + && ! preg_match('/^[\x20-\x7f]*$/D', $next_char) + && ! preg_match('/^[\x20-\x7f]*$/D', $prev_char)) + { + substr_replace($output, '', $position[1], 1); + } + } + } // Put the opening and closing tags back if applicable return isset($open_tag) -- cgit v1.2.3-24-g4f1b From 464a7b79e6fe3d73c6ae9d82ba34f4f8effae684 Mon Sep 17 00:00:00 2001 From: Andrew Podner Date: Tue, 25 Dec 2012 21:43:55 -0500 Subject: issue #2092 : Improve/Revise JS and CSS minify method --- system/core/Output.php | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/system/core/Output.php b/system/core/Output.php index 6f250b110..f62885a72 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -842,12 +842,9 @@ class CI_Output { // Replace tabs with spaces $output = preg_replace('/\t/', ' ', $output); - // Replace carriage returns with new line - $output = preg_replace('/\r/', "\n", $output); - - // Replace multiple new line with single new line + // Replace carriage returns & multiple new lines with single new line // and trim any leading or trailing whitespace - $output = trim(preg_replace('/\n+/', "\n", $output)); + $output = trim(preg_replace(array('/\r/', '/\n+/'), "\n", $output)); // Remove spaces when safe to do so. $in_string = $in_dstring = $prev = FALSE; @@ -864,11 +861,9 @@ class CI_Output { // Strip spaces preceded/followed by a non-ASCII character // or not preceded/followed by an alphanumeric // or not preceded/followed \ $ and _ - if ((preg_match('/^[\x20-\x7f]*$/D', $next) - || preg_match('/^[\x20-\x7f]*$/D', $prev)) + if ((preg_match('/^[\x20-\x7f]*$/D', $next) or preg_match('/^[\x20-\x7f]*$/D', $prev)) && ( ! ctype_alnum($next) || ! ctype_alnum($prev)) - && ( ! in_array($next, array('\\', '_', '$')) - && ! in_array($prev, array('\\', '_', '$')))) + && ( ! in_array($next, array('\\', '_', '$')) && ! in_array($prev, array('\\', '_', '$')))) { unset($array_output[$key]); } @@ -897,18 +892,18 @@ class CI_Output { // Remove new line characters unless previous or next character is // printable or Non-ASCII preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE); + $removed_lf = 0; foreach ($lf as $feed_position) { - foreach($feed_position as $position) + foreach ($feed_position as $position) { - $next_char = substr($output, $position[1] + 1, 1); - $prev_char = substr($output, $position[1] - 1, 1); - if ( ! ctype_print($next_char) - && ! ctype_print($prev_char) - && ! preg_match('/^[\x20-\x7f]*$/D', $next_char) - && ! preg_match('/^[\x20-\x7f]*$/D', $prev_char)) + $next_char = substr($output, $position[1] - $removed_lf + 1, 1); + $prev_char = substr($output, $position[1] - $removed_lf - 1, 1); + if ( ! ctype_print($next_char) && ! ctype_print($prev_char) + && ! preg_match('/^[\x20-\x7f]*$/D', $next_char) && ! preg_match('/^[\x20-\x7f]*$/D', $prev_char)) { - substr_replace($output, '', $position[1], 1); + $output = substr_replace($output, '', $position[1] - $removed_lf, 1); + $removed_lf++; } } } -- cgit v1.2.3-24-g4f1b From 58594ed44dfa39a4a1309b220a5420094dec23f7 Mon Sep 17 00:00:00 2001 From: Andrew Podner Date: Tue, 25 Dec 2012 21:46:05 -0500 Subject: issue #2092 : Improve/Revise JS and CSS minify method --- system/core/Output.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/core/Output.php b/system/core/Output.php index f62885a72..4d89975a7 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -862,7 +862,7 @@ class CI_Output { // or not preceded/followed by an alphanumeric // or not preceded/followed \ $ and _ if ((preg_match('/^[\x20-\x7f]*$/D', $next) or preg_match('/^[\x20-\x7f]*$/D', $prev)) - && ( ! ctype_alnum($next) || ! ctype_alnum($prev)) + && ( ! ctype_alnum($next) or ! ctype_alnum($prev)) && ( ! in_array($next, array('\\', '_', '$')) && ! in_array($prev, array('\\', '_', '$')))) { unset($array_output[$key]); -- cgit v1.2.3-24-g4f1b From ae8c2d9d2644727bb347495a917bf437798596b4 Mon Sep 17 00:00:00 2001 From: Andrew Podner Date: Wed, 26 Dec 2012 08:05:44 -0500 Subject: issue #2092 : Improve/Revise JS and CSS minify method (code refinements) --- system/core/Output.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/core/Output.php b/system/core/Output.php index 4d89975a7..769ec1915 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -861,8 +861,8 @@ class CI_Output { // Strip spaces preceded/followed by a non-ASCII character // or not preceded/followed by an alphanumeric // or not preceded/followed \ $ and _ - if ((preg_match('/^[\x20-\x7f]*$/D', $next) or preg_match('/^[\x20-\x7f]*$/D', $prev)) - && ( ! ctype_alnum($next) or ! ctype_alnum($prev)) + if ((preg_match('/^[\x20-\x7f]*$/D', $next) OR preg_match('/^[\x20-\x7f]*$/D', $prev)) + && ( ! ctype_alnum($next) OR ! ctype_alnum($prev)) && ( ! in_array($next, array('\\', '_', '$')) && ! in_array($prev, array('\\', '_', '$')))) { unset($array_output[$key]); -- cgit v1.2.3-24-g4f1b From 96b9501f42ac773c9ec4fcda2a6ecabe72222365 Mon Sep 17 00:00:00 2001 From: Andrew Podner Date: Fri, 28 Dec 2012 08:30:43 -0500 Subject: issue #2092 : code refinements --- system/core/Output.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/system/core/Output.php b/system/core/Output.php index 769ec1915..b6f69fd88 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -840,11 +840,9 @@ class CI_Output { $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!i', '$1', $output); // Replace tabs with spaces - $output = preg_replace('/\t/', ' ', $output); - // Replace carriage returns & multiple new lines with single new line // and trim any leading or trailing whitespace - $output = trim(preg_replace(array('/\r/', '/\n+/'), "\n", $output)); + $output = trim(preg_replace(array('/\t+/', '/\r/', '/\n+/'), array(' ', "\n", "\n"), $output)); // Remove spaces when safe to do so. $in_string = $in_dstring = $prev = FALSE; @@ -900,10 +898,10 @@ class CI_Output { $next_char = substr($output, $position[1] - $removed_lf + 1, 1); $prev_char = substr($output, $position[1] - $removed_lf - 1, 1); if ( ! ctype_print($next_char) && ! ctype_print($prev_char) - && ! preg_match('/^[\x20-\x7f]*$/D', $next_char) && ! preg_match('/^[\x20-\x7f]*$/D', $prev_char)) + && ! preg_match('/^[\x20-\x7f]*$/D', $next_char) + && ! preg_match('/^[\x20-\x7f]*$/D', $prev_char)) { - $output = substr_replace($output, '', $position[1] - $removed_lf, 1); - $removed_lf++; + $output = substr_replace($output, '', $position[1] - $removed_lf++, 1); } } } -- cgit v1.2.3-24-g4f1b