Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Rodrigo54/93169db48194d470188f to your computer and use it in GitHub Desktop.
Save Rodrigo54/93169db48194d470188f 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-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, '</style>') !== false) {
$input = preg_replace_callback('#<style(.*?)>(.*?)</style>#is', function($matches) {
return '<style' . $matches[1] .'>'. minify_css($matches[2]) . '</style>';
}, $input);
}
if(strpos($input, '</script>') !== false) {
$input = preg_replace_callback('#<script(.*?)>(.*?)</script>#is', function($matches) {
return '<script' . $matches[1] .'>'. minify_js($matches[2]) . '</script>';
}, $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
'#(&nbsp;)&nbsp;(?![<\s])#', // clean up ...
'#(?<=\>)(&nbsp;)(?=\<)#', // --ibid
// Remove HTML comment(s) except IE comment(s)
'#\s*<!--(?!\[if\s).*?-->\s*|(?<!\>)\n+(?=\<[^!])#s'
),
array(
'<$1$2</$1>',
'$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
'#(\/\*(?>.*?\*\/))|(?<!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',
// 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*|\s*$#',
// Remove white-space(s) outside the string and regex
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\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);
}
@alan-zhang-
Copy link

alan-zhang- commented Jun 27, 2017

It's a great fork that saved me for original one caused a weird bug for code:

{% for lang_abbr, lang_name in langs %}
    <li>
        <a class="flag flag-{{ lang_abbr }}" title="{{ lang_name }}" href="{{ sites[lang_abbr] ~ uri }}">
            {{ lang_name }}
        </a>
    </li>
{% endfor %}

@saosangmo
Copy link

this code will return wrong result
<script type="text/javascript"><!--$('.vtabs a').tabs();</script>

@thunder87
Copy link

thunder87 commented Dec 15, 2017

@saosangmo

Ofc it will, it's not valid code. You have a HTML comment tag that shouldn't be there :)

@Simbiat
Copy link

Simbiat commented Mar 3, 2018

CSS function strips spaces that are required in "calc" functions

@Simbiat
Copy link

Simbiat commented Mar 3, 2018

Javascript function turns
string = string.replace(/\//g, '_').replace(/\+/g, '-');
into
string = string.replace(/\

@kiptoyot
Copy link

How to solve this error in suiteCRM.when i try to create a target list it shows this error
Fatal error: Uncaught Error: Call to undefined function minify_css() in C:\xampp\htdocs\SuiteCRM\include\Smarty\plugins\block.minify.php:15 Stack trace: #0 [internal function]: {closure}(Array) #1 C:\xampp\htdocs\SuiteCRM\include\Smarty\plugins\block.minify.php(16): preg_replace_callback('#<([^<]+?)\s+st...', Object(Closure), '<label for="dom...') #2 C:\xampp\htdocs\SuiteCRM\cache\smarty\templates_c%%B9^B9B^B9B2C976%%EditView.tpl.php(654): smarty_block_minify(Array, '<label for="dom...', Object(Sugar_Smarty), false) #3 C:\xampp\htdocs\SuiteCRM\include\Smarty\Smarty.class.php(1264): include('C:\xampp\htdocs...') #4 C:\xampp\htdocs\SuiteCRM\include\Sugar_Smarty.php(151): Smarty->fetch('cache/themes/Su...', NULL, NULL, false) #5 C:\xampp\htdocs\SuiteCRM\include\TemplateHandler\TemplateHandler.php(365): Sugar_Smarty->fetch('cache/themes/Su...') #6 C:\xampp\htdocs\SuiteCRM\include\EditView\EditView2.php(909): TemplateHandler->displayTemplate('ProspectLists', 'EditView', 'include/EditVie...', false, Array) #7 C:\xampp\htdoc in C:\xampp\htdocs\SuiteCRM\include\Smarty\plugins\block.minify.php on line 15

@kiptoyot
Copy link

Guys i need your assistance please

@MattIPv4
Copy link

Hey guys, this removes spaces in css that are inside a calc() which leads to it becoming an invalid property value, does anyone know the fix?

Copy link

ghost commented May 24, 2019

Thanks <3

@TriForceX
Copy link

Hey guys, this removes spaces in css that are inside a calc() which leads to it becoming an invalid property value, does anyone know the fix?

maybe is too late, but just FYI ive fixed it on a old project i made TriForceX/BootstrapExtended#14

@AugustGarcia
Copy link

Ran into a bug using this function with exceptionally large files (like 1 MB+ worth of HTML to minify). Specifically, above a certain string size, minify_html seems to return an empty string (or some other false-y value).

Added a "ghetto hack" as shown below. HTML will not be minified, but will at least return the original HTML.

    $original_input = $input; 

   /* The rest of the function */ 

    if (!$input)
        return $original_input;  
    return $input; 

@cproetti
Copy link

cproetti commented Mar 6, 2020

One problem, it removes whitespace in CSS calc() for example
font-size: calc(36px + (80 - 36) * (100vw - 320px) / (1366 - 320));

Becomes:
font-size: calc(36px+(80-36) * (100vw-320px) / (1366-320));

Which is invalid.

@Rodrigo54
Copy link
Author

Fixed problem in whitespace in CSS calc()

thanks @jcmarchi and @TriForceX for solution

@sabrysuleiman
Copy link

sabrysuleiman commented Jul 21, 2020

css replace 0% It will cause crash keyframes uses ( 0% ) ...

@jcmarchi
Copy link

css replace 0% It will cause crash keyframes uses ( 0% ) ...

Hi Rodrigo, any lucky looking into this one? keyframes are increasingly getting more important in nowadays CSS implementations and it can surely start being a problem in many cases.

Copy link

ghost commented Oct 12, 2020

css replace 0% It will cause crash keyframes uses ( 0% ) ...

Though I don't do css much, I think \d% in keyframe rules is always followed by {. Hence this pattern would work: (?<=[\s:])(0)(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)(?!\s*\{).

@jamesit8791
Copy link

One problem,
var loadPage = function(){
// Content
}
var loadPage = function(){
// Content
}
When compressing an error.

Here is correct.
var loadPage = function(){
// Content
};
var loadPage = function(){
// Content
};
How to fix this.
Thank!

@JiveDig
Copy link

JiveDig commented Jan 11, 2023

These are great, thanks! Like others, I removed the 0 replacement line. Thanks for much for sharing.

@sonomzy
Copy link

sonomzy commented Nov 14, 2023

Thank you so much

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