PluginProbe ʕ •ᴥ•ʔ
10Web Booster – Website speed optimization, Cache & Page Speed optimizer / trunk
10Web Booster – Website speed optimization, Cache & Page Speed optimizer vtrunk
2.33.6 2.33.5 2.33.0 2.30.5 2.30.7 2.30.9 2.31.10 2.31.8 2.32.11 2.32.21 2.32.3 2.32.4 2.32.7 2.6.31 2.6.40 2.6.42 2.6.7 2.7.37 2.7.44 2.7.47 2.8.18 2.8.19 2.8.32 2.8.34 2.8.35 2.9.23 2.9.24 2.9.25 2.9.27 v2.27.4 trunk 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.17 2.0.18 2.0.21 2.0.22 2.0.25 2.0.26 2.0.27 2.0.3 2.0.7 2.0.9 2.10.46 2.10.65 2.10.66 2.10.68 2.11.41 2.11.42 2.11.43 2.12.15 2.12.21 2.12.22 2.12.23 2.12.26 2.13.37 2.13.40 2.13.41 2.13.42 2.13.44 2.13.45 2.13.47 2.14.49 2.14.50 2.15.18 2.17.21 2.17.23 2.18.17 2.19.44 2.19.45 2.19.46 2.19.49 2.2.12 2.2.15 2.2.16 2.2.18 2.2.8 2.20.31 2.20.32 2.20.33 2.21.11 2.21.12 2.21.16 2.21.25 2.22.32 2.23.13 2.23.15 2.23.16 2.23.18 2.24.12 2.24.14 2.24.18 2.25.14 2.26.6 2.28.10 2.28.13 2.28.14 2.28.7 2.29.1 2.29.2 2.29.3 2.3.0 2.3.1 2.3.2 2.3.3 2.30.18
tenweb-speed-optimizer / vendor / pfaciana / tiny-html-minifier / src / TinyHtmlMinifier.php
tenweb-speed-optimizer / vendor / pfaciana / tiny-html-minifier / src Last commit date
TinyHtmlMinifier.php 3 years ago TinyMinify.php 3 years ago
TinyHtmlMinifier.php
286 lines
1 <?php
2
3 namespace Minifier;
4
5 class TinyHtmlMinifier
6 {
7 private $options;
8 private $output;
9 private $build;
10 private $skip;
11 private $skipName;
12 private $head;
13 private $elements;
14
15 public function __construct(array $options)
16 {
17 $this->options = $options;
18 $this->output = '';
19 $this->build = [];
20 $this->skip = 0;
21 $this->skipName = '';
22 $this->head = false;
23 $this->elements = [
24 'skip' => [
25 'code',
26 'pre',
27 'script',
28 'textarea',
29 ],
30 'inline' => [
31 'a',
32 'abbr',
33 'acronym',
34 'b',
35 'bdo',
36 'big',
37 'br',
38 'cite',
39 'code',
40 'dfn',
41 'em',
42 'i',
43 'img',
44 'kbd',
45 'map',
46 'object',
47 'samp',
48 'small',
49 'span',
50 'strong',
51 'sub',
52 'sup',
53 'tt',
54 'var',
55 'q',
56 ],
57 'hard' => [
58 '!doctype',
59 'body',
60 'html',
61 ]
62 ];
63 }
64
65 // Run minifier
66 public function minify(string $html) : string
67 {
68 if (!isset($this->options['disable_comments']) ||
69 !$this->options['disable_comments']) {
70 $html = $this->removeComments($html);
71 }
72
73 $rest = $html;
74
75 while (!empty($rest)) {
76 $parts = explode('<', $rest, 2);
77 $this->walk($parts[0]);
78 $rest = (isset($parts[1])) ? $parts[1] : '';
79 }
80
81 return $this->output;
82 }
83
84 // Walk trough html
85 private function walk(&$part)
86 {
87 $tag_parts = explode('>', $part);
88 $tag_content = $tag_parts[0];
89
90 if (!empty($tag_content)) {
91 $name = $this->findName($tag_content);
92 $element = $this->toElement($tag_content, $part, $name);
93 $type = $this->toType($element);
94
95 if ($name == 'head') {
96 $this->head = $type === 'open';
97 }
98
99 $this->build[] = [
100 'name' => $name,
101 'content' => $element,
102 'type' => $type
103 ];
104
105 $this->setSkip($name, $type);
106
107 if (!empty($tag_content)) {
108 $content = (isset($tag_parts[1])) ? $tag_parts[1] : '';
109 if ($content !== '') {
110 $this->build[] = [
111 'content' => $this->compact($content, $name, $element),
112 'type' => 'content'
113 ];
114 }
115 }
116
117 $this->buildHtml();
118 }
119 }
120
121 // Remove comments
122 private function removeComments($content = '')
123 {
124 return preg_replace('/(?=<!--)([\s\S]*?)-->/', '', $content);
125 }
126
127 // Check if string contains string
128 private function contains($needle, $haystack)
129 {
130 return strpos($haystack, $needle) !== false;
131 }
132
133 // Return type of element
134 private function toType($element)
135 {
136 return (substr($element, 1, 1) == '/') ? 'close' : 'open';
137 }
138
139 // Create element
140 private function toElement($element, $noll, $name)
141 {
142 $element = $this->stripWhitespace($element);
143 $element = $this->addChevrons($element, $noll);
144 $element = $this->removeSelfSlash($element);
145 $element = $this->removeMeta($element, $name);
146 return $element;
147 }
148
149 // Remove unneeded element meta
150 private function removeMeta($element, $name)
151 {
152 if ($name == 'style') {
153 $element = str_replace(
154 [
155 ' type="text/css"',
156 "' type='text/css'"
157 ],
158 ['', ''],
159 $element
160 );
161 } elseif ($name == 'script') {
162 $element = str_replace(
163 [
164 ' type="text/javascript"',
165 " type='text/javascript'"
166 ],
167 ['', ''],
168 $element
169 );
170 }
171 return $element;
172 }
173
174 // Strip whitespace from element
175 private function stripWhitespace($element)
176 {
177 if ($this->skip == 0) {
178 $element = preg_replace('/\s+/', ' ', $element);
179 }
180 return trim($element);
181 }
182
183 // Add chevrons around element
184 private function addChevrons($element, $noll)
185 {
186 if (empty($element)) {
187 return $element;
188 }
189 $char = ($this->contains('>', $noll)) ? '>' : '';
190 $element = '<' . $element . $char;
191 return $element;
192 }
193
194 // Remove unneeded self slash
195 private function removeSelfSlash($element)
196 {
197 if (substr($element, -3) == ' />') {
198 $element = substr($element, 0, -3) . '>';
199 }
200 return $element;
201 }
202
203 // Compact content
204 private function compact($content, $name, $element)
205 {
206 if ($this->skip != 0) {
207 $name = $this->skipName;
208 } else {
209 $content = preg_replace('/\s+/', ' ', $content);
210 }
211
212 if (in_array($name, $this->elements['skip'])) {
213 return $content;
214 } elseif (in_array($name, $this->elements['hard']) ||
215 $this->head) {
216 return $this->minifyHard($content);
217 } else {
218 return $this->minifyKeepSpaces($content);
219 }
220 }
221
222 // Build html
223 private function buildHtml()
224 {
225 foreach ($this->build as $build) {
226
227 if (!empty($this->options['collapse_whitespace'])) {
228
229 if (strlen(trim($build['content'])) == 0)
230 continue;
231
232 elseif ($build['type'] != 'content' && !in_array($build['name'], $this->elements['inline']))
233 trim($build['content']);
234
235 }
236
237 $this->output .= $build['content'];
238 }
239
240 $this->build = [];
241 }
242
243 // Find name by part
244 private function findName($part)
245 {
246 $name_cut = explode(" ", $part, 2)[0];
247 $name_cut = explode(">", $name_cut, 2)[0];
248 $name_cut = explode("\n", $name_cut, 2)[0];
249 $name_cut = preg_replace('/\s+/', '', $name_cut);
250 $name_cut = strtolower(str_replace('/', '', $name_cut));
251 return $name_cut;
252 }
253
254 // Set skip if elements are blocked from minification
255 private function setSkip($name, $type)
256 {
257 foreach ($this->elements['skip'] as $element) {
258 if ($element == $name && $this->skip == 0) {
259 $this->skipName = $name;
260 }
261 }
262 if (in_array($name, $this->elements['skip'])) {
263 if ($type == 'open') {
264 $this->skip++;
265 }
266 if ($type == 'close') {
267 $this->skip--;
268 }
269 }
270 }
271
272 // Minify all, even spaces between elements
273 private function minifyHard($element)
274 {
275 $element = preg_replace('!\s+!', ' ', $element);
276 $element = trim($element);
277 return trim($element);
278 }
279
280 // Strip but keep one space
281 private function minifyKeepSpaces($element)
282 {
283 return preg_replace('!\s+!', ' ', $element);
284 }
285 }
286