Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save skhani/3888f69b54509408b028 to your computer and use it in GitHub Desktop.
Save skhani/3888f69b54509408b028 to your computer and use it in GitHub Desktop.
PHP Function to Minify HTML, CSS and JavaScript
<?php
/**
* -----------------------------------------------------------------------------------------
* Based on `https://github.com/mecha-cms/mecha-cms/blob/master/system/kernel/converter.php`
* -----------------------------------------------------------------------------------------
*/
// HTML Minifier
function minify_html($input) {
if(trim($input) === "") return $input;
// Remove extra white-spaces between HTML attributes
$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] . '>';
}, $input);
// Minify inline CSS declarations
if(strpos($input, ' style=') !== false) {
$input = preg_replace_callback('#\s+style=([\'"]?)(.*?)\1(?=[\/\s>])#s', function($matches) {
return ' style=' . $matches[1] . minify_css($matches[2]) . $matches[1];
}, $input);
}
return preg_replace(
array(
// Remove HTML comments except IE comments
'#\s*(<\!--(?=\[if).*?-->)\s*|\s*<\!--.*?-->\s*#s',
// Do not remove white-space after image and
// input tag that is followed by a tag open
'#(<(?:img|input)(?:\/?>|\s[^<>]*?\/?>))\s+(?=\<[^\/])#s',
// Remove two or more white-spaces between tags
'#(<\!--.*?-->)|(>)\s{2,}|\s{2,}(<)|(>)\s{2,}(<)#s',
// Proofing ...
// o: tag open, c: tag close, t: text
// If `<tag> </tag>` remove white-space
// If `</tag> <tag>` keep white-space
// If `<tag> <tag>` remove white-space
// If `</tag> </tag>` remove white-space
// If `<tag> ...</tag>` remove white-spaces
// If `</tag> ...<tag>` remove white-spaces
// If `<tag> ...<tag>` remove white-spaces
// If `</tag> ...</tag>` remove white-spaces
// If `abc <tag>` keep white-space
// If `<tag> abc` remove white-space
// If `abc </tag>` remove white-space
// If `</tag> abc` keep white-space
// TODO: If `abc ...<tag>` keep one white-space
// If `<tag> ...abc` remove white-spaces
// If `abc ...</tag>` remove white-spaces
// TODO: If `</tag> ...abc` keep one white-space
'#(<\!--.*?-->)|(<(?:img|input)(?:\/?>|\s[^<>]*?\/?>))\s+(?!\<\/)#s', // o+t | o+o
'#(<\!--.*?-->)|(<[^\/\s<>]+(?:>|\s[^<>]*?>))\s+(?=\<[^\/])#s', // o+o
'#(<\!--.*?-->)|(<\/[^\/\s<>]+?>)\s+(?=\<\/)#s', // c+c
'#(<\!--.*?-->)|(<([^\/\s<>]+)(?:>|\s[^<>]*?>))\s+(<\/\3>)#s', // o+c
'#(<\!--.*?-->)|(<[^\/\s<>]+(?:>|\s[^<>]*?>))\s+(?!\<)#s', // o+t
'#(<\!--.*?-->)|(?!\>)\s+(<\/[^\/\s<>]+?>)#s', // t+c
'#(<\!--.*?-->)|(?!\>)\s+(?=\<[^\/])#s', // t+o
'#(<\!--.*?-->)|(<\/[^\/\s<>]+?>)\s+(?!\<)#s', // c+t
'#(<\!--.*?-->)|(\/>)\s+(?!\<)#', // o+t
// Replace `&nbsp;&nbsp;&nbsp;` with `&nbsp; &nbsp;`
'#(?<=&nbsp;)(&nbsp;){2}#',
// Proofing ...
'#(?<=\>)&nbsp;(?!\s|&nbsp;|<\/)#',
'#(?<=--\>)(?:\s|&nbsp;)+(?=\<)#'
),
array(
'$1',
'$1&nbsp;',
'$1$2$3$4$5',
'$1$2&nbsp;', // o+t | o+o
'$1$2', // o+o
'$1$2', //c+c
'$1$2$4', // o+c
'$1$2', // o+t
'$1$2', // t+c
'$1$2 ', // t+o
'$1$2 ', // c+t
'$1$2 ', // o+t
' $1',
' ',
""
),
trim($input));
}
// CSS Minifier => http://ideone.com/Q5USEF + improvement(s)
function minify_css($input) {
if(trim($input) === "") return $input;
return preg_replace(
array(
// Remove comments
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')|\/\*(?!\!)(?>.*?\*\/)#s',
// Remove unused white-spaces
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/))|\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
'#(\/\*(?>.*?\*\/))|(?<!content\:)([\'"])([a-z_][a-z0-9\-_]*?)\2(?=[\s\{\}\];,])#si',
'#(\/\*(?>.*?\*\/))|(\burl\()([\'"])([^\s]+?)\3(\))#si',
// Minify HEX color code
'#(?<=[:\-,\s]\#)([a-f0-6]+)\1([a-f0-6]+)\2([a-f0-6]+)\3#i',
// Remove empty selectors
'#(\/\*(?>.*?\*\/))|(^|[\{\}])(?:[^\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$2'
),
trim($input));
}
// JavaScript Minifier
function minify_js($input) {
if(trim($input) === "") return $input;
return preg_replace(
array(
// '#(?<!\\\)\\\\\"#',
// '#(?<!\\\)\\\\\'#',
// Remove comments
'#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*\s*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*[\n\r]*#',
// Remove unused white-space characters outside the string and regex
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\.,;]|[gimuy]))|\s*([+\-\=\/%\(\)\{\}\[\]<>\|&\?\!\:;\.,])\s*#s',
// Remove the last semicolon
'#;+\}#',
// Replace `true` with `!0`
// '#\btrue\b#',
// Replace `false` with `!1`
// '#\bfalse\b#',
// Minify object attribute except JSON attribute. 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(
// '\\u0022',
// '\\u0027',
'$1',
'$1$2',
'}',
// '!0',
// '!1',
'$1$3',
'$1.$3'
),
trim($input));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment