From 70612c09b8f4637c8cef06afcfc3b55574aa8ad2 Mon Sep 17 00:00:00 2001 From: Emad Ha Date: Thu, 8 Feb 2018 17:52:47 +0200 Subject: [PATCH] Minify Customizations Adding $options to minify, usefull for customizing behaviours, etc. --- src/CSS.php | 89 +++++++++++++++++++++++++++++--------------------- src/Minify.php | 72 +++++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 54 deletions(-) diff --git a/src/CSS.php b/src/CSS.php index 78d02bc..92ae88b 100644 --- a/src/CSS.php +++ b/src/CSS.php @@ -37,16 +37,16 @@ class CSS extends Minify * @var string[] valid import extensions */ protected $importExtensions = array( - 'gif' => 'data:image/gif', - 'png' => 'data:image/png', - 'jpe' => 'data:image/jpeg', - 'jpg' => 'data:image/jpeg', + 'gif' => 'data:image/gif', + 'png' => 'data:image/png', + 'jpe' => 'data:image/jpeg', + 'jpg' => 'data:image/jpeg', 'jpeg' => 'data:image/jpeg', - 'svg' => 'data:image/svg+xml', + 'svg' => 'data:image/svg+xml', 'woff' => 'data:application/x-font-woff', - 'tif' => 'image/tiff', + 'tif' => 'image/tiff', 'tiff' => 'image/tiff', - 'xbm' => 'image/x-xbitmap', + 'xbm' => 'image/x-xbitmap', ); /** @@ -93,7 +93,7 @@ protected function moveImportsToTop($content) } // add to top - $content = implode(';', $matches[2]).';'.trim($content, ';'); + $content = implode(';', $matches[2]) . ';' . trim($content, ';'); } return $content; @@ -105,8 +105,8 @@ protected function moveImportsToTop($content) * @import's will be loaded and their content merged into the original file, * to save HTTP requests. * - * @param string $source The file to combine imports for - * @param string $content The CSS content to combine imports for + * @param string $source The file to combine imports for + * @param string $content The CSS content to combine imports for * @param string[] $parents Parent paths, for circular reference checks * * @return string @@ -200,7 +200,7 @@ protected function combineImports($source, $content, $parents) // loop the matches foreach ($matches as $match) { // get the path for the file that will be imported - $importPath = dirname($source).'/'.$match['path']; + $importPath = dirname($source) . '/' . $match['path']; // only replace the import with the content if we can grab the // content of the file @@ -211,7 +211,7 @@ protected function combineImports($source, $content, $parents) // check if current file was not imported previously in the same // import chain. if (in_array($importPath, $parents)) { - throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.'); + throw new FileImportException('Failed to import file "' . $importPath . '": circular reference detected.'); } // grab referenced file & minify it (which may include importing @@ -221,7 +221,7 @@ protected function combineImports($source, $content, $parents) // check if this is only valid for certain media if (!empty($match['media'])) { - $importContent = '@media '.$match['media'].'{'.$importContent.'}'; + $importContent = '@media ' . $match['media'] . '{' . $importContent . '}'; } // add to replacement array @@ -239,7 +239,7 @@ protected function combineImports($source, $content, $parents) * @url(image.jpg) images will be loaded and their content merged into the * original file, to save HTTP requests. * - * @param string $source The file to import files for + * @param string $source The file to import files for * @param string $content The CSS content to import files for * * @return string @@ -260,7 +260,7 @@ protected function importFiles($source, $content) // get the path for the file that will be imported $path = $match[2]; - $path = dirname($source).'/'.$path; + $path = dirname($source) . '/' . $path; // only replace the import with the content if we're able to get // the content of the file, and it's relatively small @@ -271,7 +271,7 @@ protected function importFiles($source, $content) // build replacement $search[] = $match[0]; - $replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')'; + $replace[] = 'url(' . $this->importExtensions[$extension] . ';base64,' . $importContent . ')'; } } @@ -304,15 +304,28 @@ public function execute($path = null, $parents = array()) * we should leave it alone. E.g.: * p { content: "a test" } */ + $this->extractStrings(); - $this->stripComments(); + + if ($this->options['css-strip-comments'] === true) + $this->stripComments(); + $css = $this->replace($css); - $css = $this->stripWhitespace($css); - $css = $this->shortenHex($css); - $css = $this->shortenZeroes($css); - $css = $this->shortenFontWeights($css); - $css = $this->stripEmptyTags($css); + if ($this->options['css-strip-whitespace'] === true) + $css = $this->stripWhitespace($css); + + if ($this->options['css-shorten-hex'] === true) + $css = $this->shortenHex($css); + + if ($this->options['css-shorten-zeroes'] === true) + $css = $this->shortenZeroes($css); + + if ($this->options['css-shorten-font-weights'] === true) + $css = $this->shortenFontWeights($css); + + if ($this->options['css-strip-empty-tags'] === true) + $css = $this->stripEmptyTags($css); // restore the string we've extracted earlier $css = $this->restoreExtractedData($css); @@ -379,7 +392,7 @@ private function removeDuplicates($content) * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper). * * @param ConverterInterface $converter Relative path converter - * @param string $content The CSS content to update relative urls for + * @param string $content The CSS content to update relative urls for * * @return string */ @@ -493,9 +506,9 @@ protected function move(ConverterInterface $converter, $content) // build replacement $search[] = $match[0]; if ($type === 'url') { - $replace[] = 'url('.$url.')'; + $replace[] = 'url(' . $url . ')'; } elseif ($type === 'import') { - $replace[] = '@import "'.$url.'"'; + $replace[] = '@import "' . $url . '"'; } } @@ -535,7 +548,7 @@ protected function shortenHex($content) '#FFC0CB' => 'pink', '#DDA0DD' => 'plum', '#800080' => 'purple', - '#F00' => 'red', + '#F00' => 'red', '#FA8072' => 'salmon', '#A0522D' => 'sienna', '#C0C0C0' => 'silver', @@ -547,7 +560,7 @@ protected function shortenHex($content) ); return preg_replace_callback( - '/(?<=[: ])('.implode(array_keys($colors), '|').')(?=[; }])/i', + '/(?<=[: ])(' . implode(array_keys($colors), '|') . ')(?=[; }])/i', function ($match) use ($colors) { return $colors[strtoupper($match[0])]; }, @@ -566,14 +579,14 @@ protected function shortenFontWeights($content) { $weights = array( 'normal' => 400, - 'bold' => 700, + 'bold' => 700, ); $callback = function ($match) use ($weights) { - return $match[1].$weights[$match[2]]; + return $match[1] . $weights[$match[2]]; }; - return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content); + return preg_replace_callback('/(font-weight\s*:\s*)(' . implode('|', array_keys($weights)) . ')(?=[;}])/', $callback, $content); } /** @@ -609,19 +622,19 @@ protected function shortenZeroes($content) // practice, Webkit (especially Safari) seems to stumble over at least // 0%, potentially other units as well. Only stripping 'px' for now. // @see https://github.com/matthiasmullie/minify/issues/60 - $content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content); + $content = preg_replace('/' . $before . '(-?0*(\.0+)?)(?<=0)px' . $after . '/', '\\1', $content); // strip 0-digits (.0 -> 0) - $content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content); + $content = preg_replace('/' . $before . '\.0+' . $units . '?' . $after . '/', '0\\1', $content); // strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px - $content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content); + $content = preg_replace('/' . $before . '(-?[0-9]+\.[0-9]+)0+' . $units . '?' . $after . '/', '\\1\\2', $content); // strip trailing 0: 50.00 -> 50, 50.00px -> 50px - $content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content); + $content = preg_replace('/' . $before . '(-?[0-9]+)\.0+' . $units . '?' . $after . '/', '\\1\\2', $content); // strip leading 0: 0.1 -> .1, 01.1 -> 1.1 - $content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content); + $content = preg_replace('/' . $before . '(-?)0+([0-9]*\.[0-9]+)' . $units . '?' . $after . '/', '\\1\\2\\3', $content); // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0) - $content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content); + $content = preg_replace('/' . $before . '-?0+' . $units . '?' . $after . '/', '0\\1', $content); // IE doesn't seem to understand a unitless flex-basis value (correct - // it goes against the spec), so let's add it in again (make it `%`, @@ -687,7 +700,7 @@ protected function stripWhitespace($content) // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or // selectors like `div.weird- p` $pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type'); - $content = preg_replace('/:('.implode('|', $pseudos).')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content); + $content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content); // remove semicolon/whitespace followed by closing bracket $content = str_replace(';}', '}', $content); @@ -722,7 +735,7 @@ protected function findCalcs($content) } } - $results['calc('.count($results).')'] = 'calc'.$expr; + $results['calc(' . count($results) . ')'] = 'calc' . $expr; } return $results; diff --git a/src/Minify.php b/src/Minify.php index ac87292..3ee652c 100644 --- a/src/Minify.php +++ b/src/Minify.php @@ -8,6 +8,7 @@ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved * @license MIT License */ + namespace MatthiasMullie\Minify; use MatthiasMullie\Minify\Exceptions\IOException; @@ -25,6 +26,44 @@ */ abstract class Minify { + + /** + * Default Minify Options list + * + * @var array + */ + public $options = array( + 'css-strip-comments' => true, + 'css-strip-whitespace' => true, + 'css-shorten-hex' => true, + 'css-shorten-zeroes' => true, + 'css-shorten-font-weights' => true, + 'css-strip-empty-tags' => true, + ); + + /** + * Set Minify options + * useful for class customizations. + * + * @param $key + * @param null $value + * @return $this + */ + public function setOptions($key, $value = null) + { + + if (is_array($key)) { + foreach ($key as $_key => $_value) + $this->setOptions($_key, $_value); + } else { + if (array_key_exists($key, $this->options)) + $this->options[$key] = $value; + } + + + return $this; + } + /** * The data to be minified. * @@ -82,7 +121,7 @@ public function add($data /* $data = null, ... */) } // redefine var - $data = (string) $data; + $data = (string)$data; // load data $value = $this->load($data); @@ -105,6 +144,7 @@ public function add($data /* $data = null, ... */) * @param string[optional] $path Path to write the data to * * @return string The minified data + * @throws IOException */ public function minify($path = null) { @@ -122,9 +162,9 @@ public function minify($path = null) * Minify & gzip the data & (optionally) saves it to a file. * * @param string[optional] $path Path to write the data to - * @param int[optional] $level Compression level, from 0 to 9 - * + * @param int $level * @return string The minified & gzipped data + * @throws IOException */ public function gzip($path = null, $level = 9) { @@ -189,7 +229,7 @@ protected function load($data) * Save to file. * * @param string $content The minified data - * @param string $path The path to save the minified data to + * @param string $path The path to save the minified data to * * @throws IOException */ @@ -205,7 +245,7 @@ protected function save($content, $path) /** * Register a pattern to execute against the source content. * - * @param string $pattern PCRE pattern + * @param string $pattern PCRE pattern * @param string|callable $replacement Replacement value for matched pattern */ protected function registerPattern($pattern, $replacement = '') @@ -281,8 +321,8 @@ protected function replace($content) // figure out which part of the string was unmatched; that's the // part we'll execute the patterns on again next - $content = (string) substr($content, $discardLength); - $unmatched = (string) substr($content, strpos($content, $match) + strlen($match)); + $content = (string)substr($content, $discardLength); + $unmatched = (string)substr($content, strpos($content, $match) + strlen($match)); // move the replaced part to $processed and prepare $content to // again match batch of patterns against @@ -306,9 +346,9 @@ protected function replace($content) * This function will be called plenty of times, where $content will always * move up 1 character. * - * @param string $pattern Pattern to match + * @param string $pattern Pattern to match * @param string|callable $replacement Replacement value - * @param string $content Content to match pattern against + * @param string $content Content to match pattern against * * @return string */ @@ -352,8 +392,8 @@ protected function extractStrings($chars = '\'"', $placeholderPrefix = '') } $count = count($minifier->extracted); - $placeholder = $match[1].$placeholderPrefix.$count.$match[1]; - $minifier->extracted[$placeholder] = $match[1].$match[2].$match[1]; + $placeholder = $match[1] . $placeholderPrefix . $count . $match[1]; + $minifier->extracted[$placeholder] = $match[1] . $match[2] . $match[1]; return $placeholder; }; @@ -370,7 +410,7 @@ protected function extractStrings($chars = '\'"', $placeholderPrefix = '') * considered as escape-char (times 2) and to get it in the regex, * escaped (times 2) */ - $this->registerPattern('/(['.$chars.'])(.*?(?registerPattern('/([' . $chars . '])(.*?(?