Skip to content

Commit d08ddca

Browse files
authored
Create css-transformer.php
1 parent 74b5dfe commit d08ddca

File tree

1 file changed

+376
-0
lines changed

1 file changed

+376
-0
lines changed

css-transformer.php

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
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 &amp; 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 &amp; 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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/\'/g, "&#039;");
368+
});
369+
hljs.tabReplace = " ";
370+
hljs.initHighlightingOnLoad();
371+
</script>
372+
</body>
373+
</html>
374+
';
375+
376+
/* EOF - END OF FILE */

0 commit comments

Comments
 (0)