|
| 1 | +<?php /* 377 Lines */ |
| 2 | + |
| 3 | +/** |
| 4 | + * |
| 5 | + * CSS Compiler / Obfuscator / Minifier / Transpiler (PHP 5.3.0 or >) |
| 6 | + * |
| 7 | + * Stylesheet Compiler makes it possible to rename CSS class names |
| 8 | + * in your stylesheet, which helps reduce the size of the CSS that |
| 9 | + * is sent down to your users. |
| 10 | + * Of course, this is not particularly useful unless the class names |
| 11 | + * are renamed consistently in the HTML and CSS files that use the names. |
| 12 | + * Fortunately, you can use the Stylesheet Compiler to update the class |
| 13 | + * names in your CSS and to update the class names in your HTML. |
| 14 | +
|
| 15 | + * Also it is an unique way to protect your stylesheets from theft. |
| 16 | + * Actually, it surly doesn't protects sheets from stealing, |
| 17 | + * because it's not really possible in the web technology. |
| 18 | + * |
| 19 | + * So how it works? |
| 20 | + * This software will transform your stylesheets in a way, |
| 21 | + * no one will want to modify them. They can steal it, |
| 22 | + * but who wants to use (and adjust) stylesheet, |
| 23 | + * which looks like if it's made of the worst coder in the universe? |
| 24 | + * |
| 25 | + * Got it? Try it! |
| 26 | + * |
| 27 | + * Copyright 2020 phpSoftware |
| 28 | + * |
| 29 | + * TODO |
| 30 | + * ALSO PARSE <style></style> TAG IN THE HTML FILE |
| 31 | + * |
| 32 | + */ |
| 33 | + |
| 34 | +// SETUP |
| 35 | +$delimiter = '--VANGATO--'; |
| 36 | +$DEBUG = false; // NEVER SET TO true IN LIVE SYSTEM |
| 37 | + |
| 38 | +// GET POST INPUTS |
| 39 | +$htmlFile = ''; |
| 40 | +if ( isset($_POST['htmlFile']) and !empty($_POST['htmlFile']) and filter_var($_POST['htmlFile'], FILTER_VALIDATE_URL)) { |
| 41 | + $htmlFile = strtok($_POST['htmlFile'], '?'); |
| 42 | + $htmlFile = htmlentities($htmlFile); |
| 43 | +} |
| 44 | + |
| 45 | +$cssFile = ''; |
| 46 | +if ( isset($_POST['cssFile']) and !empty($_POST['cssFile']) and filter_var($_POST['cssFile'], FILTER_VALIDATE_URL)) { |
| 47 | + $cssFile = strtok($_POST['cssFile'], '?'); |
| 48 | + $cssFile = htmlentities($cssFile); |
| 49 | +} |
| 50 | + |
| 51 | +$removeLineBreaks = 'No'; |
| 52 | +if ( isset($_POST['removeLineBreaks']) && $_POST['removeLineBreaks']=='Yes' ) { |
| 53 | + $removeLineBreaks = 'Yes'; |
| 54 | +} |
| 55 | + |
| 56 | +// PRINT HEADER |
| 57 | +echo '<!DOCTYPE html> |
| 58 | +<html lang="en"> |
| 59 | + <head> |
| 60 | + <meta charset="UTF-8"/> |
| 61 | + <title> CSS Compiler / Obfuscator / Minifier / Transpiler </title> |
| 62 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 63 | + <link href="data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAVFFOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEAABEAAAABEAAAARAAAAEQAAABEAAAARAAAAEQAAABEAAAARAAABEAAAAAEQABEAAAAAABEAEQAAAAAAEQABEAAAAAEQAAARAAAAEQAAABEAAAARAAAAEQAAABEAAAARAAAAEQAAAAEQAAEQAAAAAAAAAAAAD//wAA888AAOfnAADn5wAA5+cAAOfnAADP8wAAn/kAAJ/5AADP8wAA5+cAAOfnAADn5wAA5+cAAPPPAAD//wAA" rel="icon" type="image/x-icon"> |
| 64 | +
|
| 65 | + <!-- CLASSLESS CSS FRAMEWORK - https://yegor256.github.io/tacit/ --> |
| 66 | + <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css.min.css"> |
| 67 | + |
| 68 | + <!-- SYNTAX LIGHTNING https://highlightjs.org/ --> |
| 69 | + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/default.min.css"> |
| 70 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script> |
| 71 | + |
| 72 | + <!-- SYNTAX LIGHTNING THEMES --> |
| 73 | + <link rel="stylesheet" href="css-transformer.css"> |
| 74 | + |
| 75 | + <!-- SYNTAX LIGHTNING CUSTOME CSS FOR TACIT.CSS --> |
| 76 | + <style> |
| 77 | + body { padding: 0 5px } |
| 78 | + h2 { margin-top: 10px; font-weight: 700 } |
| 79 | + select { width: 100%; -webkit-appearance: none; -moz-appearance: none; appearance: none; background:url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'8\' height=\'8\' fill=\'silver\'><polygon points=\'0,0 8,0 4,4\'/></svg>") no-repeat scroll 98% 60% transparent } |
| 80 | + input:not([type="submit"]){ width: 100% } |
| 81 | + pre { border-left: 0; padding-left: 0; height: 50px; display: block; margin-bottom: 10px; background: #2b2b2b; border-radius: 3.6px } |
| 82 | + pre code { line-height: 20px } |
| 83 | + xmp { line-height: 1; color: #f8f8f2; padding: 0.5em; word-wrap: break-word } |
| 84 | + footer { float: right } |
| 85 | + </style> |
| 86 | + </head> |
| 87 | + <body> |
| 88 | + <section> |
| 89 | + <h2> CSS Compiler / Obfuscator / Minifier / Transpiler </h2> |
| 90 | + <form action="" method="POST"> |
| 91 | + <fieldset> |
| 92 | + <label><strong>URL TO HTML FILE</strong></label> |
| 93 | + <input size="100" type="text" name="htmlFile" value="' . $htmlFile . '"> |
| 94 | + <label><strong>URL TO MATCHING CSS FILE</strong></label> |
| 95 | + <input size="100" type="text" name="cssFile" value="' . $cssFile . '"> |
| 96 | + <label><strong>REMOVE LINE BREAKS</strong> (in CSS)</label> |
| 97 | + <select name="removeLineBreaks"> |
| 98 | + <option>' . $removeLineBreaks . '</option> |
| 99 | + <optgroup label="Select..."> |
| 100 | + <option value="Yes">Yes</option> |
| 101 | + <option value="">No</option> |
| 102 | + </select> |
| 103 | + <input type="submit" name="submit" value="submit"> |
| 104 | + </fieldset> |
| 105 | + </form> |
| 106 | + '; |
| 107 | + |
| 108 | +// EXIT HERE IF NO FORM IS SEND |
| 109 | +if ( !isset($_POST['submit']) or empty($_POST['htmlFile']) ) exit; |
| 110 | + |
| 111 | +// INI VARs |
| 112 | +$chars = 'abcdefghijklmnopqrstuvwxyz'; |
| 113 | +$i = $z = 0; |
| 114 | + |
| 115 | +// LOAD HTML FILE |
| 116 | +$html_content = file_get_contents($htmlFile); |
| 117 | + |
| 118 | +// GET ALL CLASS NAMES FROM THE HTML |
| 119 | +preg_match_all('/class="([^\"]+)"/i', $html_content, $html_classes); |
| 120 | + |
| 121 | +// DEBUG HEADER |
| 122 | +if ($DEBUG==true) echo '<strong>DEBUG</strong><pre style="height:200px"><xmp>'; |
| 123 | + |
| 124 | +// LOOP THROUGH ALL FOUND CLASSES |
| 125 | +foreach ($html_classes[1] as $class) { |
| 126 | + if ($DEBUG==true) echo 'HTML CLASS .' . $class . PHP_EOL; // DEV ONLY |
| 127 | + // SPLIT SEVERAL SELECTORS BY SPACE |
| 128 | + $several = explode(' ', $class); |
| 129 | + // CHECK IF THERE WAS SEVERAL SELECTORS |
| 130 | + if (count($several) > 0) { |
| 131 | + // LOOP THROUGH SPLITTED SELECTORS |
| 132 | + foreach ($several as $part) { |
| 133 | + // ADD THEM ALL |
| 134 | + $classes[$part] = '.' . $part; |
| 135 | + } |
| 136 | + } else { |
| 137 | + // ADD IF ONLY ON SELECTOR WASS IN THE CLASS TAG |
| 138 | + $classes[$class] = '.' . $class; |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +// DEBUG LINE BREAK |
| 143 | +if ($DEBUG==true) echo PHP_EOL . PHP_EOL; // DEV ONLY |
| 144 | + |
| 145 | +// GET ALL IDs FROM THE HTML |
| 146 | +preg_match_all('/id="([^\"]+)"/i', $html_content, $html_ids); |
| 147 | + |
| 148 | +// LOOP THROUGH ALL FOUND IDs |
| 149 | +foreach ($html_ids[1] as $id) { |
| 150 | + if ($DEBUG==true) echo 'HTML ID #' . $id . PHP_EOL; // DEV ONLY |
| 151 | + $ids[$id] = '#' . $id; |
| 152 | +} |
| 153 | + |
| 154 | +// ADD CLASSES AND IDs ARRAY TO ONE HTML ARRAY |
| 155 | +$html = array_merge($classes, $ids); |
| 156 | + |
| 157 | +// SELECT CSS |
| 158 | +if ( !isset($cssFile) or empty($cssFile) ) { |
| 159 | + // GET INLINE CSS |
| 160 | + preg_match_all('/<style(.*)?>(.*)?<\/style>/mi', $html_content, $inlineCSS); // , PREG_SET_ORDER |
| 161 | + #echo '<pre style="height:300px">';var_dump($inlineCSS));echo '</pre>'; |
| 162 | + $css_content = implode(PHP_EOL, $inlineCSS[2]); |
| 163 | + $cssFile = '<strong>INLINE FROM HTML</strong>'; |
| 164 | +} else { |
| 165 | + // LOAD CSS FILE |
| 166 | + $css_content = file_get_contents($cssFile); |
| 167 | +} |
| 168 | + |
| 169 | +// GET ALL CLASS NAMES AND IDs FROM THE CSS |
| 170 | +#preg_match_all('/^([#|\.][_a-z]+[_a-z0-9-]*)/mi', $css_content, $css_tags); |
| 171 | +preg_match_all('/([#|\.][_a-z]+[_a-z0-9-]*) ?{/i', $css_content, $css_tags); |
| 172 | + |
| 173 | +// DEBUG LINE BREAK |
| 174 | +if ($DEBUG==true) echo PHP_EOL . PHP_EOL; // DEV ONLY |
| 175 | + |
| 176 | +// LOOP THROUGH ALL FOUND CLASSES AND IDs |
| 177 | +foreach ($css_tags[1] as $tag) { |
| 178 | + if ($DEBUG==true) echo 'CSS ' . $tag . PHP_EOL; // DEV ONLY |
| 179 | + // REMOVE FRIST CHAR # AND . |
| 180 | + $index = ltrim($tag, '#.'); |
| 181 | + // SAVE IIN MULTI ARRAY |
| 182 | + $css[$index] = $tag; |
| 183 | +} |
| 184 | + |
| 185 | +// DEBUG FOOTER |
| 186 | +if ($DEBUG==true) echo '</xmp></pre>'; |
| 187 | + |
| 188 | +// REMOVE DOUBLICATES |
| 189 | +$css = array_unique($css); |
| 190 | + |
| 191 | +// HTML RESULT TO BROWSER |
| 192 | +echo '<strong>FOUND CLASSES & IDs IN HTML FILE:</strong> <small>' . $htmlFile . '</small>'; |
| 193 | +echo '<pre><code class="css">'; |
| 194 | + |
| 195 | +// LOOP THROUGH ALL MATCHES |
| 196 | +foreach ($html as $tag) { |
| 197 | + // PRINT TO BROSER |
| 198 | + echo $tag . PHP_EOL; |
| 199 | +} |
| 200 | + |
| 201 | +// CLOSE THE OUTPUT |
| 202 | +echo '</code></pre>'; |
| 203 | + |
| 204 | +// CSS RESULT TO BROWSER |
| 205 | +echo '<strong>FOUND CLASSES & IDs IN THE CSS FILE:</strong> <small>' . $cssFile . '</small>'; |
| 206 | +if ($cssFile=='<strong>INLINE FROM HTML</strong>') { |
| 207 | + $cssFile = ''; |
| 208 | +} |
| 209 | + |
| 210 | +// START THE OUTPUT |
| 211 | +echo '<pre><code class="css">'; |
| 212 | + |
| 213 | +// LOOP THROUGH ALL MATCHES |
| 214 | +foreach ($css as $tag) { |
| 215 | + // PRINT TO BROSER |
| 216 | + echo $tag . PHP_EOL; |
| 217 | +} |
| 218 | + |
| 219 | +// CLOSE THE OUTPUT |
| 220 | +echo '</code></pre>'; |
| 221 | + |
| 222 | +// SHOW UNUSED IDs AND CLASS-NAMES IN HTML |
| 223 | +echo '<strong>DELETE THIS UNUSED IN HTML</strong> '; |
| 224 | +echo '<small>Check that # selectors are not used for ID="" Deeplinks!</small>'; |
| 225 | +echo '<pre><code class="plaintext">'; |
| 226 | + |
| 227 | +// LOOP THROUGH ALL IN HTML FILE FOUND TAGS |
| 228 | +$css_found = false; |
| 229 | +foreach ($html as $name => $value) { |
| 230 | + // GIVE HINT IF TAG FROM HTML IS NOT FOUND IN CSS THEN DELETE IT IN HTML (IT IS UNUSED IN THE CSS) |
| 231 | + if (!array_key_exists ($name, $css)) { |
| 232 | + echo $value . PHP_EOL; |
| 233 | + $css_found = true; |
| 234 | + } else { |
| 235 | + // BUILD NEW CLASS OR ID NAME |
| 236 | + $new = $chars[$z] . $delimiter . $chars[$i]; |
| 237 | + // REPLACE NAMES (CLASS & ID) IN THE CSS |
| 238 | + $css_content = str_replace($value.' ', $value[0].$new, $css_content); |
| 239 | + $css_content = str_replace($value.'{', $value[0].$new.'{', $css_content); |
| 240 | + $css_content = str_replace($value.':', $value[0].$new.':', $css_content); |
| 241 | + $css_content = str_replace($value.',', $value[0].$new.',', $css_content); |
| 242 | + $css_content = str_replace($value."\t", $value[0].$new, $css_content); |
| 243 | + $css_content = str_replace($value."\n", $value[0].$new, $css_content); |
| 244 | + $css_content = str_replace($value."\r", $value[0].$new, $css_content); |
| 245 | + // REPLACE NAMES (CLASS & ID) IN THE HMTL |
| 246 | + $html_content = str_replace('"'.ltrim($value, '#.').'"', '"'.$new.'"', $html_content); // " " |
| 247 | + $html_content = str_replace('\''.ltrim($value, '#.').'\'', '"'.$new.'"', $html_content); // ' ' |
| 248 | + $html_content = str_replace(' '.ltrim($value, '#.').' ', ' '.$new.' ', $html_content); // SPACE SPACE |
| 249 | + $html_content = str_replace(' '.ltrim($value, '#.').'"', ' '.$new.'"', $html_content); // SPACE " |
| 250 | + $html_content = str_replace(' '.ltrim($value, '#.').'\'', ' '.$new.'\'', $html_content); // SPACE ' |
| 251 | + $html_content = str_replace('"'.ltrim($value, '#.').' ', '"'.$new.' ', $html_content); // " SPACE |
| 252 | + $html_content = str_replace('\''.ltrim($value, '#.').' ', '\''.$new.' ', $html_content); // ' SPACE |
| 253 | + } |
| 254 | + // INCREMENT FIRST CAHR ON EVERY STEP |
| 255 | + ++$i; |
| 256 | + // AFTER 26 STEPS WE ARE AT "Z" SO GO BACK TO "A" (RESET INCREMENT OF $1) |
| 257 | + if ($i == 26) { |
| 258 | + $i = 0; |
| 259 | + // ALSO INCREMENT $z SO WE CAN HAVE THE NEXT CHAR AT THE SECOND POSITION |
| 260 | + ++$z; |
| 261 | + } |
| 262 | +} |
| 263 | + |
| 264 | +// IF EMPTY PRINt HINT |
| 265 | +if ($css_found!=true) { |
| 266 | + echo '👍 nothing found'; |
| 267 | +} |
| 268 | + |
| 269 | +// CLOSE THE OUTPUT |
| 270 | +echo '</code></pre>'; |
| 271 | + |
| 272 | +// SHOW UNUSED IDs AND CLASS-NAMES IN CSS |
| 273 | +echo '<strong>DELETE THIS UNUSED IN CSS</strong>'; |
| 274 | +echo '<pre><code class="plaintext">'; |
| 275 | + |
| 276 | +// LOOP THROUGH ALL IN CSS FOUND TAGS |
| 277 | +$html_found = false; |
| 278 | +foreach ($css as $name => $value) { |
| 279 | + if ($DEBUG==true) echo 'USED ' . $name . ' -- ' . $value . PHP_EOL; |
| 280 | + // GIVE HINT IF TAG FROM CSS IS NOT FOUND IN HTML THEN DELETE IT IN CSS (IT IS UNUSED IN THE HTML) |
| 281 | + if (!array_key_exists ($name, $html)) { |
| 282 | + echo $value . PHP_EOL; |
| 283 | + $html_found = true; |
| 284 | + } |
| 285 | +} |
| 286 | + |
| 287 | +// IF EMPTY PRINt HINT |
| 288 | +if ($html_found!=true) { |
| 289 | + echo '👍 nothing found'; |
| 290 | +} |
| 291 | + |
| 292 | +// CLOSE THE OUTPUT |
| 293 | +echo '</code></pre>'; |
| 294 | + |
| 295 | +// MINIMIZE THE CSS |
| 296 | +$css_content = minimizeCSSsimple($css_content, $removeLineBreaks); |
| 297 | + |
| 298 | +// SHOW CSS RESULT TO BROWSER |
| 299 | +echo '<strong>RESULT OF CSS</strong>'; |
| 300 | +echo '<pre><code class="css">'; |
| 301 | + |
| 302 | +// PRINT TO BROWSER |
| 303 | +echo $css_content; |
| 304 | + |
| 305 | +// CLOSE THE OUTPUT |
| 306 | +echo '</code></pre>'; |
| 307 | + |
| 308 | +// SET IN THE NEW CSS FILE |
| 309 | +if (!empty($cssFile)) { |
| 310 | + $html_content = str_replace('"'.basename($cssFile).'"', '"css.css"', $html_content); |
| 311 | + // WRITE THE NEW FILE TO FILESYSTEM |
| 312 | + file_put_contents('css.css', $css_content); |
| 313 | +} else { |
| 314 | + $html_content = preg_replace('/<style(.*)?>(.*)?<\/style>/', '<style>'.$css_content.'</style>', $html_content); |
| 315 | +} |
| 316 | + |
| 317 | +// MINIMIZE THE HTML |
| 318 | +$html_content = minimizeHTMLsimple($html_content, $removeLineBreaks); |
| 319 | + |
| 320 | +// SHOW HTML RESULT TO BROWSER |
| 321 | +echo '<strong>RESULT OF HTML</strong>'; |
| 322 | +echo '<pre style="height:200px;border-radius: 3.6px; border: 3px solid #2b2b2b;">'; |
| 323 | + |
| 324 | +// XMP WITHOUT OR WITH LINE BRAKES |
| 325 | +if ($removeLineBreaks=='Yes') { |
| 326 | + echo '<xmp class="html" style="white-space: normal;">'; |
| 327 | +} else { |
| 328 | + echo '<xmp class="html">'; |
| 329 | +} |
| 330 | + |
| 331 | +// PRINT TO BROWSER |
| 332 | +echo $html_content; |
| 333 | + |
| 334 | +// CLOSE THE OUTPUT |
| 335 | +echo '</xmp></pre>'; |
| 336 | + |
| 337 | +// WRITE THE NEW FILE TO FILESYSTEM |
| 338 | +file_put_contents('htm.htm', $html_content); |
| 339 | + |
| 340 | +// HELPER FUNCTIONS |
| 341 | +function minimizeCSSsimple($css, $removeLineBreaks='') { |
| 342 | + $css = preg_replace('/\/\*((?!\*\/).)*\*\//', '', $css); // negative look ahead |
| 343 | + $css = preg_replace('/\s{2,}/', ' ', $css); |
| 344 | + $css = preg_replace('/\s*([:;{}])\s*/', '$1', $css); |
| 345 | + $css = preg_replace('/;\s?}/', '}', $css); |
| 346 | + if ($removeLineBreaks=='Yes') $css = preg_replace( "/\r|\n/", '', $css); // REMOVE LINE BREAKS |
| 347 | + return trim($css); |
| 348 | +} |
| 349 | + |
| 350 | +function minimizeHTMLsimple($html, $removeLineBreaks='') { |
| 351 | + $html = preg_replace('/<!--(.|\s)*?-->/', '', $html); // REMOVE HTML COMMENTS - https://davidwalsh.name/remove-html-comments-php |
| 352 | + $html = preg_replace('/^[ \t]*/m', '', $html); // REMOVE LEADING WHITESPACE (SPACES OR TABS) - https://stackoverflow.com/a/34322250 |
| 353 | + $html = preg_replace('/[ \t]*$/m', '', $html); // REMOVE ENDING WHITESPACE (SPACES OR TABS) |
| 354 | + $html = preg_replace('/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/', "\n", $html); // REMOVE EMPTY LINES - https://stackoverflow.com/a/709684 |
| 355 | + if ($removeLineBreaks=='Yes') $html = preg_replace( "/\>[\r|\n]/", '>', $html); // REMOVE LINE BREAKS |
| 356 | + return trim($html); |
| 357 | +} |
| 358 | + |
| 359 | +// PRINT FOOTER TO BROWSER |
| 360 | +echo ' |
| 361 | + <footer> |
| 362 | + <p><small>Copright '.date('Y').' <a href="https://www.adilbo.com/">www.adilbo.com</a></small></p> |
| 363 | + </footer> |
| 364 | + </section> |
| 365 | + <script> |
| 366 | + document.querySelectorAll("code").forEach(function(element) { |
| 367 | + element.innerHTML = element.innerHTML.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/\'/g, "'"); |
| 368 | + }); |
| 369 | + hljs.tabReplace = " "; |
| 370 | + hljs.initHighlightingOnLoad(); |
| 371 | + </script> |
| 372 | + </body> |
| 373 | +</html> |
| 374 | +'; |
| 375 | + |
| 376 | +/* EOF - END OF FILE */ |
0 commit comments