Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Issue #2078: refinement of the minify function for CSS and scripts. #2079

Merged
merged 5 commits into from

2 participants

@AndrewPodner

Created a protected method for minification of CSS and Javascript, whether a file type or inside script and style tags. The idea was to isolate the opening and closing tags (if applicable) and then walk each character of the remaining file contents. If the method detects that a string is opened with a single or double quote, stripping of spaces is switched off until the string is closed with another of that same quote.

This should cure the observations made in issue #2078.

@narfbg
Owner

Please use tabs for indentation, not spaces. See our styleguide for more tips.

@AndrewPodner

That should clean it up. Sorry about that, wrong setting in IDE

system/core/Output.php
((57 lines not shown))
+ }
+
+ // 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)
@narfbg Owner
narfbg added a note

Again, per the style guide: and -> &&

Will fix and recommit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
system/core/Output.php
((59 lines not shown))
+ // 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 == ' ')
@narfbg Owner
narfbg added a note

Use === here, just in case of a zero, empty string, etc.
Could do the same for lines 850, 855 although it wouldn't matter there.

will do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
system/core/Output.php
((67 lines not shown))
+ $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;
@narfbg Owner
narfbg added a note

Spaces must be put around each occurence of the negation operator (in this case, just add one between it and the variable).
Same goes for line 857

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
system/core/Output.php
((84 lines not shown))
+
+ 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;
@narfbg Owner
narfbg added a note

No spaces around the concatenation dots please. :)
I'm not sure if the styleguide says anything about it, but it's done without spaces everywhere in CI - let's be consistent. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@AndrewPodner

@narfbg I had one other comment in my inbox regarding strpos, but it is not in this list. Was it removed or did you want to discuss it further?

@narfbg
Owner

I had missed a condition when I wrote it - removed it afterwards, ignore it. :)

@AndrewPodner

Ok, just wanted to make sure before I send this commit. Thanks! :)

system/core/Output.php
@@ -782,22 +782,91 @@ public function minify($output, $type = 'text/html')
case 'text/css':
case 'text/javascript':
- //Remove CSS comments
- $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+ $output = $this->_minify_scripts_css($output, $type);
@narfbg Owner
narfbg added a note

Sorry to bounce it back again, but this method doesn't exist. _minify_script_style() maybe?

Nope, my fault. renamed the method at the last minute. Thanks for catching it. Eventually I will get better at this! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@AndrewPodner

@narfbg Should be clean now, thanks for the help and guidance

system/core/Output.php
@@ -728,13 +728,13 @@ public function minify($output, $type = 'text/html')
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);
+ $output = str_replace($s, $this->_minify_script_style($s, $type), $output);
@narfbg Owner
narfbg added a note

Isn't $type always going to be 'text/html' here? Is that correct? (same on line 737)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@AndrewPodner

@narfbg Based on your comment above, would it make more sense if I changed the 2nd parameter to a boolean? TRUE would be that the output has tags that need to be dealt with, and FALSE would be no tags.

@narfbg
Owner

Probably, if you think that would be better. I only had the concern that it was effectively ignored (since 'text/html' is always passed to it).

@AndrewPodner

I think I will go ahead with the boolean, it is a little cleaner, and I agree, the variable was not needed.

@narfbg narfbg merged commit a916250 into from
@narfbg narfbg referenced this pull request from a commit
@narfbg narfbg [ci skip] Some micro-optimizations and style changes
(following PRs #2049, #2079)
72ed4c3
@nonchip nonchip referenced this pull request from a commit in nonchip/CodeIgniter
@narfbg narfbg [ci skip] Some micro-optimizations and style changes
(following PRs #2049, #2079)
315c303
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 82 additions and 13 deletions.
  1. +82 −13 system/core/Output.php
View
95 system/core/Output.php
@@ -728,13 +728,13 @@ public function minify($output, $type = 'text/html')
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);
+ $output = str_replace($s, $this->_minify_script_style($s, TRUE), $output);
}
// Minify the javascript in <script> tags.
foreach ($javascript_clean[0] as $s)
{
- $javascript_mini[] = $this->minify($s, 'text/javascript');
+ $javascript_mini[] = $this->_minify_script_style($s, TRUE);
}
// Replace multiple spaces with a single space.
@@ -782,22 +782,91 @@ public function minify($output, $type = 'text/html')
case 'text/css':
case 'text/javascript':
- //Remove CSS comments
- $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+ $output = $this->_minify_script_style($output);
- // 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;
+ }
+
+ return $output;
+ }
- // Remove breaklines and tabs
- $output = preg_replace('/[\r\n\t]/', '', $output);
- break;
+ // --------------------------------------------------------------------
- default: break;
+ /**
+ * 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 bool $has_tags specify if the output has style or script tags
+ * @return string Minified output
+ */
+ protected function _minify_script_style($output, $has_tags = FALSE)
+ {
+ // We only need this if there are tags in the file
+ if ($has_tags === TRUE)
+ {
+ // 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 && $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;
Something went wrong with that request. Please try again.