From c78ac37372dd33611588db8a6da72a417c5c6154 Mon Sep 17 00:00:00 2001 From: Yaya Laressa Date: Sat, 3 Jul 2021 17:53:53 +0700 Subject: [PATCH] add function minifier and file cache auto minifier --- README.md | 2 +- system/includes/dispatch.php | 133 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f7dc9cd..d2c0f90 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Features - Responsive Design - User Roles - Online Backup -- File Caching +- File Caching (Auto Minify HTML support) - Online Update - Post Draft - i18n diff --git a/system/includes/dispatch.php b/system/includes/dispatch.php index 7bb9b16..bd33cec 100644 --- a/system/includes/dispatch.php +++ b/system/includes/dispatch.php @@ -136,6 +136,134 @@ if (extension_loaded('mcrypt')) { } +// Based on +// HTML Minifier +function minify_html($input) { + if(trim($input) === "") return $input; + // Remove extra white-space(s) between HTML attribute(s) + $input = preg_replace_callback('#<([^\/\s<>!]+)(?:\s+([^<>]*?)\s*|\s*)(\/?)>#s', function($matches) { + return '<' . $matches[1] . preg_replace('#([^\s=]+)(\=([\'"]?)(.*?)\3)?(\s+|$)#s', ' $1$2', $matches[2]) . $matches[3] . '>'; + }, str_replace("\r", "", $input)); + // Minify inline CSS declaration(s) + if(strpos($input, ' style=') !== false) { + $input = preg_replace_callback('#<([^<]+?)\s+style=([\'"])(.*?)\2(?=[\/\s>])#s', function($matches) { + return '<' . $matches[1] . ' style=' . $matches[2] . minify_css($matches[3]) . $matches[2]; + }, $input); + } + if(strpos($input, '') !== false) { + $input = preg_replace_callback('#(.*?)#is', function($matches) { + return ''. minify_css($matches[2]) . ''; + }, $input); + } + if(strpos($input, '') !== false) { + $input = preg_replace_callback('#(.*?)#is', function($matches) { + return ''. minify_js($matches[2]) . ''; + }, $input); + } + + return preg_replace( + array( + // t = text + // o = tag open + // c = tag close + // Keep important white-space(s) after self-closing HTML tag(s) + '#<(img|input)(>| .*?>)#s', + // Remove a line break and two or more white-space(s) between tag(s) + '#()|(>)(?:\n*|\s{2,})(<)|^\s*|\s*$#s', + '#()|(?)\s+(<\/.*?>)|(<[^\/]*?>)\s+(?!\<)#s', // t+c || o+t + '#()|(<[^\/]*?>)\s+(<[^\/]*?>)|(<\/.*?>)\s+(<\/.*?>)#s', // o+o || c+c + '#()|(<\/.*?>)\s+(\s)(?!\<)|(?)\s+(\s)(<[^\/]*?\/?>)|(<[^\/]*?\/?>)\s+(\s)(?!\<)#s', // c+t || t+o || o+t -- separated by long white-space(s) + '#()|(<[^\/]*?>)\s+(<\/.*?>)#s', // empty tag + '#<(img|input)(>| .*?>)<\/\1>#s', // reset previous fix + '#( ) (?![<\s])#', // clean up ... + '#(?<=\>)( )(?=\<)#', // --ibid + // Remove HTML comment(s) except IE comment(s) + '#\s*\s*|(?)\n+(?=\<[^!])#s' + ), + array( + '<$1$2', + '$1$2$3', + '$1$2$3', + '$1$2$3$4$5', + '$1$2$3$4$5$6$7', + '$1$2$3', + '<$1$2', + '$1 ', + '$1', + "" + ), + $input); +} + +// CSS Minifier => http://ideone.com/Q5USEF + improvement(s) +function minify_css($input) { + if(trim($input) === "") return $input; + return preg_replace( + array( + // Remove comment(s) + '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')|\/\*(?!\!)(?>.*?\*\/)|^\s*|\s*$#s', + // Remove unused white-space(s) + '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/))|\s*+;\s*+(})\s*+|\s*+([*$~^|]?+=|[{};,>~]|\s(?![0-9\.])|!important\b)\s*+|([[(:])\s++|\s++([])])|\s++(:)\s*+(?!(?>[^{}"\']++|"(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')*+{)|^\s++|\s++\z|(\s)\s+#si', + // Replace `0(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)` with `0` + '#(?<=[\s:])(0)(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)#si', + // Replace `:0 0 0 0` with `:0` + '#:(0\s+0|0\s+0\s+0\s+0)(?=[;\}]|\!important)#i', + // Replace `background-position:0` with `background-position:0 0` + '#(background-position):0(?=[;\}])#si', + // Replace `0.6` with `.6`, but only when preceded by `:`, `,`, `-` or a white-space + '#(?<=[\s:,\-])0+\.(\d+)#s', + // Minify string value + '#(\/\*(?>.*?\*\/))|(?.*?\*\/))|(\burl\()([\'"])([^\s]+?)\3(\))#si', + // Minify HEX color code + '#(?<=[\s:,\-]\#)([a-f0-6]+)\1([a-f0-6]+)\2([a-f0-6]+)\3#i', + // Replace `(border|outline):none` with `(border|outline):0` + '#(?<=[\{;])(border|outline):none(?=[;\}\!])#', + // Remove empty selector(s) + '#(\/\*(?>.*?\*\/))|(^|[\{\}])(?:[^\s\{\}]+)\{\}#s' + ), + array( + '$1', + '$1$2$3$4$5$6$7', + '$1', + ':0', + '$1:0 0', + '.$1', + '$1$3', + '$1$2$4$5', + '$1$2$3', + '$1:0', + '$1$2' + ), + $input); +} + +// JavaScript Minifier +function minify_js($input) { + if(trim($input) === "") return $input; + return preg_replace( + array( + // Remove comment(s) + '#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s', + // Remove the last semicolon + '#;+\}#', + // Minify object attribute(s) except JSON attribute(s). From `{'foo':'bar'}` to `{foo:'bar'}` + '#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i', + // --ibid. From `foo['bar']` to `foo.bar` + '#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i' + ), + array( + '$1', + '$1$2', + '}', + '$1$3', + '$1.$3' + ), + $input); +} + function set_cookie($name, $value, $expire = 31536000, $path = '/') { $value = (function_exists('encrypt') ? encrypt($value) : $value); @@ -361,10 +489,11 @@ function render($view, $locals = null, $layout = null) } if (!$login && $view != '404') { if (!file_exists($cachefile)) { + $content = minify_html(ob_get_contents()); // Minify HTML if (config('cache.timestamp') == 'true') { - echo "\n" . ''; + $content .= "\n" . ''; } - file_put_contents($cachefile, ob_get_contents()); + file_put_contents($cachefile, $content); } } echo trim(ob_get_clean());