summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Podner <a.podner@me.com>2012-12-18 04:32:02 +0100
committerAndrew Podner <a.podner@me.com>2012-12-18 04:32:02 +0100
commit369b314c57bb7fd7d32949fe5f47c307468913eb (patch)
tree0ad59322480b91c650d1e331c3e42a092aac1d5f
parentd8dba5d3ecbe1ff4502b04a9cf3086908db140d1 (diff)
Issue #2078: refinement of the minify function for CSS and scripts.
-rw-r--r--system/core/Output.php215
1 files changed, 142 insertions, 73 deletions
diff --git a/system/core/Output.php b/system/core/Output.php
index 0ba0a5743..1fafa848b 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -705,103 +705,172 @@ class CI_Output {
* @return string Minified output
*/
public function minify($output, $type = 'text/html')
- {
- switch ($type)
- {
- case 'text/html':
+ {
+ switch ($type)
+ {
+ case 'text/html':
- $size_before = strlen($output);
+ $size_before = strlen($output);
- if ($size_before === 0)
- {
- return '';
- }
+ if ($size_before === 0)
+ {
+ return '';
+ }
- // Find all the <pre>,<code>,<textarea>, and <javascript> tags
- // We'll want to return them to this unprocessed state later.
- preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);
- preg_match_all('{<code.+</code>}msU', $output, $codes_clean);
- preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);
- preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);
+ // Find all the <pre>,<code>,<textarea>, and <javascript> tags
+ // We'll want to return them to this unprocessed state later.
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);
+ preg_match_all('{<code.+</code>}msU', $output, $codes_clean);
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);
- // Minify the CSS in all the <style> tags.
- preg_match_all('{<style.+</style>}msU', $output, $style_clean);
- foreach ($style_clean[0] as $s)
- {
- $output = str_replace($s, $this->minify($s, 'text/css'), $output);
- }
+ // Minify the CSS in all the <style> tags.
+ preg_match_all('{<style.+</style>}msU', $output, $style_clean);
+ foreach ($style_clean[0] as $s)
+ {
+ $output = str_replace($s, $this->_minify_script_style($s, $type), $output);
+ }
- // Minify the javascript in <script> tags.
- foreach ($javascript_clean[0] as $s)
- {
- $javascript_mini[] = $this->minify($s, 'text/javascript');
- }
+ // Minify the javascript in <script> tags.
+ foreach ($javascript_clean[0] as $s)
+ {
+ $javascript_mini[] = $this->_minify_script_style($s, $type);
+ }
- // Replace multiple spaces with a single space.
- $output = preg_replace('!\s{2,}!', ' ', $output);
+ // Replace multiple spaces with a single space.
+ $output = preg_replace('!\s{2,}!', ' ', $output);
- // Remove comments (non-MSIE conditionals)
- $output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output);
+ // Remove comments (non-MSIE conditionals)
+ $output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output);
- // Remove spaces around block-level elements.
- $output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output);
+ // Remove spaces around block-level elements.
+ $output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output);
- // Replace mangled <pre> etc. tags with unprocessed ones.
+ // Replace mangled <pre> etc. tags with unprocessed ones.
- if ( ! empty($pres_clean))
- {
- preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);
- $output = str_replace($pres_messed[0], $pres_clean[0], $output);
- }
+ if ( ! empty($pres_clean))
+ {
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);
+ $output = str_replace($pres_messed[0], $pres_clean[0], $output);
+ }
- if ( ! empty($codes_clean))
- {
- preg_match_all('{<code.+</code>}msU', $output, $codes_messed);
- $output = str_replace($codes_messed[0], $codes_clean[0], $output);
- }
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<code.+</code>}msU', $output, $codes_messed);
+ $output = str_replace($codes_messed[0], $codes_clean[0], $output);
+ }
- if ( ! empty($codes_clean))
- {
- preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);
- $output = str_replace($textareas_messed[0], $textareas_clean[0], $output);
- }
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);
+ $output = str_replace($textareas_messed[0], $textareas_clean[0], $output);
+ }
- if (isset($javascript_mini))
- {
- preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);
- $output = str_replace($javascript_messed[0], $javascript_mini, $output);
- }
+ if (isset($javascript_mini))
+ {
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);
+ $output = str_replace($javascript_messed[0], $javascript_mini, $output);
+ }
- $size_removed = $size_before - strlen($output);
- $savings_percent = round(($size_removed / $size_before * 100));
+ $size_removed = $size_before - strlen($output);
+ $savings_percent = round(($size_removed / $size_before * 100));
- log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');
+ log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');
- break;
+ break;
- case 'text/css':
- case 'text/javascript':
+ case 'text/css':
+ case 'text/javascript':
- //Remove CSS comments
- $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+ $output = $this->_minify_scripts_css($output, $type);
- // Remove spaces around curly brackets, colons,
- // semi-colons, parenthesis, commas
- $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!', '$1', $output);
+ break;
- // Remove spaces
- $output = preg_replace('/ /s', ' ', $output);
+ default: break;
+ }
- // Remove breaklines and tabs
- $output = preg_replace('/[\r\n\t]/', '', $output);
+ return $output;
+ }
- break;
- default: break;
- }
+ // --------------------------------------------------------------------
- return $output;
- }
+ /**
+ * Minify Style and Script
+ *
+ * Reduce excessive size of CSS/JavaScript content. To remove spaces this
+ * script walks the string as an array and determines if the pointer is inside
+ * a string created by single quotes or double quotes. spaces inside those
+ * strings are not stripped. Opening and closing tags are severed from
+ * 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
+ * @param string $type Output content MIME type
+ * @return string Minified output
+ */
+ protected function _minify_script_style($output, $type = 'text/html')
+ {
+ // We only need this if there are tags in the file
+ if ($type == 'text/html')
+ {
+ // Remove opening tag and save for later
+ $pos = strpos($output, '>');
+ $open_tag = substr($output, 0, $pos);
+ $output = substr_replace($output, '', 0, $pos);
+
+ // Remove closing tag and save it for later
+ $end_pos = strlen($output);
+ $pos = strpos($output, '</');
+ $closing_tag = substr($output, $pos, $end_pos);
+ $output = substr_replace($output, '', $pos);
+ }
+
+ // Remove CSS comments
+ $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+
+ // Remove spaces around curly brackets, colons,
+ // semi-colons, parenthesis, commas
+ $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!', '$1', $output);
+
+ // Remove spaces
+ $in_string = FALSE;
+ $in_dstring = FALSE;
+ $array_output = str_split($output);
+ foreach ($array_output as $key => $value)
+ {
+ if ($in_string === FALSE and $in_dstring === FALSE)
+ {
+ if ($value == ' ')
+ {
+ unset($array_output[$key]);
+ }
+ }
+
+ if ($value == "'")
+ {
+ $in_string = !$in_string;
+ }
+
+ if ($value == '"')
+ {
+ $in_dstring = !$in_dstring;
+ }
+ }
+
+ $output = implode($array_output);
+
+ // Remove breaklines and tabs
+ $output = preg_replace('/[\r\n\t]/', '', $output);
+
+ // Put the opening and closing tags back if applicable
+ if (isset($open_tag))
+ {
+ $output = $open_tag . $output . $closing_tag;
+ }
+
+ return $output;
+ }
}