Version Description
[2022.12.11] = * custom cache directory fixes * upgraded matthiasmullie's PHP Minify to 1.3.70 * move the viewport meta tag up, before preloading tags
Download this release
Release Info
Developer | Alignak |
Plugin | Fast Velocity Minify |
Version | 3.3.3 |
Comparing to | |
See all releases |
Code changes from version 3.3.1 to 3.3.3
- README.md +3 -0
- fvm.php +14 -6
- inc/common.php +3 -3
- inc/frontend.php +890 -873
- libs/matthiasmullie/minify/src/CSS.php +115 -37
- libs/matthiasmullie/minify/src/Exception.php +5 -3
- libs/matthiasmullie/minify/src/Exceptions/BasicException.php +4 -3
- libs/matthiasmullie/minify/src/Exceptions/FileImportException.php +4 -3
- libs/matthiasmullie/minify/src/Exceptions/IOException.php +4 -3
- libs/matthiasmullie/minify/src/JS.php +70 -40
- libs/matthiasmullie/minify/src/Minify.php +64 -50
- readme.txt +13 -3
README.md
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
# fast-velocity-minify
|
2 |
+
Official repository for Fast Velocity Minify
|
3 |
+
https://wordpress.org/plugins/fast-velocity-minify/
|
fvm.php
CHANGED
@@ -6,7 +6,7 @@ Description: Improve your speed score on GTmetrix, Pingdom Tools and Google Page
|
|
6 |
Author: Raul Peixoto
|
7 |
Author URI: http://fastvelocity.com
|
8 |
Text Domain: fast-velocity-minify
|
9 |
-
Version: 3.3.
|
10 |
License: GPL2
|
11 |
|
12 |
------------------------------------------------------------------------
|
@@ -34,11 +34,11 @@ if(function_exists('wp_opcache_invalidate') && stripos(__FILE__, '/fvm.php') !==
|
|
34 |
}
|
35 |
|
36 |
# info, variables, paths
|
37 |
-
if (!defined('
|
38 |
-
$fvm_var_dir_path =
|
39 |
-
$fvm_var_file =
|
40 |
-
$fvm_var_inc_dir =
|
41 |
-
$fvm_var_inc_lib =
|
42 |
$fvm_var_basename = plugin_basename($fvm_var_file); # pluginname/wpr.php
|
43 |
$fvm_var_url_path = plugins_url(dirname($fvm_var_basename)) . '/'; # https://example.com/wp-content/plugins/pluginname/
|
44 |
$fvm_var_plugin_version = get_file_data($fvm_var_file, array('Version' => 'Version'), false)['Version'];
|
@@ -107,5 +107,13 @@ if(!is_admin()) {
|
|
107 |
# actions for frontend only
|
108 |
add_action('template_redirect', 'fvm_start_buffer', 999999);
|
109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
}
|
111 |
|
6 |
Author: Raul Peixoto
|
7 |
Author URI: http://fastvelocity.com
|
8 |
Text Domain: fast-velocity-minify
|
9 |
+
Version: 3.3.3
|
10 |
License: GPL2
|
11 |
|
12 |
------------------------------------------------------------------------
|
34 |
}
|
35 |
|
36 |
# info, variables, paths
|
37 |
+
if (!defined('FVM_PDIR')) { define('FVM_PDIR', __DIR__ . '/'); } # /home/path/plugins/pluginname/
|
38 |
+
$fvm_var_dir_path = FVM_PDIR; # /home/path/plugins/pluginname/
|
39 |
+
$fvm_var_file = FVM_PDIR . 'fvm.php'; # /home/path/plugins/pluginname/wpr.php
|
40 |
+
$fvm_var_inc_dir = FVM_PDIR . 'inc' . DIRECTORY_SEPARATOR; # /home/path/plugins/pluginname/inc/
|
41 |
+
$fvm_var_inc_lib = FVM_PDIR . 'libs' . DIRECTORY_SEPARATOR; # /home/path/plugins/pluginname/libs/
|
42 |
$fvm_var_basename = plugin_basename($fvm_var_file); # pluginname/wpr.php
|
43 |
$fvm_var_url_path = plugins_url(dirname($fvm_var_basename)) . '/'; # https://example.com/wp-content/plugins/pluginname/
|
44 |
$fvm_var_plugin_version = get_file_data($fvm_var_file, array('Version' => 'Version'), false)['Version'];
|
107 |
# actions for frontend only
|
108 |
add_action('template_redirect', 'fvm_start_buffer', 999999);
|
109 |
|
110 |
+
# add with positive priority, remove with negative as suggested by:
|
111 |
+
# https://github.com/nextend/wp-ob-plugins-themes
|
112 |
+
|
113 |
+
# allow overwrite
|
114 |
+
if (!defined('FVM_HOOK_INTO')) { define('FVM_HOOK_INTO', 'setup_theme'); }
|
115 |
+
add_action(constant("FVM_HOOK_INTO"), 'fvm_start_buffer', 50);
|
116 |
+
add_action('shutdown', 'fvm_end_buffer', -50);
|
117 |
+
|
118 |
}
|
119 |
|
inc/common.php
CHANGED
@@ -59,12 +59,12 @@ function fvm_admintoolbar() {
|
|
59 |
function fvm_get_cache_location() {
|
60 |
|
61 |
# custom path
|
62 |
-
if (defined('
|
63 |
|
64 |
# define paths and url
|
65 |
$sep = DIRECTORY_SEPARATOR;
|
66 |
-
$dir = trim(rtrim(
|
67 |
-
$durl = trim(rtrim(
|
68 |
|
69 |
# create and return
|
70 |
if(!is_dir($dir) && function_exists('wp_mkdir_p')) { wp_mkdir_p($dir); }
|
59 |
function fvm_get_cache_location() {
|
60 |
|
61 |
# custom path
|
62 |
+
if (defined('FVM_CACHE_DIR') && defined('FVM_CACHE_URL')){
|
63 |
|
64 |
# define paths and url
|
65 |
$sep = DIRECTORY_SEPARATOR;
|
66 |
+
$dir = trim(rtrim(FVM_CACHE_DIR, '/\\')). $sep . 'cache' . $sep . 'fvm'. $sep . 'min';
|
67 |
+
$durl = trim(rtrim(FVM_CACHE_URL, '/')). '/cache/fvm/min';
|
68 |
|
69 |
# create and return
|
70 |
if(!is_dir($dir) && function_exists('wp_mkdir_p')) { wp_mkdir_p($dir); }
|
inc/frontend.php
CHANGED
@@ -32,192 +32,292 @@ include_once($fvm_var_inc_lib_mm . 'path-converter' . DIRECTORY_SEPARATOR . 'src
|
|
32 |
################################################
|
33 |
|
34 |
|
35 |
-
# start buffering
|
36 |
function fvm_start_buffer() {
|
37 |
if(fvm_can_minify_css() || fvm_can_minify_js() || fvm_can_process_html()) {
|
38 |
-
ob_start('fvm_process_page', 0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
}
|
41 |
|
42 |
# process html
|
43 |
function fvm_process_page($html) {
|
44 |
|
45 |
-
|
46 |
-
global $fvm_settings, $fvm_cache_paths, $fvm_urls;
|
47 |
-
|
48 |
-
# get html into an object
|
49 |
-
# https://simplehtmldom.sourceforge.io/manual.htm
|
50 |
-
$html_object = fvm_str_get_html($html, false, true, 'UTF-8', false, PHP_EOL, ' ');
|
51 |
-
|
52 |
-
# return early if html is not an object, or overwrite html into an object for processing
|
53 |
-
if (!is_object($html_object)) {
|
54 |
-
return $html . '<!-- simplehtmldom failed to process the html -->';
|
55 |
-
} else {
|
56 |
-
$html_src = $html;
|
57 |
-
$html = $html_object;
|
58 |
-
}
|
59 |
-
|
60 |
-
# get globals
|
61 |
-
global $fvm_settings, $fvm_urls;
|
62 |
-
|
63 |
-
# defaults
|
64 |
-
$tvers = get_option('fvm_last_cache_update', '0');
|
65 |
-
$htmlpreloads = array();
|
66 |
-
$htmlcssheader = array();
|
67 |
-
$htmljsheader = array();
|
68 |
-
$htmljsdefer = array();
|
69 |
-
|
70 |
-
# only error possible for now
|
71 |
-
$fvm_error = PHP_EOL . '<!-- ['.date('r').'] FVM has no write access for CSS / JS cache files under '. fvm_get_cache_location()['ch_url'] . ' -->'. PHP_EOL;
|
72 |
-
|
73 |
|
74 |
-
|
75 |
-
|
76 |
|
77 |
-
#
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
$
|
|
|
86 |
}
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
# START CSS PROCESSING
|
92 |
-
if(fvm_can_minify_css()) {
|
93 |
-
|
94 |
# defaults
|
95 |
-
$
|
96 |
-
$
|
97 |
-
$
|
|
|
|
|
98 |
|
99 |
-
#
|
100 |
-
$
|
101 |
-
$css_total = 0;
|
102 |
|
103 |
-
# start log
|
104 |
-
$log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
|
105 |
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
$
|
111 |
-
|
112 |
-
|
113 |
-
# collect all styles, but filter out if excluded
|
114 |
-
foreach($html->find('link[rel=stylesheet], style') as $element) {
|
115 |
-
if(!in_array($element->outertext, $excl)) {
|
116 |
-
$allcss[] = $element;
|
117 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
}
|
119 |
|
120 |
-
|
121 |
-
|
|
|
122 |
|
123 |
-
#
|
124 |
-
|
|
|
|
|
125 |
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
}
|
137 |
-
|
138 |
-
} else {
|
139 |
-
# must have
|
140 |
-
$tag->media = 'all';
|
141 |
}
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
if($tag->tag == 'link' && isset($tag->href)) {
|
146 |
|
147 |
-
#
|
148 |
-
|
149 |
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
$arr = fvm_string_toarray($fvm_settings['css']['ignore']);
|
154 |
-
if(is_array($arr) && count($arr) > 0) {
|
155 |
-
foreach ($arr as $e) {
|
156 |
-
if(stripos($href, $e) !== false) {
|
157 |
-
unset($allcss[$k]);
|
158 |
-
continue 2;
|
159 |
-
}
|
160 |
-
}
|
161 |
}
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
foreach ($arr as $e) {
|
169 |
-
if(stripos($href, $e) !== false) {
|
170 |
-
$tag->outertext = '';
|
171 |
-
unset($allcss[$k]);
|
172 |
-
continue 2;
|
173 |
-
}
|
174 |
-
}
|
175 |
}
|
|
|
|
|
|
|
|
|
176 |
}
|
177 |
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
|
181 |
-
#
|
182 |
-
$css
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
|
184 |
-
|
|
|
|
|
|
|
|
|
185 |
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
unset($allcss[$k]);
|
190 |
continue;
|
|
|
191 |
}
|
|
|
|
|
|
|
|
|
|
|
192 |
|
193 |
-
#
|
194 |
-
|
195 |
-
$extract_fonts_arr = fvm_extract_fonts($css['code'], $href);
|
196 |
-
$css_lowpriority_code.= '/* '.$href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
|
197 |
-
$css_code = $extract_fonts_arr['code'];
|
198 |
-
} else {
|
199 |
-
$css_code = $css['code'];
|
200 |
-
}
|
201 |
-
|
202 |
|
203 |
-
|
204 |
-
|
205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
$arr = fvm_string_toarray($fvm_settings['css']['async']);
|
207 |
if(is_array($arr) && count($arr) > 0) {
|
208 |
foreach ($arr as $aa) {
|
209 |
if(stripos($href, $aa) !== false) {
|
210 |
|
211 |
-
#
|
212 |
-
$
|
213 |
-
|
|
|
|
|
214 |
# log
|
215 |
$size = strlen($css['code']);
|
216 |
$css_total = $css_total + $size;
|
217 |
$log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
218 |
-
|
219 |
# finish early
|
220 |
-
$tag->
|
221 |
unset($allcss[$k]);
|
222 |
continue 2;
|
223 |
|
@@ -225,863 +325,780 @@ function fvm_process_page($html) {
|
|
225 |
}
|
226 |
}
|
227 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
}
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
# finish early
|
241 |
$tag->outertext = '';
|
242 |
unset($allcss[$k]);
|
243 |
continue;
|
244 |
-
|
245 |
}
|
246 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
|
|
|
|
|
|
|
248 |
|
249 |
-
# minify
|
250 |
if(!isset($fvm_settings['css']['min_disable']) || (isset($fvm_settings['css']['min_disable'])&& $fvm_settings['css']['min_disable'] != true)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
-
|
253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
-
|
|
|
|
|
|
|
|
|
|
|
256 |
|
257 |
-
#
|
258 |
-
if(
|
259 |
-
$
|
260 |
-
unset($allcss[$k]);
|
261 |
continue;
|
262 |
}
|
263 |
|
264 |
-
#
|
265 |
-
|
266 |
-
|
267 |
-
$css_lowpriority_code.= '/* '.$href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
|
268 |
-
$css_code = $extract_fonts_arr['code'];
|
269 |
-
} else {
|
270 |
-
$css_code = $css['code'];
|
271 |
-
}
|
272 |
-
|
273 |
-
# empty files
|
274 |
-
if(empty(trim($css_code))) {
|
275 |
-
$tag->outertext = '';
|
276 |
-
unset($allcss[$k]);
|
277 |
-
continue;
|
278 |
-
} else {
|
279 |
-
$css_code = '/* '.$href.' */'. PHP_EOL . $css_code;
|
280 |
-
}
|
281 |
-
|
282 |
-
# generate url
|
283 |
-
$ind_css_url = fvm_generate_min_url($href, $css['tkey'], 'css', $css_code);
|
284 |
-
if($ind_css_url === false) {
|
285 |
return $html_src . $fvm_error;
|
286 |
}
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
$tag->as = 'style';
|
303 |
-
$tag->onload = "this.rel='stylesheet';this.onload=null";
|
304 |
-
|
305 |
-
# log
|
306 |
-
$size = strlen($css['code']);
|
307 |
-
$css_total = $css_total + $size;
|
308 |
-
$log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
309 |
-
|
310 |
-
# finish early
|
311 |
-
$tag->href = $ind_css_url;
|
312 |
-
unset($allcss[$k]);
|
313 |
-
continue 2;
|
314 |
-
|
315 |
-
}
|
316 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
}
|
318 |
-
}
|
319 |
-
|
320 |
-
# force render blocking for other files
|
321 |
-
|
322 |
-
# http and html preload for render blocking css
|
323 |
-
if(!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) {
|
324 |
-
$htmlpreloads[] = '<link rel="preload" href="'.$ind_css_url.'" as="style" media="'.$tag->media.'" />';
|
325 |
-
}
|
326 |
-
|
327 |
-
# log
|
328 |
-
$size = strlen($css['code']);
|
329 |
-
$css_total = $css_total + $size;
|
330 |
-
$log[] = '[CSS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
331 |
-
|
332 |
-
# finish early
|
333 |
-
$tag->href = $ind_css_url;
|
334 |
-
unset($allcss[$k]);
|
335 |
|
336 |
}
|
337 |
}
|
338 |
}
|
339 |
-
# END CSS
|
340 |
-
|
341 |
-
|
342 |
-
# START STYLE TAGS
|
343 |
-
if($tag->tag == 'style' && !isset($tag->href)) {
|
344 |
-
|
345 |
-
# remove if empty
|
346 |
-
if(strlen(trim($tag->innertext)) == 0) {
|
347 |
-
$tag->outertext = '';
|
348 |
-
unset($allcss[$k]);
|
349 |
-
continue;
|
350 |
-
}
|
351 |
-
|
352 |
-
# default
|
353 |
-
$css = $tag->innertext;
|
354 |
-
|
355 |
-
# minify?
|
356 |
-
if(!isset($fvm_settings['css']['min_disable_styles']) || (isset($fvm_settings['css']['min_disable_styles'])&& $fvm_settings['css']['min_disable_styles'] != true)) {
|
357 |
-
$css = fvm_minify_css_string($css);
|
358 |
-
}
|
359 |
-
|
360 |
-
# handle import rules
|
361 |
-
$css = fvm_replace_css_imports($css);
|
362 |
-
|
363 |
-
# simplify font face
|
364 |
-
$arr = fvm_simplify_fontface($css);
|
365 |
-
if($arr !== false && is_array($arr)) {
|
366 |
-
$css = str_replace($arr['before'], $arr['after'], $css);
|
367 |
-
}
|
368 |
-
|
369 |
-
# extract fonts and icons
|
370 |
-
if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
|
371 |
-
$extract_fonts_arr = fvm_extract_fonts($css);
|
372 |
-
$css_lowpriority_code.= $extract_fonts_arr['fonts'];
|
373 |
-
$css = $extract_fonts_arr['code'];
|
374 |
-
}
|
375 |
-
|
376 |
-
# add filtered css code
|
377 |
-
if(!empty($css)) {
|
378 |
-
$tag->innertext = $css;
|
379 |
-
unset($allcss[$k]);
|
380 |
-
continue;
|
381 |
-
}
|
382 |
-
|
383 |
-
}
|
384 |
-
# END STYLE TAGS
|
385 |
-
|
386 |
}
|
387 |
-
# END CSS
|
388 |
|
389 |
-
# START CSS LOG
|
390 |
-
if(count($log) > 1) {
|
391 |
-
$log[] = str_pad('-', 22, '-',STR_PAD_LEFT) . PHP_EOL;
|
392 |
-
$log[] = '[CSS Total: '.str_pad(fvm_format_filesize($css_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
|
393 |
-
$log[] = str_pad('-', 22, '-',STR_PAD_LEFT);
|
394 |
-
fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
|
395 |
-
}
|
396 |
-
# END CSS LOG
|
397 |
-
|
398 |
|
399 |
-
# START
|
400 |
-
if(
|
|
|
|
|
|
|
|
|
|
|
401 |
|
402 |
-
#
|
403 |
-
|
404 |
-
|
405 |
-
}
|
406 |
|
407 |
-
#
|
408 |
-
$
|
409 |
|
410 |
-
#
|
411 |
-
$
|
412 |
-
|
413 |
-
|
414 |
}
|
415 |
-
|
416 |
-
# cdn
|
417 |
-
if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
|
418 |
-
$css_fonts_url = fvm_rewrite_cdn_url($css_fonts_url);
|
419 |
-
}
|
420 |
-
|
421 |
-
# preload
|
422 |
-
$htmlcssheader[0] = '<link rel="preload" fetchpriority="low" id="fvmfonts-css" href="'.$css_fonts_url.'" as="style" media="all" onload="this.rel=\'stylesheet\';this.onload=null">';
|
423 |
-
|
424 |
-
|
425 |
-
}
|
426 |
-
# END OPTIMIZED FONT DELIVERY
|
427 |
-
|
428 |
-
# START COMBINING CSS
|
429 |
-
if(is_array($fvm_styles) && count($fvm_styles) > 0) {
|
430 |
-
|
431 |
-
# process mediatypes
|
432 |
-
foreach ($fvm_styles as $mediatype=>$css_arr) {
|
433 |
-
|
434 |
-
# process types, block or async
|
435 |
-
foreach ($css_arr as $css_method=>$css_arr2) {
|
436 |
-
|
437 |
-
# merge and hash
|
438 |
-
$merged_css = implode(PHP_EOL, $css_arr2);
|
439 |
-
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_css), 'css');
|
440 |
|
441 |
-
|
442 |
-
|
443 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
444 |
continue;
|
445 |
}
|
446 |
|
447 |
-
#
|
448 |
-
$
|
449 |
-
|
450 |
-
|
451 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
|
453 |
-
#
|
454 |
-
|
455 |
-
$merged_css_url = fvm_rewrite_cdn_url($merged_css_url);
|
456 |
-
}
|
457 |
|
458 |
-
#
|
459 |
-
if($
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
|
|
467 |
}
|
468 |
-
|
469 |
-
} else {
|
470 |
-
|
471 |
-
# async
|
472 |
-
$htmlcssheader[] = '<link rel="preload" as="style" href="'.$merged_css_url.'" media="'.$mediatype.'" onload="this.rel=\'stylesheet\'" />';
|
473 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
474 |
}
|
475 |
-
|
476 |
-
}
|
477 |
-
}
|
478 |
-
}
|
479 |
-
# END COMBINING CSS
|
480 |
-
|
481 |
-
}
|
482 |
-
# END CSS PROCESSING
|
483 |
-
|
484 |
-
|
485 |
-
# START JS PROCESSING
|
486 |
-
if(fvm_can_minify_js()) {
|
487 |
-
|
488 |
-
# defaults
|
489 |
-
$scripts_duplicate_check = array();
|
490 |
-
$fvm_scripts_header = array();
|
491 |
-
$fvm_scripts_defer = array();
|
492 |
-
|
493 |
-
# start log
|
494 |
-
$log = array();
|
495 |
-
$js_total = 0;
|
496 |
-
|
497 |
-
# start log
|
498 |
-
$log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
|
499 |
-
|
500 |
-
# get all scripts
|
501 |
-
$allscripts = array();
|
502 |
-
foreach($html->find('script') as $element) {
|
503 |
-
$allscripts[] = $element;
|
504 |
-
}
|
505 |
-
|
506 |
-
# START JS LOOP
|
507 |
-
if (is_array($allscripts) && count($allscripts) > 0) {
|
508 |
-
foreach($allscripts as $k=>$tag) {
|
509 |
-
|
510 |
-
# handle application/ld+json or application/json before anything else
|
511 |
-
if(isset($tag->type) && ($tag->type == 'application/ld+json' || $tag->type == 'application/json')) {
|
512 |
-
|
513 |
-
# minify
|
514 |
-
if(isset($fvm_settings['js']['js_enable_min_inline']) && $fvm_settings['js']['js_enable_min_inline'] == true) { $tag->innertext = fvm_minify_microdata($tag->innertext); }
|
515 |
-
|
516 |
-
# remove
|
517 |
-
unset($allscripts[$k]);
|
518 |
-
continue;
|
519 |
-
}
|
520 |
-
|
521 |
-
# skip unknown script types
|
522 |
-
if(isset($tag->type) && $tag->type != 'text/javascript') {
|
523 |
-
unset($allscripts[$k]);
|
524 |
-
continue;
|
525 |
-
}
|
526 |
-
|
527 |
-
# remove default script type
|
528 |
-
if(isset($tag->type) && $tag->type == 'text/javascript') { unset($tag->type); }
|
529 |
-
|
530 |
-
# START JS FILES
|
531 |
-
if(isset($tag->src)) {
|
532 |
-
|
533 |
-
# filter url
|
534 |
-
$href = fvm_normalize_url($tag->src);
|
535 |
-
|
536 |
-
# ignore js files
|
537 |
-
if(isset($fvm_settings['js']['ignore']) && !empty($fvm_settings['js']['ignore'])) {
|
538 |
-
$arr = fvm_string_toarray($fvm_settings['js']['ignore']);
|
539 |
-
if(is_array($arr) && count($arr) > 0) {
|
540 |
-
foreach ($arr as $a) {
|
541 |
-
if(stripos($tag->src, $a) !== false) {
|
542 |
-
unset($allscripts[$k]);
|
543 |
-
continue 2;
|
544 |
-
}
|
545 |
-
}
|
546 |
-
}
|
547 |
-
}
|
548 |
-
|
549 |
-
# remove js files
|
550 |
-
if(isset($fvm_settings['js']['remove']) && !empty($fvm_settings['js']['remove'])) {
|
551 |
-
$arr = fvm_string_toarray($fvm_settings['js']['remove']);
|
552 |
-
if(is_array($arr) && count($arr) > 0) {
|
553 |
-
foreach ($arr as $a) {
|
554 |
-
if(stripos($tag->src, $a) !== false) {
|
555 |
-
$tag->outertext = '';
|
556 |
-
unset($allscripts[$k]);
|
557 |
-
continue 2;
|
558 |
-
}
|
559 |
-
}
|
560 |
-
}
|
561 |
-
}
|
562 |
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
if(is_array($arr) && count($arr) > 0) {
|
568 |
-
foreach ($arr as $ac) {
|
569 |
-
if(stripos($tag->src, $ac) !== false) {
|
570 |
-
|
571 |
-
# unique identifier
|
572 |
-
$uid = fvm_generate_hash_with_prefix(hash('sha256', $tag->outertext), 'js');
|
573 |
-
|
574 |
-
# remove exact duplicates, or replace transformed tag
|
575 |
-
if(isset($scripts_duplicate_check[$uid])) {
|
576 |
-
$tag->outertext = '';
|
577 |
-
} else {
|
578 |
-
$tag->type = 'fvmdelay';
|
579 |
-
$scripts_duplicate_check[$uid] = $uid;
|
580 |
-
}
|
581 |
-
|
582 |
-
# mark as processed, unset and break inner loop
|
583 |
-
unset($allscripts[$k]);
|
584 |
-
continue 2;
|
585 |
-
|
586 |
-
}
|
587 |
-
}
|
588 |
-
}
|
589 |
-
}
|
590 |
-
|
591 |
-
|
592 |
-
# START MERGING JS
|
593 |
-
if(isset($fvm_settings['js']['combine']) && $fvm_settings['js']['combine'] == true) {
|
594 |
-
|
595 |
-
# force render blocking
|
596 |
-
if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
|
597 |
-
$arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
|
598 |
if(is_array($arr) && count($arr) > 0) {
|
599 |
-
foreach ($arr as $
|
600 |
-
if(stripos($tag->src, $
|
601 |
|
602 |
-
#
|
603 |
-
$
|
604 |
-
if($js !== false && is_array($js)) {
|
605 |
-
|
606 |
-
# error
|
607 |
-
if(isset($js['error'])) {
|
608 |
-
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
609 |
-
unset($allscripts[$k]);
|
610 |
-
continue 2;
|
611 |
-
}
|
612 |
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
# log
|
617 |
-
$size = strlen($js['code']);
|
618 |
-
$js_total = $js_total + $size;
|
619 |
-
$log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
620 |
-
|
621 |
-
# remove from html
|
622 |
$tag->outertext = '';
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
}
|
|
|
|
|
|
|
|
|
|
|
627 |
}
|
628 |
}
|
629 |
}
|
630 |
}
|
631 |
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
if($
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
642 |
|
643 |
-
|
644 |
-
|
645 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
unset($allscripts[$k]);
|
647 |
continue 2;
|
|
|
648 |
}
|
649 |
-
|
650 |
-
|
651 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
652 |
|
653 |
-
#
|
654 |
-
$
|
655 |
-
$
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
|
|
662 |
|
663 |
-
|
664 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
665 |
}
|
666 |
}
|
667 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
668 |
|
669 |
-
|
670 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
671 |
|
672 |
-
#
|
673 |
-
|
674 |
-
|
|
|
|
|
675 |
}
|
676 |
|
677 |
-
#
|
678 |
-
if(
|
679 |
-
$
|
680 |
-
|
681 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
682 |
}
|
683 |
|
684 |
-
#
|
685 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
686 |
unset($allscripts[$k]);
|
687 |
continue;
|
688 |
-
}
|
689 |
-
|
|
|
690 |
}
|
691 |
-
# END
|
692 |
|
693 |
|
694 |
-
# START
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
unset($allscripts[$k]);
|
702 |
continue;
|
703 |
}
|
704 |
|
705 |
-
#
|
706 |
-
|
707 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
708 |
if(is_array($arr) && count($arr) > 0) {
|
709 |
-
foreach ($arr as $
|
710 |
-
if(stripos($
|
711 |
|
712 |
-
#
|
713 |
-
$
|
714 |
-
if($js !== false && is_array($js)) {
|
715 |
-
|
716 |
-
# error
|
717 |
-
if(isset($js['error'])) {
|
718 |
-
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
719 |
-
unset($allscripts[$k]);
|
720 |
-
continue 2;
|
721 |
-
}
|
722 |
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
return $html_src . $fvm_error;
|
727 |
-
}
|
728 |
-
|
729 |
-
# cdn
|
730 |
-
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
731 |
-
$ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
|
732 |
-
}
|
733 |
-
|
734 |
-
# render block
|
735 |
-
if(isset($tag->async)) { unset($tag->async); }
|
736 |
-
if(isset($tag->defer)) { unset($tag->defer); }
|
737 |
-
|
738 |
-
# http and html preload for render blocking scripts
|
739 |
-
if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
|
740 |
-
$htmlpreloads[] = '<link rel="preload" href="'.$ind_js_url.'" as="script" />';
|
741 |
-
}
|
742 |
-
|
743 |
-
# log
|
744 |
-
$size = strlen($js['code']);
|
745 |
-
$js_total = $js_total + $size;
|
746 |
-
$log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
747 |
-
|
748 |
-
# finish early
|
749 |
-
$tag->src = $ind_js_url;
|
750 |
-
unset($allscripts[$k]);
|
751 |
-
continue 2;
|
752 |
-
|
753 |
}
|
754 |
-
|
|
|
|
|
|
|
|
|
755 |
}
|
756 |
}
|
757 |
}
|
758 |
-
|
759 |
-
#
|
760 |
-
if(isset($fvm_settings['js']['
|
761 |
-
$arr = fvm_string_toarray($fvm_settings['js']['
|
762 |
if(is_array($arr) && count($arr) > 0) {
|
763 |
-
foreach ($arr as $
|
764 |
-
if(stripos($
|
765 |
-
|
766 |
-
# download or fetch from transient, minified
|
767 |
-
$js = fvm_get_js_from_file($tag);
|
768 |
-
if($js !== false && is_array($js)) {
|
769 |
-
|
770 |
-
# error
|
771 |
-
if(isset($js['error'])) {
|
772 |
-
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
773 |
-
unset($allscripts[$k]);
|
774 |
-
continue 2;
|
775 |
-
}
|
776 |
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
# cdn
|
784 |
-
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
785 |
-
$ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
|
786 |
-
}
|
787 |
-
|
788 |
-
# add defer
|
789 |
-
if(!isset($tag->defer)) { $tag->defer = 'defer'; }
|
790 |
-
|
791 |
-
# log
|
792 |
-
$size = strlen($js['code']);
|
793 |
-
$js_total = $js_total + $size;
|
794 |
-
$log[] = '[JS Defer: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
795 |
-
|
796 |
-
# finish early
|
797 |
-
$tag->src = $ind_js_url;
|
798 |
-
unset($allscripts[$k]);
|
799 |
-
continue 2;
|
800 |
-
|
801 |
}
|
802 |
-
|
|
|
|
|
|
|
|
|
803 |
}
|
804 |
}
|
805 |
-
}
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
continue;
|
810 |
-
}
|
811 |
-
# END INDIVIDUAL JS MINIFICATION
|
812 |
-
|
813 |
}
|
814 |
-
|
815 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
816 |
|
817 |
-
#
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
# default
|
828 |
-
$js = ''; $js = $tag->innertext;
|
829 |
|
830 |
-
#
|
831 |
-
if(
|
832 |
-
$
|
833 |
}
|
834 |
|
835 |
-
#
|
836 |
-
if(isset($fvm_settings['js']['
|
837 |
-
$
|
838 |
-
if(is_array($arr) && count($arr) > 0) {
|
839 |
-
foreach ($arr as $b) {
|
840 |
-
if(stripos($js, $b) !== false || stripos($js, $b) !== false) {
|
841 |
-
|
842 |
-
# delay
|
843 |
-
$tag->type = 'fvmdelay';
|
844 |
-
|
845 |
-
# minified
|
846 |
-
if(!empty($js)) {
|
847 |
-
$tag->innertext = $js;
|
848 |
-
}
|
849 |
-
|
850 |
-
# unset
|
851 |
-
unset($allscripts[$k]);
|
852 |
-
continue 2;
|
853 |
-
}
|
854 |
-
}
|
855 |
-
}
|
856 |
}
|
|
|
|
|
|
|
857 |
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
# jquery document ready needs to execute before deferred scripts
|
867 |
-
if(!empty($js) && stripos($js, ').ready(') === false) {
|
868 |
-
$tag->src = 'data:application/javascript,'.rawurlencode($js);
|
869 |
-
$tag->innertext = '';
|
870 |
-
}
|
871 |
-
|
872 |
-
# unset
|
873 |
-
unset($allscripts[$k]);
|
874 |
-
continue 2;
|
875 |
-
}
|
876 |
-
}
|
877 |
-
}
|
878 |
-
}
|
879 |
-
}
|
880 |
-
# END INLINED SCRIPTS
|
881 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
882 |
}
|
|
|
883 |
}
|
884 |
-
# END JS
|
885 |
-
|
886 |
-
|
887 |
-
# START JS LOG
|
888 |
-
if(count($log) > 1) {
|
889 |
-
$log[] = str_pad('-', 21, '-',STR_PAD_LEFT) . PHP_EOL;
|
890 |
-
$log[] = '[JS Total: '.str_pad(fvm_format_filesize($js_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
|
891 |
-
$log[] = str_pad('-', 21, '-',STR_PAD_LEFT);
|
892 |
-
fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
|
893 |
-
}
|
894 |
-
# END JS LOG
|
895 |
-
|
896 |
-
# START COMBINING JS
|
897 |
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
$merged_js = implode(PHP_EOL, $fvm_scripts_header);
|
903 |
-
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_js), 'js');
|
904 |
-
|
905 |
-
# generate url
|
906 |
-
$merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
|
907 |
-
if($merged_js_url === false) {
|
908 |
-
return $html_src . $fvm_error;
|
909 |
-
}
|
910 |
|
911 |
-
|
912 |
-
|
913 |
-
|
|
|
914 |
}
|
|
|
|
|
|
|
|
|
915 |
|
916 |
-
#
|
917 |
-
|
918 |
-
|
919 |
}
|
920 |
|
921 |
-
#
|
922 |
-
$
|
923 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
924 |
}
|
925 |
|
926 |
-
#
|
927 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
928 |
|
929 |
-
|
930 |
-
|
931 |
-
$
|
932 |
-
|
933 |
-
# generate url
|
934 |
-
$merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
|
935 |
-
if($merged_js_url === false) {
|
936 |
-
return $html_src . $fvm_error;
|
937 |
-
}
|
938 |
-
|
939 |
-
# cdn
|
940 |
-
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
941 |
-
$merged_js_url = fvm_rewrite_cdn_url($merged_js_url);
|
942 |
-
}
|
943 |
-
|
944 |
-
# header, no preload for deferred files
|
945 |
-
$htmljsheader[] = "<script defer='defer' src='".$merged_js_url."'></script>";
|
946 |
-
|
947 |
}
|
948 |
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
# process HTML minification, if not disabled ###############################
|
955 |
-
if(fvm_can_process_html()) {
|
956 |
-
|
957 |
-
# Remove HTML comments and IE conditionals
|
958 |
-
if(isset($fvm_settings['html']['nocomments']) && $fvm_settings['html']['nocomments'] == true) {
|
959 |
-
foreach($html->find('comment') as $element) {
|
960 |
-
$element->outertext = '';
|
961 |
-
}
|
962 |
}
|
963 |
|
964 |
-
#
|
965 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
966 |
|
967 |
-
#
|
968 |
-
|
969 |
-
|
|
|
|
|
|
|
970 |
}
|
971 |
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
}
|
980 |
}
|
981 |
-
|
982 |
-
}
|
983 |
-
|
984 |
-
# build extra head and footer ###############################
|
985 |
-
|
986 |
-
# header and footer markers
|
987 |
-
$hm = '<!-- h_preheader --><!-- h_header_function -->';
|
988 |
-
$hm_late = '<!-- h_cssheader --><!-- h_jsheader -->';
|
989 |
-
$fm = '<!-- h_footer_fvm_scripts -->';
|
990 |
-
|
991 |
-
# add our function to head
|
992 |
-
if(fvm_can_minify_css() || fvm_can_minify_js()) {
|
993 |
-
$hm = fvm_add_header_function($hm);
|
994 |
-
}
|
995 |
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
foreach($html->find('head meta, head title, head link[rel=canonical], head link[rel=alternate], head link[rel=pingback], head script[type=application/ld+json]') as $element) {
|
1004 |
-
$hm_late = str_replace('<!-- h_cssheader -->', $element->outertext.'<!-- h_cssheader -->', $hm_late);
|
1005 |
-
$element->outertext = '';
|
1006 |
-
}
|
1007 |
-
|
1008 |
-
# preload headers, by fetchpriority attribute
|
1009 |
-
if(is_array($htmlpreloads)) {
|
1010 |
|
1011 |
-
#
|
1012 |
-
|
|
|
|
|
|
|
|
|
|
|
1013 |
|
1014 |
-
#
|
1015 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1016 |
|
1017 |
-
#
|
1018 |
-
if(
|
1019 |
-
$
|
|
|
|
|
|
|
1020 |
}
|
1021 |
|
1022 |
-
}
|
1023 |
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
}
|
1031 |
-
|
1032 |
-
# add header scripts
|
1033 |
-
if(isset($htmljsheader)) {
|
1034 |
-
if(is_array($htmljsheader) && count($htmljsheader) > 0) {
|
1035 |
-
ksort($htmljsheader); # priority
|
1036 |
-
$hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljsheader).'<!-- h_jsheader -->', $hm_late);
|
1037 |
-
}
|
1038 |
-
}
|
1039 |
-
|
1040 |
-
# add defer scripts
|
1041 |
-
if(isset($htmljscodedefer)) {
|
1042 |
-
if(is_array($htmljscodedefer) && count($htmljscodedefer) > 0) {
|
1043 |
-
ksort($htmljscodedefer); # priority
|
1044 |
-
$hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljscodedefer), $hm_late);
|
1045 |
}
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
# cleanup leftover markers
|
1054 |
-
$hm = str_replace(array('<!-- h_preheader -->', '<!-- h_header_function -->'), '', $hm);
|
1055 |
-
$hm_late = str_replace(array('<!-- h_cssheader -->', '<!-- h_jsheader -->'), '', $hm_late);
|
1056 |
-
$fm = str_replace('<!-- h_footer_fvm_scripts -->', '', $fm);
|
1057 |
-
|
1058 |
-
# append header and footer
|
1059 |
-
if(!is_null($html->find('head', 0)) && !is_null($html->find('body', -1))) {
|
1060 |
-
if(!is_null($html->find('head', 0)->first_child()) && !is_null($html->find('body', -1)->last_child())) {
|
1061 |
-
$html->find('head', 0)->first_child()->outertext = $hm . $html->find('head', 0)->first_child()->outertext . $hm_late;
|
1062 |
-
$html->find('body', -1)->last_child()->outertext = $html->find('body', -1)->last_child ()->outertext . $fm;
|
1063 |
}
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
$html = trim($html->save());
|
1069 |
-
|
1070 |
-
# process cdn optimization
|
1071 |
-
if(fvm_can_process_cdn()) {
|
1072 |
-
$html = fvm_process_cdn($html);
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
# minify remaining HTML at the end, if enabled
|
1076 |
-
if(fvm_can_process_html()) {
|
1077 |
-
if(!isset($fvm_settings['html']['min_disable']) || (isset($fvm_settings['html']['min_disable']) && $fvm_settings['html']['min_disable'] != true)) {
|
1078 |
-
$html = fvm_raisermin_html($html);
|
1079 |
}
|
1080 |
-
}
|
1081 |
|
1082 |
-
# filter final html if needed
|
1083 |
-
if(function_exists('fvm_filter_final_html')) {
|
1084 |
-
$html = fvm_filter_final_html($html);
|
1085 |
}
|
1086 |
|
1087 |
# return html
|
32 |
################################################
|
33 |
|
34 |
|
35 |
+
# start buffering on template load
|
36 |
function fvm_start_buffer() {
|
37 |
if(fvm_can_minify_css() || fvm_can_minify_js() || fvm_can_process_html()) {
|
38 |
+
ob_start('fvm_process_page', 0, PHP_OUTPUT_HANDLER_FLUSHABLE);
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
# process the buffer
|
43 |
+
function fvm_end_buffer() {
|
44 |
+
if(fvm_can_minify_css() || fvm_can_minify_js() || fvm_can_process_html()) {
|
45 |
+
ob_end_flush();
|
46 |
}
|
47 |
}
|
48 |
|
49 |
# process html
|
50 |
function fvm_process_page($html) {
|
51 |
|
52 |
+
if(fvm_can_minify_css() || fvm_can_minify_js() || fvm_can_process_html()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
+
# get globals
|
55 |
+
global $fvm_settings, $fvm_cache_paths, $fvm_urls;
|
56 |
|
57 |
+
# get html into an object
|
58 |
+
# https://simplehtmldom.sourceforge.io/manual.htm
|
59 |
+
$html_object = fvm_str_get_html($html, false, true, 'UTF-8', false, PHP_EOL, ' ');
|
60 |
+
|
61 |
+
# return early if html is not an object, or overwrite html into an object for processing
|
62 |
+
if (!is_object($html_object)) {
|
63 |
+
return $html . '<!-- simplehtmldom failed to process the html -->';
|
64 |
+
} else {
|
65 |
+
$html_src = $html;
|
66 |
+
$html = $html_object;
|
67 |
}
|
68 |
|
69 |
+
# get globals
|
70 |
+
global $fvm_settings, $fvm_urls;
|
71 |
+
|
|
|
|
|
|
|
72 |
# defaults
|
73 |
+
$tvers = get_option('fvm_last_cache_update', '0');
|
74 |
+
$htmlpreloads = array();
|
75 |
+
$htmlcssheader = array();
|
76 |
+
$htmljsheader = array();
|
77 |
+
$htmljsdefer = array();
|
78 |
|
79 |
+
# only error possible for now
|
80 |
+
$fvm_error = PHP_EOL . '<!-- ['.date('r').'] FVM has no write access for CSS / JS cache files under '. fvm_get_cache_location()['ch_url'] . ' -->'. PHP_EOL;
|
|
|
81 |
|
|
|
|
|
82 |
|
83 |
+
# collect all link preload headers, skip amp
|
84 |
+
if(fvm_is_amp_page() !== true) {
|
85 |
+
|
86 |
+
# skip on web stories
|
87 |
+
if(count($html->find('script[src*=cdn.ampproject.org]')) > 0) {
|
88 |
+
return $html_src . DIRECTORY_SEPARATOR . '<!-- FVM ['.date('r').'] does not support AMP -->';
|
|
|
|
|
|
|
|
|
|
|
89 |
}
|
90 |
+
|
91 |
+
# add other preloads
|
92 |
+
foreach($html->find('link[rel=preload]') as $tag) {
|
93 |
+
$htmlpreloads[] = $tag->outertext;
|
94 |
+
$tag->outertext = '';
|
95 |
+
}
|
96 |
+
|
97 |
}
|
98 |
|
99 |
+
|
100 |
+
# START CSS PROCESSING
|
101 |
+
if(fvm_can_minify_css()) {
|
102 |
|
103 |
+
# defaults
|
104 |
+
$fvm_styles = array();
|
105 |
+
$allcss = array();
|
106 |
+
$css_lowpriority_code = '';
|
107 |
|
108 |
+
# start log
|
109 |
+
$log = array();
|
110 |
+
$css_total = 0;
|
111 |
+
|
112 |
+
# start log
|
113 |
+
$log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
|
114 |
+
|
115 |
+
|
116 |
+
# exclude styles and link tags inside scripts, no scripts or html comments
|
117 |
+
$excl = array();
|
118 |
+
foreach($html->find('script link[rel=stylesheet], script style, noscript style, noscript link[rel=stylesheet], comment') as $element) {
|
119 |
+
$excl[] = $element->outertext;
|
120 |
+
}
|
121 |
+
|
122 |
+
# collect all styles, but filter out if excluded
|
123 |
+
foreach($html->find('link[rel=stylesheet], style') as $element) {
|
124 |
+
if(!in_array($element->outertext, $excl)) {
|
125 |
+
$allcss[] = $element;
|
126 |
}
|
|
|
|
|
|
|
|
|
127 |
}
|
128 |
|
129 |
+
# START CSS LOOP
|
130 |
+
foreach($allcss as $k=>$tag) {
|
|
|
131 |
|
132 |
+
# mediatypes
|
133 |
+
if(isset($tag->media)) {
|
134 |
|
135 |
+
# Normalize mediatypes
|
136 |
+
if($tag->media == 'screen' || $tag->media == 'screen, print' || strlen($tag->media) == 0) {
|
137 |
+
$tag->media = 'all';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
}
|
139 |
+
|
140 |
+
# Remove print styles
|
141 |
+
if(isset($fvm_settings['css']['noprint']) && $fvm_settings['css']['noprint'] == true && $tag->media == 'print'){
|
142 |
+
$tag->outertext = '';
|
143 |
+
unset($allcss[$k]);
|
144 |
+
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
}
|
146 |
+
|
147 |
+
} else {
|
148 |
+
# must have
|
149 |
+
$tag->media = 'all';
|
150 |
}
|
151 |
|
152 |
+
|
153 |
+
# START CSS FILES
|
154 |
+
if($tag->tag == 'link' && isset($tag->href)) {
|
155 |
+
|
156 |
+
# filter url
|
157 |
+
$href = fvm_normalize_url($tag->href);
|
158 |
+
|
159 |
+
# Ignore css files
|
160 |
+
$ignore_css_merging = false;
|
161 |
+
if(isset($fvm_settings['css']['ignore']) && !empty($fvm_settings['css']['ignore'])) {
|
162 |
+
$arr = fvm_string_toarray($fvm_settings['css']['ignore']);
|
163 |
+
if(is_array($arr) && count($arr) > 0) {
|
164 |
+
foreach ($arr as $e) {
|
165 |
+
if(stripos($href, $e) !== false) {
|
166 |
+
unset($allcss[$k]);
|
167 |
+
continue 2;
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
|
173 |
+
# Remove CSS files
|
174 |
+
if(isset($fvm_settings['css']['remove']) && !empty($fvm_settings['css']['remove'])) {
|
175 |
+
$arr = fvm_string_toarray($fvm_settings['css']['remove']);
|
176 |
+
if(is_array($arr) && count($arr) > 0) {
|
177 |
+
foreach ($arr as $e) {
|
178 |
+
if(stripos($href, $e) !== false) {
|
179 |
+
$tag->outertext = '';
|
180 |
+
unset($allcss[$k]);
|
181 |
+
continue 2;
|
182 |
+
}
|
183 |
+
}
|
184 |
+
}
|
185 |
+
}
|
186 |
|
187 |
+
# css merging functionality
|
188 |
+
if(isset($fvm_settings['css']['combine']) && $fvm_settings['css']['combine'] == true) {
|
189 |
+
|
190 |
+
# download or fetch from transient, minified
|
191 |
+
$css = fvm_get_css_from_file($tag);
|
192 |
|
193 |
+
if($css !== false && is_array($css)) {
|
194 |
+
|
195 |
+
# error
|
196 |
+
if(isset($css['error'])) {
|
197 |
+
$tag->outertext = '/* Error on '.$href.' : '.$css['error'].' */'. PHP_EOL . $tag->outertext;
|
198 |
+
unset($allcss[$k]);
|
199 |
+
continue;
|
200 |
+
}
|
201 |
+
|
202 |
+
# extract fonts and icons
|
203 |
+
if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
|
204 |
+
$extract_fonts_arr = fvm_extract_fonts($css['code'], $href);
|
205 |
+
$css_lowpriority_code.= '/* '.$href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
|
206 |
+
$css_code = $extract_fonts_arr['code'];
|
207 |
+
} else {
|
208 |
+
$css_code = $css['code'];
|
209 |
+
}
|
210 |
+
|
211 |
+
|
212 |
+
# async from the list only
|
213 |
+
if(isset($fvm_settings['css']['async']) && $fvm_settings['css']['async'] == true) {
|
214 |
+
if(isset($fvm_settings['css']['async']) && !empty($fvm_settings['css']['async'])) {
|
215 |
+
$arr = fvm_string_toarray($fvm_settings['css']['async']);
|
216 |
+
if(is_array($arr) && count($arr) > 0) {
|
217 |
+
foreach ($arr as $aa) {
|
218 |
+
if(stripos($href, $aa) !== false) {
|
219 |
+
|
220 |
+
# save css for merging
|
221 |
+
$fvm_styles[$tag->media]['async'][] = $css_code;
|
222 |
+
|
223 |
+
# log
|
224 |
+
$size = strlen($css['code']);
|
225 |
+
$css_total = $css_total + $size;
|
226 |
+
$log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
227 |
+
|
228 |
+
# finish early
|
229 |
+
$tag->outertext = '';
|
230 |
+
unset($allcss[$k]);
|
231 |
+
continue 2;
|
232 |
+
|
233 |
+
}
|
234 |
+
}
|
235 |
+
}
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
# else render block
|
240 |
+
|
241 |
+
# save css for merging as fallback
|
242 |
+
$fvm_styles[$tag->media]['block'][] = $css_code;
|
243 |
+
|
244 |
+
# log
|
245 |
+
$size = strlen($css['code']);
|
246 |
+
$css_total = $css_total + $size;
|
247 |
+
$log[] = '[CSS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
248 |
+
|
249 |
+
# finish early
|
250 |
+
$tag->outertext = '';
|
251 |
unset($allcss[$k]);
|
252 |
continue;
|
253 |
+
|
254 |
}
|
255 |
+
}
|
256 |
+
|
257 |
+
|
258 |
+
# minify individually, if enabled
|
259 |
+
if(!isset($fvm_settings['css']['min_disable']) || (isset($fvm_settings['css']['min_disable'])&& $fvm_settings['css']['min_disable'] != true)) {
|
260 |
|
261 |
+
# download or fetch from transient, minified
|
262 |
+
$css = fvm_get_css_from_file($tag);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
|
264 |
+
if($css !== false && is_array($css)) {
|
265 |
+
|
266 |
+
# error
|
267 |
+
if(isset($css['error'])) {
|
268 |
+
$tag->outertext = '/* Error on '.$href.' : '.$css['error'].' */'. PHP_EOL . $tag->outertext;
|
269 |
+
unset($allcss[$k]);
|
270 |
+
continue;
|
271 |
+
}
|
272 |
+
|
273 |
+
# extract fonts and icons
|
274 |
+
if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
|
275 |
+
$extract_fonts_arr = fvm_extract_fonts($css['code'], $href);
|
276 |
+
$css_lowpriority_code.= '/* '.$href.' */'. PHP_EOL . $extract_fonts_arr['fonts'];
|
277 |
+
$css_code = $extract_fonts_arr['code'];
|
278 |
+
} else {
|
279 |
+
$css_code = $css['code'];
|
280 |
+
}
|
281 |
+
|
282 |
+
# empty files
|
283 |
+
if(empty(trim($css_code))) {
|
284 |
+
$tag->outertext = '';
|
285 |
+
unset($allcss[$k]);
|
286 |
+
continue;
|
287 |
+
} else {
|
288 |
+
$css_code = '/* '.$href.' */'. PHP_EOL . $css_code;
|
289 |
+
}
|
290 |
+
|
291 |
+
# generate url
|
292 |
+
$ind_css_url = fvm_generate_min_url($href, $css['tkey'], 'css', $css_code);
|
293 |
+
if($ind_css_url === false) {
|
294 |
+
return $html_src . $fvm_error;
|
295 |
+
}
|
296 |
+
|
297 |
+
# cdn
|
298 |
+
if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
|
299 |
+
$ind_css_url = fvm_rewrite_cdn_url($ind_css_url);
|
300 |
+
}
|
301 |
+
|
302 |
+
# async from the list only
|
303 |
+
if(isset($fvm_settings['css']['async']) && !empty($fvm_settings['css']['async'])) {
|
304 |
$arr = fvm_string_toarray($fvm_settings['css']['async']);
|
305 |
if(is_array($arr) && count($arr) > 0) {
|
306 |
foreach ($arr as $aa) {
|
307 |
if(stripos($href, $aa) !== false) {
|
308 |
|
309 |
+
# async attributes
|
310 |
+
$tag->rel = 'preload';
|
311 |
+
$tag->as = 'style';
|
312 |
+
$tag->onload = "this.rel='stylesheet';this.onload=null";
|
313 |
+
|
314 |
# log
|
315 |
$size = strlen($css['code']);
|
316 |
$css_total = $css_total + $size;
|
317 |
$log[] = '[CSS Async: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
318 |
+
|
319 |
# finish early
|
320 |
+
$tag->href = $ind_css_url;
|
321 |
unset($allcss[$k]);
|
322 |
continue 2;
|
323 |
|
325 |
}
|
326 |
}
|
327 |
}
|
328 |
+
|
329 |
+
# force render blocking for other files
|
330 |
+
|
331 |
+
# http and html preload for render blocking css
|
332 |
+
if(!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) {
|
333 |
+
$htmlpreloads[] = '<link rel="preload" href="'.$ind_css_url.'" as="style" media="'.$tag->media.'" />';
|
334 |
+
}
|
335 |
+
|
336 |
+
# log
|
337 |
+
$size = strlen($css['code']);
|
338 |
+
$css_total = $css_total + $size;
|
339 |
+
$log[] = '[CSS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $css['url']). PHP_EOL;
|
340 |
+
|
341 |
+
# finish early
|
342 |
+
$tag->href = $ind_css_url;
|
343 |
+
unset($allcss[$k]);
|
344 |
+
|
345 |
}
|
346 |
+
}
|
347 |
+
}
|
348 |
+
# END CSS FILES
|
349 |
+
|
350 |
+
|
351 |
+
# START STYLE TAGS
|
352 |
+
if($tag->tag == 'style' && !isset($tag->href)) {
|
353 |
+
|
354 |
+
# remove if empty
|
355 |
+
if(strlen(trim($tag->innertext)) == 0) {
|
|
|
|
|
356 |
$tag->outertext = '';
|
357 |
unset($allcss[$k]);
|
358 |
continue;
|
|
|
359 |
}
|
360 |
+
|
361 |
+
# default
|
362 |
+
$css = $tag->innertext;
|
363 |
+
|
364 |
+
# minify?
|
365 |
+
if(!isset($fvm_settings['css']['min_disable_styles']) || (isset($fvm_settings['css']['min_disable_styles'])&& $fvm_settings['css']['min_disable_styles'] != true)) {
|
366 |
+
$css = fvm_minify_css_string($css);
|
367 |
+
}
|
368 |
+
|
369 |
+
# handle import rules
|
370 |
+
$css = fvm_replace_css_imports($css);
|
371 |
+
|
372 |
+
# simplify font face
|
373 |
+
$arr = fvm_simplify_fontface($css);
|
374 |
+
if($arr !== false && is_array($arr)) {
|
375 |
+
$css = str_replace($arr['before'], $arr['after'], $css);
|
376 |
+
}
|
377 |
+
|
378 |
+
# extract fonts and icons
|
379 |
+
if(isset($fvm_settings['css']['fonts']) && $fvm_settings['css']['fonts'] == true) {
|
380 |
+
$extract_fonts_arr = fvm_extract_fonts($css);
|
381 |
+
$css_lowpriority_code.= $extract_fonts_arr['fonts'];
|
382 |
+
$css = $extract_fonts_arr['code'];
|
383 |
+
}
|
384 |
+
|
385 |
+
# add filtered css code
|
386 |
+
if(!empty($css)) {
|
387 |
+
$tag->innertext = $css;
|
388 |
+
unset($allcss[$k]);
|
389 |
+
continue;
|
390 |
+
}
|
391 |
+
|
392 |
+
}
|
393 |
+
# END STYLE TAGS
|
394 |
+
|
395 |
+
}
|
396 |
+
# END CSS LOOP
|
397 |
+
|
398 |
+
# START CSS LOG
|
399 |
+
if(count($log) > 1) {
|
400 |
+
$log[] = str_pad('-', 22, '-',STR_PAD_LEFT) . PHP_EOL;
|
401 |
+
$log[] = '[CSS Total: '.str_pad(fvm_format_filesize($css_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
|
402 |
+
$log[] = str_pad('-', 22, '-',STR_PAD_LEFT);
|
403 |
+
fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
|
404 |
+
}
|
405 |
+
# END CSS LOG
|
406 |
|
407 |
+
|
408 |
+
# START OPTIMIZED FONT DELIVERY
|
409 |
+
if(!empty($css_lowpriority_code)) {
|
410 |
|
411 |
+
# minify?
|
412 |
if(!isset($fvm_settings['css']['min_disable']) || (isset($fvm_settings['css']['min_disable'])&& $fvm_settings['css']['min_disable'] != true)) {
|
413 |
+
$css_lowpriority_code = fvm_minify_css_string($css_lowpriority_code);
|
414 |
+
}
|
415 |
+
|
416 |
+
# save transient, if not yet saved
|
417 |
+
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $css_lowpriority_code), 'css');
|
418 |
+
|
419 |
+
# generate url
|
420 |
+
$css_fonts_url = fvm_generate_min_url('fonts', $tkey, 'css', $css_lowpriority_code);
|
421 |
+
if($css_fonts_url === false) {
|
422 |
+
return $html_src . $fvm_error;
|
423 |
+
}
|
424 |
+
|
425 |
+
# cdn
|
426 |
+
if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
|
427 |
+
$css_fonts_url = fvm_rewrite_cdn_url($css_fonts_url);
|
428 |
+
}
|
429 |
+
|
430 |
+
# preload
|
431 |
+
$htmlcssheader[0] = '<link rel="preload" fetchpriority="low" id="fvmfonts-css" href="'.$css_fonts_url.'" as="style" media="all" onload="this.rel=\'stylesheet\';this.onload=null">';
|
432 |
|
433 |
+
|
434 |
+
}
|
435 |
+
# END OPTIMIZED FONT DELIVERY
|
436 |
+
|
437 |
+
# START COMBINING CSS
|
438 |
+
if(is_array($fvm_styles) && count($fvm_styles) > 0) {
|
439 |
+
|
440 |
+
# process mediatypes
|
441 |
+
foreach ($fvm_styles as $mediatype=>$css_arr) {
|
442 |
|
443 |
+
# process types, block or async
|
444 |
+
foreach ($css_arr as $css_method=>$css_arr2) {
|
445 |
+
|
446 |
+
# merge and hash
|
447 |
+
$merged_css = implode(PHP_EOL, $css_arr2);
|
448 |
+
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_css), 'css');
|
449 |
|
450 |
+
# inline if small
|
451 |
+
if(strlen($merged_css) < 15000 && $css_method == 'block') {
|
452 |
+
$htmlcssheader[] = '<style type="text/css" media="'.$mediatype.'">'.$merged_css.'</style>';
|
|
|
453 |
continue;
|
454 |
}
|
455 |
|
456 |
+
# url, preload, add
|
457 |
+
$merged_css_url = fvm_generate_min_url('combined', $tkey, 'css', $merged_css);
|
458 |
+
if($merged_css_url === false) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
return $html_src . $fvm_error;
|
460 |
}
|
461 |
+
|
462 |
+
# cdn
|
463 |
+
if(isset($fvm_settings['cdn']['cssok']) && $fvm_settings['cdn']['cssok'] == true) {
|
464 |
+
$merged_css_url = fvm_rewrite_cdn_url($merged_css_url);
|
465 |
+
}
|
466 |
+
|
467 |
+
# http, html preload + header
|
468 |
+
if($css_method == 'block') {
|
469 |
+
|
470 |
+
# add to header
|
471 |
+
$htmlcssheader[] = '<link rel="stylesheet" href="'.$merged_css_url.'" media="'.$mediatype.'" />';
|
472 |
+
|
473 |
+
# http and html preload for render blocking css
|
474 |
+
if(!isset($fvm_settings['css']['nopreload']) || (isset($fvm_settings['css']['nopreload']) && $fvm_settings['css']['nopreload'] != true)) {
|
475 |
+
$htmlpreloads[] = '<link rel="preload" href="'.$merged_css_url.'" as="style" media="'.$mediatype.'" />';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
476 |
}
|
477 |
+
|
478 |
+
} else {
|
479 |
+
|
480 |
+
# async
|
481 |
+
$htmlcssheader[] = '<link rel="preload" as="style" href="'.$merged_css_url.'" media="'.$mediatype.'" onload="this.rel=\'stylesheet\'" />';
|
482 |
+
|
483 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
|
485 |
}
|
486 |
}
|
487 |
}
|
488 |
+
# END COMBINING CSS
|
489 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
490 |
}
|
491 |
+
# END CSS PROCESSING
|
492 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
493 |
|
494 |
+
# START JS PROCESSING
|
495 |
+
if(fvm_can_minify_js()) {
|
496 |
+
|
497 |
+
# defaults
|
498 |
+
$scripts_duplicate_check = array();
|
499 |
+
$fvm_scripts_header = array();
|
500 |
+
$fvm_scripts_defer = array();
|
501 |
|
502 |
+
# start log
|
503 |
+
$log = array();
|
504 |
+
$js_total = 0;
|
|
|
505 |
|
506 |
+
# start log
|
507 |
+
$log[]= 'PAGE - '. fvm_get_uripath(true) . PHP_EOL . '---' . PHP_EOL;
|
508 |
|
509 |
+
# get all scripts
|
510 |
+
$allscripts = array();
|
511 |
+
foreach($html->find('script') as $element) {
|
512 |
+
$allscripts[] = $element;
|
513 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
|
515 |
+
# START JS LOOP
|
516 |
+
if (is_array($allscripts) && count($allscripts) > 0) {
|
517 |
+
foreach($allscripts as $k=>$tag) {
|
518 |
+
|
519 |
+
# handle application/ld+json or application/json before anything else
|
520 |
+
if(isset($tag->type) && ($tag->type == 'application/ld+json' || $tag->type == 'application/json')) {
|
521 |
+
|
522 |
+
# minify
|
523 |
+
if(isset($fvm_settings['js']['js_enable_min_inline']) && $fvm_settings['js']['js_enable_min_inline'] == true) { $tag->innertext = fvm_minify_microdata($tag->innertext); }
|
524 |
+
|
525 |
+
# remove
|
526 |
+
unset($allscripts[$k]);
|
527 |
continue;
|
528 |
}
|
529 |
|
530 |
+
# skip unknown script types
|
531 |
+
if(isset($tag->type) && $tag->type != 'text/javascript') {
|
532 |
+
unset($allscripts[$k]);
|
533 |
+
continue;
|
534 |
}
|
535 |
+
|
536 |
+
# remove default script type
|
537 |
+
if(isset($tag->type) && $tag->type == 'text/javascript') { unset($tag->type); }
|
538 |
+
|
539 |
+
# START JS FILES
|
540 |
+
if(isset($tag->src)) {
|
541 |
|
542 |
+
# filter url
|
543 |
+
$href = fvm_normalize_url($tag->src);
|
|
|
|
|
544 |
|
545 |
+
# ignore js files
|
546 |
+
if(isset($fvm_settings['js']['ignore']) && !empty($fvm_settings['js']['ignore'])) {
|
547 |
+
$arr = fvm_string_toarray($fvm_settings['js']['ignore']);
|
548 |
+
if(is_array($arr) && count($arr) > 0) {
|
549 |
+
foreach ($arr as $a) {
|
550 |
+
if(stripos($tag->src, $a) !== false) {
|
551 |
+
unset($allscripts[$k]);
|
552 |
+
continue 2;
|
553 |
+
}
|
554 |
+
}
|
555 |
}
|
556 |
+
}
|
|
|
|
|
|
|
|
|
557 |
|
558 |
+
# remove js files
|
559 |
+
if(isset($fvm_settings['js']['remove']) && !empty($fvm_settings['js']['remove'])) {
|
560 |
+
$arr = fvm_string_toarray($fvm_settings['js']['remove']);
|
561 |
+
if(is_array($arr) && count($arr) > 0) {
|
562 |
+
foreach ($arr as $a) {
|
563 |
+
if(stripos($tag->src, $a) !== false) {
|
564 |
+
$tag->outertext = '';
|
565 |
+
unset($allscripts[$k]);
|
566 |
+
continue 2;
|
567 |
+
}
|
568 |
+
}
|
569 |
+
}
|
570 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
|
572 |
+
|
573 |
+
# JS files to delay until user interaction (unmergeable)
|
574 |
+
if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
|
575 |
+
$arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
576 |
if(is_array($arr) && count($arr) > 0) {
|
577 |
+
foreach ($arr as $ac) {
|
578 |
+
if(stripos($tag->src, $ac) !== false) {
|
579 |
|
580 |
+
# unique identifier
|
581 |
+
$uid = fvm_generate_hash_with_prefix(hash('sha256', $tag->outertext), 'js');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
582 |
|
583 |
+
# remove exact duplicates, or replace transformed tag
|
584 |
+
if(isset($scripts_duplicate_check[$uid])) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
585 |
$tag->outertext = '';
|
586 |
+
} else {
|
587 |
+
$tag->type = 'fvmdelay';
|
588 |
+
$scripts_duplicate_check[$uid] = $uid;
|
589 |
+
}
|
590 |
+
|
591 |
+
# mark as processed, unset and break inner loop
|
592 |
+
unset($allscripts[$k]);
|
593 |
+
continue 2;
|
594 |
+
|
595 |
}
|
596 |
}
|
597 |
}
|
598 |
}
|
599 |
|
600 |
+
|
601 |
+
# START MERGING JS
|
602 |
+
if(isset($fvm_settings['js']['combine']) && $fvm_settings['js']['combine'] == true) {
|
603 |
+
|
604 |
+
# force render blocking
|
605 |
+
if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
|
606 |
+
$arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
|
607 |
+
if(is_array($arr) && count($arr) > 0) {
|
608 |
+
foreach ($arr as $aa) {
|
609 |
+
if(stripos($tag->src, $aa) !== false) {
|
610 |
+
|
611 |
+
# download or fetch from transient, minified
|
612 |
+
$js = fvm_get_js_from_file($tag);
|
613 |
+
if($js !== false && is_array($js)) {
|
614 |
+
|
615 |
+
# error
|
616 |
+
if(isset($js['error'])) {
|
617 |
+
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
618 |
+
unset($allscripts[$k]);
|
619 |
+
continue 2;
|
620 |
+
}
|
621 |
|
622 |
+
# save js for merging
|
623 |
+
$fvm_scripts_header[] = $js['code'];
|
624 |
+
|
625 |
+
# log
|
626 |
+
$size = strlen($js['code']);
|
627 |
+
$js_total = $js_total + $size;
|
628 |
+
$log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
629 |
+
|
630 |
+
# remove from html
|
631 |
+
$tag->outertext = '';
|
632 |
unset($allscripts[$k]);
|
633 |
continue 2;
|
634 |
+
|
635 |
}
|
636 |
+
}
|
637 |
+
}
|
638 |
+
}
|
639 |
+
}
|
640 |
+
|
641 |
+
# force defer
|
642 |
+
if(isset($fvm_settings['js']['merge_defer']) && !empty($fvm_settings['js']['merge_defer'])) {
|
643 |
+
$arr = fvm_string_toarray($fvm_settings['js']['merge_defer']);
|
644 |
+
if(is_array($arr) && count($arr) > 0) {
|
645 |
+
foreach ($arr as $aa) {
|
646 |
+
if(stripos($tag->src, $aa) !== false) {
|
647 |
|
648 |
+
# download or fetch from transient, minified
|
649 |
+
$js = fvm_get_js_from_file($tag);
|
650 |
+
if($js !== false && is_array($js)) {
|
651 |
+
|
652 |
+
# error
|
653 |
+
if(isset($js['error'])) {
|
654 |
+
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
655 |
+
unset($allscripts[$k]);
|
656 |
+
continue 2;
|
657 |
+
}
|
658 |
|
659 |
+
# save js for merging
|
660 |
+
$fvm_scripts_defer[] = $js['code'];
|
661 |
+
|
662 |
+
# log
|
663 |
+
$size = strlen($js['code']);
|
664 |
+
$js_total = $js_total + $size;
|
665 |
+
$log[] = '[JS Defer: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
666 |
+
|
667 |
+
# remove from html
|
668 |
+
$tag->outertext = '';
|
669 |
+
unset($allscripts[$k]);
|
670 |
+
continue 2;
|
671 |
+
|
672 |
+
}
|
673 |
+
}
|
674 |
+
}
|
675 |
}
|
676 |
}
|
677 |
+
|
678 |
+
# jquery needs to load earlier, if not being merged (while merging is active)
|
679 |
+
if(stripos($tag->src, '/jquery.js') !== false || stripos($tag->src, '/jquery.min.js') !== false || stripos($tag->src, '/jquery-migrate') !== false) {
|
680 |
+
|
681 |
+
# http and html preload for render blocking js
|
682 |
+
if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
|
683 |
+
$htmlpreloads[] = '<link rel="preload" href="'.$href.'" as="script" />';
|
684 |
+
}
|
685 |
|
686 |
+
# header
|
687 |
+
if(stripos($tag->src, '/jquery-migrate') !== false) {
|
688 |
+
$htmljsheader[1] = "<script data-cfasync='false' src='".$href."'></script>"; # jquery migrate
|
689 |
+
} else {
|
690 |
+
$htmljsheader[0] = "<script data-cfasync='false' src='".$href."'></script>"; # jquery
|
691 |
+
}
|
692 |
+
|
693 |
+
# content
|
694 |
+
$tag->outertext = '';
|
695 |
+
unset($allscripts[$k]);
|
696 |
+
continue;
|
697 |
+
}
|
698 |
+
|
699 |
+
}
|
700 |
+
# END MERGING JS
|
701 |
+
|
702 |
+
|
703 |
+
# START INDIVIDUAL JS MINIFICATION
|
704 |
+
# minify individually, if enabled
|
705 |
+
if(!isset($fvm_settings['js']['min_disable']) || (isset($fvm_settings['js']['min_disable'])&& $fvm_settings['js']['min_disable'] != true)) {
|
706 |
|
707 |
+
# skip third party scripts, unless allowed
|
708 |
+
$allowed = array($fvm_urls['wp_domain'], '/ajax.aspnetcdn.com/ajax/', '/ajax.googleapis.com/ajax/libs/', '/cdnjs.cloudflare.com/ajax/libs/');
|
709 |
+
if(str_replace($allowed, '', $href) == $href) {
|
710 |
+
unset($allscripts[$k]);
|
711 |
+
continue;
|
712 |
}
|
713 |
|
714 |
+
# force render blocking
|
715 |
+
if(isset($fvm_settings['js']['merge_header']) && !empty($fvm_settings['js']['merge_header'])) {
|
716 |
+
$arr = fvm_string_toarray($fvm_settings['js']['merge_header']);
|
717 |
+
if(is_array($arr) && count($arr) > 0) {
|
718 |
+
foreach ($arr as $aa) {
|
719 |
+
if(stripos($tag->src, $aa) !== false) {
|
720 |
+
|
721 |
+
# download or fetch from transient, minified
|
722 |
+
$js = fvm_get_js_from_file($tag);
|
723 |
+
if($js !== false && is_array($js)) {
|
724 |
+
|
725 |
+
# error
|
726 |
+
if(isset($js['error'])) {
|
727 |
+
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
728 |
+
unset($allscripts[$k]);
|
729 |
+
continue 2;
|
730 |
+
}
|
731 |
+
|
732 |
+
# generate url
|
733 |
+
$ind_js_url = fvm_generate_min_url($tag->src, $js['tkey'], 'js', $js['code']);
|
734 |
+
if($ind_js_url === false) {
|
735 |
+
return $html_src . $fvm_error;
|
736 |
+
}
|
737 |
+
|
738 |
+
# cdn
|
739 |
+
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
740 |
+
$ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
|
741 |
+
}
|
742 |
+
|
743 |
+
# render block
|
744 |
+
if(isset($tag->async)) { unset($tag->async); }
|
745 |
+
if(isset($tag->defer)) { unset($tag->defer); }
|
746 |
+
|
747 |
+
# http and html preload for render blocking scripts
|
748 |
+
if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
|
749 |
+
$htmlpreloads[] = '<link rel="preload" href="'.$ind_js_url.'" as="script" />';
|
750 |
+
}
|
751 |
+
|
752 |
+
# log
|
753 |
+
$size = strlen($js['code']);
|
754 |
+
$js_total = $js_total + $size;
|
755 |
+
$log[] = '[JS Block: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
756 |
+
|
757 |
+
# finish early
|
758 |
+
$tag->src = $ind_js_url;
|
759 |
+
unset($allscripts[$k]);
|
760 |
+
continue 2;
|
761 |
+
|
762 |
+
}
|
763 |
+
}
|
764 |
+
}
|
765 |
+
}
|
766 |
}
|
767 |
|
768 |
+
# force defer
|
769 |
+
if(isset($fvm_settings['js']['merge_defer']) && !empty($fvm_settings['js']['merge_defer'])) {
|
770 |
+
$arr = fvm_string_toarray($fvm_settings['js']['merge_defer']);
|
771 |
+
if(is_array($arr) && count($arr) > 0) {
|
772 |
+
foreach ($arr as $aa) {
|
773 |
+
if(stripos($tag->src, $aa) !== false) {
|
774 |
+
|
775 |
+
# download or fetch from transient, minified
|
776 |
+
$js = fvm_get_js_from_file($tag);
|
777 |
+
if($js !== false && is_array($js)) {
|
778 |
+
|
779 |
+
# error
|
780 |
+
if(isset($js['error'])) {
|
781 |
+
$tag->outertext = '/* Error on '.$href.' : '.$js['error'].' */'. PHP_EOL . $tag->outertext;
|
782 |
+
unset($allscripts[$k]);
|
783 |
+
continue 2;
|
784 |
+
}
|
785 |
+
|
786 |
+
# generate url
|
787 |
+
$ind_js_url = fvm_generate_min_url($tag->src, $js['tkey'], 'js', $js['code']);
|
788 |
+
if($ind_js_url === false) {
|
789 |
+
return $html_src . $fvm_error;
|
790 |
+
}
|
791 |
+
|
792 |
+
# cdn
|
793 |
+
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
794 |
+
$ind_js_url = fvm_rewrite_cdn_url($ind_js_url);
|
795 |
+
}
|
796 |
+
|
797 |
+
# add defer
|
798 |
+
if(!isset($tag->defer)) { $tag->defer = 'defer'; }
|
799 |
+
|
800 |
+
# log
|
801 |
+
$size = strlen($js['code']);
|
802 |
+
$js_total = $js_total + $size;
|
803 |
+
$log[] = '[JS Defer: '.str_pad(fvm_format_filesize($size), 9,' ',STR_PAD_LEFT).']'."\t".str_replace($fvm_urls['wp_site_url'], '', $js['url']). PHP_EOL;
|
804 |
+
|
805 |
+
# finish early
|
806 |
+
$tag->src = $ind_js_url;
|
807 |
+
unset($allscripts[$k]);
|
808 |
+
continue 2;
|
809 |
+
|
810 |
+
}
|
811 |
+
}
|
812 |
+
}
|
813 |
+
}
|
814 |
+
}
|
815 |
+
|
816 |
+
# remove unprocessed scripts from loop
|
817 |
unset($allscripts[$k]);
|
818 |
continue;
|
819 |
+
}
|
820 |
+
# END INDIVIDUAL JS MINIFICATION
|
821 |
+
|
822 |
}
|
823 |
+
# END JS FILES
|
824 |
|
825 |
|
826 |
+
# START INLINED SCRIPTS
|
827 |
+
if(!isset($tag->src)) {
|
828 |
+
|
829 |
+
# remove if empty
|
830 |
+
if(strlen(trim($tag->innertext)) == 0) {
|
831 |
+
$tag->outertext = '';
|
832 |
+
unset($allcss[$k]);
|
|
|
833 |
continue;
|
834 |
}
|
835 |
|
836 |
+
# default
|
837 |
+
$js = ''; $js = $tag->innertext;
|
838 |
+
|
839 |
+
# minify?
|
840 |
+
if(!isset($fvm_settings['js']['min_disable_inline']) || (isset($fvm_settings['js']['min_disable_inline'])&& $fvm_settings['js']['min_disable_inline'] != true)) {
|
841 |
+
$js = PHP_EOL . fvm_maybe_minify_js($js, null, true) . PHP_EOL;
|
842 |
+
}
|
843 |
+
|
844 |
+
# delay inline scripts until user interaction (unmergeable)
|
845 |
+
if(isset($fvm_settings['js']['thirdparty']) && !empty($fvm_settings['js']['thirdparty'])) {
|
846 |
+
$arr = fvm_string_toarray($fvm_settings['js']['thirdparty']);
|
847 |
if(is_array($arr) && count($arr) > 0) {
|
848 |
+
foreach ($arr as $b) {
|
849 |
+
if(stripos($js, $b) !== false || stripos($js, $b) !== false) {
|
850 |
|
851 |
+
# delay
|
852 |
+
$tag->type = 'fvmdelay';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
853 |
|
854 |
+
# minified
|
855 |
+
if(!empty($js)) {
|
856 |
+
$tag->innertext = $js;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
857 |
}
|
858 |
+
|
859 |
+
# unset
|
860 |
+
unset($allscripts[$k]);
|
861 |
+
continue 2;
|
862 |
+
}
|
863 |
}
|
864 |
}
|
865 |
}
|
866 |
+
|
867 |
+
# defer inline scripts
|
868 |
+
if(isset($fvm_settings['js']['defer_dependencies']) && !empty($fvm_settings['js']['defer_dependencies'])) {
|
869 |
+
$arr = fvm_string_toarray($fvm_settings['js']['defer_dependencies']);
|
870 |
if(is_array($arr) && count($arr) > 0) {
|
871 |
+
foreach ($arr as $b) {
|
872 |
+
if((stripos($js, $b) !== false || stripos($js, $b) !== false) && !isset($tag->src)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
873 |
|
874 |
+
# defer and rawurlencode
|
875 |
+
# jquery document ready needs to execute before deferred scripts
|
876 |
+
if(!empty($js) && stripos($js, ').ready(') === false) {
|
877 |
+
$tag->src = 'data:application/javascript,'.rawurlencode($js);
|
878 |
+
$tag->innertext = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
879 |
}
|
880 |
+
|
881 |
+
# unset
|
882 |
+
unset($allscripts[$k]);
|
883 |
+
continue 2;
|
884 |
+
}
|
885 |
}
|
886 |
}
|
887 |
+
}
|
888 |
+
}
|
889 |
+
# END INLINED SCRIPTS
|
890 |
+
|
|
|
|
|
|
|
|
|
891 |
}
|
892 |
+
}
|
893 |
+
# END JS LOOP
|
894 |
+
|
895 |
+
|
896 |
+
# START JS LOG
|
897 |
+
if(count($log) > 1) {
|
898 |
+
$log[] = str_pad('-', 21, '-',STR_PAD_LEFT) . PHP_EOL;
|
899 |
+
$log[] = '[JS Total: '.str_pad(fvm_format_filesize($js_total), 9,' ',STR_PAD_LEFT).']' . PHP_EOL;
|
900 |
+
$log[] = str_pad('-', 21, '-',STR_PAD_LEFT);
|
901 |
+
fvm_save_log(array('type'=>'min','msg'=>implode('', $log)));
|
902 |
+
}
|
903 |
+
# END JS LOG
|
904 |
+
|
905 |
+
# START COMBINING JS
|
906 |
+
|
907 |
+
# header scripts
|
908 |
+
if(is_array($fvm_scripts_header) && count($fvm_scripts_header) > 0) {
|
909 |
|
910 |
+
# merge code, hash
|
911 |
+
$merged_js = implode(PHP_EOL, $fvm_scripts_header);
|
912 |
+
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_js), 'js');
|
913 |
+
|
914 |
+
# generate url
|
915 |
+
$merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
|
916 |
+
if($merged_js_url === false) {
|
917 |
+
return $html_src . $fvm_error;
|
918 |
+
}
|
|
|
|
|
|
|
919 |
|
920 |
+
# cdn
|
921 |
+
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
922 |
+
$merged_js_url = fvm_rewrite_cdn_url($merged_js_url);
|
923 |
}
|
924 |
|
925 |
+
# http and html preload for render blocking scripts
|
926 |
+
if(!isset($fvm_settings['js']['nopreload']) || (isset($fvm_settings['js']['nopreload']) && $fvm_settings['js']['nopreload'] != true)) {
|
927 |
+
$htmlpreloads[] = '<link rel="preload" href="'.$merged_js_url.'" as="script" />';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
928 |
}
|
929 |
+
|
930 |
+
# add to header
|
931 |
+
$htmljsheader[] = "<script data-cfasync='false' src='".$merged_js_url."'></script>";
|
932 |
|
933 |
+
}
|
934 |
+
|
935 |
+
# deferred scripts
|
936 |
+
if(is_array($fvm_scripts_defer) && count($fvm_scripts_defer) > 0) {
|
937 |
+
|
938 |
+
# merge code, hash
|
939 |
+
$merged_js = implode(PHP_EOL, $fvm_scripts_defer);
|
940 |
+
$tkey = fvm_generate_hash_with_prefix(hash('sha256', $merged_js), 'js');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
941 |
|
942 |
+
# generate url
|
943 |
+
$merged_js_url = fvm_generate_min_url('combined', $tkey, 'js', $merged_js);
|
944 |
+
if($merged_js_url === false) {
|
945 |
+
return $html_src . $fvm_error;
|
946 |
+
}
|
947 |
+
|
948 |
+
# cdn
|
949 |
+
if(isset($fvm_settings['cdn']['jsok']) && $fvm_settings['cdn']['jsok'] == true) {
|
950 |
+
$merged_js_url = fvm_rewrite_cdn_url($merged_js_url);
|
951 |
+
}
|
952 |
+
|
953 |
+
# header, no preload for deferred files
|
954 |
+
$htmljsheader[] = "<script defer='defer' src='".$merged_js_url."'></script>";
|
955 |
+
|
956 |
}
|
957 |
+
|
958 |
}
|
959 |
+
# END JS PROCESSING
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
960 |
|
961 |
+
|
962 |
+
|
963 |
+
# process HTML minification, if not disabled ###############################
|
964 |
+
if(fvm_can_process_html()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
965 |
|
966 |
+
# Remove HTML comments and IE conditionals
|
967 |
+
if(isset($fvm_settings['html']['nocomments']) && $fvm_settings['html']['nocomments'] == true) {
|
968 |
+
foreach($html->find('comment') as $element) {
|
969 |
+
$element->outertext = '';
|
970 |
}
|
971 |
+
}
|
972 |
+
|
973 |
+
# Remove generator tags
|
974 |
+
if(isset($fvm_settings['html']['cleanup_header']) && $fvm_settings['html']['cleanup_header'] == true) {
|
975 |
|
976 |
+
# remove
|
977 |
+
foreach($html->find('head meta[name=generator], head link[rel=shortlink], head link[rel=dns-prefetch], head link[rel=preconnect], head link[rel=prefetch], head link[rel=prerender], head meta[name*=msapplication], head link[rel=apple-touch-icon], head link[rel=EditURI], head link[rel=preconnect], head link[rel=wlwmanifest], head link[rel=https://api.w.org/], head link[href*=/wp-json/], head link[rel=pingback], head link[type=application/json+oembed], head link[type=text/xml+oembed]') as $element) {
|
978 |
+
$element->outertext = '';
|
979 |
}
|
980 |
|
981 |
+
# allow only the last link[rel=icon]
|
982 |
+
$ic = array(); $ic = $html->find('head link[rel=icon]');
|
983 |
+
$i = 1; $len = count($ic);
|
984 |
+
if($len > 1) {
|
985 |
+
foreach($ic as $element) {
|
986 |
+
if ($i != $len) { $element->outertext = ''; } $i++; # delete except if last
|
987 |
+
}
|
988 |
+
}
|
989 |
+
}
|
990 |
+
|
991 |
}
|
992 |
|
993 |
+
# build extra head and footer ###############################
|
994 |
+
|
995 |
+
# header and footer markers
|
996 |
+
$hm = '<!-- h_preheader --><!-- h_header_function -->';
|
997 |
+
$hm_late = '<!-- h_cssheader --><!-- h_jsheader -->';
|
998 |
+
$fm = '<!-- h_footer_fvm_scripts -->';
|
999 |
+
|
1000 |
+
# add our function to head
|
1001 |
+
if(fvm_can_minify_css() || fvm_can_minify_js()) {
|
1002 |
+
$hm = fvm_add_header_function($hm);
|
1003 |
+
}
|
1004 |
|
1005 |
+
# move viewport meta tag up
|
1006 |
+
if(!is_null($html->find('meta[viewport]', 0))) {
|
1007 |
+
$hm = str_replace('<!-- h_preheader -->', $html->find('meta[viewport]', 0)->outertext.'<!-- h_preheader -->', $hm);
|
1008 |
+
foreach($html->find('meta[viewport]') as $element) { $element->outertext = ''; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1009 |
}
|
1010 |
|
1011 |
+
# move charset meta tag up
|
1012 |
+
if(!is_null($html->find('meta[charset]', 0))) {
|
1013 |
+
$hm = str_replace('<!-- h_preheader -->', $html->find('meta[charset]', 0)->outertext.'<!-- h_preheader -->', $hm);
|
1014 |
+
foreach($html->find('meta[charset]') as $element) { $element->outertext = ''; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1015 |
}
|
1016 |
|
1017 |
+
# remove other meta tag and collect them between preload and css/js files
|
1018 |
+
foreach($html->find('head meta, head title, head link[rel=canonical], head link[rel=alternate], head link[rel=pingback], head script[type=application/ld+json]') as $element) {
|
1019 |
+
$hm_late = str_replace('<!-- h_cssheader -->', $element->outertext.'<!-- h_cssheader -->', $hm_late);
|
1020 |
+
$element->outertext = '';
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
# preload headers, by fetchpriority attribute
|
1024 |
+
if(is_array($htmlpreloads)) {
|
1025 |
+
|
1026 |
+
# deduplicate
|
1027 |
+
$htmlpreloads = array_unique($htmlpreloads);
|
1028 |
|
1029 |
+
# get values
|
1030 |
+
$pre_html = array_values($htmlpreloads);
|
1031 |
+
|
1032 |
+
# add preload html header
|
1033 |
+
if(count($pre_html) > 0) {
|
1034 |
+
$hm = str_replace('<!-- h_preheader -->', implode(PHP_EOL, $pre_html).'<!-- h_preheader -->', $hm);
|
1035 |
}
|
1036 |
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
# add stylesheets
|
1040 |
+
if(isset($htmlcssheader)) {
|
1041 |
+
if(is_array($htmlcssheader) && count($htmlcssheader) > 0) {
|
1042 |
+
ksort($htmlcssheader); # priority
|
1043 |
+
$hm_late = str_replace('<!-- h_cssheader -->', implode(PHP_EOL, $htmlcssheader).'<!-- h_cssheader -->', $hm_late);
|
1044 |
}
|
1045 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1046 |
|
1047 |
+
# add header scripts
|
1048 |
+
if(isset($htmljsheader)) {
|
1049 |
+
if(is_array($htmljsheader) && count($htmljsheader) > 0) {
|
1050 |
+
ksort($htmljsheader); # priority
|
1051 |
+
$hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljsheader).'<!-- h_jsheader -->', $hm_late);
|
1052 |
+
}
|
1053 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1054 |
|
1055 |
+
# add defer scripts
|
1056 |
+
if(isset($htmljscodedefer)) {
|
1057 |
+
if(is_array($htmljscodedefer) && count($htmljscodedefer) > 0) {
|
1058 |
+
ksort($htmljscodedefer); # priority
|
1059 |
+
$hm_late = str_replace('<!-- h_jsheader -->', implode(PHP_EOL, $htmljscodedefer), $hm_late);
|
1060 |
+
}
|
1061 |
+
}
|
1062 |
|
1063 |
+
# add fvm_footer scripts, if enabled
|
1064 |
+
if(fvm_can_minify_js()) {
|
1065 |
+
$fm = fvm_add_footer_function($fm);
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
# cleanup leftover markers
|
1069 |
+
$hm = str_replace(array('<!-- h_preheader -->', '<!-- h_header_function -->'), '', $hm);
|
1070 |
+
$hm_late = str_replace(array('<!-- h_cssheader -->', '<!-- h_jsheader -->'), '', $hm_late);
|
1071 |
+
$fm = str_replace('<!-- h_footer_fvm_scripts -->', '', $fm);
|
1072 |
|
1073 |
+
# append header and footer
|
1074 |
+
if(!is_null($html->find('head', 0)) && !is_null($html->find('body', -1))) {
|
1075 |
+
if(!is_null($html->find('head', 0)->first_child()) && !is_null($html->find('body', -1)->last_child())) {
|
1076 |
+
$html->find('head', 0)->first_child()->outertext = $hm . $html->find('head', 0)->first_child()->outertext . $hm_late;
|
1077 |
+
$html->find('body', -1)->last_child()->outertext = $html->find('body', -1)->last_child ()->outertext . $fm;
|
1078 |
+
}
|
1079 |
}
|
1080 |
|
|
|
1081 |
|
1082 |
+
# convert html object to string, save all objects to string
|
1083 |
+
$html = trim($html->save());
|
1084 |
+
|
1085 |
+
# process cdn optimization
|
1086 |
+
if(fvm_can_process_cdn()) {
|
1087 |
+
$html = fvm_process_cdn($html);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1088 |
}
|
1089 |
+
|
1090 |
+
# minify remaining HTML at the end, if enabled
|
1091 |
+
if(fvm_can_process_html()) {
|
1092 |
+
if(!isset($fvm_settings['html']['min_disable']) || (isset($fvm_settings['html']['min_disable']) && $fvm_settings['html']['min_disable'] != true)) {
|
1093 |
+
$html = fvm_raisermin_html($html);
|
1094 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1095 |
}
|
1096 |
+
|
1097 |
+
# filter final html if needed
|
1098 |
+
if(function_exists('fvm_filter_final_html')) {
|
1099 |
+
$html = fvm_filter_final_html($html);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1100 |
}
|
|
|
1101 |
|
|
|
|
|
|
|
1102 |
}
|
1103 |
|
1104 |
# return html
|
libs/matthiasmullie/minify/src/CSS.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* CSS Minifier
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -12,15 +13,14 @@
|
|
12 |
namespace FVM\MatthiasMullie\Minify;
|
13 |
|
14 |
use FVM\MatthiasMullie\Minify\Exceptions\FileImportException;
|
15 |
-
use FVM\MatthiasMullie\PathConverter\ConverterInterface;
|
16 |
use FVM\MatthiasMullie\PathConverter\Converter;
|
|
|
17 |
|
18 |
/**
|
19 |
-
* CSS minifier
|
20 |
*
|
21 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
22 |
*
|
23 |
-
* @package Minify
|
24 |
* @author Matthias Mullie <minify@mullie.eu>
|
25 |
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
26 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
@@ -44,6 +44,10 @@ class CSS extends Minify
|
|
44 |
'jpeg' => 'data:image/jpeg',
|
45 |
'svg' => 'data:image/svg+xml',
|
46 |
'woff' => 'data:application/x-font-woff',
|
|
|
|
|
|
|
|
|
47 |
'tif' => 'image/tiff',
|
48 |
'tiff' => 'image/tiff',
|
49 |
'xbm' => 'image/x-xbitmap',
|
@@ -93,7 +97,7 @@ class CSS extends Minify
|
|
93 |
}
|
94 |
|
95 |
// add to top
|
96 |
-
$content = implode(';', $matches[2]).';'.trim($content, ';');
|
97 |
}
|
98 |
|
99 |
return $content;
|
@@ -102,8 +106,8 @@ class CSS extends Minify
|
|
102 |
/**
|
103 |
* Combine CSS from import statements.
|
104 |
*
|
105 |
-
*
|
106 |
-
* to save HTTP requests.
|
107 |
*
|
108 |
* @param string $source The file to combine imports for
|
109 |
* @param string $content The CSS content to combine imports for
|
@@ -200,7 +204,7 @@ class CSS extends Minify
|
|
200 |
// loop the matches
|
201 |
foreach ($matches as $match) {
|
202 |
// get the path for the file that will be imported
|
203 |
-
$importPath = dirname($source).'/'
|
204 |
|
205 |
// only replace the import with the content if we can grab the
|
206 |
// content of the file
|
@@ -211,19 +215,19 @@ class CSS extends Minify
|
|
211 |
// check if current file was not imported previously in the same
|
212 |
// import chain.
|
213 |
if (in_array($importPath, $parents)) {
|
214 |
-
throw new FileImportException('Failed to import file "'
|
215 |
}
|
216 |
|
217 |
// grab referenced file & minify it (which may include importing
|
218 |
// yet other @import statements recursively)
|
219 |
-
$minifier = new
|
220 |
$minifier->setMaxImportSize($this->maxImportSize);
|
221 |
$minifier->setImportExtensions($this->importExtensions);
|
222 |
$importContent = $minifier->execute($source, $parents);
|
223 |
|
224 |
// check if this is only valid for certain media
|
225 |
if (!empty($match['media'])) {
|
226 |
-
$importContent = '@media '
|
227 |
}
|
228 |
|
229 |
// add to replacement array
|
@@ -262,7 +266,7 @@ class CSS extends Minify
|
|
262 |
|
263 |
// get the path for the file that will be imported
|
264 |
$path = $match[2];
|
265 |
-
$path = dirname($source).'/'
|
266 |
|
267 |
// only replace the import with the content if we're able to get
|
268 |
// the content of the file, and it's relatively small
|
@@ -273,7 +277,7 @@ class CSS extends Minify
|
|
273 |
|
274 |
// build replacement
|
275 |
$search[] = $match[0];
|
276 |
-
$replace[] = 'url('
|
277 |
}
|
278 |
}
|
279 |
|
@@ -289,7 +293,7 @@ class CSS extends Minify
|
|
289 |
* Perform CSS optimizations.
|
290 |
*
|
291 |
* @param string[optional] $path Path to write the data to
|
292 |
-
* @param string[]
|
293 |
*
|
294 |
* @return string The minified data
|
295 |
*/
|
@@ -307,7 +311,8 @@ class CSS extends Minify
|
|
307 |
*/
|
308 |
$this->extractStrings();
|
309 |
$this->stripComments();
|
310 |
-
$this->
|
|
|
311 |
$css = $this->replace($css);
|
312 |
|
313 |
$css = $this->stripWhitespace($css);
|
@@ -464,9 +469,9 @@ class CSS extends Minify
|
|
464 |
// build replacement
|
465 |
$search[] = $match[0];
|
466 |
if ($type === 'url') {
|
467 |
-
$replace[] = 'url('
|
468 |
} elseif ($type === 'import') {
|
469 |
-
$replace[] = '@import "'
|
470 |
}
|
471 |
}
|
472 |
|
@@ -525,7 +530,7 @@ class CSS extends Minify
|
|
525 |
);
|
526 |
|
527 |
return preg_replace_callback(
|
528 |
-
'/(?<=[: ])('.implode('|', array_keys($colors)).')(?=[; }])/i',
|
529 |
function ($match) use ($colors) {
|
530 |
return $colors[strtoupper($match[0])];
|
531 |
},
|
@@ -548,10 +553,10 @@ class CSS extends Minify
|
|
548 |
);
|
549 |
|
550 |
$callback = function ($match) use ($weights) {
|
551 |
-
return $match[1]
|
552 |
};
|
553 |
|
554 |
-
return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content);
|
555 |
}
|
556 |
|
557 |
/**
|
@@ -563,7 +568,47 @@ class CSS extends Minify
|
|
563 |
*/
|
564 |
protected function shortenZeroes($content)
|
565 |
{
|
566 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
567 |
return $content;
|
568 |
}
|
569 |
|
@@ -591,7 +636,7 @@ class CSS extends Minify
|
|
591 |
$minifier = $this;
|
592 |
$callback = function ($match) use ($minifier) {
|
593 |
$count = count($minifier->extracted);
|
594 |
-
$placeholder = '/*'
|
595 |
$minifier->extracted[$placeholder] = $match[0];
|
596 |
|
597 |
return $placeholder;
|
@@ -629,7 +674,7 @@ class CSS extends Minify
|
|
629 |
// not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
|
630 |
// selectors like `div.weird- p`
|
631 |
$pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
|
632 |
-
$content = preg_replace('/:('.implode('|', $pseudos).')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
|
633 |
|
634 |
// remove semicolon/whitespace followed by closing bracket
|
635 |
$content = str_replace(';}', '}', $content);
|
@@ -638,38 +683,71 @@ class CSS extends Minify
|
|
638 |
}
|
639 |
|
640 |
/**
|
641 |
-
* Replace all
|
|
|
642 |
*/
|
643 |
-
protected function
|
644 |
{
|
|
|
|
|
|
|
645 |
// PHP only supports $this inside anonymous functions since 5.4
|
646 |
$minifier = $this;
|
647 |
-
$callback = function ($match) use ($minifier) {
|
648 |
-
$
|
|
|
649 |
$expr = '';
|
650 |
$opened = 0;
|
651 |
|
652 |
-
|
653 |
-
|
|
|
|
|
|
|
|
|
|
|
654 |
$expr .= $char;
|
655 |
if ($char === '(') {
|
656 |
-
|
657 |
} elseif ($char === ')' && --$opened === 0) {
|
658 |
break;
|
659 |
}
|
660 |
}
|
661 |
-
$rest = str_replace($expr, '', $match[1]);
|
662 |
-
$expr = trim(substr($expr, 1, -1));
|
663 |
|
|
|
664 |
$count = count($minifier->extracted);
|
665 |
-
$placeholder = '
|
666 |
-
$minifier->extracted[$placeholder] = '
|
667 |
|
668 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
669 |
};
|
670 |
|
671 |
-
$this->registerPattern(
|
672 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
673 |
}
|
674 |
|
675 |
/**
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* CSS Minifier.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
13 |
namespace FVM\MatthiasMullie\Minify;
|
14 |
|
15 |
use FVM\MatthiasMullie\Minify\Exceptions\FileImportException;
|
|
|
16 |
use FVM\MatthiasMullie\PathConverter\Converter;
|
17 |
+
use FVM\MatthiasMullie\PathConverter\ConverterInterface;
|
18 |
|
19 |
/**
|
20 |
+
* CSS minifier.
|
21 |
*
|
22 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
23 |
*
|
|
|
24 |
* @author Matthias Mullie <minify@mullie.eu>
|
25 |
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
26 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
44 |
'jpeg' => 'data:image/jpeg',
|
45 |
'svg' => 'data:image/svg+xml',
|
46 |
'woff' => 'data:application/x-font-woff',
|
47 |
+
'woff2' => 'data:application/x-font-woff2',
|
48 |
+
'avif' => 'data:image/avif',
|
49 |
+
'apng' => 'data:image/apng',
|
50 |
+
'webp' => 'data:image/webp',
|
51 |
'tif' => 'image/tiff',
|
52 |
'tiff' => 'image/tiff',
|
53 |
'xbm' => 'image/x-xbitmap',
|
97 |
}
|
98 |
|
99 |
// add to top
|
100 |
+
$content = implode(';', $matches[2]) . ';' . trim($content, ';');
|
101 |
}
|
102 |
|
103 |
return $content;
|
106 |
/**
|
107 |
* Combine CSS from import statements.
|
108 |
*
|
109 |
+
* Import statements will be loaded and their content merged into the original
|
110 |
+
* file, to save HTTP requests.
|
111 |
*
|
112 |
* @param string $source The file to combine imports for
|
113 |
* @param string $content The CSS content to combine imports for
|
204 |
// loop the matches
|
205 |
foreach ($matches as $match) {
|
206 |
// get the path for the file that will be imported
|
207 |
+
$importPath = dirname($source) . '/' . $match['path'];
|
208 |
|
209 |
// only replace the import with the content if we can grab the
|
210 |
// content of the file
|
215 |
// check if current file was not imported previously in the same
|
216 |
// import chain.
|
217 |
if (in_array($importPath, $parents)) {
|
218 |
+
throw new FileImportException('Failed to import file "' . $importPath . '": circular reference detected.');
|
219 |
}
|
220 |
|
221 |
// grab referenced file & minify it (which may include importing
|
222 |
// yet other @import statements recursively)
|
223 |
+
$minifier = new self($importPath);
|
224 |
$minifier->setMaxImportSize($this->maxImportSize);
|
225 |
$minifier->setImportExtensions($this->importExtensions);
|
226 |
$importContent = $minifier->execute($source, $parents);
|
227 |
|
228 |
// check if this is only valid for certain media
|
229 |
if (!empty($match['media'])) {
|
230 |
+
$importContent = '@media ' . $match['media'] . '{' . $importContent . '}';
|
231 |
}
|
232 |
|
233 |
// add to replacement array
|
266 |
|
267 |
// get the path for the file that will be imported
|
268 |
$path = $match[2];
|
269 |
+
$path = dirname($source) . '/' . $path;
|
270 |
|
271 |
// only replace the import with the content if we're able to get
|
272 |
// the content of the file, and it's relatively small
|
277 |
|
278 |
// build replacement
|
279 |
$search[] = $match[0];
|
280 |
+
$replace[] = 'url(' . $this->importExtensions[$extension] . ';base64,' . $importContent . ')';
|
281 |
}
|
282 |
}
|
283 |
|
293 |
* Perform CSS optimizations.
|
294 |
*
|
295 |
* @param string[optional] $path Path to write the data to
|
296 |
+
* @param string[] $parents Parent paths, for circular reference checks
|
297 |
*
|
298 |
* @return string The minified data
|
299 |
*/
|
311 |
*/
|
312 |
$this->extractStrings();
|
313 |
$this->stripComments();
|
314 |
+
$this->extractMath();
|
315 |
+
$this->extractCustomProperties();
|
316 |
$css = $this->replace($css);
|
317 |
|
318 |
$css = $this->stripWhitespace($css);
|
469 |
// build replacement
|
470 |
$search[] = $match[0];
|
471 |
if ($type === 'url') {
|
472 |
+
$replace[] = 'url(' . $url . ')';
|
473 |
} elseif ($type === 'import') {
|
474 |
+
$replace[] = '@import "' . $url . '"';
|
475 |
}
|
476 |
}
|
477 |
|
530 |
);
|
531 |
|
532 |
return preg_replace_callback(
|
533 |
+
'/(?<=[: ])(' . implode('|', array_keys($colors)) . ')(?=[; }])/i',
|
534 |
function ($match) use ($colors) {
|
535 |
return $colors[strtoupper($match[0])];
|
536 |
},
|
553 |
);
|
554 |
|
555 |
$callback = function ($match) use ($weights) {
|
556 |
+
return $match[1] . $weights[$match[2]];
|
557 |
};
|
558 |
|
559 |
+
return preg_replace_callback('/(font-weight\s*:\s*)(' . implode('|', array_keys($weights)) . ')(?=[;}])/', $callback, $content);
|
560 |
}
|
561 |
|
562 |
/**
|
568 |
*/
|
569 |
protected function shortenZeroes($content)
|
570 |
{
|
571 |
+
// we don't want to strip units in `calc()` expressions:
|
572 |
+
// `5px - 0px` is valid, but `5px - 0` is not
|
573 |
+
// `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but
|
574 |
+
// `10 * 0` is invalid
|
575 |
+
// we've extracted calcs earlier, so we don't need to worry about this
|
576 |
+
|
577 |
+
// reusable bits of code throughout these regexes:
|
578 |
+
// before & after are used to make sure we don't match lose unintended
|
579 |
+
// 0-like values (e.g. in #000, or in http://url/1.0)
|
580 |
+
// units can be stripped from 0 values, or used to recognize non 0
|
581 |
+
// values (where wa may be able to strip a .0 suffix)
|
582 |
+
$before = '(?<=[:(, ])';
|
583 |
+
$after = '(?=[ ,);}])';
|
584 |
+
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
|
585 |
+
|
586 |
+
// strip units after zeroes (0px -> 0)
|
587 |
+
// NOTE: it should be safe to remove all units for a 0 value, but in
|
588 |
+
// practice, Webkit (especially Safari) seems to stumble over at least
|
589 |
+
// 0%, potentially other units as well. Only stripping 'px' for now.
|
590 |
+
// @see https://github.com/matthiasmullie/minify/issues/60
|
591 |
+
$content = preg_replace('/' . $before . '(-?0*(\.0+)?)(?<=0)px' . $after . '/', '\\1', $content);
|
592 |
+
|
593 |
+
// strip 0-digits (.0 -> 0)
|
594 |
+
$content = preg_replace('/' . $before . '\.0+' . $units . '?' . $after . '/', '0\\1', $content);
|
595 |
+
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
|
596 |
+
$content = preg_replace('/' . $before . '(-?[0-9]+\.[0-9]+)0+' . $units . '?' . $after . '/', '\\1\\2', $content);
|
597 |
+
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
|
598 |
+
$content = preg_replace('/' . $before . '(-?[0-9]+)\.0+' . $units . '?' . $after . '/', '\\1\\2', $content);
|
599 |
+
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
|
600 |
+
$content = preg_replace('/' . $before . '(-?)0+([0-9]*\.[0-9]+)' . $units . '?' . $after . '/', '\\1\\2\\3', $content);
|
601 |
+
|
602 |
+
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
|
603 |
+
$content = preg_replace('/' . $before . '-?0+' . $units . '?' . $after . '/', '0\\1', $content);
|
604 |
+
|
605 |
+
// IE doesn't seem to understand a unitless flex-basis value (correct -
|
606 |
+
// it goes against the spec), so let's add it in again (make it `%`,
|
607 |
+
// which is only 1 char: 0%, 0px, 0 anything, it's all just the same)
|
608 |
+
// @see https://developer.mozilla.org/nl/docs/Web/CSS/flex
|
609 |
+
$content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content);
|
610 |
+
$content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
|
611 |
+
|
612 |
return $content;
|
613 |
}
|
614 |
|
636 |
$minifier = $this;
|
637 |
$callback = function ($match) use ($minifier) {
|
638 |
$count = count($minifier->extracted);
|
639 |
+
$placeholder = '/*' . $count . '*/';
|
640 |
$minifier->extracted[$placeholder] = $match[0];
|
641 |
|
642 |
return $placeholder;
|
674 |
// not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
|
675 |
// selectors like `div.weird- p`
|
676 |
$pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
|
677 |
+
$content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
|
678 |
|
679 |
// remove semicolon/whitespace followed by closing bracket
|
680 |
$content = str_replace(';}', '}', $content);
|
683 |
}
|
684 |
|
685 |
/**
|
686 |
+
* Replace all occurrences of functions that may contain math, where
|
687 |
+
* whitespace around operators needs to be preserved (e.g. calc, clamp).
|
688 |
*/
|
689 |
+
protected function extractMath()
|
690 |
{
|
691 |
+
$functions = array('calc', 'clamp', 'min', 'max');
|
692 |
+
$pattern = '/\b(' . implode('|', $functions) . ')(\(.+?)(?=$|;|})/m';
|
693 |
+
|
694 |
// PHP only supports $this inside anonymous functions since 5.4
|
695 |
$minifier = $this;
|
696 |
+
$callback = function ($match) use ($minifier, $pattern, &$callback) {
|
697 |
+
$function = $match[1];
|
698 |
+
$length = strlen($match[2]);
|
699 |
$expr = '';
|
700 |
$opened = 0;
|
701 |
|
702 |
+
// the regular expression for extracting math has 1 significant problem:
|
703 |
+
// it can't determine the correct closing parenthesis...
|
704 |
+
// instead, it'll match a larger portion of code to where it's certain that
|
705 |
+
// the calc() musts have ended, and we'll figure out which is the correct
|
706 |
+
// closing parenthesis here, by counting how many have opened
|
707 |
+
for ($i = 0; $i < $length; ++$i) {
|
708 |
+
$char = $match[2][$i];
|
709 |
$expr .= $char;
|
710 |
if ($char === '(') {
|
711 |
+
++$opened;
|
712 |
} elseif ($char === ')' && --$opened === 0) {
|
713 |
break;
|
714 |
}
|
715 |
}
|
|
|
|
|
716 |
|
717 |
+
// now that we've figured out where the calc() starts and ends, extract it
|
718 |
$count = count($minifier->extracted);
|
719 |
+
$placeholder = 'math(' . $count . ')';
|
720 |
+
$minifier->extracted[$placeholder] = $function . '(' . trim(substr($expr, 1, -1)) . ')';
|
721 |
|
722 |
+
// and since we've captured more code than required, we may have some leftover
|
723 |
+
// calc() in here too - go recursive on the remaining but of code to go figure
|
724 |
+
// that out and extract what is needed
|
725 |
+
$rest = $minifier->str_replace_first($function . $expr, '', $match[0]);
|
726 |
+
$rest = preg_replace_callback($pattern, $callback, $rest);
|
727 |
+
|
728 |
+
return $placeholder . $rest;
|
729 |
};
|
730 |
|
731 |
+
$this->registerPattern($pattern, $callback);
|
732 |
+
}
|
733 |
+
|
734 |
+
/**
|
735 |
+
* Replace custom properties, whose values may be used in scenarios where
|
736 |
+
* we wouldn't want them to be minified (e.g. inside calc).
|
737 |
+
*/
|
738 |
+
protected function extractCustomProperties()
|
739 |
+
{
|
740 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
741 |
+
$minifier = $this;
|
742 |
+
$this->registerPattern(
|
743 |
+
'/(?<=^|[;}{])\s*(--[^:;{}"\'\s]+)\s*:([^;{}]+)/m',
|
744 |
+
function ($match) use ($minifier) {
|
745 |
+
$placeholder = '--custom-' . count($minifier->extracted) . ':0';
|
746 |
+
$minifier->extracted[$placeholder] = $match[1] . ':' . trim($match[2]);
|
747 |
+
|
748 |
+
return $placeholder;
|
749 |
+
}
|
750 |
+
);
|
751 |
}
|
752 |
|
753 |
/**
|
libs/matthiasmullie/minify/src/Exception.php
CHANGED
@@ -1,18 +1,20 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* Base Exception
|
4 |
*
|
5 |
* @deprecated Use Exceptions\BasicException instead
|
6 |
*
|
7 |
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
*/
|
|
|
9 |
namespace FVM\MatthiasMullie\Minify;
|
10 |
|
11 |
/**
|
12 |
-
* Base Exception Class
|
|
|
13 |
* @deprecated Use Exceptions\BasicException instead
|
14 |
*
|
15 |
-
* @package Minify
|
16 |
* @author Matthias Mullie <minify@mullie.eu>
|
17 |
*/
|
18 |
abstract class Exception extends \Exception
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* Base Exception.
|
5 |
*
|
6 |
* @deprecated Use Exceptions\BasicException instead
|
7 |
*
|
8 |
* @author Matthias Mullie <minify@mullie.eu>
|
9 |
*/
|
10 |
+
|
11 |
namespace FVM\MatthiasMullie\Minify;
|
12 |
|
13 |
/**
|
14 |
+
* Base Exception Class.
|
15 |
+
*
|
16 |
* @deprecated Use Exceptions\BasicException instead
|
17 |
*
|
|
|
18 |
* @author Matthias Mullie <minify@mullie.eu>
|
19 |
*/
|
20 |
abstract class Exception extends \Exception
|
libs/matthiasmullie/minify/src/Exceptions/BasicException.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* Basic exception
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -8,14 +9,14 @@
|
|
8 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
* @license MIT License
|
10 |
*/
|
|
|
11 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
12 |
|
13 |
use FVM\MatthiasMullie\Minify\Exception;
|
14 |
|
15 |
/**
|
16 |
-
* Basic Exception Class
|
17 |
*
|
18 |
-
* @package Minify\Exception
|
19 |
* @author Matthias Mullie <minify@mullie.eu>
|
20 |
*/
|
21 |
abstract class BasicException extends Exception
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* Basic exception.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
9 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
10 |
* @license MIT License
|
11 |
*/
|
12 |
+
|
13 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
14 |
|
15 |
use FVM\MatthiasMullie\Minify\Exception;
|
16 |
|
17 |
/**
|
18 |
+
* Basic Exception Class.
|
19 |
*
|
|
|
20 |
* @author Matthias Mullie <minify@mullie.eu>
|
21 |
*/
|
22 |
abstract class BasicException extends Exception
|
libs/matthiasmullie/minify/src/Exceptions/FileImportException.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* File Import Exception
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -8,12 +9,12 @@
|
|
8 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
* @license MIT License
|
10 |
*/
|
|
|
11 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
12 |
|
13 |
/**
|
14 |
-
* File Import Exception Class
|
15 |
*
|
16 |
-
* @package Minify\Exception
|
17 |
* @author Matthias Mullie <minify@mullie.eu>
|
18 |
*/
|
19 |
class FileImportException extends BasicException
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* File Import Exception.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
9 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
10 |
* @license MIT License
|
11 |
*/
|
12 |
+
|
13 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
14 |
|
15 |
/**
|
16 |
+
* File Import Exception Class.
|
17 |
*
|
|
|
18 |
* @author Matthias Mullie <minify@mullie.eu>
|
19 |
*/
|
20 |
class FileImportException extends BasicException
|
libs/matthiasmullie/minify/src/Exceptions/IOException.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* IO Exception
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -8,12 +9,12 @@
|
|
8 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
* @license MIT License
|
10 |
*/
|
|
|
11 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
12 |
|
13 |
/**
|
14 |
-
* IO Exception Class
|
15 |
*
|
16 |
-
* @package Minify\Exception
|
17 |
* @author Matthias Mullie <minify@mullie.eu>
|
18 |
*/
|
19 |
class IOException extends BasicException
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* IO Exception.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
9 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
10 |
* @license MIT License
|
11 |
*/
|
12 |
+
|
13 |
namespace FVM\MatthiasMullie\Minify\Exceptions;
|
14 |
|
15 |
/**
|
16 |
+
* IO Exception Class.
|
17 |
*
|
|
|
18 |
* @author Matthias Mullie <minify@mullie.eu>
|
19 |
*/
|
20 |
class IOException extends BasicException
|
libs/matthiasmullie/minify/src/JS.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* JavaScript minifier
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -8,14 +9,14 @@
|
|
8 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
* @license MIT License
|
10 |
*/
|
|
|
11 |
namespace FVM\MatthiasMullie\Minify;
|
12 |
|
13 |
/**
|
14 |
-
* JavaScript Minifier Class
|
15 |
*
|
16 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
17 |
*
|
18 |
-
* @package Minify
|
19 |
* @author Matthias Mullie <minify@mullie.eu>
|
20 |
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
21 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
@@ -29,6 +30,8 @@ class JS extends Minify
|
|
29 |
* Note that regular expressions using that bit must have the PCRE_UTF8
|
30 |
* pattern modifier (/u) set.
|
31 |
*
|
|
|
|
|
32 |
* @var string
|
33 |
*/
|
34 |
const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
|
@@ -124,16 +127,16 @@ class JS extends Minify
|
|
124 |
*/
|
125 |
public function __construct()
|
126 |
{
|
127 |
-
call_user_func_array(array('
|
128 |
|
129 |
-
$dataDir = __DIR__.'/../data/js/';
|
130 |
$options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
|
131 |
-
$this->keywordsReserved = file($dataDir.'keywords_reserved.txt', $options);
|
132 |
-
$this->keywordsBefore = file($dataDir.'keywords_before.txt', $options);
|
133 |
-
$this->keywordsAfter = file($dataDir.'keywords_after.txt', $options);
|
134 |
-
$this->operators = file($dataDir.'operators.txt', $options);
|
135 |
-
$this->operatorsBefore = file($dataDir.'operators_before.txt', $options);
|
136 |
-
$this->operatorsAfter = file($dataDir.'operators_after.txt', $options);
|
137 |
}
|
138 |
|
139 |
/**
|
@@ -174,7 +177,7 @@ class JS extends Minify
|
|
174 |
$js = $this->stripWhitespace($js);
|
175 |
|
176 |
// combine js: separating the scripts by a ;
|
177 |
-
$content .= $js.
|
178 |
}
|
179 |
|
180 |
// clean up leftover `;`s from the combination of multiple scripts
|
@@ -198,15 +201,25 @@ class JS extends Minify
|
|
198 |
// PHP only supports $this inside anonymous functions since 5.4
|
199 |
$minifier = $this;
|
200 |
$callback = function ($match) use ($minifier) {
|
201 |
-
|
202 |
-
|
203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
-
return $
|
206 |
};
|
|
|
207 |
// multi-line comments
|
208 |
-
$this->registerPattern('
|
209 |
-
$this->registerPattern('/\/\*.*?\*\//s', '');
|
210 |
|
211 |
// single-line comments
|
212 |
$this->registerPattern('/\/\/.*$/m', '');
|
@@ -235,7 +248,7 @@ class JS extends Minify
|
|
235 |
$minifier = $this;
|
236 |
$callback = function ($match) use ($minifier) {
|
237 |
$count = count($minifier->extracted);
|
238 |
-
$placeholder = '"'
|
239 |
$minifier->extracted[$placeholder] = $match[0];
|
240 |
|
241 |
return $placeholder;
|
@@ -254,7 +267,7 @@ class JS extends Minify
|
|
254 |
// of the RegExp methods (a `\` followed by a variable or value is
|
255 |
// likely part of a division, not a regex)
|
256 |
$keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof');
|
257 |
-
$before = '([
|
258 |
$propertiesAndMethods = array(
|
259 |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
|
260 |
'constructor',
|
@@ -274,8 +287,8 @@ class JS extends Minify
|
|
274 |
);
|
275 |
$delimiters = array_fill(0, count($propertiesAndMethods), '/');
|
276 |
$propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
|
277 |
-
$after = '(?=\s*([
|
278 |
-
$this->registerPattern('/'
|
279 |
|
280 |
// regular expressions following a `)` are rather annoying to detect...
|
281 |
// quite often, `/` after `)` is a division operator & if it happens to
|
@@ -289,8 +302,8 @@ class JS extends Minify
|
|
289 |
// if a regex following `)` is not followed by `.<property or method>`,
|
290 |
// it's quite likely not a regex
|
291 |
$before = '\)\s*';
|
292 |
-
$after = '(?=\s*\.('.implode('|', $propertiesAndMethods).'))';
|
293 |
-
$this->registerPattern('/'
|
294 |
|
295 |
// 1 more edge case: a regex can be followed by a lot more operators or
|
296 |
// keywords if there's a newline (ASI) in between, where the operator
|
@@ -298,8 +311,8 @@ class JS extends Minify
|
|
298 |
// (https://github.com/matthiasmullie/minify/issues/56)
|
299 |
$operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
|
300 |
$operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
|
301 |
-
$after = '(?=\s*\n\s*('.implode('|', $operators).'))';
|
302 |
-
$this->registerPattern('/'
|
303 |
}
|
304 |
|
305 |
/**
|
@@ -343,8 +356,8 @@ class JS extends Minify
|
|
343 |
unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
|
344 |
$content = preg_replace(
|
345 |
array(
|
346 |
-
'/('.implode('|', $operatorsBefore).')\s+/',
|
347 |
-
'/\s+('.implode('|', $operatorsAfter).')/',
|
348 |
),
|
349 |
'\\1',
|
350 |
$content
|
@@ -361,8 +374,8 @@ class JS extends Minify
|
|
361 |
);
|
362 |
|
363 |
// collapse whitespace around reserved words into single space
|
364 |
-
$content = preg_replace('/(^|[;\}\s])\K('.implode('|', $keywordsBefore).')\s+/', '\\2 ', $content);
|
365 |
-
$content = preg_replace('/\s+('.implode('|', $keywordsAfter).')(?=([;\{\s]|$))/', ' \\1', $content);
|
366 |
|
367 |
/*
|
368 |
* We didn't strip whitespace after a couple of operators because they
|
@@ -372,8 +385,8 @@ class JS extends Minify
|
|
372 |
*/
|
373 |
$operatorsDiffBefore = array_diff($operators, $operatorsBefore);
|
374 |
$operatorsDiffAfter = array_diff($operators, $operatorsAfter);
|
375 |
-
$content = preg_replace('/('.implode('|', $operatorsDiffBefore).')[^\S\n]+/', '\\1', $content);
|
376 |
-
$content = preg_replace('/[^\S\n]+('.implode('|', $operatorsDiffAfter).')/', '\\1', $content);
|
377 |
|
378 |
/*
|
379 |
* Whitespace after `return` can be omitted in a few occasions
|
@@ -405,9 +418,26 @@ class JS extends Minify
|
|
405 |
* to be the for-loop's body... Same goes for while loops.
|
406 |
* I'm going to double that semicolon (if any) so after the next line,
|
407 |
* which strips semicolons here & there, we're still left with this one.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
*/
|
409 |
-
$content = preg_replace('/(for\([^;\{]
|
|
|
|
|
|
|
410 |
$content = preg_replace('/(for\([^;\{]+\s+in\s+[^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
/*
|
412 |
* Below will also keep `;` after a `do{}while();` along with `while();`
|
413 |
* While these could be stripped after do-while, detecting this
|
@@ -465,7 +495,7 @@ class JS extends Minify
|
|
465 |
|
466 |
// don't confuse = with other assignment shortcuts (e.g. +=)
|
467 |
$chars = preg_quote('+-*\=<>%&|', $delimiter);
|
468 |
-
$operators['='] = '(?<!['
|
469 |
|
470 |
return $operators;
|
471 |
}
|
@@ -487,7 +517,7 @@ class JS extends Minify
|
|
487 |
|
488 |
// add word boundaries
|
489 |
array_walk($keywords, function ($value) {
|
490 |
-
return '\b'
|
491 |
});
|
492 |
|
493 |
$keywords = array_combine($keywords, $escaped);
|
@@ -524,11 +554,11 @@ class JS extends Minify
|
|
524 |
* array['key-here'] can't be replaced by array.key-here since '-'
|
525 |
* is not a valid character there.
|
526 |
*/
|
527 |
-
if (!preg_match('/^'
|
528 |
return $match[0];
|
529 |
}
|
530 |
|
531 |
-
return '.'
|
532 |
};
|
533 |
|
534 |
/*
|
@@ -549,9 +579,9 @@ class JS extends Minify
|
|
549 |
* separate look-behind assertions, one for each keyword.
|
550 |
*/
|
551 |
$keywords = $this->getKeywordsForRegex($keywords);
|
552 |
-
$keywords = '(?<!'.implode(')(?<!', $keywords).')';
|
553 |
|
554 |
-
return preg_replace_callback('/(?<='
|
555 |
}
|
556 |
|
557 |
/**
|
@@ -575,7 +605,7 @@ class JS extends Minify
|
|
575 |
return $match[0];
|
576 |
}
|
577 |
|
578 |
-
return $match[1].($match[2] === 'true' ? '!0' : '!1');
|
579 |
};
|
580 |
$content = preg_replace_callback('/(^|.\s*)\b(true|false)\b(?!:)/', $callback, $content);
|
581 |
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* JavaScript minifier.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
9 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
10 |
* @license MIT License
|
11 |
*/
|
12 |
+
|
13 |
namespace FVM\MatthiasMullie\Minify;
|
14 |
|
15 |
/**
|
16 |
+
* JavaScript Minifier Class.
|
17 |
*
|
18 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
19 |
*
|
|
|
20 |
* @author Matthias Mullie <minify@mullie.eu>
|
21 |
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
22 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
30 |
* Note that regular expressions using that bit must have the PCRE_UTF8
|
31 |
* pattern modifier (/u) set.
|
32 |
*
|
33 |
+
* @internal
|
34 |
+
*
|
35 |
* @var string
|
36 |
*/
|
37 |
const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
|
127 |
*/
|
128 |
public function __construct()
|
129 |
{
|
130 |
+
call_user_func_array(array('\\FVM\\MatthiasMullie\Minify\\Minify', '__construct'), func_get_args());
|
131 |
|
132 |
+
$dataDir = __DIR__ . '/../data/js/';
|
133 |
$options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
|
134 |
+
$this->keywordsReserved = file($dataDir . 'keywords_reserved.txt', $options);
|
135 |
+
$this->keywordsBefore = file($dataDir . 'keywords_before.txt', $options);
|
136 |
+
$this->keywordsAfter = file($dataDir . 'keywords_after.txt', $options);
|
137 |
+
$this->operators = file($dataDir . 'operators.txt', $options);
|
138 |
+
$this->operatorsBefore = file($dataDir . 'operators_before.txt', $options);
|
139 |
+
$this->operatorsAfter = file($dataDir . 'operators_after.txt', $options);
|
140 |
}
|
141 |
|
142 |
/**
|
177 |
$js = $this->stripWhitespace($js);
|
178 |
|
179 |
// combine js: separating the scripts by a ;
|
180 |
+
$content .= $js . ';';
|
181 |
}
|
182 |
|
183 |
// clean up leftover `;`s from the combination of multiple scripts
|
201 |
// PHP only supports $this inside anonymous functions since 5.4
|
202 |
$minifier = $this;
|
203 |
$callback = function ($match) use ($minifier) {
|
204 |
+
if (
|
205 |
+
substr($match[2], 0, 1) === '!' ||
|
206 |
+
strpos($match[2], '@license') !== false ||
|
207 |
+
strpos($match[2], '@preserve') !== false
|
208 |
+
) {
|
209 |
+
// preserve multi-line comments that start with /*!
|
210 |
+
// or contain @license or @preserve annotations
|
211 |
+
$count = count($minifier->extracted);
|
212 |
+
$placeholder = '/*' . $count . '*/';
|
213 |
+
$minifier->extracted[$placeholder] = $match[0];
|
214 |
+
|
215 |
+
return $match[1] . $placeholder . $match[3];
|
216 |
+
}
|
217 |
|
218 |
+
return $match[1] . $match[3];
|
219 |
};
|
220 |
+
|
221 |
// multi-line comments
|
222 |
+
$this->registerPattern('/(\n?)\/\*(.*?)\*\/(\n?)/s', $callback);
|
|
|
223 |
|
224 |
// single-line comments
|
225 |
$this->registerPattern('/\/\/.*$/m', '');
|
248 |
$minifier = $this;
|
249 |
$callback = function ($match) use ($minifier) {
|
250 |
$count = count($minifier->extracted);
|
251 |
+
$placeholder = '"' . $count . '"';
|
252 |
$minifier->extracted[$placeholder] = $match[0];
|
253 |
|
254 |
return $placeholder;
|
267 |
// of the RegExp methods (a `\` followed by a variable or value is
|
268 |
// likely part of a division, not a regex)
|
269 |
$keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof');
|
270 |
+
$before = '(^|[=:,;\+\-\*\?\/\}\(\{\[&\|!]|' . implode('|', $keywords) . ')\s*';
|
271 |
$propertiesAndMethods = array(
|
272 |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
|
273 |
'constructor',
|
287 |
);
|
288 |
$delimiters = array_fill(0, count($propertiesAndMethods), '/');
|
289 |
$propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
|
290 |
+
$after = '(?=\s*([\.,;:\)\}&\|+]|\/\/|$|\.(' . implode('|', $propertiesAndMethods) . ')))';
|
291 |
+
$this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
|
292 |
|
293 |
// regular expressions following a `)` are rather annoying to detect...
|
294 |
// quite often, `/` after `)` is a division operator & if it happens to
|
302 |
// if a regex following `)` is not followed by `.<property or method>`,
|
303 |
// it's quite likely not a regex
|
304 |
$before = '\)\s*';
|
305 |
+
$after = '(?=\s*\.(' . implode('|', $propertiesAndMethods) . '))';
|
306 |
+
$this->registerPattern('/' . $before . '\K' . $pattern . $after . '/', $callback);
|
307 |
|
308 |
// 1 more edge case: a regex can be followed by a lot more operators or
|
309 |
// keywords if there's a newline (ASI) in between, where the operator
|
311 |
// (https://github.com/matthiasmullie/minify/issues/56)
|
312 |
$operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
|
313 |
$operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
|
314 |
+
$after = '(?=\s*\n\s*(' . implode('|', $operators) . '))';
|
315 |
+
$this->registerPattern('/' . $pattern . $after . '/', $callback);
|
316 |
}
|
317 |
|
318 |
/**
|
356 |
unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
|
357 |
$content = preg_replace(
|
358 |
array(
|
359 |
+
'/(' . implode('|', $operatorsBefore) . ')\s+/',
|
360 |
+
'/\s+(' . implode('|', $operatorsAfter) . ')/',
|
361 |
),
|
362 |
'\\1',
|
363 |
$content
|
374 |
);
|
375 |
|
376 |
// collapse whitespace around reserved words into single space
|
377 |
+
$content = preg_replace('/(^|[;\}\s])\K(' . implode('|', $keywordsBefore) . ')\s+/', '\\2 ', $content);
|
378 |
+
$content = preg_replace('/\s+(' . implode('|', $keywordsAfter) . ')(?=([;\{\s]|$))/', ' \\1', $content);
|
379 |
|
380 |
/*
|
381 |
* We didn't strip whitespace after a couple of operators because they
|
385 |
*/
|
386 |
$operatorsDiffBefore = array_diff($operators, $operatorsBefore);
|
387 |
$operatorsDiffAfter = array_diff($operators, $operatorsAfter);
|
388 |
+
$content = preg_replace('/(' . implode('|', $operatorsDiffBefore) . ')[^\S\n]+/', '\\1', $content);
|
389 |
+
$content = preg_replace('/[^\S\n]+(' . implode('|', $operatorsDiffAfter) . ')/', '\\1', $content);
|
390 |
|
391 |
/*
|
392 |
* Whitespace after `return` can be omitted in a few occasions
|
418 |
* to be the for-loop's body... Same goes for while loops.
|
419 |
* I'm going to double that semicolon (if any) so after the next line,
|
420 |
* which strips semicolons here & there, we're still left with this one.
|
421 |
+
* Note the special recursive construct in the three inner parts of the for:
|
422 |
+
* (\{([^\{\}]*(?-2))*[^\{\}]*\})? - it is intended to match inline
|
423 |
+
* functions bodies, e.g.: i<arr.map(function(e){return e}).length.
|
424 |
+
* Also note that the construct is applied only once and multiplied
|
425 |
+
* for each part of the for, otherwise it risks a catastrophic backtracking.
|
426 |
+
* The limitation is that it will not allow closures in more than one
|
427 |
+
* of the three parts for a specific for() case.
|
428 |
+
* REGEX throwing catastrophic backtracking: $content = preg_replace('/(for\([^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*;[^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*;[^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*\));(\}|$)/s', '\\1;;\\8', $content);
|
429 |
*/
|
430 |
+
$content = preg_replace('/(for\((?:[^;\{]*|[^;\{]*function[^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*);[^;\{]*;[^;\{]*\));(\}|$)/s', '\\1;;\\4', $content);
|
431 |
+
$content = preg_replace('/(for\([^;\{]*;(?:[^;\{]*|[^;\{]*function[^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*);[^;\{]*\));(\}|$)/s', '\\1;;\\4', $content);
|
432 |
+
$content = preg_replace('/(for\([^;\{]*;[^;\{]*;(?:[^;\{]*|[^;\{]*function[^;\{]*(\{([^\{\}]*(?-2))*[^\{\}]*\})?[^;\{]*)\));(\}|$)/s', '\\1;;\\4', $content);
|
433 |
+
|
434 |
$content = preg_replace('/(for\([^;\{]+\s+in\s+[^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);
|
435 |
+
|
436 |
+
/*
|
437 |
+
* Do the same for the if's that don't have a body but are followed by ;}
|
438 |
+
*/
|
439 |
+
$content = preg_replace('/(\bif\s*\([^{;]*\));\}/s', '\\1;;}', $content);
|
440 |
+
|
441 |
/*
|
442 |
* Below will also keep `;` after a `do{}while();` along with `while();`
|
443 |
* While these could be stripped after do-while, detecting this
|
495 |
|
496 |
// don't confuse = with other assignment shortcuts (e.g. +=)
|
497 |
$chars = preg_quote('+-*\=<>%&|', $delimiter);
|
498 |
+
$operators['='] = '(?<![' . $chars . '])\=';
|
499 |
|
500 |
return $operators;
|
501 |
}
|
517 |
|
518 |
// add word boundaries
|
519 |
array_walk($keywords, function ($value) {
|
520 |
+
return '\b' . $value . '\b';
|
521 |
});
|
522 |
|
523 |
$keywords = array_combine($keywords, $escaped);
|
554 |
* array['key-here'] can't be replaced by array.key-here since '-'
|
555 |
* is not a valid character there.
|
556 |
*/
|
557 |
+
if (!preg_match('/^' . $minifier::REGEX_VARIABLE . '$/u', $property)) {
|
558 |
return $match[0];
|
559 |
}
|
560 |
|
561 |
+
return '.' . $property;
|
562 |
};
|
563 |
|
564 |
/*
|
579 |
* separate look-behind assertions, one for each keyword.
|
580 |
*/
|
581 |
$keywords = $this->getKeywordsForRegex($keywords);
|
582 |
+
$keywords = '(?<!' . implode(')(?<!', $keywords) . ')';
|
583 |
|
584 |
+
return preg_replace_callback('/(?<=' . $previousChar . '|\])' . $keywords . '\[\s*(([\'"])[0-9]+\\2)\s*\]/u', $callback, $content);
|
585 |
}
|
586 |
|
587 |
/**
|
605 |
return $match[0];
|
606 |
}
|
607 |
|
608 |
+
return $match[1] . ($match[2] === 'true' ? '!0' : '!1');
|
609 |
};
|
610 |
$content = preg_replace_callback('/(^|.\s*)\b(true|false)\b(?!:)/', $callback, $content);
|
611 |
|
libs/matthiasmullie/minify/src/Minify.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
|
|
2 |
/**
|
3 |
-
* Abstract minifier class
|
4 |
*
|
5 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
*
|
@@ -8,6 +9,7 @@
|
|
8 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
* @license MIT License
|
10 |
*/
|
|
|
11 |
namespace FVM\MatthiasMullie\Minify;
|
12 |
|
13 |
use FVM\MatthiasMullie\Minify\Exceptions\IOException;
|
@@ -18,7 +20,6 @@ use Psr\Cache\CacheItemInterface;
|
|
18 |
*
|
19 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
20 |
*
|
21 |
-
* @package Minify
|
22 |
* @author Matthias Mullie <minify@mullie.eu>
|
23 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
24 |
* @license MIT License
|
@@ -44,6 +45,8 @@ abstract class Minify
|
|
44 |
* been extracted from the JS source code, so we can reliably match "code",
|
45 |
* without having to worry about potential "code-like" characters inside.
|
46 |
*
|
|
|
|
|
47 |
* @var string[]
|
48 |
*/
|
49 |
public $extracted = array();
|
@@ -105,7 +108,7 @@ abstract class Minify
|
|
105 |
* @param string|string[] $data
|
106 |
*
|
107 |
* @return static
|
108 |
-
*
|
109 |
* @throws IOException
|
110 |
*/
|
111 |
public function addFile($data /* $data = null, ... */)
|
@@ -128,7 +131,7 @@ abstract class Minify
|
|
128 |
|
129 |
// check if we can read the file
|
130 |
if (!$this->canImportFile($path)) {
|
131 |
-
throw new IOException('The file "'
|
132 |
}
|
133 |
|
134 |
$this->add($path);
|
@@ -243,6 +246,9 @@ abstract class Minify
|
|
243 |
/**
|
244 |
* Register a pattern to execute against the source content.
|
245 |
*
|
|
|
|
|
|
|
246 |
* @param string $pattern PCRE pattern
|
247 |
* @param string|callable $replacement Replacement value for matched pattern
|
248 |
*/
|
@@ -268,11 +274,13 @@ abstract class Minify
|
|
268 |
*/
|
269 |
protected function replace($content)
|
270 |
{
|
271 |
-
$
|
|
|
|
|
272 |
$positions = array_fill(0, count($this->patterns), -1);
|
273 |
$matches = array();
|
274 |
|
275 |
-
while ($
|
276 |
// find first match for all patterns
|
277 |
foreach ($this->patterns as $i => $pattern) {
|
278 |
list($pattern, $replacement) = $pattern;
|
@@ -285,12 +293,12 @@ abstract class Minify
|
|
285 |
|
286 |
// no need to re-run matches that are still in the part of the
|
287 |
// content that hasn't been processed
|
288 |
-
if ($positions[$i] >=
|
289 |
continue;
|
290 |
}
|
291 |
|
292 |
$match = null;
|
293 |
-
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) {
|
294 |
$matches[$i] = $match;
|
295 |
|
296 |
// we'll store the match position as well; that way, we
|
@@ -307,61 +315,53 @@ abstract class Minify
|
|
307 |
|
308 |
// no more matches to find: everything's been processed, break out
|
309 |
if (!$matches) {
|
310 |
-
|
|
|
311 |
break;
|
312 |
}
|
313 |
|
314 |
// see which of the patterns actually found the first thing (we'll
|
315 |
// only want to execute that one, since we're unsure if what the
|
316 |
// other found was not inside what the first found)
|
317 |
-
$
|
318 |
-
$firstPattern = array_search($
|
319 |
-
$match = $matches[$firstPattern]
|
320 |
|
321 |
// execute the pattern that matches earliest in the content string
|
322 |
-
list(
|
323 |
-
|
324 |
-
|
325 |
-
//
|
326 |
-
|
327 |
-
|
328 |
-
$
|
329 |
-
|
330 |
-
|
331 |
-
// again match batch of patterns against
|
332 |
-
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
|
333 |
-
$content = $unmatched;
|
334 |
-
|
335 |
-
// first match has been replaced & that content is to be left alone,
|
336 |
-
// the next matches will start after this replacement, so we should
|
337 |
-
// fix their offsets
|
338 |
-
foreach ($positions as $i => $position) {
|
339 |
-
$positions[$i] -= $discardLength + strlen($match);
|
340 |
-
}
|
341 |
}
|
342 |
|
343 |
-
return $
|
344 |
}
|
345 |
|
346 |
/**
|
347 |
-
*
|
348 |
-
*
|
349 |
-
* This function will be called plenty of times, where $content will always
|
350 |
-
* move up 1 character.
|
351 |
*
|
352 |
-
* @param string $pattern Pattern to match
|
353 |
* @param string|callable $replacement Replacement value
|
354 |
-
* @param
|
355 |
*
|
356 |
* @return string
|
357 |
*/
|
358 |
-
protected function
|
359 |
{
|
360 |
-
if (is_callable($replacement)) {
|
361 |
-
return
|
362 |
-
}
|
363 |
-
|
|
|
|
|
364 |
}
|
|
|
|
|
365 |
}
|
366 |
|
367 |
/**
|
@@ -395,8 +395,8 @@ abstract class Minify
|
|
395 |
}
|
396 |
|
397 |
$count = count($minifier->extracted);
|
398 |
-
$placeholder = $match[1]
|
399 |
-
$minifier->extracted[$placeholder] = $match[1]
|
400 |
|
401 |
return $placeholder;
|
402 |
};
|
@@ -413,7 +413,7 @@ abstract class Minify
|
|
413 |
* considered as escape-char (times 2) and to get it in the regex,
|
414 |
* escaped (times 2)
|
415 |
*/
|
416 |
-
$this->registerPattern('/(['
|
417 |
}
|
418 |
|
419 |
/**
|
@@ -472,8 +472,8 @@ abstract class Minify
|
|
472 |
*/
|
473 |
protected function openFileForWriting($path)
|
474 |
{
|
475 |
-
if (($handler = @fopen($path, 'w')) === false) {
|
476 |
-
throw new IOException('The file "'
|
477 |
}
|
478 |
|
479 |
return $handler;
|
@@ -490,8 +490,22 @@ abstract class Minify
|
|
490 |
*/
|
491 |
protected function writeToFile($handler, $content, $path = '')
|
492 |
{
|
493 |
-
if (
|
494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
495 |
}
|
|
|
|
|
496 |
}
|
497 |
}
|
1 |
<?php
|
2 |
+
|
3 |
/**
|
4 |
+
* Abstract minifier class.
|
5 |
*
|
6 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
7 |
*
|
9 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
10 |
* @license MIT License
|
11 |
*/
|
12 |
+
|
13 |
namespace FVM\MatthiasMullie\Minify;
|
14 |
|
15 |
use FVM\MatthiasMullie\Minify\Exceptions\IOException;
|
20 |
*
|
21 |
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
22 |
*
|
|
|
23 |
* @author Matthias Mullie <minify@mullie.eu>
|
24 |
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
25 |
* @license MIT License
|
45 |
* been extracted from the JS source code, so we can reliably match "code",
|
46 |
* without having to worry about potential "code-like" characters inside.
|
47 |
*
|
48 |
+
* @internal
|
49 |
+
*
|
50 |
* @var string[]
|
51 |
*/
|
52 |
public $extracted = array();
|
108 |
* @param string|string[] $data
|
109 |
*
|
110 |
* @return static
|
111 |
+
*
|
112 |
* @throws IOException
|
113 |
*/
|
114 |
public function addFile($data /* $data = null, ... */)
|
131 |
|
132 |
// check if we can read the file
|
133 |
if (!$this->canImportFile($path)) {
|
134 |
+
throw new IOException('The file "' . $path . '" could not be opened for reading. Check if PHP has enough permissions.');
|
135 |
}
|
136 |
|
137 |
$this->add($path);
|
246 |
/**
|
247 |
* Register a pattern to execute against the source content.
|
248 |
*
|
249 |
+
* If $replacement is a string, it must be plain text. Placeholders like $1 or \2 don't work.
|
250 |
+
* If you need that functionality, use a callback instead.
|
251 |
+
*
|
252 |
* @param string $pattern PCRE pattern
|
253 |
* @param string|callable $replacement Replacement value for matched pattern
|
254 |
*/
|
274 |
*/
|
275 |
protected function replace($content)
|
276 |
{
|
277 |
+
$contentLength = strlen($content);
|
278 |
+
$output = '';
|
279 |
+
$processedOffset = 0;
|
280 |
$positions = array_fill(0, count($this->patterns), -1);
|
281 |
$matches = array();
|
282 |
|
283 |
+
while ($processedOffset < $contentLength) {
|
284 |
// find first match for all patterns
|
285 |
foreach ($this->patterns as $i => $pattern) {
|
286 |
list($pattern, $replacement) = $pattern;
|
293 |
|
294 |
// no need to re-run matches that are still in the part of the
|
295 |
// content that hasn't been processed
|
296 |
+
if ($positions[$i] >= $processedOffset) {
|
297 |
continue;
|
298 |
}
|
299 |
|
300 |
$match = null;
|
301 |
+
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) {
|
302 |
$matches[$i] = $match;
|
303 |
|
304 |
// we'll store the match position as well; that way, we
|
315 |
|
316 |
// no more matches to find: everything's been processed, break out
|
317 |
if (!$matches) {
|
318 |
+
// output the remaining content
|
319 |
+
$output .= substr($content, $processedOffset);
|
320 |
break;
|
321 |
}
|
322 |
|
323 |
// see which of the patterns actually found the first thing (we'll
|
324 |
// only want to execute that one, since we're unsure if what the
|
325 |
// other found was not inside what the first found)
|
326 |
+
$matchOffset = min($positions);
|
327 |
+
$firstPattern = array_search($matchOffset, $positions);
|
328 |
+
$match = $matches[$firstPattern];
|
329 |
|
330 |
// execute the pattern that matches earliest in the content string
|
331 |
+
list(, $replacement) = $this->patterns[$firstPattern];
|
332 |
+
|
333 |
+
// add the part of the input between $processedOffset and the first match;
|
334 |
+
// that content wasn't matched by anything
|
335 |
+
$output .= substr($content, $processedOffset, $matchOffset - $processedOffset);
|
336 |
+
// add the replacement for the match
|
337 |
+
$output .= $this->executeReplacement($replacement, $match);
|
338 |
+
// advance $processedOffset past the match
|
339 |
+
$processedOffset = $matchOffset + strlen($match[0][0]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
}
|
341 |
|
342 |
+
return $output;
|
343 |
}
|
344 |
|
345 |
/**
|
346 |
+
* If $replacement is a callback, execute it, passing in the match data.
|
347 |
+
* If it's a string, just pass it through.
|
|
|
|
|
348 |
*
|
|
|
349 |
* @param string|callable $replacement Replacement value
|
350 |
+
* @param array $match Match data, in PREG_OFFSET_CAPTURE form
|
351 |
*
|
352 |
* @return string
|
353 |
*/
|
354 |
+
protected function executeReplacement($replacement, $match)
|
355 |
{
|
356 |
+
if (!is_callable($replacement)) {
|
357 |
+
return $replacement;
|
358 |
+
}
|
359 |
+
// convert $match from the PREG_OFFSET_CAPTURE form to the form the callback expects
|
360 |
+
foreach ($match as &$matchItem) {
|
361 |
+
$matchItem = $matchItem[0];
|
362 |
}
|
363 |
+
|
364 |
+
return $replacement($match);
|
365 |
}
|
366 |
|
367 |
/**
|
395 |
}
|
396 |
|
397 |
$count = count($minifier->extracted);
|
398 |
+
$placeholder = $match[1] . $placeholderPrefix . $count . $match[1];
|
399 |
+
$minifier->extracted[$placeholder] = $match[1] . $match[2] . $match[1];
|
400 |
|
401 |
return $placeholder;
|
402 |
};
|
413 |
* considered as escape-char (times 2) and to get it in the regex,
|
414 |
* escaped (times 2)
|
415 |
*/
|
416 |
+
$this->registerPattern('/([' . $chars . '])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
|
417 |
}
|
418 |
|
419 |
/**
|
472 |
*/
|
473 |
protected function openFileForWriting($path)
|
474 |
{
|
475 |
+
if ($path === '' || ($handler = @fopen($path, 'w')) === false) {
|
476 |
+
throw new IOException('The file "' . $path . '" could not be opened for writing. Check if PHP has enough permissions.');
|
477 |
}
|
478 |
|
479 |
return $handler;
|
490 |
*/
|
491 |
protected function writeToFile($handler, $content, $path = '')
|
492 |
{
|
493 |
+
if (
|
494 |
+
!is_resource($handler) ||
|
495 |
+
($result = @fwrite($handler, $content)) === false ||
|
496 |
+
($result < strlen($content))
|
497 |
+
) {
|
498 |
+
throw new IOException('The file "' . $path . '" could not be written to. Check your disk space and file permissions.');
|
499 |
+
}
|
500 |
+
}
|
501 |
+
|
502 |
+
protected static function str_replace_first($search, $replace, $subject)
|
503 |
+
{
|
504 |
+
$pos = strpos($subject, $search);
|
505 |
+
if ($pos !== false) {
|
506 |
+
return substr_replace($subject, $replace, $pos, strlen($search));
|
507 |
}
|
508 |
+
|
509 |
+
return $subject;
|
510 |
}
|
511 |
}
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: Alignak
|
|
3 |
Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, Merging, Minification, Optimization, Speed, Performance, FVM
|
4 |
Requires at least: 5.0
|
5 |
Requires PHP: 7.0
|
6 |
-
Stable tag: 3.3.
|
7 |
-
Tested up to: 6.
|
8 |
Text Domain: fast-velocity-minify
|
9 |
License: GPLv3 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
@@ -32,7 +32,7 @@ I can offer you additional `custom made` optimization on top of this plugin. If
|
|
32 |
* Purge all caches on the entire network (linux): `wp site list --field=url | xargs -n1 -I % wp --url=% fvm purge`
|
33 |
|
34 |
= How to customize the cache path ? =
|
35 |
-
You need a public directory to store and serve minified cache files. If you need to customize the path and url, you need to edit your `wp-config.php` and add both `define('
|
36 |
|
37 |
|
38 |
== Installation ==
|
@@ -49,6 +49,16 @@ You need a public directory to store and serve minified cache files. If you need
|
|
49 |
|
50 |
== Changelog ==
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
= 3.3.1 [2022.10.06] =
|
53 |
* bug fix
|
54 |
|
3 |
Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, Merging, Minification, Optimization, Speed, Performance, FVM
|
4 |
Requires at least: 5.0
|
5 |
Requires PHP: 7.0
|
6 |
+
Stable tag: 3.3.3
|
7 |
+
Tested up to: 6.1.3
|
8 |
Text Domain: fast-velocity-minify
|
9 |
License: GPLv3 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
32 |
* Purge all caches on the entire network (linux): `wp site list --field=url | xargs -n1 -I % wp --url=% fvm purge`
|
33 |
|
34 |
= How to customize the cache path ? =
|
35 |
+
You need a public directory to store and serve minified cache files. If you need to customize the path and url, you need to edit your `wp-config.php` and add both `define('FVM_CACHE_DIR', '/absolute/path/to/example.com/your/public/directory');` and `define('FVM_CACHE_URL', 'https://example.com/your/public/directory');` .
|
36 |
|
37 |
|
38 |
== Installation ==
|
49 |
|
50 |
== Changelog ==
|
51 |
|
52 |
+
= 3.3.3 [2022.12.11] =
|
53 |
+
* custom cache directory fixes
|
54 |
+
* upgraded matthiasmullie's PHP Minify to 1.3.70
|
55 |
+
* move the viewport meta tag up, before preloading tags
|
56 |
+
|
57 |
+
= 3.3.2 [2022.10.07] =
|
58 |
+
* improved compatibility with WP Links and All in One SEO
|
59 |
+
* additional constant for custom initialization
|
60 |
+
* better output buffer processor
|
61 |
+
|
62 |
= 3.3.1 [2022.10.06] =
|
63 |
* bug fix
|
64 |
|