From f168cf686316022dda1345ecacb6140e5027d1b1 Mon Sep 17 00:00:00 2001 From: KingOfDog Date: Thu, 1 Nov 2018 11:19:02 +0100 Subject: [PATCH] Minify CSS and JS --- combine.php | 465 ++++++++++++++++++++++++++-------------------------- 1 file changed, 234 insertions(+), 231 deletions(-) diff --git a/combine.php b/combine.php index 19a62b6..0a6465c 100644 --- a/combine.php +++ b/combine.php @@ -1,253 +1,256 @@ '); -define('X', "\x1A"); + // Check for buggy versions of Internet Explorer + if (!strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') && + preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $matches)) { + $version = floatval($matches[1]); -function n($s) -{ - return str_replace(["\r\n", "\r"], "\n", $s); -} + if ($version < 6) + $encoding = 'none'; -function t($a, $b) -{ - if ($a && strpos($a, $b) === 0 && substr($a, -strlen($b)) === $b) { - return substr(substr($a, strlen($b)), 0, -strlen($b)); - } - return $a; -} - -function fn_minify($pattern, $input) -{ - return preg_split('#(' . implode('|', $pattern) . ')#', $input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); -} - -function fn_minify_css($input, $comment = 2, $quote = 2) -{ - if (!is_string($input) || !$input = n(trim($input))) return $input; - $output = $prev = ""; - foreach (fn_minify([MINIFY_COMMENT_CSS, MINIFY_STRING], $input) as $part) { - if (trim($part) === "") continue; - if ($comment !== 1 && strpos($part, '/*') === 0 && substr($part, -2) === '*/') { - if ( - $comment === 2 && ( - // Detect special comment(s) from the third character. It should be a `!` or `*` → `/*! keep */` or `/** keep */` - strpos('*!', $part[2]) !== false || - // Detect license comment(s) from the content. It should contains character(s) like `@license` - stripos($part, '@licence') !== false || // noun - stripos($part, '@license') !== false || // verb - stripos($part, '@preserve') !== false - ) - ) { - $output .= $part; + if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'EV1')) + $encoding = 'none'; } - continue; - } - if ($part[0] === '"' && substr($part, -1) === '"' || $part[0] === "'" && substr($part, -1) === "'") { - // Remove quote(s) where possible … - $q = $part[0]; - if ( - $quote !== 1 && ( - // - substr($prev, -4) === 'url(' && preg_match('#\burl\($#', $prev) || - // - substr($prev, -1) === '=' && preg_match('#^' . $q . '[a-zA-Z_][\w-]*?' . $q . '$#', $part) - ) - ) { - $part = t($part, $q); // trim quote(s) + + // Try the cache first to see if the combined files were already generated + $cachefile = 'cache-' . $hash . '.' . $type . ($encoding != 'none' ? '.' . $encoding : ''); + + if (file_exists($cachedir . '/' . $cachefile)) { + if ($fp = fopen($cachedir . '/' . $cachefile, 'rb')) { + + if ($encoding != 'none') { + header("Content-Encoding: " . $encoding); + } + + header("Content-Type: text/" . $type); + header("Content-Length: " . filesize($cachedir . '/' . $cachefile)); + + fpassthru($fp); + fclose($fp); + exit; + } } - $output .= $part; + } + + // Get contents of the files + $contents = ''; + reset($elements); + while (list(, $element) = each($elements)) { + $path = realpath($base . '/' . $element); + $contents .= "\n\n" . file_get_contents($path); + $contents = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $contents); + $contents = str_replace(': ', ':', $contents); + $contents = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $contents); +// $contents = fn_minify_css($contents); + } + + // Send Content-Type + header("Content-Type: text/" . $type); + + if (isset($encoding) && $encoding != 'none') { + // Send compressed contents + $contents = gzencode($contents, 9, $gzip ? FORCE_GZIP : FORCE_DEFLATE); + header("Content-Encoding: " . $encoding); + header('Content-Length: ' . strlen($contents)); + echo $contents; } else { - $output .= fn_minify_css_union($part); + // Send regular contents + header('Content-Length: ' . strlen($contents)); + echo $contents; } - $prev = $part; - } - return trim($output); -} + echo strlen($contents); -function fn_minify_css_union($input) -{ - if (stripos($input, 'calc(') !== false) { - // Keep important white–space(s) in `calc()` - $input = preg_replace_callback('#\b(calc\()\s*(.*?)\s*\)#i', function ($m) { - return $m[1] . preg_replace('#\s+#', X, $m[2]) . ')'; - }, $input); + // Store cache + if ($cache) { + if ($fp = fopen($cachedir . '/' . $cachefile, 'wb')) { + fwrite($fp, $contents); + fclose($fp); + } + } } - $input = preg_replace([ - // Fix case for `#foo[bar="baz"]`, `#foo*` and `#foo:first-child` [^1] - '#(?<=[\w])\s+(\*|\[|:[\w-]+)#', - // Fix case for `[bar="baz"].foo`, `*.foo`, `:nth-child(2).foo` and `@media(foo: bar)and(baz: qux)` [^2] - '#([*\]\)])\s+(?=[\w\#.])#', '#\b\s+\(#', '#\)\s+\b#', - // Minify HEX color code … [^3] - '#\#([a-f\d])\1([a-f\d])\2([a-f\d])\3\b#i', - // Remove white–space(s) around punctuation(s) [^4] - '#\s*([~!@*\(\)+=\{\}\[\]:;,>\/])\s*#', - // Replace zero unit(s) with `0` [^5] - '#\b(?'); + define('X', "\x1A"); + + function n($s) + { + return str_replace(["\r\n", "\r"], "\n", $s); + } + + function t($a, $b) + { + if ($a && strpos($a, $b) === 0 && substr($a, -strlen($b)) === $b) { + return substr(substr($a, strlen($b)), 0, -strlen($b)); + } + return $a; + } + + function fn_minify($pattern, $input) + { + return preg_split('#(' . implode('|', $pattern) . ')#', $input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + } + + function fn_minify_css($input, $comment = 2, $quote = 2) + { + if (!is_string($input) || !$input = n(trim($input))) return $input; + $output = $prev = ""; + foreach (fn_minify([MINIFY_COMMENT_CSS, MINIFY_STRING], $input) as $part) { + if (trim($part) === "") continue; + if ($comment !== 1 && strpos($part, '/*') === 0 && substr($part, -2) === '*/') { + if ( + $comment === 2 && ( + // Detect special comment(s) from the third character. It should be a `!` or `*` → `/*! keep */` or `/** keep */` + strpos('*!', $part[2]) !== false || + // Detect license comment(s) from the content. It should contains character(s) like `@license` + stripos($part, '@licence') !== false || // noun + stripos($part, '@license') !== false || // verb + stripos($part, '@preserve') !== false + ) + ) { + $output .= $part; + } + continue; + } + if ($part[0] === '"' && substr($part, -1) === '"' || $part[0] === "'" && substr($part, -1) === "'") { + // Remove quote(s) where possible … + $q = $part[0]; + if ( + $quote !== 1 && ( + // + substr($prev, -4) === 'url(' && preg_match('#\burl\($#', $prev) || + // + substr($prev, -1) === '=' && preg_match('#^' . $q . '[a-zA-Z_][\w-]*?' . $q . '$#', $part) + ) + ) { + $part = t($part, $q); // trim quote(s) + } + $output .= $part; + } else { + $output .= fn_minify_css_union($part); + } + $prev = $part; + } + return trim($output); + } + + function fn_minify_css_union($input) + { + if (stripos($input, 'calc(') !== false) { + // Keep important white–space(s) in `calc()` + $input = preg_replace_callback('#\b(calc\()\s*(.*?)\s*\)#i', function ($m) { + return $m[1] . preg_replace('#\s+#', X, $m[2]) . ')'; + }, $input); + } + $input = preg_replace([ + // Fix case for `#foo[bar="baz"]`, `#foo*` and `#foo:first-child` [^1] + '#(?<=[\w])\s+(\*|\[|:[\w-]+)#', + // Fix case for `[bar="baz"].foo`, `*.foo`, `:nth-child(2).foo` and `@media(foo: bar)and(baz: qux)` [^2] + '#([*\]\)])\s+(?=[\w\#.])#', '#\b\s+\(#', '#\)\s+\b#', + // Minify HEX color code … [^3] + '#\#([a-f\d])\1([a-f\d])\2([a-f\d])\3\b#i', + // Remove white–space(s) around punctuation(s) [^4] + '#\s*([~!@*\(\)+=\{\}\[\]:;,>\/])\s*#', + // Replace zero unit(s) with `0` [^5] + '#\b(?