Version Description
[2020.02.06] = * updated PHP Minify with full support for PHP 7.4 * added try, catch wrappers for merged javacript files with console log errors (instead of letting the browser stop execution on error) * improved compatibility with windows servers * improved compatibility for font paths with some themes
Download this release
Release Info
Developer | Alignak |
Plugin | Fast Velocity Minify |
Version | 2.7.8 |
Comparing to | |
See all releases |
Code changes from version 2.7.4 to 2.7.8
- fvm.php +32 -18
- inc/functions-cache.php +26 -13
- inc/functions.php +12 -2
- libs/matthiasmullie/minify/bin/minifycss +45 -45
- libs/matthiasmullie/minify/bin/minifyjs +45 -45
- libs/matthiasmullie/minify/data/js/keywords_after.txt +6 -6
- libs/matthiasmullie/minify/data/js/keywords_before.txt +25 -25
- libs/matthiasmullie/minify/data/js/keywords_reserved.txt +62 -62
- libs/matthiasmullie/minify/data/js/operators.txt +45 -45
- libs/matthiasmullie/minify/data/js/operators_after.txt +42 -42
- libs/matthiasmullie/minify/data/js/operators_before.txt +43 -43
- libs/matthiasmullie/minify/src/CSS.php +751 -736
- libs/matthiasmullie/minify/src/Exception.php +20 -20
- libs/matthiasmullie/minify/src/Exceptions/BasicException.php +23 -23
- libs/matthiasmullie/minify/src/Exceptions/FileImportException.php +21 -21
- libs/matthiasmullie/minify/src/Exceptions/IOException.php +21 -21
- libs/matthiasmullie/minify/src/JS.php +612 -598
- libs/matthiasmullie/minify/src/Minify.php +459 -459
- libs/matthiasmullie/path-converter/src/Converter.php +196 -196
- libs/matthiasmullie/path-converter/src/ConverterInterface.php +24 -24
- libs/matthiasmullie/path-converter/src/NoConverter.php +23 -23
- readme.txt +22 -296
fvm.php
CHANGED
@@ -5,7 +5,7 @@ Plugin URI: http://fastvelocity.com
|
|
5 |
Description: Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS and JavaScript files into groups, compressing HTML and other speed optimizations.
|
6 |
Author: Raul Peixoto
|
7 |
Author URI: http://fastvelocity.com
|
8 |
-
Version: 2.7.
|
9 |
License: GPL2
|
10 |
|
11 |
------------------------------------------------------------------------
|
@@ -303,7 +303,7 @@ function fastvelocity_admintoolbar() {
|
|
303 |
|
304 |
# function to list all cache files
|
305 |
function fastvelocity_min_files_callback() {
|
306 |
-
|
307 |
# must be able to cleanup cache
|
308 |
if (!current_user_can('manage_options')) {
|
309 |
wp_die( __('You do not have sufficient permissions to access this page.'));
|
@@ -317,9 +317,9 @@ function fastvelocity_min_files_callback() {
|
|
317 |
|
318 |
# inspect directory with opendir, since glob might not be available in some systems
|
319 |
clearstatcache();
|
320 |
-
if ($handle = opendir($cachedir.
|
321 |
while (false !== ($file = readdir($handle))) {
|
322 |
-
$file = $cachedir.
|
323 |
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
324 |
if (in_array($ext, array('js', 'css'))) {
|
325 |
$log = ''; if (file_exists($file.'.txt')) { $log = file_get_contents($file.'.txt'); }
|
@@ -1302,7 +1302,7 @@ for($i=0,$l=count($header);$i<$l;$i++) {
|
|
1302 |
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']));
|
1303 |
|
1304 |
# create cache files and urls
|
1305 |
-
$file = $cachedir.
|
1306 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');
|
1307 |
|
1308 |
# generate a new cache file
|
@@ -1346,16 +1346,23 @@ for($i=0,$l=count($header);$i<$l;$i++) {
|
|
1346 |
continue;
|
1347 |
}
|
1348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1349 |
# append code to merged file
|
1350 |
-
$code.= $res['code'];
|
1351 |
$log.= $res['log'];
|
1352 |
|
1353 |
-
# Add extra data from wp_add_inline_script
|
1354 |
if (!empty( $wp_scripts->registered[$handle]->extra)) {
|
1355 |
-
if (!empty( $wp_scripts->registered[$handle]->extra['
|
1356 |
-
$code.= PHP_EOL . implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['
|
1357 |
}
|
1358 |
-
}
|
1359 |
|
1360 |
# consider dependencies on handles with an empty src
|
1361 |
} else {
|
@@ -1496,7 +1503,7 @@ for($i=0,$l=count($footer);$i<$l;$i++) {
|
|
1496 |
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']));
|
1497 |
|
1498 |
# create cache files and urls
|
1499 |
-
$file = $cachedir.
|
1500 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');
|
1501 |
|
1502 |
# generate a new cache file
|
@@ -1541,14 +1548,21 @@ for($i=0,$l=count($footer);$i<$l;$i++) {
|
|
1541 |
continue;
|
1542 |
}
|
1543 |
|
1544 |
-
# append code to merged file
|
1545 |
-
$code.= $res['code'];
|
1546 |
-
$log.= $res['log'];
|
1547 |
-
|
1548 |
# Add extra data from wp_add_inline_script before
|
1549 |
if (!empty($wp_scripts->registered[$handle]->extra)){
|
1550 |
if (!empty($wp_scripts->registered[$handle]->extra['before'])){
|
1551 |
-
$code.= PHP_EOL.implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['before']);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1552 |
}
|
1553 |
}
|
1554 |
|
@@ -1976,7 +1990,7 @@ for($i=0,$l=count($header);$i<$l;$i++) {
|
|
1976 |
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']).$inline_css_hash);
|
1977 |
|
1978 |
# create cache files and urls
|
1979 |
-
$file = $cachedir.
|
1980 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css');
|
1981 |
|
1982 |
# generate a new cache file
|
@@ -2366,7 +2380,7 @@ for($i=0,$l=count($footer);$i<$l;$i++) {
|
|
2366 |
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']).$inline_css_hash);
|
2367 |
|
2368 |
# create cache files and urls
|
2369 |
-
$file = $cachedir.
|
2370 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css');
|
2371 |
|
2372 |
# generate a new cache file
|
5 |
Description: Improve your speed score on GTmetrix, Pingdom Tools and Google PageSpeed Insights by merging and minifying CSS and JavaScript files into groups, compressing HTML and other speed optimizations.
|
6 |
Author: Raul Peixoto
|
7 |
Author URI: http://fastvelocity.com
|
8 |
+
Version: 2.7.8
|
9 |
License: GPL2
|
10 |
|
11 |
------------------------------------------------------------------------
|
303 |
|
304 |
# function to list all cache files
|
305 |
function fastvelocity_min_files_callback() {
|
306 |
+
|
307 |
# must be able to cleanup cache
|
308 |
if (!current_user_can('manage_options')) {
|
309 |
wp_die( __('You do not have sufficient permissions to access this page.'));
|
317 |
|
318 |
# inspect directory with opendir, since glob might not be available in some systems
|
319 |
clearstatcache();
|
320 |
+
if ($handle = opendir($cachedir.fastvelocity_get_os_slash())) {
|
321 |
while (false !== ($file = readdir($handle))) {
|
322 |
+
$file = $cachedir.fastvelocity_get_os_slash().$file;
|
323 |
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
324 |
if (in_array($ext, array('js', 'css'))) {
|
325 |
$log = ''; if (file_exists($file.'.txt')) { $log = file_get_contents($file.'.txt'); }
|
1302 |
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']));
|
1303 |
|
1304 |
# create cache files and urls
|
1305 |
+
$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.js';
|
1306 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');
|
1307 |
|
1308 |
# generate a new cache file
|
1346 |
continue;
|
1347 |
}
|
1348 |
|
1349 |
+
# Add extra data from wp_add_inline_script before
|
1350 |
+
if (!empty( $wp_scripts->registered[$handle]->extra)) {
|
1351 |
+
if (!empty( $wp_scripts->registered[$handle]->extra['before'])){
|
1352 |
+
$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['before']));
|
1353 |
+
}
|
1354 |
+
}
|
1355 |
+
|
1356 |
# append code to merged file
|
1357 |
+
$code.= fastvelocity_try_catch_wrap($res['code']);
|
1358 |
$log.= $res['log'];
|
1359 |
|
1360 |
+
# Add extra data from wp_add_inline_script after
|
1361 |
if (!empty( $wp_scripts->registered[$handle]->extra)) {
|
1362 |
+
if (!empty( $wp_scripts->registered[$handle]->extra['after'])){
|
1363 |
+
$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['after']));
|
1364 |
}
|
1365 |
+
}
|
1366 |
|
1367 |
# consider dependencies on handles with an empty src
|
1368 |
} else {
|
1503 |
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']));
|
1504 |
|
1505 |
# create cache files and urls
|
1506 |
+
$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.js';
|
1507 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.js');
|
1508 |
|
1509 |
# generate a new cache file
|
1548 |
continue;
|
1549 |
}
|
1550 |
|
|
|
|
|
|
|
|
|
1551 |
# Add extra data from wp_add_inline_script before
|
1552 |
if (!empty($wp_scripts->registered[$handle]->extra)){
|
1553 |
if (!empty($wp_scripts->registered[$handle]->extra['before'])){
|
1554 |
+
$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['before']));
|
1555 |
+
}
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
# append code to merged file
|
1559 |
+
$code.= fastvelocity_try_catch_wrap($res['code']);
|
1560 |
+
$log.= $res['log'];
|
1561 |
+
|
1562 |
+
# Add extra data from wp_add_inline_script after
|
1563 |
+
if (!empty($wp_scripts->registered[$handle]->extra)){
|
1564 |
+
if (!empty($wp_scripts->registered[$handle]->extra['after'])){
|
1565 |
+
$code.= PHP_EOL . fastvelocity_try_catch_wrap(implode(PHP_EOL, $wp_scripts->registered[$handle]->extra['after']));
|
1566 |
}
|
1567 |
}
|
1568 |
|
1990 |
$hash = 'header-'.hash('adler32',implode('',$header[$i]['handles']).$inline_css_hash);
|
1991 |
|
1992 |
# create cache files and urls
|
1993 |
+
$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.css';
|
1994 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css');
|
1995 |
|
1996 |
# generate a new cache file
|
2380 |
$hash = 'footer-'.hash('adler32',implode('',$footer[$i]['handles']).$inline_css_hash);
|
2381 |
|
2382 |
# create cache files and urls
|
2383 |
+
$file = $cachedir.fastvelocity_get_os_slash().$hash.'.min.css';
|
2384 |
$file_url = fvm_get_protocol($cachedirurl.'/'.$hash.'.min.css');
|
2385 |
|
2386 |
# generate a new cache file
|
inc/functions-cache.php
CHANGED
@@ -1,6 +1,19 @@
|
|
1 |
<?php
|
2 |
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
# Fix the permission bits on generated files
|
5 |
function fastvelocity_fix_permission_bits($file){
|
6 |
if(function_exists('stat') && fvm_function_available('stat')) {
|
@@ -23,7 +36,7 @@ function fastvelocity_fix_permission_bits($file){
|
|
23 |
if ($perms != ($perms & ~umask())){
|
24 |
$folder_parts = explode( '/', substr( $file, strlen(dirname($file)) + 1 ) );
|
25 |
for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
|
26 |
-
@chmod(dirname($file) .
|
27 |
}
|
28 |
}
|
29 |
}
|
@@ -36,8 +49,8 @@ function fastvelocity_fix_permission_bits($file){
|
|
36 |
function fvm_cachepath() {
|
37 |
|
38 |
# custom directory
|
39 |
-
$fvm_change_cache_path = trim(rtrim(get_option('fastvelocity_min_change_cache_path', ''),
|
40 |
-
$fvm_change_cache_base = trim(rtrim(get_option('fastvelocity_min_change_cache_base_url', ''),
|
41 |
$upload = array();
|
42 |
|
43 |
if(strlen($fvm_change_cache_path) > 1 && strlen($fvm_change_cache_base) > 10 && is_dir($fvm_change_cache_path) && is_writable($fvm_change_cache_path)) {
|
@@ -53,13 +66,13 @@ if(strlen($fvm_change_cache_path) > 1 && strlen($fvm_change_cache_base) > 10 &&
|
|
53 |
$ctime = get_option('fvm-last-cache-update', '0');
|
54 |
|
55 |
# create
|
56 |
-
$uploadsdir = str_ireplace('cache
|
57 |
$uploadsurl = str_ireplace('cache/cache', 'cache', $upload['baseurl'].'/cache');
|
58 |
-
$cachebase = $uploadsdir.'
|
59 |
$cachebaseurl = $uploadsurl.'/fvm/'.$ctime;
|
60 |
-
$cachedir = $cachebase.'
|
61 |
-
$tmpdir = $cachebase.'
|
62 |
-
$headerdir = $cachebase.'
|
63 |
$cachedirurl = $cachebaseurl.'/out';
|
64 |
|
65 |
# get permissions from uploads directory
|
@@ -74,9 +87,9 @@ foreach ($dirs as $target) {
|
|
74 |
if(!is_dir($target)) {
|
75 |
if (@mkdir($target, $dir_perms, true)){
|
76 |
if ($dir_perms != ($dir_perms & ~umask())){
|
77 |
-
$folder_parts = explode(
|
78 |
for ($i = 1, $c = count($folder_parts ); $i <= $c; $i++){
|
79 |
-
@chmod(dirname($target) .
|
80 |
}
|
81 |
}
|
82 |
} else {
|
@@ -141,7 +154,7 @@ function fvm_purge_old() {
|
|
141 |
while (false !== ($d = readdir($handle))) {
|
142 |
if (strcmp($d, '.')==0 || strcmp($d, '..')==0) { continue; }
|
143 |
if($d != $ctime && (is_numeric($d) && $d <= $expires)) {
|
144 |
-
$dir = $cachebaseparent.
|
145 |
if(is_dir($dir)) {
|
146 |
fastvelocity_rrmdir($dir);
|
147 |
if(is_dir($dir)) { @rmdir($dir); }
|
@@ -177,7 +190,7 @@ function fastvelocity_purge_all_global() {
|
|
177 |
function fvm_get_transient($key) {
|
178 |
$cachepath = fvm_cachepath();
|
179 |
$tmpdir = $cachepath['tmpdir'];
|
180 |
-
$f = $tmpdir.
|
181 |
clearstatcache();
|
182 |
if(file_exists($f)) {
|
183 |
return file_get_contents($f);
|
@@ -191,7 +204,7 @@ function fvm_set_transient($key, $code) {
|
|
191 |
if(is_null($code) || empty($code)) { return false; }
|
192 |
$cachepath = fvm_cachepath();
|
193 |
$tmpdir = $cachepath['tmpdir'];
|
194 |
-
$f = $tmpdir.
|
195 |
file_put_contents($f, $code);
|
196 |
fastvelocity_fix_permission_bits($f);
|
197 |
return true;
|
1 |
<?php
|
2 |
|
3 |
|
4 |
+
# get windows or unix slashes
|
5 |
+
function fastvelocity_get_os_slash() {
|
6 |
+
|
7 |
+
if(fvm_server_is_windows() === false) {
|
8 |
+
$slash = '/'; # unix
|
9 |
+
} else {
|
10 |
+
$slash = '\\'; # windows
|
11 |
+
}
|
12 |
+
|
13 |
+
return $slash;
|
14 |
+
}
|
15 |
+
|
16 |
+
|
17 |
# Fix the permission bits on generated files
|
18 |
function fastvelocity_fix_permission_bits($file){
|
19 |
if(function_exists('stat') && fvm_function_available('stat')) {
|
36 |
if ($perms != ($perms & ~umask())){
|
37 |
$folder_parts = explode( '/', substr( $file, strlen(dirname($file)) + 1 ) );
|
38 |
for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
|
39 |
+
@chmod(dirname($file) . fastvelocity_get_os_slash() . implode( fastvelocity_get_os_slash(), array_slice( $folder_parts, 0, $i ) ), $perms );
|
40 |
}
|
41 |
}
|
42 |
}
|
49 |
function fvm_cachepath() {
|
50 |
|
51 |
# custom directory
|
52 |
+
$fvm_change_cache_path = trim(rtrim(get_option('fastvelocity_min_change_cache_path', ''), fastvelocity_get_os_slash()));
|
53 |
+
$fvm_change_cache_base = trim(rtrim(get_option('fastvelocity_min_change_cache_base_url', ''), fastvelocity_get_os_slash()));
|
54 |
$upload = array();
|
55 |
|
56 |
if(strlen($fvm_change_cache_path) > 1 && strlen($fvm_change_cache_base) > 10 && is_dir($fvm_change_cache_path) && is_writable($fvm_change_cache_path)) {
|
66 |
$ctime = get_option('fvm-last-cache-update', '0');
|
67 |
|
68 |
# create
|
69 |
+
$uploadsdir = str_ireplace('cache'.fastvelocity_get_os_slash().'cache', 'cache', $upload['basedir'].fastvelocity_get_os_slash().'cache');
|
70 |
$uploadsurl = str_ireplace('cache/cache', 'cache', $upload['baseurl'].'/cache');
|
71 |
+
$cachebase = $uploadsdir.fastvelocity_get_os_slash().'fvm'.fastvelocity_get_os_slash().$ctime;
|
72 |
$cachebaseurl = $uploadsurl.'/fvm/'.$ctime;
|
73 |
+
$cachedir = $cachebase.fastvelocity_get_os_slash().'out';
|
74 |
+
$tmpdir = $cachebase.fastvelocity_get_os_slash().'tmp';
|
75 |
+
$headerdir = $cachebase.fastvelocity_get_os_slash().'header';
|
76 |
$cachedirurl = $cachebaseurl.'/out';
|
77 |
|
78 |
# get permissions from uploads directory
|
87 |
if(!is_dir($target)) {
|
88 |
if (@mkdir($target, $dir_perms, true)){
|
89 |
if ($dir_perms != ($dir_perms & ~umask())){
|
90 |
+
$folder_parts = explode( fastvelocity_get_os_slash(), substr($target, strlen(dirname($target)) + 1 ));
|
91 |
for ($i = 1, $c = count($folder_parts ); $i <= $c; $i++){
|
92 |
+
@chmod(dirname($target) . fastvelocity_get_os_slash() . implode( fastvelocity_get_os_slash(), array_slice( $folder_parts, 0, $i ) ), $dir_perms );
|
93 |
}
|
94 |
}
|
95 |
} else {
|
154 |
while (false !== ($d = readdir($handle))) {
|
155 |
if (strcmp($d, '.')==0 || strcmp($d, '..')==0) { continue; }
|
156 |
if($d != $ctime && (is_numeric($d) && $d <= $expires)) {
|
157 |
+
$dir = $cachebaseparent.fastvelocity_get_os_slash().$d;
|
158 |
if(is_dir($dir)) {
|
159 |
fastvelocity_rrmdir($dir);
|
160 |
if(is_dir($dir)) { @rmdir($dir); }
|
190 |
function fvm_get_transient($key) {
|
191 |
$cachepath = fvm_cachepath();
|
192 |
$tmpdir = $cachepath['tmpdir'];
|
193 |
+
$f = $tmpdir.fastvelocity_get_os_slash().$key.'.transient';
|
194 |
clearstatcache();
|
195 |
if(file_exists($f)) {
|
196 |
return file_get_contents($f);
|
204 |
if(is_null($code) || empty($code)) { return false; }
|
205 |
$cachepath = fvm_cachepath();
|
206 |
$tmpdir = $cachepath['tmpdir'];
|
207 |
+
$f = $tmpdir.fastvelocity_get_os_slash().$key.'.transient';
|
208 |
file_put_contents($f, $code);
|
209 |
fastvelocity_fix_permission_bits($f);
|
210 |
return true;
|
inc/functions.php
CHANGED
@@ -110,6 +110,11 @@ function fastvelocity_plugin_uninstall() {
|
|
110 |
}
|
111 |
|
112 |
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
# detect external or internal scripts
|
115 |
function fvm_is_local_domain($src) {
|
@@ -351,9 +356,14 @@ global $wp_domain, $fvm_debug;
|
|
351 |
$css = fastvelocity_min_remove_utf8_bom($css);
|
352 |
|
353 |
# fix url paths
|
354 |
-
if(!empty($url)) {
|
|
|
|
|
355 |
$css = preg_replace("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"])(.+?)['\"]?\s*\)/ui", "url(".dirname($url)."/$1)", $css);
|
356 |
-
}
|
|
|
|
|
|
|
357 |
|
358 |
# remove query strings from fonts (for better seo, but add a small cache buster based on most recent updates)
|
359 |
$ctime = get_option('fvm-last-cache-update', '0'); # last update or zero
|
110 |
}
|
111 |
|
112 |
|
113 |
+
# try catch wrapper for merged javascript
|
114 |
+
function fastvelocity_try_catch_wrap($js) {
|
115 |
+
return 'try{'.PHP_EOL . $js . PHP_EOL . '}' . PHP_EOL . 'catch(e){console.error("An error has occurred: "+e.message);}'.PHP_EOL;
|
116 |
+
}
|
117 |
+
|
118 |
|
119 |
# detect external or internal scripts
|
120 |
function fvm_is_local_domain($src) {
|
356 |
$css = fastvelocity_min_remove_utf8_bom($css);
|
357 |
|
358 |
# fix url paths
|
359 |
+
if(!empty($url)) {
|
360 |
+
$matches = array(); preg_match_all("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"])(.+?)['\"]?\s*\)/ui", $css, $matches);
|
361 |
+
foreach($matches[1] as $a) { $b = trim($a); if($b != $a) { $css = str_replace($a, $b, $css); } }
|
362 |
$css = preg_replace("/url\(\s*['\"]?(?!data:)(?!http)(?![\/'\"])(.+?)['\"]?\s*\)/ui", "url(".dirname($url)."/$1)", $css);
|
363 |
+
}
|
364 |
+
|
365 |
+
# no utf8 garbage
|
366 |
+
$css = str_ireplace('@charset "UTF-8";', '', $css);
|
367 |
|
368 |
# remove query strings from fonts (for better seo, but add a small cache buster based on most recent updates)
|
369 |
$ctime = get_option('fvm-last-cache-update', '0'); # last update or zero
|
libs/matthiasmullie/minify/bin/minifycss
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
#!/usr/bin/env php
|
2 |
-
<?php
|
3 |
-
use MatthiasMullie\Minify;
|
4 |
-
|
5 |
-
// command line utility to minify CSS
|
6 |
-
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
-
// if composer install
|
8 |
-
require_once __DIR__ . '/../../../autoload.php';
|
9 |
-
} else {
|
10 |
-
require_once __DIR__ . '/../src/Minify.php';
|
11 |
-
require_once __DIR__ . '/../src/CSS.php';
|
12 |
-
require_once __DIR__ . '/../src/Exception.php';
|
13 |
-
}
|
14 |
-
|
15 |
-
error_reporting(E_ALL);
|
16 |
-
// check PHP setup for cli arguments
|
17 |
-
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
-
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
-
exit(1);
|
20 |
-
} elseif (!isset($argv)) {
|
21 |
-
$argv = $_SERVER['argv'];
|
22 |
-
}
|
23 |
-
// check if path to file given
|
24 |
-
if (!isset($argv[1])) {
|
25 |
-
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
-
exit(1);
|
27 |
-
}
|
28 |
-
// check if script run in cli environment
|
29 |
-
if ('cli' !== php_sapi_name()) {
|
30 |
-
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
-
exit(1);
|
32 |
-
}
|
33 |
-
// check if source file exists
|
34 |
-
if (!file_exists($argv[1])) {
|
35 |
-
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
-
exit(1);
|
37 |
-
}
|
38 |
-
|
39 |
-
try {
|
40 |
-
$minifier = new Minify\CSS($argv[1]);
|
41 |
-
echo $minifier->minify();
|
42 |
-
} catch (Exception $e) {
|
43 |
-
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
-
exit(1);
|
45 |
-
}
|
1 |
+
#!/usr/bin/env php
|
2 |
+
<?php
|
3 |
+
use MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
// command line utility to minify CSS
|
6 |
+
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
+
// if composer install
|
8 |
+
require_once __DIR__ . '/../../../autoload.php';
|
9 |
+
} else {
|
10 |
+
require_once __DIR__ . '/../src/Minify.php';
|
11 |
+
require_once __DIR__ . '/../src/CSS.php';
|
12 |
+
require_once __DIR__ . '/../src/Exception.php';
|
13 |
+
}
|
14 |
+
|
15 |
+
error_reporting(E_ALL);
|
16 |
+
// check PHP setup for cli arguments
|
17 |
+
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
+
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
+
exit(1);
|
20 |
+
} elseif (!isset($argv)) {
|
21 |
+
$argv = $_SERVER['argv'];
|
22 |
+
}
|
23 |
+
// check if path to file given
|
24 |
+
if (!isset($argv[1])) {
|
25 |
+
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
+
exit(1);
|
27 |
+
}
|
28 |
+
// check if script run in cli environment
|
29 |
+
if ('cli' !== php_sapi_name()) {
|
30 |
+
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
+
exit(1);
|
32 |
+
}
|
33 |
+
// check if source file exists
|
34 |
+
if (!file_exists($argv[1])) {
|
35 |
+
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
+
exit(1);
|
37 |
+
}
|
38 |
+
|
39 |
+
try {
|
40 |
+
$minifier = new Minify\CSS($argv[1]);
|
41 |
+
echo $minifier->minify();
|
42 |
+
} catch (Exception $e) {
|
43 |
+
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
+
exit(1);
|
45 |
+
}
|
libs/matthiasmullie/minify/bin/minifyjs
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
#!/usr/bin/env php
|
2 |
-
<?php
|
3 |
-
use MatthiasMullie\Minify;
|
4 |
-
|
5 |
-
// command line utility to minify JS
|
6 |
-
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
-
// if composer install
|
8 |
-
require_once __DIR__ . '/../../../autoload.php';
|
9 |
-
} else {
|
10 |
-
require_once __DIR__ . '/../src/Minify.php';
|
11 |
-
require_once __DIR__ . '/../src/JS.php';
|
12 |
-
require_once __DIR__ . '/../src/Exception.php';
|
13 |
-
}
|
14 |
-
|
15 |
-
error_reporting(E_ALL);
|
16 |
-
// check PHP setup for cli arguments
|
17 |
-
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
-
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
-
exit(1);
|
20 |
-
} elseif (!isset($argv)) {
|
21 |
-
$argv = $_SERVER['argv'];
|
22 |
-
}
|
23 |
-
// check if path to file given
|
24 |
-
if (!isset($argv[1])) {
|
25 |
-
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
-
exit(1);
|
27 |
-
}
|
28 |
-
// check if script run in cli environment
|
29 |
-
if ('cli' !== php_sapi_name()) {
|
30 |
-
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
-
exit(1);
|
32 |
-
}
|
33 |
-
// check if source file exists
|
34 |
-
if (!file_exists($argv[1])) {
|
35 |
-
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
-
exit(1);
|
37 |
-
}
|
38 |
-
|
39 |
-
try {
|
40 |
-
$minifier = new Minify\JS($argv[1]);
|
41 |
-
echo $minifier->minify();
|
42 |
-
} catch (Exception $e) {
|
43 |
-
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
-
exit(1);
|
45 |
-
}
|
1 |
+
#!/usr/bin/env php
|
2 |
+
<?php
|
3 |
+
use MatthiasMullie\Minify;
|
4 |
+
|
5 |
+
// command line utility to minify JS
|
6 |
+
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
7 |
+
// if composer install
|
8 |
+
require_once __DIR__ . '/../../../autoload.php';
|
9 |
+
} else {
|
10 |
+
require_once __DIR__ . '/../src/Minify.php';
|
11 |
+
require_once __DIR__ . '/../src/JS.php';
|
12 |
+
require_once __DIR__ . '/../src/Exception.php';
|
13 |
+
}
|
14 |
+
|
15 |
+
error_reporting(E_ALL);
|
16 |
+
// check PHP setup for cli arguments
|
17 |
+
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
18 |
+
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
19 |
+
exit(1);
|
20 |
+
} elseif (!isset($argv)) {
|
21 |
+
$argv = $_SERVER['argv'];
|
22 |
+
}
|
23 |
+
// check if path to file given
|
24 |
+
if (!isset($argv[1])) {
|
25 |
+
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
26 |
+
exit(1);
|
27 |
+
}
|
28 |
+
// check if script run in cli environment
|
29 |
+
if ('cli' !== php_sapi_name()) {
|
30 |
+
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
31 |
+
exit(1);
|
32 |
+
}
|
33 |
+
// check if source file exists
|
34 |
+
if (!file_exists($argv[1])) {
|
35 |
+
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
36 |
+
exit(1);
|
37 |
+
}
|
38 |
+
|
39 |
+
try {
|
40 |
+
$minifier = new Minify\JS($argv[1]);
|
41 |
+
echo $minifier->minify();
|
42 |
+
} catch (Exception $e) {
|
43 |
+
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
44 |
+
exit(1);
|
45 |
+
}
|
libs/matthiasmullie/minify/data/js/keywords_after.txt
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
-
in
|
2 |
-
public
|
3 |
-
extends
|
4 |
-
private
|
5 |
-
protected
|
6 |
-
implements
|
7 |
instanceof
|
1 |
+
in
|
2 |
+
public
|
3 |
+
extends
|
4 |
+
private
|
5 |
+
protected
|
6 |
+
implements
|
7 |
instanceof
|
libs/matthiasmullie/minify/data/js/keywords_before.txt
CHANGED
@@ -1,26 +1,26 @@
|
|
1 |
-
do
|
2 |
-
in
|
3 |
-
let
|
4 |
-
new
|
5 |
-
var
|
6 |
-
case
|
7 |
-
else
|
8 |
-
enum
|
9 |
-
void
|
10 |
-
with
|
11 |
-
class
|
12 |
-
const
|
13 |
-
yield
|
14 |
-
delete
|
15 |
-
export
|
16 |
-
import
|
17 |
-
public
|
18 |
-
static
|
19 |
-
typeof
|
20 |
-
extends
|
21 |
-
package
|
22 |
-
private
|
23 |
-
function
|
24 |
-
protected
|
25 |
-
implements
|
26 |
instanceof
|
1 |
+
do
|
2 |
+
in
|
3 |
+
let
|
4 |
+
new
|
5 |
+
var
|
6 |
+
case
|
7 |
+
else
|
8 |
+
enum
|
9 |
+
void
|
10 |
+
with
|
11 |
+
class
|
12 |
+
const
|
13 |
+
yield
|
14 |
+
delete
|
15 |
+
export
|
16 |
+
import
|
17 |
+
public
|
18 |
+
static
|
19 |
+
typeof
|
20 |
+
extends
|
21 |
+
package
|
22 |
+
private
|
23 |
+
function
|
24 |
+
protected
|
25 |
+
implements
|
26 |
instanceof
|
libs/matthiasmullie/minify/data/js/keywords_reserved.txt
CHANGED
@@ -1,63 +1,63 @@
|
|
1 |
-
do
|
2 |
-
if
|
3 |
-
in
|
4 |
-
for
|
5 |
-
let
|
6 |
-
new
|
7 |
-
try
|
8 |
-
var
|
9 |
-
case
|
10 |
-
else
|
11 |
-
enum
|
12 |
-
eval
|
13 |
-
null
|
14 |
-
this
|
15 |
-
true
|
16 |
-
void
|
17 |
-
with
|
18 |
-
break
|
19 |
-
catch
|
20 |
-
class
|
21 |
-
const
|
22 |
-
false
|
23 |
-
super
|
24 |
-
throw
|
25 |
-
while
|
26 |
-
yield
|
27 |
-
delete
|
28 |
-
export
|
29 |
-
import
|
30 |
-
public
|
31 |
-
return
|
32 |
-
static
|
33 |
-
switch
|
34 |
-
typeof
|
35 |
-
default
|
36 |
-
extends
|
37 |
-
finally
|
38 |
-
package
|
39 |
-
private
|
40 |
-
continue
|
41 |
-
debugger
|
42 |
-
function
|
43 |
-
arguments
|
44 |
-
interface
|
45 |
-
protected
|
46 |
-
implements
|
47 |
-
instanceof
|
48 |
-
abstract
|
49 |
-
boolean
|
50 |
-
byte
|
51 |
-
char
|
52 |
-
double
|
53 |
-
final
|
54 |
-
float
|
55 |
-
goto
|
56 |
-
int
|
57 |
-
long
|
58 |
-
native
|
59 |
-
short
|
60 |
-
synchronized
|
61 |
-
throws
|
62 |
-
transient
|
63 |
volatile
|
1 |
+
do
|
2 |
+
if
|
3 |
+
in
|
4 |
+
for
|
5 |
+
let
|
6 |
+
new
|
7 |
+
try
|
8 |
+
var
|
9 |
+
case
|
10 |
+
else
|
11 |
+
enum
|
12 |
+
eval
|
13 |
+
null
|
14 |
+
this
|
15 |
+
true
|
16 |
+
void
|
17 |
+
with
|
18 |
+
break
|
19 |
+
catch
|
20 |
+
class
|
21 |
+
const
|
22 |
+
false
|
23 |
+
super
|
24 |
+
throw
|
25 |
+
while
|
26 |
+
yield
|
27 |
+
delete
|
28 |
+
export
|
29 |
+
import
|
30 |
+
public
|
31 |
+
return
|
32 |
+
static
|
33 |
+
switch
|
34 |
+
typeof
|
35 |
+
default
|
36 |
+
extends
|
37 |
+
finally
|
38 |
+
package
|
39 |
+
private
|
40 |
+
continue
|
41 |
+
debugger
|
42 |
+
function
|
43 |
+
arguments
|
44 |
+
interface
|
45 |
+
protected
|
46 |
+
implements
|
47 |
+
instanceof
|
48 |
+
abstract
|
49 |
+
boolean
|
50 |
+
byte
|
51 |
+
char
|
52 |
+
double
|
53 |
+
final
|
54 |
+
float
|
55 |
+
goto
|
56 |
+
int
|
57 |
+
long
|
58 |
+
native
|
59 |
+
short
|
60 |
+
synchronized
|
61 |
+
throws
|
62 |
+
transient
|
63 |
volatile
|
libs/matthiasmullie/minify/data/js/operators.txt
CHANGED
@@ -1,46 +1,46 @@
|
|
1 |
-
+
|
2 |
-
-
|
3 |
-
*
|
4 |
-
/
|
5 |
-
%
|
6 |
-
=
|
7 |
-
+=
|
8 |
-
-=
|
9 |
-
*=
|
10 |
-
/=
|
11 |
-
%=
|
12 |
-
<<=
|
13 |
-
>>=
|
14 |
-
>>>=
|
15 |
-
&=
|
16 |
-
^=
|
17 |
-
|=
|
18 |
-
&
|
19 |
-
|
|
20 |
-
^
|
21 |
-
~
|
22 |
-
<<
|
23 |
-
>>
|
24 |
-
>>>
|
25 |
-
==
|
26 |
-
===
|
27 |
-
!=
|
28 |
-
!==
|
29 |
-
>
|
30 |
-
<
|
31 |
-
>=
|
32 |
-
<=
|
33 |
-
&&
|
34 |
-
||
|
35 |
-
!
|
36 |
-
.
|
37 |
-
[
|
38 |
-
]
|
39 |
-
?
|
40 |
-
:
|
41 |
-
,
|
42 |
-
;
|
43 |
-
(
|
44 |
-
)
|
45 |
-
{
|
46 |
}
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
!
|
36 |
+
.
|
37 |
+
[
|
38 |
+
]
|
39 |
+
?
|
40 |
+
:
|
41 |
+
,
|
42 |
+
;
|
43 |
+
(
|
44 |
+
)
|
45 |
+
{
|
46 |
}
|
libs/matthiasmullie/minify/data/js/operators_after.txt
CHANGED
@@ -1,43 +1,43 @@
|
|
1 |
-
+
|
2 |
-
-
|
3 |
-
*
|
4 |
-
/
|
5 |
-
%
|
6 |
-
=
|
7 |
-
+=
|
8 |
-
-=
|
9 |
-
*=
|
10 |
-
/=
|
11 |
-
%=
|
12 |
-
<<=
|
13 |
-
>>=
|
14 |
-
>>>=
|
15 |
-
&=
|
16 |
-
^=
|
17 |
-
|=
|
18 |
-
&
|
19 |
-
|
|
20 |
-
^
|
21 |
-
<<
|
22 |
-
>>
|
23 |
-
>>>
|
24 |
-
==
|
25 |
-
===
|
26 |
-
!=
|
27 |
-
!==
|
28 |
-
>
|
29 |
-
<
|
30 |
-
>=
|
31 |
-
<=
|
32 |
-
&&
|
33 |
-
||
|
34 |
-
.
|
35 |
-
[
|
36 |
-
]
|
37 |
-
?
|
38 |
-
:
|
39 |
-
,
|
40 |
-
;
|
41 |
-
(
|
42 |
-
)
|
43 |
}
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
<<
|
22 |
+
>>
|
23 |
+
>>>
|
24 |
+
==
|
25 |
+
===
|
26 |
+
!=
|
27 |
+
!==
|
28 |
+
>
|
29 |
+
<
|
30 |
+
>=
|
31 |
+
<=
|
32 |
+
&&
|
33 |
+
||
|
34 |
+
.
|
35 |
+
[
|
36 |
+
]
|
37 |
+
?
|
38 |
+
:
|
39 |
+
,
|
40 |
+
;
|
41 |
+
(
|
42 |
+
)
|
43 |
}
|
libs/matthiasmullie/minify/data/js/operators_before.txt
CHANGED
@@ -1,43 +1,43 @@
|
|
1 |
-
+
|
2 |
-
-
|
3 |
-
*
|
4 |
-
/
|
5 |
-
%
|
6 |
-
=
|
7 |
-
+=
|
8 |
-
-=
|
9 |
-
*=
|
10 |
-
/=
|
11 |
-
%=
|
12 |
-
<<=
|
13 |
-
>>=
|
14 |
-
>>>=
|
15 |
-
&=
|
16 |
-
^=
|
17 |
-
|=
|
18 |
-
&
|
19 |
-
|
|
20 |
-
^
|
21 |
-
~
|
22 |
-
<<
|
23 |
-
>>
|
24 |
-
>>>
|
25 |
-
==
|
26 |
-
===
|
27 |
-
!=
|
28 |
-
!==
|
29 |
-
>
|
30 |
-
<
|
31 |
-
>=
|
32 |
-
<=
|
33 |
-
&&
|
34 |
-
||
|
35 |
-
!
|
36 |
-
.
|
37 |
-
[
|
38 |
-
?
|
39 |
-
:
|
40 |
-
,
|
41 |
-
;
|
42 |
-
(
|
43 |
-
{
|
1 |
+
+
|
2 |
+
-
|
3 |
+
*
|
4 |
+
/
|
5 |
+
%
|
6 |
+
=
|
7 |
+
+=
|
8 |
+
-=
|
9 |
+
*=
|
10 |
+
/=
|
11 |
+
%=
|
12 |
+
<<=
|
13 |
+
>>=
|
14 |
+
>>>=
|
15 |
+
&=
|
16 |
+
^=
|
17 |
+
|=
|
18 |
+
&
|
19 |
+
|
|
20 |
+
^
|
21 |
+
~
|
22 |
+
<<
|
23 |
+
>>
|
24 |
+
>>>
|
25 |
+
==
|
26 |
+
===
|
27 |
+
!=
|
28 |
+
!==
|
29 |
+
>
|
30 |
+
<
|
31 |
+
>=
|
32 |
+
<=
|
33 |
+
&&
|
34 |
+
||
|
35 |
+
!
|
36 |
+
.
|
37 |
+
[
|
38 |
+
?
|
39 |
+
:
|
40 |
+
,
|
41 |
+
;
|
42 |
+
(
|
43 |
+
{
|
libs/matthiasmullie/minify/src/CSS.php
CHANGED
@@ -1,736 +1,751 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* CSS Minifier
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace MatthiasMullie\Minify;
|
13 |
-
|
14 |
-
use MatthiasMullie\Minify\Exceptions\FileImportException;
|
15 |
-
use MatthiasMullie\PathConverter\ConverterInterface;
|
16 |
-
use 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
|
27 |
-
* @license MIT License
|
28 |
-
*/
|
29 |
-
class CSS extends Minify
|
30 |
-
{
|
31 |
-
/**
|
32 |
-
* @var int maximum inport size in kB
|
33 |
-
*/
|
34 |
-
protected $maxImportSize = 5;
|
35 |
-
|
36 |
-
/**
|
37 |
-
* @var string[] valid import extensions
|
38 |
-
*/
|
39 |
-
protected $importExtensions = array(
|
40 |
-
'gif' => 'data:image/gif',
|
41 |
-
'png' => 'data:image/png',
|
42 |
-
'jpe' => 'data:image/jpeg',
|
43 |
-
'jpg' => 'data:image/jpeg',
|
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',
|
50 |
-
);
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Set the maximum size if files to be imported.
|
54 |
-
*
|
55 |
-
* Files larger than this size (in kB) will not be imported into the CSS.
|
56 |
-
* Importing files into the CSS as data-uri will save you some connections,
|
57 |
-
* but we should only import relatively small decorative images so that our
|
58 |
-
* CSS file doesn't get too bulky.
|
59 |
-
*
|
60 |
-
* @param int $size Size in kB
|
61 |
-
*/
|
62 |
-
public function setMaxImportSize($size)
|
63 |
-
{
|
64 |
-
$this->maxImportSize = $size;
|
65 |
-
}
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Set the type of extensions to be imported into the CSS (to save network
|
69 |
-
* connections).
|
70 |
-
* Keys of the array should be the file extensions & respective values
|
71 |
-
* should be the data type.
|
72 |
-
*
|
73 |
-
* @param string[] $extensions Array of file extensions
|
74 |
-
*/
|
75 |
-
public function setImportExtensions(array $extensions)
|
76 |
-
{
|
77 |
-
$this->importExtensions = $extensions;
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Move any import statements to the top.
|
82 |
-
*
|
83 |
-
* @param string $content Nearly finished CSS content
|
84 |
-
*
|
85 |
-
* @return string
|
86 |
-
*/
|
87 |
-
protected function moveImportsToTop($content)
|
88 |
-
{
|
89 |
-
if (preg_match_all('/(;?)(@import (?<url>url\()?(?P<quotes>["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
|
90 |
-
// remove from content
|
91 |
-
foreach ($matches[0] as $import) {
|
92 |
-
$content = str_replace($import, '', $content);
|
93 |
-
}
|
94 |
-
|
95 |
-
// add to top
|
96 |
-
$content = implode(';', $matches[2]).';'.trim($content, ';');
|
97 |
-
}
|
98 |
-
|
99 |
-
return $content;
|
100 |
-
}
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Combine CSS from import statements.
|
104 |
-
*
|
105 |
-
* @import's will be loaded and their content merged into the original file,
|
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
|
110 |
-
* @param string[] $parents Parent paths, for circular reference checks
|
111 |
-
*
|
112 |
-
* @return string
|
113 |
-
*
|
114 |
-
* @throws FileImportException
|
115 |
-
*/
|
116 |
-
protected function combineImports($source, $content, $parents)
|
117 |
-
{
|
118 |
-
$importRegexes = array(
|
119 |
-
// @import url(xxx)
|
120 |
-
'/
|
121 |
-
# import statement
|
122 |
-
@import
|
123 |
-
|
124 |
-
# whitespace
|
125 |
-
\s+
|
126 |
-
|
127 |
-
# open url()
|
128 |
-
url\(
|
129 |
-
|
130 |
-
# (optional) open path enclosure
|
131 |
-
(?P<quotes>["\']?)
|
132 |
-
|
133 |
-
# fetch path
|
134 |
-
(?P<path>.+?)
|
135 |
-
|
136 |
-
# (optional) close path enclosure
|
137 |
-
(?P=quotes)
|
138 |
-
|
139 |
-
# close url()
|
140 |
-
\)
|
141 |
-
|
142 |
-
# (optional) trailing whitespace
|
143 |
-
\s*
|
144 |
-
|
145 |
-
# (optional) media statement(s)
|
146 |
-
(?P<media>[^;]*)
|
147 |
-
|
148 |
-
# (optional) trailing whitespace
|
149 |
-
\s*
|
150 |
-
|
151 |
-
# (optional) closing semi-colon
|
152 |
-
;?
|
153 |
-
|
154 |
-
/ix',
|
155 |
-
|
156 |
-
// @import 'xxx'
|
157 |
-
'/
|
158 |
-
|
159 |
-
# import statement
|
160 |
-
@import
|
161 |
-
|
162 |
-
# whitespace
|
163 |
-
\s+
|
164 |
-
|
165 |
-
# open path enclosure
|
166 |
-
(?P<quotes>["\'])
|
167 |
-
|
168 |
-
# fetch path
|
169 |
-
(?P<path>.+?)
|
170 |
-
|
171 |
-
# close path enclosure
|
172 |
-
(?P=quotes)
|
173 |
-
|
174 |
-
# (optional) trailing whitespace
|
175 |
-
\s*
|
176 |
-
|
177 |
-
# (optional) media statement(s)
|
178 |
-
(?P<media>[^;]*)
|
179 |
-
|
180 |
-
# (optional) trailing whitespace
|
181 |
-
\s*
|
182 |
-
|
183 |
-
# (optional) closing semi-colon
|
184 |
-
;?
|
185 |
-
|
186 |
-
/ix',
|
187 |
-
);
|
188 |
-
|
189 |
-
// find all relative imports in css
|
190 |
-
$matches = array();
|
191 |
-
foreach ($importRegexes as $importRegex) {
|
192 |
-
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
193 |
-
$matches = array_merge($matches, $regexMatches);
|
194 |
-
}
|
195 |
-
}
|
196 |
-
|
197 |
-
$search = array();
|
198 |
-
$replace = array();
|
199 |
-
|
200 |
-
// loop the matches
|
201 |
-
foreach ($matches as $match) {
|
202 |
-
// get the path for the file that will be imported
|
203 |
-
$importPath = dirname($source).'/'.$match['path'];
|
204 |
-
|
205 |
-
// only replace the import with the content if we can grab the
|
206 |
-
// content of the file
|
207 |
-
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
|
208 |
-
continue;
|
209 |
-
}
|
210 |
-
|
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 "'.$importPath.'": circular reference detected.');
|
215 |
-
}
|
216 |
-
|
217 |
-
// grab referenced file & minify it (which may include importing
|
218 |
-
// yet other @import statements recursively)
|
219 |
-
$minifier = new static($importPath);
|
220 |
-
$
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
*
|
240 |
-
*
|
241 |
-
*
|
242 |
-
*
|
243 |
-
*
|
244 |
-
*
|
245 |
-
* @
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
if
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
*
|
289 |
-
*
|
290 |
-
*
|
291 |
-
*
|
292 |
-
* @
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
*
|
304 |
-
*
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
$
|
309 |
-
|
310 |
-
$
|
311 |
-
$css = $this->
|
312 |
-
|
313 |
-
$css = $this->
|
314 |
-
$css = $this->
|
315 |
-
|
316 |
-
|
317 |
-
$css = $this->
|
318 |
-
|
319 |
-
|
320 |
-
$
|
321 |
-
|
322 |
-
$
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
*
|
329 |
-
*
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
$
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
*
|
348 |
-
*
|
349 |
-
*
|
350 |
-
*
|
351 |
-
*
|
352 |
-
* @
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
*
|
361 |
-
*
|
362 |
-
*
|
363 |
-
*
|
364 |
-
*
|
365 |
-
*
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
url
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
'
|
393 |
-
|
394 |
-
@import
|
395 |
-
|
396 |
-
#
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
#
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
$url = $
|
438 |
-
|
439 |
-
//
|
440 |
-
$url
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
* Urls with
|
448 |
-
*
|
449 |
-
*
|
450 |
-
* Urls with
|
451 |
-
*
|
452 |
-
*
|
453 |
-
*
|
454 |
-
*
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
*
|
479 |
-
*
|
480 |
-
*
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
$
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
'#
|
496 |
-
'#
|
497 |
-
'#
|
498 |
-
'#
|
499 |
-
'#
|
500 |
-
'#
|
501 |
-
'#
|
502 |
-
'#
|
503 |
-
'#
|
504 |
-
'#
|
505 |
-
'#
|
506 |
-
'#
|
507 |
-
'#
|
508 |
-
'#
|
509 |
-
'#
|
510 |
-
'#
|
511 |
-
'#
|
512 |
-
'#
|
513 |
-
'#
|
514 |
-
'#
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
'
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
//
|
567 |
-
//
|
568 |
-
// 0
|
569 |
-
//
|
570 |
-
//
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
//
|
576 |
-
//
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
//
|
583 |
-
|
584 |
-
//
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
// strip
|
589 |
-
$content = preg_replace('/'.$before.'
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
//
|
595 |
-
|
596 |
-
|
597 |
-
//
|
598 |
-
$content = preg_replace('/
|
599 |
-
|
600 |
-
|
601 |
-
//
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
*
|
612 |
-
*
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
$
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
//
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
$content = preg_replace('
|
659 |
-
|
660 |
-
// remove
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
$
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
*
|
716 |
-
*
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
*
|
728 |
-
*
|
729 |
-
*
|
730 |
-
*
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* CSS Minifier
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
|
12 |
+
namespace MatthiasMullie\Minify;
|
13 |
+
|
14 |
+
use MatthiasMullie\Minify\Exceptions\FileImportException;
|
15 |
+
use MatthiasMullie\PathConverter\ConverterInterface;
|
16 |
+
use 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
|
27 |
+
* @license MIT License
|
28 |
+
*/
|
29 |
+
class CSS extends Minify
|
30 |
+
{
|
31 |
+
/**
|
32 |
+
* @var int maximum inport size in kB
|
33 |
+
*/
|
34 |
+
protected $maxImportSize = 5;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @var string[] valid import extensions
|
38 |
+
*/
|
39 |
+
protected $importExtensions = array(
|
40 |
+
'gif' => 'data:image/gif',
|
41 |
+
'png' => 'data:image/png',
|
42 |
+
'jpe' => 'data:image/jpeg',
|
43 |
+
'jpg' => 'data:image/jpeg',
|
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',
|
50 |
+
);
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Set the maximum size if files to be imported.
|
54 |
+
*
|
55 |
+
* Files larger than this size (in kB) will not be imported into the CSS.
|
56 |
+
* Importing files into the CSS as data-uri will save you some connections,
|
57 |
+
* but we should only import relatively small decorative images so that our
|
58 |
+
* CSS file doesn't get too bulky.
|
59 |
+
*
|
60 |
+
* @param int $size Size in kB
|
61 |
+
*/
|
62 |
+
public function setMaxImportSize($size)
|
63 |
+
{
|
64 |
+
$this->maxImportSize = $size;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Set the type of extensions to be imported into the CSS (to save network
|
69 |
+
* connections).
|
70 |
+
* Keys of the array should be the file extensions & respective values
|
71 |
+
* should be the data type.
|
72 |
+
*
|
73 |
+
* @param string[] $extensions Array of file extensions
|
74 |
+
*/
|
75 |
+
public function setImportExtensions(array $extensions)
|
76 |
+
{
|
77 |
+
$this->importExtensions = $extensions;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Move any import statements to the top.
|
82 |
+
*
|
83 |
+
* @param string $content Nearly finished CSS content
|
84 |
+
*
|
85 |
+
* @return string
|
86 |
+
*/
|
87 |
+
protected function moveImportsToTop($content)
|
88 |
+
{
|
89 |
+
if (preg_match_all('/(;?)(@import (?<url>url\()?(?P<quotes>["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
|
90 |
+
// remove from content
|
91 |
+
foreach ($matches[0] as $import) {
|
92 |
+
$content = str_replace($import, '', $content);
|
93 |
+
}
|
94 |
+
|
95 |
+
// add to top
|
96 |
+
$content = implode(';', $matches[2]).';'.trim($content, ';');
|
97 |
+
}
|
98 |
+
|
99 |
+
return $content;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Combine CSS from import statements.
|
104 |
+
*
|
105 |
+
* @import's will be loaded and their content merged into the original file,
|
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
|
110 |
+
* @param string[] $parents Parent paths, for circular reference checks
|
111 |
+
*
|
112 |
+
* @return string
|
113 |
+
*
|
114 |
+
* @throws FileImportException
|
115 |
+
*/
|
116 |
+
protected function combineImports($source, $content, $parents)
|
117 |
+
{
|
118 |
+
$importRegexes = array(
|
119 |
+
// @import url(xxx)
|
120 |
+
'/
|
121 |
+
# import statement
|
122 |
+
@import
|
123 |
+
|
124 |
+
# whitespace
|
125 |
+
\s+
|
126 |
+
|
127 |
+
# open url()
|
128 |
+
url\(
|
129 |
+
|
130 |
+
# (optional) open path enclosure
|
131 |
+
(?P<quotes>["\']?)
|
132 |
+
|
133 |
+
# fetch path
|
134 |
+
(?P<path>.+?)
|
135 |
+
|
136 |
+
# (optional) close path enclosure
|
137 |
+
(?P=quotes)
|
138 |
+
|
139 |
+
# close url()
|
140 |
+
\)
|
141 |
+
|
142 |
+
# (optional) trailing whitespace
|
143 |
+
\s*
|
144 |
+
|
145 |
+
# (optional) media statement(s)
|
146 |
+
(?P<media>[^;]*)
|
147 |
+
|
148 |
+
# (optional) trailing whitespace
|
149 |
+
\s*
|
150 |
+
|
151 |
+
# (optional) closing semi-colon
|
152 |
+
;?
|
153 |
+
|
154 |
+
/ix',
|
155 |
+
|
156 |
+
// @import 'xxx'
|
157 |
+
'/
|
158 |
+
|
159 |
+
# import statement
|
160 |
+
@import
|
161 |
+
|
162 |
+
# whitespace
|
163 |
+
\s+
|
164 |
+
|
165 |
+
# open path enclosure
|
166 |
+
(?P<quotes>["\'])
|
167 |
+
|
168 |
+
# fetch path
|
169 |
+
(?P<path>.+?)
|
170 |
+
|
171 |
+
# close path enclosure
|
172 |
+
(?P=quotes)
|
173 |
+
|
174 |
+
# (optional) trailing whitespace
|
175 |
+
\s*
|
176 |
+
|
177 |
+
# (optional) media statement(s)
|
178 |
+
(?P<media>[^;]*)
|
179 |
+
|
180 |
+
# (optional) trailing whitespace
|
181 |
+
\s*
|
182 |
+
|
183 |
+
# (optional) closing semi-colon
|
184 |
+
;?
|
185 |
+
|
186 |
+
/ix',
|
187 |
+
);
|
188 |
+
|
189 |
+
// find all relative imports in css
|
190 |
+
$matches = array();
|
191 |
+
foreach ($importRegexes as $importRegex) {
|
192 |
+
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
193 |
+
$matches = array_merge($matches, $regexMatches);
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
$search = array();
|
198 |
+
$replace = array();
|
199 |
+
|
200 |
+
// loop the matches
|
201 |
+
foreach ($matches as $match) {
|
202 |
+
// get the path for the file that will be imported
|
203 |
+
$importPath = dirname($source).'/'.$match['path'];
|
204 |
+
|
205 |
+
// only replace the import with the content if we can grab the
|
206 |
+
// content of the file
|
207 |
+
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
|
208 |
+
continue;
|
209 |
+
}
|
210 |
+
|
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 "'.$importPath.'": circular reference detected.');
|
215 |
+
}
|
216 |
+
|
217 |
+
// grab referenced file & minify it (which may include importing
|
218 |
+
// yet other @import statements recursively)
|
219 |
+
$minifier = new static($importPath);
|
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 '.$match['media'].'{'.$importContent.'}';
|
227 |
+
}
|
228 |
+
|
229 |
+
// add to replacement array
|
230 |
+
$search[] = $match[0];
|
231 |
+
$replace[] = $importContent;
|
232 |
+
}
|
233 |
+
|
234 |
+
// replace the import statements
|
235 |
+
return str_replace($search, $replace, $content);
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Import files into the CSS, base64-ized.
|
240 |
+
*
|
241 |
+
* @url(image.jpg) images will be loaded and their content merged into the
|
242 |
+
* original file, to save HTTP requests.
|
243 |
+
*
|
244 |
+
* @param string $source The file to import files for
|
245 |
+
* @param string $content The CSS content to import files for
|
246 |
+
*
|
247 |
+
* @return string
|
248 |
+
*/
|
249 |
+
protected function importFiles($source, $content)
|
250 |
+
{
|
251 |
+
$regex = '/url\((["\']?)(.+?)\\1\)/i';
|
252 |
+
if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
|
253 |
+
$search = array();
|
254 |
+
$replace = array();
|
255 |
+
|
256 |
+
// loop the matches
|
257 |
+
foreach ($matches as $match) {
|
258 |
+
$extension = substr(strrchr($match[2], '.'), 1);
|
259 |
+
if ($extension && !array_key_exists($extension, $this->importExtensions)) {
|
260 |
+
continue;
|
261 |
+
}
|
262 |
+
|
263 |
+
// get the path for the file that will be imported
|
264 |
+
$path = $match[2];
|
265 |
+
$path = dirname($source).'/'.$path;
|
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
|
269 |
+
if ($this->canImportFile($path) && $this->canImportBySize($path)) {
|
270 |
+
// grab content && base64-ize
|
271 |
+
$importContent = $this->load($path);
|
272 |
+
$importContent = base64_encode($importContent);
|
273 |
+
|
274 |
+
// build replacement
|
275 |
+
$search[] = $match[0];
|
276 |
+
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
// replace the import statements
|
281 |
+
$content = str_replace($search, $replace, $content);
|
282 |
+
}
|
283 |
+
|
284 |
+
return $content;
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Minify the data.
|
289 |
+
* Perform CSS optimizations.
|
290 |
+
*
|
291 |
+
* @param string[optional] $path Path to write the data to
|
292 |
+
* @param string[] $parents Parent paths, for circular reference checks
|
293 |
+
*
|
294 |
+
* @return string The minified data
|
295 |
+
*/
|
296 |
+
public function execute($path = null, $parents = array())
|
297 |
+
{
|
298 |
+
$content = '';
|
299 |
+
|
300 |
+
// loop CSS data (raw data and files)
|
301 |
+
foreach ($this->data as $source => $css) {
|
302 |
+
/*
|
303 |
+
* Let's first take out strings & comments, since we can't just
|
304 |
+
* remove whitespace anywhere. If whitespace occurs inside a string,
|
305 |
+
* we should leave it alone. E.g.:
|
306 |
+
* p { content: "a test" }
|
307 |
+
*/
|
308 |
+
$this->extractStrings();
|
309 |
+
$this->stripComments();
|
310 |
+
$this->extractCalcs();
|
311 |
+
$css = $this->replace($css);
|
312 |
+
|
313 |
+
$css = $this->stripWhitespace($css);
|
314 |
+
$css = $this->shortenColors($css);
|
315 |
+
$css = $this->shortenZeroes($css);
|
316 |
+
$css = $this->shortenFontWeights($css);
|
317 |
+
$css = $this->stripEmptyTags($css);
|
318 |
+
|
319 |
+
// restore the string we've extracted earlier
|
320 |
+
$css = $this->restoreExtractedData($css);
|
321 |
+
|
322 |
+
$source = is_int($source) ? '' : $source;
|
323 |
+
$parents = $source ? array_merge($parents, array($source)) : $parents;
|
324 |
+
$css = $this->combineImports($source, $css, $parents);
|
325 |
+
$css = $this->importFiles($source, $css);
|
326 |
+
|
327 |
+
/*
|
328 |
+
* If we'll save to a new path, we'll have to fix the relative paths
|
329 |
+
* to be relative no longer to the source file, but to the new path.
|
330 |
+
* If we don't write to a file, fall back to same path so no
|
331 |
+
* conversion happens (because we still want it to go through most
|
332 |
+
* of the move code, which also addresses url() & @import syntax...)
|
333 |
+
*/
|
334 |
+
$converter = $this->getPathConverter($source, $path ?: $source);
|
335 |
+
$css = $this->move($converter, $css);
|
336 |
+
|
337 |
+
// combine css
|
338 |
+
$content .= $css;
|
339 |
+
}
|
340 |
+
|
341 |
+
$content = $this->moveImportsToTop($content);
|
342 |
+
|
343 |
+
return $content;
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Moving a css file should update all relative urls.
|
348 |
+
* Relative references (e.g. ../images/image.gif) in a certain css file,
|
349 |
+
* will have to be updated when a file is being saved at another location
|
350 |
+
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
|
351 |
+
*
|
352 |
+
* @param ConverterInterface $converter Relative path converter
|
353 |
+
* @param string $content The CSS content to update relative urls for
|
354 |
+
*
|
355 |
+
* @return string
|
356 |
+
*/
|
357 |
+
protected function move(ConverterInterface $converter, $content)
|
358 |
+
{
|
359 |
+
/*
|
360 |
+
* Relative path references will usually be enclosed by url(). @import
|
361 |
+
* is an exception, where url() is not necessary around the path (but is
|
362 |
+
* allowed).
|
363 |
+
* This *could* be 1 regular expression, where both regular expressions
|
364 |
+
* in this array are on different sides of a |. But we're using named
|
365 |
+
* patterns in both regexes, the same name on both regexes. This is only
|
366 |
+
* possible with a (?J) modifier, but that only works after a fairly
|
367 |
+
* recent PCRE version. That's why I'm doing 2 separate regular
|
368 |
+
* expressions & combining the matches after executing of both.
|
369 |
+
*/
|
370 |
+
$relativeRegexes = array(
|
371 |
+
// url(xxx)
|
372 |
+
'/
|
373 |
+
# open url()
|
374 |
+
url\(
|
375 |
+
|
376 |
+
\s*
|
377 |
+
|
378 |
+
# open path enclosure
|
379 |
+
(?P<quotes>["\'])?
|
380 |
+
|
381 |
+
# fetch path
|
382 |
+
(?P<path>.+?)
|
383 |
+
|
384 |
+
# close path enclosure
|
385 |
+
(?(quotes)(?P=quotes))
|
386 |
+
|
387 |
+
\s*
|
388 |
+
|
389 |
+
# close url()
|
390 |
+
\)
|
391 |
+
|
392 |
+
/ix',
|
393 |
+
|
394 |
+
// @import "xxx"
|
395 |
+
'/
|
396 |
+
# import statement
|
397 |
+
@import
|
398 |
+
|
399 |
+
# whitespace
|
400 |
+
\s+
|
401 |
+
|
402 |
+
# we don\'t have to check for @import url(), because the
|
403 |
+
# condition above will already catch these
|
404 |
+
|
405 |
+
# open path enclosure
|
406 |
+
(?P<quotes>["\'])
|
407 |
+
|
408 |
+
# fetch path
|
409 |
+
(?P<path>.+?)
|
410 |
+
|
411 |
+
# close path enclosure
|
412 |
+
(?P=quotes)
|
413 |
+
|
414 |
+
/ix',
|
415 |
+
);
|
416 |
+
|
417 |
+
// find all relative urls in css
|
418 |
+
$matches = array();
|
419 |
+
foreach ($relativeRegexes as $relativeRegex) {
|
420 |
+
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
421 |
+
$matches = array_merge($matches, $regexMatches);
|
422 |
+
}
|
423 |
+
}
|
424 |
+
|
425 |
+
$search = array();
|
426 |
+
$replace = array();
|
427 |
+
|
428 |
+
// loop all urls
|
429 |
+
foreach ($matches as $match) {
|
430 |
+
// determine if it's a url() or an @import match
|
431 |
+
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
|
432 |
+
|
433 |
+
$url = $match['path'];
|
434 |
+
if ($this->canImportByPath($url)) {
|
435 |
+
// attempting to interpret GET-params makes no sense, so let's discard them for awhile
|
436 |
+
$params = strrchr($url, '?');
|
437 |
+
$url = $params ? substr($url, 0, -strlen($params)) : $url;
|
438 |
+
|
439 |
+
// fix relative url
|
440 |
+
$url = $converter->convert($url);
|
441 |
+
|
442 |
+
// now that the path has been converted, re-apply GET-params
|
443 |
+
$url .= $params;
|
444 |
+
}
|
445 |
+
|
446 |
+
/*
|
447 |
+
* Urls with control characters above 0x7e should be quoted.
|
448 |
+
* According to Mozilla's parser, whitespace is only allowed at the
|
449 |
+
* end of unquoted urls.
|
450 |
+
* Urls with `)` (as could happen with data: uris) should also be
|
451 |
+
* quoted to avoid being confused for the url() closing parentheses.
|
452 |
+
* And urls with a # have also been reported to cause issues.
|
453 |
+
* Urls with quotes inside should also remain escaped.
|
454 |
+
*
|
455 |
+
* @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
|
456 |
+
* @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
|
457 |
+
* @see https://github.com/matthiasmullie/minify/issues/193
|
458 |
+
*/
|
459 |
+
$url = trim($url);
|
460 |
+
if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) {
|
461 |
+
$url = $match['quotes'] . $url . $match['quotes'];
|
462 |
+
}
|
463 |
+
|
464 |
+
// build replacement
|
465 |
+
$search[] = $match[0];
|
466 |
+
if ($type === 'url') {
|
467 |
+
$replace[] = 'url('.$url.')';
|
468 |
+
} elseif ($type === 'import') {
|
469 |
+
$replace[] = '@import "'.$url.'"';
|
470 |
+
}
|
471 |
+
}
|
472 |
+
|
473 |
+
// replace urls
|
474 |
+
return str_replace($search, $replace, $content);
|
475 |
+
}
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Shorthand hex color codes.
|
479 |
+
* #FF0000 -> #F00.
|
480 |
+
*
|
481 |
+
* @param string $content The CSS content to shorten the hex color codes for
|
482 |
+
*
|
483 |
+
* @return string
|
484 |
+
*/
|
485 |
+
protected function shortenColors($content)
|
486 |
+
{
|
487 |
+
$content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?:([0-9a-z])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
|
488 |
+
|
489 |
+
// remove alpha channel if it's pointless...
|
490 |
+
$content = preg_replace('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i', '#$1', $content);
|
491 |
+
$content = preg_replace('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i', '#$1', $content);
|
492 |
+
|
493 |
+
$colors = array(
|
494 |
+
// we can shorten some even more by replacing them with their color name
|
495 |
+
'#F0FFFF' => 'azure',
|
496 |
+
'#F5F5DC' => 'beige',
|
497 |
+
'#A52A2A' => 'brown',
|
498 |
+
'#FF7F50' => 'coral',
|
499 |
+
'#FFD700' => 'gold',
|
500 |
+
'#808080' => 'gray',
|
501 |
+
'#008000' => 'green',
|
502 |
+
'#4B0082' => 'indigo',
|
503 |
+
'#FFFFF0' => 'ivory',
|
504 |
+
'#F0E68C' => 'khaki',
|
505 |
+
'#FAF0E6' => 'linen',
|
506 |
+
'#800000' => 'maroon',
|
507 |
+
'#000080' => 'navy',
|
508 |
+
'#808000' => 'olive',
|
509 |
+
'#CD853F' => 'peru',
|
510 |
+
'#FFC0CB' => 'pink',
|
511 |
+
'#DDA0DD' => 'plum',
|
512 |
+
'#800080' => 'purple',
|
513 |
+
'#F00' => 'red',
|
514 |
+
'#FA8072' => 'salmon',
|
515 |
+
'#A0522D' => 'sienna',
|
516 |
+
'#C0C0C0' => 'silver',
|
517 |
+
'#FFFAFA' => 'snow',
|
518 |
+
'#D2B48C' => 'tan',
|
519 |
+
'#FF6347' => 'tomato',
|
520 |
+
'#EE82EE' => 'violet',
|
521 |
+
'#F5DEB3' => 'wheat',
|
522 |
+
// or the other way around
|
523 |
+
'WHITE' => '#fff',
|
524 |
+
'BLACK' => '#000',
|
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 |
+
},
|
532 |
+
$content
|
533 |
+
);
|
534 |
+
}
|
535 |
+
|
536 |
+
/**
|
537 |
+
* Shorten CSS font weights.
|
538 |
+
*
|
539 |
+
* @param string $content The CSS content to shorten the font weights for
|
540 |
+
*
|
541 |
+
* @return string
|
542 |
+
*/
|
543 |
+
protected function shortenFontWeights($content)
|
544 |
+
{
|
545 |
+
$weights = array(
|
546 |
+
'normal' => 400,
|
547 |
+
'bold' => 700,
|
548 |
+
);
|
549 |
+
|
550 |
+
$callback = function ($match) use ($weights) {
|
551 |
+
return $match[1].$weights[$match[2]];
|
552 |
+
};
|
553 |
+
|
554 |
+
return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content);
|
555 |
+
}
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Shorthand 0 values to plain 0, instead of e.g. -0em.
|
559 |
+
*
|
560 |
+
* @param string $content The CSS content to shorten the zero values for
|
561 |
+
*
|
562 |
+
* @return string
|
563 |
+
*/
|
564 |
+
protected function shortenZeroes($content)
|
565 |
+
{
|
566 |
+
// we don't want to strip units in `calc()` expressions:
|
567 |
+
// `5px - 0px` is valid, but `5px - 0` is not
|
568 |
+
// `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but
|
569 |
+
// `10 * 0` is invalid
|
570 |
+
// we've extracted calcs earlier, so we don't need to worry about this
|
571 |
+
|
572 |
+
// reusable bits of code throughout these regexes:
|
573 |
+
// before & after are used to make sure we don't match lose unintended
|
574 |
+
// 0-like values (e.g. in #000, or in http://url/1.0)
|
575 |
+
// units can be stripped from 0 values, or used to recognize non 0
|
576 |
+
// values (where wa may be able to strip a .0 suffix)
|
577 |
+
$before = '(?<=[:(, ])';
|
578 |
+
$after = '(?=[ ,);}])';
|
579 |
+
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
|
580 |
+
|
581 |
+
// strip units after zeroes (0px -> 0)
|
582 |
+
// NOTE: it should be safe to remove all units for a 0 value, but in
|
583 |
+
// practice, Webkit (especially Safari) seems to stumble over at least
|
584 |
+
// 0%, potentially other units as well. Only stripping 'px' for now.
|
585 |
+
// @see https://github.com/matthiasmullie/minify/issues/60
|
586 |
+
$content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content);
|
587 |
+
|
588 |
+
// strip 0-digits (.0 -> 0)
|
589 |
+
$content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content);
|
590 |
+
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
|
591 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
592 |
+
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
|
593 |
+
$content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
594 |
+
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
|
595 |
+
$content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content);
|
596 |
+
|
597 |
+
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
|
598 |
+
$content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
|
599 |
+
|
600 |
+
// IE doesn't seem to understand a unitless flex-basis value (correct -
|
601 |
+
// it goes against the spec), so let's add it in again (make it `%`,
|
602 |
+
// which is only 1 char: 0%, 0px, 0 anything, it's all just the same)
|
603 |
+
// @see https://developer.mozilla.org/nl/docs/Web/CSS/flex
|
604 |
+
$content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content);
|
605 |
+
$content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
|
606 |
+
|
607 |
+
return $content;
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Strip empty tags from source code.
|
612 |
+
*
|
613 |
+
* @param string $content
|
614 |
+
*
|
615 |
+
* @return string
|
616 |
+
*/
|
617 |
+
protected function stripEmptyTags($content)
|
618 |
+
{
|
619 |
+
$content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content);
|
620 |
+
$content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content);
|
621 |
+
|
622 |
+
return $content;
|
623 |
+
}
|
624 |
+
|
625 |
+
/**
|
626 |
+
* Strip comments from source code.
|
627 |
+
*/
|
628 |
+
protected function stripComments()
|
629 |
+
{
|
630 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
631 |
+
$minifier = $this;
|
632 |
+
$callback = function ($match) use ($minifier) {
|
633 |
+
$count = count($minifier->extracted);
|
634 |
+
$placeholder = '/*'.$count.'*/';
|
635 |
+
$minifier->extracted[$placeholder] = $match[0];
|
636 |
+
|
637 |
+
return $placeholder;
|
638 |
+
};
|
639 |
+
$this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback);
|
640 |
+
|
641 |
+
$this->registerPattern('/\/\*.*?\*\//s', '');
|
642 |
+
}
|
643 |
+
|
644 |
+
/**
|
645 |
+
* Strip whitespace.
|
646 |
+
*
|
647 |
+
* @param string $content The CSS content to strip the whitespace for
|
648 |
+
*
|
649 |
+
* @return string
|
650 |
+
*/
|
651 |
+
protected function stripWhitespace($content)
|
652 |
+
{
|
653 |
+
// remove leading & trailing whitespace
|
654 |
+
$content = preg_replace('/^\s*/m', '', $content);
|
655 |
+
$content = preg_replace('/\s*$/m', '', $content);
|
656 |
+
|
657 |
+
// replace newlines with a single space
|
658 |
+
$content = preg_replace('/\s+/', ' ', $content);
|
659 |
+
|
660 |
+
// remove whitespace around meta characters
|
661 |
+
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
|
662 |
+
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
|
663 |
+
$content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
|
664 |
+
$content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
|
665 |
+
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
|
666 |
+
|
667 |
+
// whitespace around + and - can only be stripped inside some pseudo-
|
668 |
+
// classes, like `:nth-child(3+2n)`
|
669 |
+
// not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
|
670 |
+
// selectors like `div.weird- p`
|
671 |
+
$pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
|
672 |
+
$content = preg_replace('/:('.implode('|', $pseudos).')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
|
673 |
+
|
674 |
+
// remove semicolon/whitespace followed by closing bracket
|
675 |
+
$content = str_replace(';}', '}', $content);
|
676 |
+
|
677 |
+
return trim($content);
|
678 |
+
}
|
679 |
+
|
680 |
+
/**
|
681 |
+
* Replace all `calc()` occurrences.
|
682 |
+
*/
|
683 |
+
protected function extractCalcs()
|
684 |
+
{
|
685 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
686 |
+
$minifier = $this;
|
687 |
+
$callback = function ($match) use ($minifier) {
|
688 |
+
$length = strlen($match[1]);
|
689 |
+
$expr = '';
|
690 |
+
$opened = 0;
|
691 |
+
|
692 |
+
for ($i = 0; $i < $length; $i++) {
|
693 |
+
$char = $match[1][$i];
|
694 |
+
$expr .= $char;
|
695 |
+
if ($char === '(') {
|
696 |
+
$opened++;
|
697 |
+
} elseif ($char === ')' && --$opened === 0) {
|
698 |
+
break;
|
699 |
+
}
|
700 |
+
}
|
701 |
+
$rest = str_replace($expr, '', $match[1]);
|
702 |
+
$expr = trim(substr($expr, 1, -1));
|
703 |
+
|
704 |
+
$count = count($minifier->extracted);
|
705 |
+
$placeholder = 'calc('.$count.')';
|
706 |
+
$minifier->extracted[$placeholder] = 'calc('.$expr.')';
|
707 |
+
|
708 |
+
return $placeholder.$rest;
|
709 |
+
};
|
710 |
+
|
711 |
+
$this->registerPattern('/calc(\(.+?)(?=$|;|calc\()/', $callback);
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Check if file is small enough to be imported.
|
716 |
+
*
|
717 |
+
* @param string $path The path to the file
|
718 |
+
*
|
719 |
+
* @return bool
|
720 |
+
*/
|
721 |
+
protected function canImportBySize($path)
|
722 |
+
{
|
723 |
+
return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
|
724 |
+
}
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Check if file a file can be imported, going by the path.
|
728 |
+
*
|
729 |
+
* @param string $path
|
730 |
+
*
|
731 |
+
* @return bool
|
732 |
+
*/
|
733 |
+
protected function canImportByPath($path)
|
734 |
+
{
|
735 |
+
return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
|
736 |
+
}
|
737 |
+
|
738 |
+
/**
|
739 |
+
* Return a converter to update relative paths to be relative to the new
|
740 |
+
* destination.
|
741 |
+
*
|
742 |
+
* @param string $source
|
743 |
+
* @param string $target
|
744 |
+
*
|
745 |
+
* @return ConverterInterface
|
746 |
+
*/
|
747 |
+
protected function getPathConverter($source, $target)
|
748 |
+
{
|
749 |
+
return new Converter($source, $target);
|
750 |
+
}
|
751 |
+
}
|
libs/matthiasmullie/minify/src/Exception.php
CHANGED
@@ -1,20 +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 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
|
19 |
-
{
|
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 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
|
19 |
+
{
|
20 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/BasicException.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Basic exception
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
namespace MatthiasMullie\Minify\Exceptions;
|
12 |
-
|
13 |
-
use 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
|
22 |
-
{
|
23 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Basic exception
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
namespace MatthiasMullie\Minify\Exceptions;
|
12 |
+
|
13 |
+
use 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
|
22 |
+
{
|
23 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/FileImportException.php
CHANGED
@@ -1,21 +1,21 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* File Import Exception
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
namespace 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
|
20 |
-
{
|
21 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* File Import Exception
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
namespace 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
|
20 |
+
{
|
21 |
+
}
|
libs/matthiasmullie/minify/src/Exceptions/IOException.php
CHANGED
@@ -1,21 +1,21 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* IO Exception
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
namespace 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
|
20 |
-
{
|
21 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* IO Exception
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
namespace 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
|
20 |
+
{
|
21 |
+
}
|
libs/matthiasmullie/minify/src/JS.php
CHANGED
@@ -1,598 +1,612 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* JavaScript minifier
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
namespace 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
|
22 |
-
* @license MIT License
|
23 |
-
*/
|
24 |
-
class JS extends Minify
|
25 |
-
{
|
26 |
-
/**
|
27 |
-
* Var-matching regex based on http://stackoverflow.com/a/9337047/802993.
|
28 |
-
*
|
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';
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Full list of JavaScript reserved words.
|
38 |
-
* Will be loaded from /data/js/keywords_reserved.txt.
|
39 |
-
*
|
40 |
-
* @see https://mathiasbynens.be/notes/reserved-keywords
|
41 |
-
*
|
42 |
-
* @var string[]
|
43 |
-
*/
|
44 |
-
protected $keywordsReserved = array();
|
45 |
-
|
46 |
-
/**
|
47 |
-
* List of JavaScript reserved words that accept a <variable, value, ...>
|
48 |
-
* after them. Some end of lines are not the end of a statement, like with
|
49 |
-
* these keywords.
|
50 |
-
*
|
51 |
-
* E.g.: we shouldn't insert a ; after this else
|
52 |
-
* else
|
53 |
-
* console.log('this is quite fine')
|
54 |
-
*
|
55 |
-
* Will be loaded from /data/js/keywords_before.txt
|
56 |
-
*
|
57 |
-
* @var string[]
|
58 |
-
*/
|
59 |
-
protected $keywordsBefore = array();
|
60 |
-
|
61 |
-
/**
|
62 |
-
* List of JavaScript reserved words that accept a <variable, value, ...>
|
63 |
-
* before them. Some end of lines are not the end of a statement, like when
|
64 |
-
* continued by one of these keywords on the newline.
|
65 |
-
*
|
66 |
-
* E.g.: we shouldn't insert a ; before this instanceof
|
67 |
-
* variable
|
68 |
-
* instanceof String
|
69 |
-
*
|
70 |
-
* Will be loaded from /data/js/keywords_after.txt
|
71 |
-
*
|
72 |
-
* @var string[]
|
73 |
-
*/
|
74 |
-
protected $keywordsAfter = array();
|
75 |
-
|
76 |
-
/**
|
77 |
-
* List of all JavaScript operators.
|
78 |
-
*
|
79 |
-
* Will be loaded from /data/js/operators.txt
|
80 |
-
*
|
81 |
-
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
82 |
-
*
|
83 |
-
* @var string[]
|
84 |
-
*/
|
85 |
-
protected $operators = array();
|
86 |
-
|
87 |
-
/**
|
88 |
-
* List of JavaScript operators that accept a <variable, value, ...> after
|
89 |
-
* them. Some end of lines are not the end of a statement, like with these
|
90 |
-
* operators.
|
91 |
-
*
|
92 |
-
* Note: Most operators are fine, we've only removed ++ and --.
|
93 |
-
* ++ & -- have to be joined with the value they're in-/decrementing.
|
94 |
-
*
|
95 |
-
* Will be loaded from /data/js/operators_before.txt
|
96 |
-
*
|
97 |
-
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
98 |
-
*
|
99 |
-
* @var string[]
|
100 |
-
*/
|
101 |
-
protected $operatorsBefore = array();
|
102 |
-
|
103 |
-
/**
|
104 |
-
* List of JavaScript operators that accept a <variable, value, ...> before
|
105 |
-
* them. Some end of lines are not the end of a statement, like when
|
106 |
-
* continued by one of these operators on the newline.
|
107 |
-
*
|
108 |
-
* Note: Most operators are fine, we've only removed ), ], ++, --, ! and ~.
|
109 |
-
* There can't be a newline separating ! or ~ and whatever it is negating.
|
110 |
-
* ++ & -- have to be joined with the value they're in-/decrementing.
|
111 |
-
* ) & ] are "special" in that they have lots or usecases. () for example
|
112 |
-
* is used for function calls, for grouping, in if () and for (), ...
|
113 |
-
*
|
114 |
-
* Will be loaded from /data/js/operators_after.txt
|
115 |
-
*
|
116 |
-
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
117 |
-
*
|
118 |
-
* @var string[]
|
119 |
-
*/
|
120 |
-
protected $operatorsAfter = array();
|
121 |
-
|
122 |
-
/**
|
123 |
-
* {@inheritdoc}
|
124 |
-
*/
|
125 |
-
public function __construct()
|
126 |
-
{
|
127 |
-
call_user_func_array(array('parent', '__construct'), func_get_args());
|
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 |
-
/**
|
140 |
-
* Minify the data.
|
141 |
-
* Perform JS optimizations.
|
142 |
-
*
|
143 |
-
* @param string[optional] $path Path to write the data to
|
144 |
-
*
|
145 |
-
* @return string The minified data
|
146 |
-
*/
|
147 |
-
public function execute($path = null)
|
148 |
-
{
|
149 |
-
$content = '';
|
150 |
-
|
151 |
-
/*
|
152 |
-
* Let's first take out strings, comments and regular expressions.
|
153 |
-
* All of these can contain JS code-like characters, and we should make
|
154 |
-
* sure any further magic ignores anything inside of these.
|
155 |
-
*
|
156 |
-
* Consider this example, where we should not strip any whitespace:
|
157 |
-
* var str = "a test";
|
158 |
-
*
|
159 |
-
* Comments will be removed altogether, strings and regular expressions
|
160 |
-
* will be replaced by placeholder text, which we'll restore later.
|
161 |
-
*/
|
162 |
-
$this->extractStrings('\'"`');
|
163 |
-
$this->stripComments();
|
164 |
-
$this->extractRegex();
|
165 |
-
|
166 |
-
// loop files
|
167 |
-
foreach ($this->data as $source => $js) {
|
168 |
-
// take out strings, comments & regex (for which we've registered
|
169 |
-
// the regexes just a few lines earlier)
|
170 |
-
$js = $this->replace($js);
|
171 |
-
|
172 |
-
$js = $this->propertyNotation($js);
|
173 |
-
$js = $this->shortenBools($js);
|
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
|
181 |
-
$content = ltrim($content, ';');
|
182 |
-
$content = (string) substr($content, 0, -1);
|
183 |
-
|
184 |
-
/*
|
185 |
-
* Earlier, we extracted strings & regular expressions and replaced them
|
186 |
-
* with placeholder text. This will restore them.
|
187 |
-
*/
|
188 |
-
$content = $this->restoreExtractedData($content);
|
189 |
-
|
190 |
-
return $content;
|
191 |
-
}
|
192 |
-
|
193 |
-
/**
|
194 |
-
* Strip comments from source code.
|
195 |
-
*/
|
196 |
-
protected function stripComments()
|
197 |
-
{
|
198 |
-
//
|
199 |
-
$this
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
*
|
217 |
-
*
|
218 |
-
*
|
219 |
-
*
|
220 |
-
*
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
//
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
//
|
245 |
-
//
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
'
|
261 |
-
'
|
262 |
-
'
|
263 |
-
'
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
//
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
//
|
286 |
-
//
|
287 |
-
//
|
288 |
-
//
|
289 |
-
|
290 |
-
|
291 |
-
$
|
292 |
-
$
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
*
|
307 |
-
*
|
308 |
-
*
|
309 |
-
*
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
$
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
//
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
);
|
340 |
-
|
341 |
-
//
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
*
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
*
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
*
|
390 |
-
*
|
391 |
-
*
|
392 |
-
*
|
393 |
-
*
|
394 |
-
*/
|
395 |
-
$content = preg_replace('
|
396 |
-
$content = preg_replace('
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
*
|
401 |
-
*
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
*
|
407 |
-
*
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
$
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
$keywords
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
*
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* JavaScript minifier
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
namespace 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
|
22 |
+
* @license MIT License
|
23 |
+
*/
|
24 |
+
class JS extends Minify
|
25 |
+
{
|
26 |
+
/**
|
27 |
+
* Var-matching regex based on http://stackoverflow.com/a/9337047/802993.
|
28 |
+
*
|
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';
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Full list of JavaScript reserved words.
|
38 |
+
* Will be loaded from /data/js/keywords_reserved.txt.
|
39 |
+
*
|
40 |
+
* @see https://mathiasbynens.be/notes/reserved-keywords
|
41 |
+
*
|
42 |
+
* @var string[]
|
43 |
+
*/
|
44 |
+
protected $keywordsReserved = array();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* List of JavaScript reserved words that accept a <variable, value, ...>
|
48 |
+
* after them. Some end of lines are not the end of a statement, like with
|
49 |
+
* these keywords.
|
50 |
+
*
|
51 |
+
* E.g.: we shouldn't insert a ; after this else
|
52 |
+
* else
|
53 |
+
* console.log('this is quite fine')
|
54 |
+
*
|
55 |
+
* Will be loaded from /data/js/keywords_before.txt
|
56 |
+
*
|
57 |
+
* @var string[]
|
58 |
+
*/
|
59 |
+
protected $keywordsBefore = array();
|
60 |
+
|
61 |
+
/**
|
62 |
+
* List of JavaScript reserved words that accept a <variable, value, ...>
|
63 |
+
* before them. Some end of lines are not the end of a statement, like when
|
64 |
+
* continued by one of these keywords on the newline.
|
65 |
+
*
|
66 |
+
* E.g.: we shouldn't insert a ; before this instanceof
|
67 |
+
* variable
|
68 |
+
* instanceof String
|
69 |
+
*
|
70 |
+
* Will be loaded from /data/js/keywords_after.txt
|
71 |
+
*
|
72 |
+
* @var string[]
|
73 |
+
*/
|
74 |
+
protected $keywordsAfter = array();
|
75 |
+
|
76 |
+
/**
|
77 |
+
* List of all JavaScript operators.
|
78 |
+
*
|
79 |
+
* Will be loaded from /data/js/operators.txt
|
80 |
+
*
|
81 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
82 |
+
*
|
83 |
+
* @var string[]
|
84 |
+
*/
|
85 |
+
protected $operators = array();
|
86 |
+
|
87 |
+
/**
|
88 |
+
* List of JavaScript operators that accept a <variable, value, ...> after
|
89 |
+
* them. Some end of lines are not the end of a statement, like with these
|
90 |
+
* operators.
|
91 |
+
*
|
92 |
+
* Note: Most operators are fine, we've only removed ++ and --.
|
93 |
+
* ++ & -- have to be joined with the value they're in-/decrementing.
|
94 |
+
*
|
95 |
+
* Will be loaded from /data/js/operators_before.txt
|
96 |
+
*
|
97 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
98 |
+
*
|
99 |
+
* @var string[]
|
100 |
+
*/
|
101 |
+
protected $operatorsBefore = array();
|
102 |
+
|
103 |
+
/**
|
104 |
+
* List of JavaScript operators that accept a <variable, value, ...> before
|
105 |
+
* them. Some end of lines are not the end of a statement, like when
|
106 |
+
* continued by one of these operators on the newline.
|
107 |
+
*
|
108 |
+
* Note: Most operators are fine, we've only removed ), ], ++, --, ! and ~.
|
109 |
+
* There can't be a newline separating ! or ~ and whatever it is negating.
|
110 |
+
* ++ & -- have to be joined with the value they're in-/decrementing.
|
111 |
+
* ) & ] are "special" in that they have lots or usecases. () for example
|
112 |
+
* is used for function calls, for grouping, in if () and for (), ...
|
113 |
+
*
|
114 |
+
* Will be loaded from /data/js/operators_after.txt
|
115 |
+
*
|
116 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
|
117 |
+
*
|
118 |
+
* @var string[]
|
119 |
+
*/
|
120 |
+
protected $operatorsAfter = array();
|
121 |
+
|
122 |
+
/**
|
123 |
+
* {@inheritdoc}
|
124 |
+
*/
|
125 |
+
public function __construct()
|
126 |
+
{
|
127 |
+
call_user_func_array(array('parent', '__construct'), func_get_args());
|
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 |
+
/**
|
140 |
+
* Minify the data.
|
141 |
+
* Perform JS optimizations.
|
142 |
+
*
|
143 |
+
* @param string[optional] $path Path to write the data to
|
144 |
+
*
|
145 |
+
* @return string The minified data
|
146 |
+
*/
|
147 |
+
public function execute($path = null)
|
148 |
+
{
|
149 |
+
$content = '';
|
150 |
+
|
151 |
+
/*
|
152 |
+
* Let's first take out strings, comments and regular expressions.
|
153 |
+
* All of these can contain JS code-like characters, and we should make
|
154 |
+
* sure any further magic ignores anything inside of these.
|
155 |
+
*
|
156 |
+
* Consider this example, where we should not strip any whitespace:
|
157 |
+
* var str = "a test";
|
158 |
+
*
|
159 |
+
* Comments will be removed altogether, strings and regular expressions
|
160 |
+
* will be replaced by placeholder text, which we'll restore later.
|
161 |
+
*/
|
162 |
+
$this->extractStrings('\'"`');
|
163 |
+
$this->stripComments();
|
164 |
+
$this->extractRegex();
|
165 |
+
|
166 |
+
// loop files
|
167 |
+
foreach ($this->data as $source => $js) {
|
168 |
+
// take out strings, comments & regex (for which we've registered
|
169 |
+
// the regexes just a few lines earlier)
|
170 |
+
$js = $this->replace($js);
|
171 |
+
|
172 |
+
$js = $this->propertyNotation($js);
|
173 |
+
$js = $this->shortenBools($js);
|
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
|
181 |
+
$content = ltrim($content, ';');
|
182 |
+
$content = (string) substr($content, 0, -1);
|
183 |
+
|
184 |
+
/*
|
185 |
+
* Earlier, we extracted strings & regular expressions and replaced them
|
186 |
+
* with placeholder text. This will restore them.
|
187 |
+
*/
|
188 |
+
$content = $this->restoreExtractedData($content);
|
189 |
+
|
190 |
+
return $content;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Strip comments from source code.
|
195 |
+
*/
|
196 |
+
protected function stripComments()
|
197 |
+
{
|
198 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
199 |
+
$minifier = $this;
|
200 |
+
$callback = function ($match) use ($minifier) {
|
201 |
+
$count = count($minifier->extracted);
|
202 |
+
$placeholder = '/*'.$count.'*/';
|
203 |
+
$minifier->extracted[$placeholder] = $match[0];
|
204 |
+
|
205 |
+
return $placeholder;
|
206 |
+
};
|
207 |
+
// multi-line comments
|
208 |
+
$this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback);
|
209 |
+
$this->registerPattern('/\/\*.*?\*\//s', '');
|
210 |
+
|
211 |
+
// single-line comments
|
212 |
+
$this->registerPattern('/\/\/.*$/m', '');
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* JS can have /-delimited regular expressions, like: /ab+c/.match(string).
|
217 |
+
*
|
218 |
+
* The content inside the regex can contain characters that may be confused
|
219 |
+
* for JS code: e.g. it could contain whitespace it needs to match & we
|
220 |
+
* don't want to strip whitespace in there.
|
221 |
+
*
|
222 |
+
* The regex can be pretty simple: we don't have to care about comments,
|
223 |
+
* (which also use slashes) because stripComments() will have stripped those
|
224 |
+
* already.
|
225 |
+
*
|
226 |
+
* This method will replace all string content with simple REGEX#
|
227 |
+
* placeholder text, so we've rid all regular expressions from characters
|
228 |
+
* that may be misinterpreted. Original regex content will be saved in
|
229 |
+
* $this->extracted and after doing all other minifying, we can restore the
|
230 |
+
* original content via restoreRegex()
|
231 |
+
*/
|
232 |
+
protected function extractRegex()
|
233 |
+
{
|
234 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
235 |
+
$minifier = $this;
|
236 |
+
$callback = function ($match) use ($minifier) {
|
237 |
+
$count = count($minifier->extracted);
|
238 |
+
$placeholder = '"'.$count.'"';
|
239 |
+
$minifier->extracted[$placeholder] = $match[0];
|
240 |
+
|
241 |
+
return $placeholder;
|
242 |
+
};
|
243 |
+
|
244 |
+
// match all chars except `/` and `\`
|
245 |
+
// `\` is allowed though, along with whatever char follows (which is the
|
246 |
+
// one being escaped)
|
247 |
+
// this should allow all chars, except for an unescaped `/` (= the one
|
248 |
+
// closing the regex)
|
249 |
+
// then also ignore bare `/` inside `[]`, where they don't need to be
|
250 |
+
// escaped: anything inside `[]` can be ignored safely
|
251 |
+
$pattern = '\\/(?!\*)(?:[^\\[\\/\\\\\n\r]++|(?:\\\\.)++|(?:\\[(?:[^\\]\\\\\n\r]++|(?:\\\\.)++)++\\])++)++\\/[gimuy]*';
|
252 |
+
|
253 |
+
// a regular expression can only be followed by a few operators or some
|
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 = '([=:,;\+\-\*\/\}\(\{\[&\|!]|^|'.implode('|', $keywords).')\s*';
|
258 |
+
$propertiesAndMethods = array(
|
259 |
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
|
260 |
+
'constructor',
|
261 |
+
'flags',
|
262 |
+
'global',
|
263 |
+
'ignoreCase',
|
264 |
+
'multiline',
|
265 |
+
'source',
|
266 |
+
'sticky',
|
267 |
+
'unicode',
|
268 |
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Methods_2
|
269 |
+
'compile(',
|
270 |
+
'exec(',
|
271 |
+
'test(',
|
272 |
+
'toSource(',
|
273 |
+
'toString(',
|
274 |
+
);
|
275 |
+
$delimiters = array_fill(0, count($propertiesAndMethods), '/');
|
276 |
+
$propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
|
277 |
+
$after = '(?=\s*([\.,;\)\}&\|+]|\/\/|$|\.('.implode('|', $propertiesAndMethods).')))';
|
278 |
+
$this->registerPattern('/'.$before.'\K'.$pattern.$after.'/', $callback);
|
279 |
+
|
280 |
+
// regular expressions following a `)` are rather annoying to detect...
|
281 |
+
// quite often, `/` after `)` is a division operator & if it happens to
|
282 |
+
// be followed by another one (or a comment), it is likely to be
|
283 |
+
// confused for a regular expression
|
284 |
+
// however, it's perfectly possible for a regex to follow a `)`: after
|
285 |
+
// a single-line `if()`, `while()`, ... statement, for example
|
286 |
+
// since, when they occur like that, they're always the start of a
|
287 |
+
// statement, there's only a limited amount of ways they can be useful:
|
288 |
+
// by calling the regex methods directly
|
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('/'.$before.'\K'.$pattern.$after.'/', $callback);
|
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
|
297 |
+
// actually starts a new statement
|
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('/'.$pattern.$after.'/', $callback);
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Strip whitespace.
|
307 |
+
*
|
308 |
+
* We won't strip *all* whitespace, but as much as possible. The thing that
|
309 |
+
* we'll preserve are newlines we're unsure about.
|
310 |
+
* JavaScript doesn't require statements to be terminated with a semicolon.
|
311 |
+
* It will automatically fix missing semicolons with ASI (automatic semi-
|
312 |
+
* colon insertion) at the end of line causing errors (without semicolon.)
|
313 |
+
*
|
314 |
+
* Because it's sometimes hard to tell if a newline is part of a statement
|
315 |
+
* that should be terminated or not, we'll just leave some of them alone.
|
316 |
+
*
|
317 |
+
* @param string $content The content to strip the whitespace for
|
318 |
+
*
|
319 |
+
* @return string
|
320 |
+
*/
|
321 |
+
protected function stripWhitespace($content)
|
322 |
+
{
|
323 |
+
// uniform line endings, make them all line feed
|
324 |
+
$content = str_replace(array("\r\n", "\r"), "\n", $content);
|
325 |
+
|
326 |
+
// collapse all non-line feed whitespace into a single space
|
327 |
+
$content = preg_replace('/[^\S\n]+/', ' ', $content);
|
328 |
+
|
329 |
+
// strip leading & trailing whitespace
|
330 |
+
$content = str_replace(array(" \n", "\n "), "\n", $content);
|
331 |
+
|
332 |
+
// collapse consecutive line feeds into just 1
|
333 |
+
$content = preg_replace('/\n+/', "\n", $content);
|
334 |
+
|
335 |
+
$operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
|
336 |
+
$operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
|
337 |
+
$operators = $this->getOperatorsForRegex($this->operators, '/');
|
338 |
+
$keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
|
339 |
+
$keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
|
340 |
+
|
341 |
+
// strip whitespace that ends in (or next line begin with) an operator
|
342 |
+
// that allows statements to be broken up over multiple lines
|
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
|
351 |
+
);
|
352 |
+
|
353 |
+
// make sure + and - can't be mistaken for, or joined into ++ and --
|
354 |
+
$content = preg_replace(
|
355 |
+
array(
|
356 |
+
'/(?<![\+\-])\s*([\+\-])(?![\+\-])/',
|
357 |
+
'/(?<![\+\-])([\+\-])\s*(?![\+\-])/',
|
358 |
+
),
|
359 |
+
'\\1',
|
360 |
+
$content
|
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
|
369 |
+
* could be used in different contexts and we can't be sure it's ok to
|
370 |
+
* strip the newlines. However, we can safely strip any non-line feed
|
371 |
+
* whitespace that follows them.
|
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
|
380 |
+
* (such as when followed by a string or regex)
|
381 |
+
* Same for whitespace in between `)` and `{`, or between `{` and some
|
382 |
+
* keywords.
|
383 |
+
*/
|
384 |
+
$content = preg_replace('/\breturn\s+(["\'\/\+\-])/', 'return$1', $content);
|
385 |
+
$content = preg_replace('/\)\s+\{/', '){', $content);
|
386 |
+
$content = preg_replace('/}\n(else|catch|finally)\b/', '}$1', $content);
|
387 |
+
|
388 |
+
/*
|
389 |
+
* Get rid of double semicolons, except where they can be used like:
|
390 |
+
* "for(v=1,_=b;;)", "for(v=1;;v++)" or "for(;;ja||(ja=true))".
|
391 |
+
* I'll safeguard these double semicolons inside for-loops by
|
392 |
+
* temporarily replacing them with an invalid condition: they won't have
|
393 |
+
* a double semicolon and will be easy to spot to restore afterwards.
|
394 |
+
*/
|
395 |
+
$content = preg_replace('/\bfor\(([^;]*);;([^;]*)\)/', 'for(\\1;-;\\2)', $content);
|
396 |
+
$content = preg_replace('/;+/', ';', $content);
|
397 |
+
$content = preg_replace('/\bfor\(([^;]*);-;([^;]*)\)/', 'for(\\1;;\\2)', $content);
|
398 |
+
|
399 |
+
/*
|
400 |
+
* Next, we'll be removing all semicolons where ASI kicks in.
|
401 |
+
* for-loops however, can have an empty body (ending in only a
|
402 |
+
* semicolon), like: `for(i=1;i<3;i++);`, of `for(i in list);`
|
403 |
+
* Here, nothing happens during the loop; it's just used to keep
|
404 |
+
* increasing `i`. With that ; omitted, the next line would be expected
|
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\([^;\{]*;[^;\{]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
|
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
|
414 |
+
* distinction is cumbersome, so I'll play it safe and make sure `;`
|
415 |
+
* after any kind of `while` is kept.
|
416 |
+
*/
|
417 |
+
$content = preg_replace('/(while\([^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);
|
418 |
+
|
419 |
+
/*
|
420 |
+
* We also can't strip empty else-statements. Even though they're
|
421 |
+
* useless and probably shouldn't be in the code in the first place, we
|
422 |
+
* shouldn't be stripping the `;` that follows it as it breaks the code.
|
423 |
+
* We can just remove those useless else-statements completely.
|
424 |
+
*
|
425 |
+
* @see https://github.com/matthiasmullie/minify/issues/91
|
426 |
+
*/
|
427 |
+
$content = preg_replace('/else;/s', '', $content);
|
428 |
+
|
429 |
+
/*
|
430 |
+
* We also don't really want to terminate statements followed by closing
|
431 |
+
* curly braces (which we've ignored completely up until now) or end-of-
|
432 |
+
* script: ASI will kick in here & we're all about minifying.
|
433 |
+
* Semicolons at beginning of the file don't make any sense either.
|
434 |
+
*/
|
435 |
+
$content = preg_replace('/;(\}|$)/s', '\\1', $content);
|
436 |
+
$content = ltrim($content, ';');
|
437 |
+
|
438 |
+
// get rid of remaining whitespace af beginning/end
|
439 |
+
return trim($content);
|
440 |
+
}
|
441 |
+
|
442 |
+
/**
|
443 |
+
* We'll strip whitespace around certain operators with regular expressions.
|
444 |
+
* This will prepare the given array by escaping all characters.
|
445 |
+
*
|
446 |
+
* @param string[] $operators
|
447 |
+
* @param string $delimiter
|
448 |
+
*
|
449 |
+
* @return string[]
|
450 |
+
*/
|
451 |
+
protected function getOperatorsForRegex(array $operators, $delimiter = '/')
|
452 |
+
{
|
453 |
+
// escape operators for use in regex
|
454 |
+
$delimiters = array_fill(0, count($operators), $delimiter);
|
455 |
+
$escaped = array_map('preg_quote', $operators, $delimiters);
|
456 |
+
|
457 |
+
$operators = array_combine($operators, $escaped);
|
458 |
+
|
459 |
+
// ignore + & - for now, they'll get special treatment
|
460 |
+
unset($operators['+'], $operators['-']);
|
461 |
+
|
462 |
+
// dot can not just immediately follow a number; it can be confused for
|
463 |
+
// decimal point, or calling a method on it, e.g. 42 .toString()
|
464 |
+
$operators['.'] = '(?<![0-9]\s)\.';
|
465 |
+
|
466 |
+
// don't confuse = with other assignment shortcuts (e.g. +=)
|
467 |
+
$chars = preg_quote('+-*\=<>%&|', $delimiter);
|
468 |
+
$operators['='] = '(?<!['.$chars.'])\=';
|
469 |
+
|
470 |
+
return $operators;
|
471 |
+
}
|
472 |
+
|
473 |
+
/**
|
474 |
+
* We'll strip whitespace around certain keywords with regular expressions.
|
475 |
+
* This will prepare the given array by escaping all characters.
|
476 |
+
*
|
477 |
+
* @param string[] $keywords
|
478 |
+
* @param string $delimiter
|
479 |
+
*
|
480 |
+
* @return string[]
|
481 |
+
*/
|
482 |
+
protected function getKeywordsForRegex(array $keywords, $delimiter = '/')
|
483 |
+
{
|
484 |
+
// escape keywords for use in regex
|
485 |
+
$delimiter = array_fill(0, count($keywords), $delimiter);
|
486 |
+
$escaped = array_map('preg_quote', $keywords, $delimiter);
|
487 |
+
|
488 |
+
// add word boundaries
|
489 |
+
array_walk($keywords, function ($value) {
|
490 |
+
return '\b'.$value.'\b';
|
491 |
+
});
|
492 |
+
|
493 |
+
$keywords = array_combine($keywords, $escaped);
|
494 |
+
|
495 |
+
return $keywords;
|
496 |
+
}
|
497 |
+
|
498 |
+
/**
|
499 |
+
* Replaces all occurrences of array['key'] by array.key.
|
500 |
+
*
|
501 |
+
* @param string $content
|
502 |
+
*
|
503 |
+
* @return string
|
504 |
+
*/
|
505 |
+
protected function propertyNotation($content)
|
506 |
+
{
|
507 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
508 |
+
$minifier = $this;
|
509 |
+
$keywords = $this->keywordsReserved;
|
510 |
+
$callback = function ($match) use ($minifier, $keywords) {
|
511 |
+
$property = trim($minifier->extracted[$match[1]], '\'"');
|
512 |
+
|
513 |
+
/*
|
514 |
+
* Check if the property is a reserved keyword. In this context (as
|
515 |
+
* property of an object literal/array) it shouldn't matter, but IE8
|
516 |
+
* freaks out with "Expected identifier".
|
517 |
+
*/
|
518 |
+
if (in_array($property, $keywords)) {
|
519 |
+
return $match[0];
|
520 |
+
}
|
521 |
+
|
522 |
+
/*
|
523 |
+
* See if the property is in a variable-like format (e.g.
|
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('/^'.$minifier::REGEX_VARIABLE.'$/u', $property)) {
|
528 |
+
return $match[0];
|
529 |
+
}
|
530 |
+
|
531 |
+
return '.'.$property;
|
532 |
+
};
|
533 |
+
|
534 |
+
/*
|
535 |
+
* Figure out if previous character is a variable name (of the array
|
536 |
+
* we want to use property notation on) - this is to make sure
|
537 |
+
* standalone ['value'] arrays aren't confused for keys-of-an-array.
|
538 |
+
* We can (and only have to) check the last character, because PHP's
|
539 |
+
* regex implementation doesn't allow unfixed-length look-behind
|
540 |
+
* assertions.
|
541 |
+
*/
|
542 |
+
preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
|
543 |
+
$previousChar = $previousChar[1];
|
544 |
+
|
545 |
+
/*
|
546 |
+
* Make sure word preceding the ['value'] is not a keyword, e.g.
|
547 |
+
* return['x']. Because -again- PHP's regex implementation doesn't allow
|
548 |
+
* unfixed-length look-behind assertions, I'm just going to do a lot of
|
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('/(?<='.$previousChar.'|\])'.$keywords.'\[\s*(([\'"])[0-9]+\\2)\s*\]/u', $callback, $content);
|
555 |
+
}
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Replaces true & false by !0 and !1.
|
559 |
+
*
|
560 |
+
* @param string $content
|
561 |
+
*
|
562 |
+
* @return string
|
563 |
+
*/
|
564 |
+
protected function shortenBools($content)
|
565 |
+
{
|
566 |
+
/*
|
567 |
+
* 'true' or 'false' could be used as property names (which may be
|
568 |
+
* followed by whitespace) - we must not replace those!
|
569 |
+
* Since PHP doesn't allow variable-length (to account for the
|
570 |
+
* whitespace) lookbehind assertions, I need to capture the leading
|
571 |
+
* character and check if it's a `.`
|
572 |
+
*/
|
573 |
+
$callback = function ($match) {
|
574 |
+
if (trim($match[1]) === '.') {
|
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 |
+
|
582 |
+
// for(;;) is exactly the same as while(true), but shorter :)
|
583 |
+
$content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);
|
584 |
+
|
585 |
+
// now make sure we didn't turn any do ... while(true) into do ... for(;;)
|
586 |
+
preg_match_all('/\bdo\b/', $content, $dos, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
|
587 |
+
|
588 |
+
// go backward to make sure positional offsets aren't altered when $content changes
|
589 |
+
$dos = array_reverse($dos);
|
590 |
+
foreach ($dos as $do) {
|
591 |
+
$offsetDo = $do[0][1];
|
592 |
+
|
593 |
+
// find all `while` (now `for`) following `do`: one of those must be
|
594 |
+
// associated with the `do` and be turned back into `while`
|
595 |
+
preg_match_all('/\bfor\(;;\)/', $content, $whiles, PREG_OFFSET_CAPTURE | PREG_SET_ORDER, $offsetDo);
|
596 |
+
foreach ($whiles as $while) {
|
597 |
+
$offsetWhile = $while[0][1];
|
598 |
+
|
599 |
+
$open = substr_count($content, '{', $offsetDo, $offsetWhile - $offsetDo);
|
600 |
+
$close = substr_count($content, '}', $offsetDo, $offsetWhile - $offsetDo);
|
601 |
+
if ($open === $close) {
|
602 |
+
// only restore `while` if amount of `{` and `}` are the same;
|
603 |
+
// otherwise, that `for` isn't associated with this `do`
|
604 |
+
$content = substr_replace($content, 'while(!0)', $offsetWhile, strlen('for(;;)'));
|
605 |
+
break;
|
606 |
+
}
|
607 |
+
}
|
608 |
+
}
|
609 |
+
|
610 |
+
return $content;
|
611 |
+
}
|
612 |
+
}
|
libs/matthiasmullie/minify/src/Minify.php
CHANGED
@@ -1,459 +1,459 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Abstract minifier class
|
4 |
-
*
|
5 |
-
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
-
*
|
7 |
-
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
-
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
-
* @license MIT License
|
10 |
-
*/
|
11 |
-
namespace MatthiasMullie\Minify;
|
12 |
-
|
13 |
-
use MatthiasMullie\Minify\Exceptions\IOException;
|
14 |
-
use Psr\Cache\CacheItemInterface;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Abstract minifier class.
|
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
|
25 |
-
*/
|
26 |
-
abstract class Minify
|
27 |
-
{
|
28 |
-
/**
|
29 |
-
* The data to be minified.
|
30 |
-
*
|
31 |
-
* @var string[]
|
32 |
-
*/
|
33 |
-
protected $data = array();
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Array of patterns to match.
|
37 |
-
*
|
38 |
-
* @var string[]
|
39 |
-
*/
|
40 |
-
protected $patterns = array();
|
41 |
-
|
42 |
-
/**
|
43 |
-
* This array will hold content of strings and regular expressions that have
|
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();
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Init the minify class - optionally, code may be passed along already.
|
53 |
-
*/
|
54 |
-
public function __construct(/* $data = null, ... */)
|
55 |
-
{
|
56 |
-
// it's possible to add the source through the constructor as well ;)
|
57 |
-
if (func_num_args()) {
|
58 |
-
call_user_func_array(array($this, 'add'), func_get_args());
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Add a file or straight-up code to be minified.
|
64 |
-
*
|
65 |
-
* @param string|string[] $data
|
66 |
-
*
|
67 |
-
* @return static
|
68 |
-
*/
|
69 |
-
public function add($data /* $data = null, ... */)
|
70 |
-
{
|
71 |
-
// bogus "usage" of parameter $data: scrutinizer warns this variable is
|
72 |
-
// not used (we're using func_get_args instead to support overloading),
|
73 |
-
// but it still needs to be defined because it makes no sense to have
|
74 |
-
// this function without argument :)
|
75 |
-
$args = array($data) + func_get_args();
|
76 |
-
|
77 |
-
// this method can be overloaded
|
78 |
-
foreach ($args as $data) {
|
79 |
-
if (is_array($data)) {
|
80 |
-
call_user_func_array(array($this, 'add'), $data);
|
81 |
-
continue;
|
82 |
-
}
|
83 |
-
|
84 |
-
// redefine var
|
85 |
-
$data = (string) $data;
|
86 |
-
|
87 |
-
// load data
|
88 |
-
$value = $this->load($data);
|
89 |
-
$key = ($data != $value) ? $data : count($this->data);
|
90 |
-
|
91 |
-
// replace CR linefeeds etc.
|
92 |
-
// @see https://github.com/matthiasmullie/minify/pull/139
|
93 |
-
$value = str_replace(array("\r\n", "\r"), "\n", $value);
|
94 |
-
|
95 |
-
// store data
|
96 |
-
$this->data[$key] = $value;
|
97 |
-
}
|
98 |
-
|
99 |
-
return $this;
|
100 |
-
}
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Minify the data & (optionally) saves it to a file.
|
104 |
-
*
|
105 |
-
* @param string[optional] $path Path to write the data to
|
106 |
-
*
|
107 |
-
* @return string The minified data
|
108 |
-
*/
|
109 |
-
public function minify($path = null)
|
110 |
-
{
|
111 |
-
$content = $this->execute($path);
|
112 |
-
|
113 |
-
// save to path
|
114 |
-
if ($path !== null) {
|
115 |
-
$this->save($content, $path);
|
116 |
-
}
|
117 |
-
|
118 |
-
return $content;
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Minify & gzip the data & (optionally) saves it to a file.
|
123 |
-
*
|
124 |
-
* @param string[optional] $path Path to write the data to
|
125 |
-
* @param int[optional] $level Compression level, from 0 to 9
|
126 |
-
*
|
127 |
-
* @return string The minified & gzipped data
|
128 |
-
*/
|
129 |
-
public function gzip($path = null, $level = 9)
|
130 |
-
{
|
131 |
-
$content = $this->execute($path);
|
132 |
-
$content = gzencode($content, $level, FORCE_GZIP);
|
133 |
-
|
134 |
-
// save to path
|
135 |
-
if ($path !== null) {
|
136 |
-
$this->save($content, $path);
|
137 |
-
}
|
138 |
-
|
139 |
-
return $content;
|
140 |
-
}
|
141 |
-
|
142 |
-
/**
|
143 |
-
* Minify the data & write it to a CacheItemInterface object.
|
144 |
-
*
|
145 |
-
* @param CacheItemInterface $item Cache item to write the data to
|
146 |
-
*
|
147 |
-
* @return CacheItemInterface Cache item with the minifier data
|
148 |
-
*/
|
149 |
-
public function cache(CacheItemInterface $item)
|
150 |
-
{
|
151 |
-
$content = $this->execute();
|
152 |
-
$item->set($content);
|
153 |
-
|
154 |
-
return $item;
|
155 |
-
}
|
156 |
-
|
157 |
-
/**
|
158 |
-
* Minify the data.
|
159 |
-
*
|
160 |
-
* @param string[optional] $path Path to write the data to
|
161 |
-
*
|
162 |
-
* @return string The minified data
|
163 |
-
*/
|
164 |
-
abstract public function execute($path = null);
|
165 |
-
|
166 |
-
/**
|
167 |
-
* Load data.
|
168 |
-
*
|
169 |
-
* @param string $data Either a path to a file or the content itself
|
170 |
-
*
|
171 |
-
* @return string
|
172 |
-
*/
|
173 |
-
protected function load($data)
|
174 |
-
{
|
175 |
-
// check if the data is a file
|
176 |
-
if ($this->canImportFile($data)) {
|
177 |
-
$data = file_get_contents($data);
|
178 |
-
|
179 |
-
// strip BOM, if any
|
180 |
-
if (substr($data, 0, 3) == "\xef\xbb\xbf") {
|
181 |
-
$data = substr($data, 3);
|
182 |
-
}
|
183 |
-
}
|
184 |
-
|
185 |
-
return $data;
|
186 |
-
}
|
187 |
-
|
188 |
-
/**
|
189 |
-
* Save to file.
|
190 |
-
*
|
191 |
-
* @param string $content The minified data
|
192 |
-
* @param string $path The path to save the minified data to
|
193 |
-
*
|
194 |
-
* @throws IOException
|
195 |
-
*/
|
196 |
-
protected function save($content, $path)
|
197 |
-
{
|
198 |
-
$handler = $this->openFileForWriting($path);
|
199 |
-
|
200 |
-
$this->writeToFile($handler, $content);
|
201 |
-
|
202 |
-
@fclose($handler);
|
203 |
-
}
|
204 |
-
|
205 |
-
/**
|
206 |
-
* Register a pattern to execute against the source content.
|
207 |
-
*
|
208 |
-
* @param string $pattern PCRE pattern
|
209 |
-
* @param string|callable $replacement Replacement value for matched pattern
|
210 |
-
*/
|
211 |
-
protected function registerPattern($pattern, $replacement = '')
|
212 |
-
{
|
213 |
-
// study the pattern, we'll execute it more than once
|
214 |
-
$pattern .= 'S';
|
215 |
-
|
216 |
-
$this->patterns[] = array($pattern, $replacement);
|
217 |
-
}
|
218 |
-
|
219 |
-
/**
|
220 |
-
* We can't "just" run some regular expressions against JavaScript: it's a
|
221 |
-
* complex language. E.g. having an occurrence of // xyz would be a comment,
|
222 |
-
* unless it's used within a string. Of you could have something that looks
|
223 |
-
* like a 'string', but inside a comment.
|
224 |
-
* The only way to accurately replace these pieces is to traverse the JS one
|
225 |
-
* character at a time and try to find whatever starts first.
|
226 |
-
*
|
227 |
-
* @param string $content The content to replace patterns in
|
228 |
-
*
|
229 |
-
* @return string The (manipulated) content
|
230 |
-
*/
|
231 |
-
protected function replace($content)
|
232 |
-
{
|
233 |
-
$processed = '';
|
234 |
-
$positions = array_fill(0, count($this->patterns), -1);
|
235 |
-
$matches = array();
|
236 |
-
|
237 |
-
while ($content) {
|
238 |
-
// find first match for all patterns
|
239 |
-
foreach ($this->patterns as $i => $pattern) {
|
240 |
-
list($pattern, $replacement) = $pattern;
|
241 |
-
|
242 |
-
// we can safely ignore patterns for positions we've unset earlier,
|
243 |
-
// because we know these won't show up anymore
|
244 |
-
if (
|
245 |
-
continue;
|
246 |
-
}
|
247 |
-
|
248 |
-
// no need to re-run matches that are still in the part of the
|
249 |
-
// content that hasn't been processed
|
250 |
-
if ($positions[$i] >= 0) {
|
251 |
-
continue;
|
252 |
-
}
|
253 |
-
|
254 |
-
$match = null;
|
255 |
-
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) {
|
256 |
-
$matches[$i] = $match;
|
257 |
-
|
258 |
-
// we'll store the match position as well; that way, we
|
259 |
-
// don't have to redo all preg_matches after changing only
|
260 |
-
// the first (we'll still know where those others are)
|
261 |
-
$positions[$i] = $match[0][1];
|
262 |
-
} else {
|
263 |
-
// if the pattern couldn't be matched, there's no point in
|
264 |
-
// executing it again in later runs on this same content;
|
265 |
-
// ignore this one until we reach end of content
|
266 |
-
unset($matches[$i], $positions[$i]);
|
267 |
-
}
|
268 |
-
}
|
269 |
-
|
270 |
-
// no more matches to find: everything's been processed, break out
|
271 |
-
if (!$matches) {
|
272 |
-
$processed .= $content;
|
273 |
-
break;
|
274 |
-
}
|
275 |
-
|
276 |
-
// see which of the patterns actually found the first thing (we'll
|
277 |
-
// only want to execute that one, since we're unsure if what the
|
278 |
-
// other found was not inside what the first found)
|
279 |
-
$discardLength = min($positions);
|
280 |
-
$firstPattern = array_search($discardLength, $positions);
|
281 |
-
$match = $matches[$firstPattern][0][0];
|
282 |
-
|
283 |
-
// execute the pattern that matches earliest in the content string
|
284 |
-
list($pattern, $replacement) = $this->patterns[$firstPattern];
|
285 |
-
$replacement = $this->replacePattern($pattern, $replacement, $content);
|
286 |
-
|
287 |
-
// figure out which part of the string was unmatched; that's the
|
288 |
-
// part we'll execute the patterns on again next
|
289 |
-
$content = (string) substr($content, $discardLength);
|
290 |
-
$unmatched = (string) substr($content, strpos($content, $match) + strlen($match));
|
291 |
-
|
292 |
-
// move the replaced part to $processed and prepare $content to
|
293 |
-
// again match batch of patterns against
|
294 |
-
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
|
295 |
-
$content = $unmatched;
|
296 |
-
|
297 |
-
// first match has been replaced & that content is to be left alone,
|
298 |
-
// the next matches will start after this replacement, so we should
|
299 |
-
// fix their offsets
|
300 |
-
foreach ($positions as $i => $position) {
|
301 |
-
$positions[$i] -= $discardLength + strlen($match);
|
302 |
-
}
|
303 |
-
}
|
304 |
-
|
305 |
-
return $processed;
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* This is where a pattern is matched against $content and the matches
|
310 |
-
* are replaced by their respective value.
|
311 |
-
* This function will be called plenty of times, where $content will always
|
312 |
-
* move up 1 character.
|
313 |
-
*
|
314 |
-
* @param string $pattern Pattern to match
|
315 |
-
* @param string|callable $replacement Replacement value
|
316 |
-
* @param string $content Content to match pattern against
|
317 |
-
*
|
318 |
-
* @return string
|
319 |
-
*/
|
320 |
-
protected function replacePattern($pattern, $replacement, $content)
|
321 |
-
{
|
322 |
-
if (is_callable($replacement)) {
|
323 |
-
return preg_replace_callback($pattern, $replacement, $content, 1, $count);
|
324 |
-
} else {
|
325 |
-
return preg_replace($pattern, $replacement, $content, 1, $count);
|
326 |
-
}
|
327 |
-
}
|
328 |
-
|
329 |
-
/**
|
330 |
-
* Strings are a pattern we need to match, in order to ignore potential
|
331 |
-
* code-like content inside them, but we just want all of the string
|
332 |
-
* content to remain untouched.
|
333 |
-
*
|
334 |
-
* This method will replace all string content with simple STRING#
|
335 |
-
* placeholder text, so we've rid all strings from characters that may be
|
336 |
-
* misinterpreted. Original string content will be saved in $this->extracted
|
337 |
-
* and after doing all other minifying, we can restore the original content
|
338 |
-
* via restoreStrings().
|
339 |
-
*
|
340 |
-
* @param string[optional] $chars
|
341 |
-
* @param string[optional] $placeholderPrefix
|
342 |
-
*/
|
343 |
-
protected function extractStrings($chars = '\'"', $placeholderPrefix = '')
|
344 |
-
{
|
345 |
-
// PHP only supports $this inside anonymous functions since 5.4
|
346 |
-
$minifier = $this;
|
347 |
-
$callback = function ($match) use ($minifier, $placeholderPrefix) {
|
348 |
-
// check the second index here, because the first always contains a quote
|
349 |
-
if ($match[2] === '') {
|
350 |
-
/*
|
351 |
-
* Empty strings need no placeholder; they can't be confused for
|
352 |
-
* anything else anyway.
|
353 |
-
* But we still needed to match them, for the extraction routine
|
354 |
-
* to skip over this particular string.
|
355 |
-
*/
|
356 |
-
return $match[0];
|
357 |
-
}
|
358 |
-
|
359 |
-
$count = count($minifier->extracted);
|
360 |
-
$placeholder = $match[1].$placeholderPrefix.$count.$match[1];
|
361 |
-
$minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
|
362 |
-
|
363 |
-
return $placeholder;
|
364 |
-
};
|
365 |
-
|
366 |
-
/*
|
367 |
-
* The \\ messiness explained:
|
368 |
-
* * Don't count ' or " as end-of-string if it's escaped (has backslash
|
369 |
-
* in front of it)
|
370 |
-
* * Unless... that backslash itself is escaped (another leading slash),
|
371 |
-
* in which case it's no longer escaping the ' or "
|
372 |
-
* * So there can be either no backslash, or an even number
|
373 |
-
* * multiply all of that times 4, to account for the escaping that has
|
374 |
-
* to be done to pass the backslash into the PHP string without it being
|
375 |
-
* considered as escape-char (times 2) and to get it in the regex,
|
376 |
-
* escaped (times 2)
|
377 |
-
*/
|
378 |
-
$this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
|
379 |
-
}
|
380 |
-
|
381 |
-
/**
|
382 |
-
* This method will restore all extracted data (strings, regexes) that were
|
383 |
-
* replaced with placeholder text in extract*(). The original content was
|
384 |
-
* saved in $this->extracted.
|
385 |
-
*
|
386 |
-
* @param string $content
|
387 |
-
*
|
388 |
-
* @return string
|
389 |
-
*/
|
390 |
-
protected function restoreExtractedData($content)
|
391 |
-
{
|
392 |
-
if (!$this->extracted) {
|
393 |
-
// nothing was extracted, nothing to restore
|
394 |
-
return $content;
|
395 |
-
}
|
396 |
-
|
397 |
-
$content = strtr($content, $this->extracted);
|
398 |
-
|
399 |
-
$this->extracted = array();
|
400 |
-
|
401 |
-
return $content;
|
402 |
-
}
|
403 |
-
|
404 |
-
/**
|
405 |
-
* Check if the path is a regular file and can be read.
|
406 |
-
*
|
407 |
-
* @param string $path
|
408 |
-
*
|
409 |
-
* @return bool
|
410 |
-
*/
|
411 |
-
protected function canImportFile($path)
|
412 |
-
{
|
413 |
-
$parsed = parse_url($path);
|
414 |
-
if (
|
415 |
-
// file is elsewhere
|
416 |
-
isset($parsed['host']) ||
|
417 |
-
// file responds to queries (may change, or need to bypass cache)
|
418 |
-
isset($parsed['query'])
|
419 |
-
) {
|
420 |
-
return false;
|
421 |
-
}
|
422 |
-
|
423 |
-
return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
|
424 |
-
}
|
425 |
-
|
426 |
-
/**
|
427 |
-
* Attempts to open file specified by $path for writing.
|
428 |
-
*
|
429 |
-
* @param string $path The path to the file
|
430 |
-
*
|
431 |
-
* @return resource Specifier for the target file
|
432 |
-
*
|
433 |
-
* @throws IOException
|
434 |
-
*/
|
435 |
-
protected function openFileForWriting($path)
|
436 |
-
{
|
437 |
-
if (($handler = @fopen($path, 'w')) === false) {
|
438 |
-
throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.');
|
439 |
-
}
|
440 |
-
|
441 |
-
return $handler;
|
442 |
-
}
|
443 |
-
|
444 |
-
/**
|
445 |
-
* Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
|
446 |
-
*
|
447 |
-
* @param resource $handler The resource to write to
|
448 |
-
* @param string $content The content to write
|
449 |
-
* @param string $path The path to the file (for exception printing only)
|
450 |
-
*
|
451 |
-
* @throws IOException
|
452 |
-
*/
|
453 |
-
protected function writeToFile($handler, $content, $path = '')
|
454 |
-
{
|
455 |
-
if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) {
|
456 |
-
throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.');
|
457 |
-
}
|
458 |
-
}
|
459 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Abstract minifier class
|
4 |
+
*
|
5 |
+
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
6 |
+
*
|
7 |
+
* @author Matthias Mullie <minify@mullie.eu>
|
8 |
+
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
|
9 |
+
* @license MIT License
|
10 |
+
*/
|
11 |
+
namespace MatthiasMullie\Minify;
|
12 |
+
|
13 |
+
use MatthiasMullie\Minify\Exceptions\IOException;
|
14 |
+
use Psr\Cache\CacheItemInterface;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Abstract minifier class.
|
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
|
25 |
+
*/
|
26 |
+
abstract class Minify
|
27 |
+
{
|
28 |
+
/**
|
29 |
+
* The data to be minified.
|
30 |
+
*
|
31 |
+
* @var string[]
|
32 |
+
*/
|
33 |
+
protected $data = array();
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Array of patterns to match.
|
37 |
+
*
|
38 |
+
* @var string[]
|
39 |
+
*/
|
40 |
+
protected $patterns = array();
|
41 |
+
|
42 |
+
/**
|
43 |
+
* This array will hold content of strings and regular expressions that have
|
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();
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Init the minify class - optionally, code may be passed along already.
|
53 |
+
*/
|
54 |
+
public function __construct(/* $data = null, ... */)
|
55 |
+
{
|
56 |
+
// it's possible to add the source through the constructor as well ;)
|
57 |
+
if (func_num_args()) {
|
58 |
+
call_user_func_array(array($this, 'add'), func_get_args());
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Add a file or straight-up code to be minified.
|
64 |
+
*
|
65 |
+
* @param string|string[] $data
|
66 |
+
*
|
67 |
+
* @return static
|
68 |
+
*/
|
69 |
+
public function add($data /* $data = null, ... */)
|
70 |
+
{
|
71 |
+
// bogus "usage" of parameter $data: scrutinizer warns this variable is
|
72 |
+
// not used (we're using func_get_args instead to support overloading),
|
73 |
+
// but it still needs to be defined because it makes no sense to have
|
74 |
+
// this function without argument :)
|
75 |
+
$args = array($data) + func_get_args();
|
76 |
+
|
77 |
+
// this method can be overloaded
|
78 |
+
foreach ($args as $data) {
|
79 |
+
if (is_array($data)) {
|
80 |
+
call_user_func_array(array($this, 'add'), $data);
|
81 |
+
continue;
|
82 |
+
}
|
83 |
+
|
84 |
+
// redefine var
|
85 |
+
$data = (string) $data;
|
86 |
+
|
87 |
+
// load data
|
88 |
+
$value = $this->load($data);
|
89 |
+
$key = ($data != $value) ? $data : count($this->data);
|
90 |
+
|
91 |
+
// replace CR linefeeds etc.
|
92 |
+
// @see https://github.com/matthiasmullie/minify/pull/139
|
93 |
+
$value = str_replace(array("\r\n", "\r"), "\n", $value);
|
94 |
+
|
95 |
+
// store data
|
96 |
+
$this->data[$key] = $value;
|
97 |
+
}
|
98 |
+
|
99 |
+
return $this;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Minify the data & (optionally) saves it to a file.
|
104 |
+
*
|
105 |
+
* @param string[optional] $path Path to write the data to
|
106 |
+
*
|
107 |
+
* @return string The minified data
|
108 |
+
*/
|
109 |
+
public function minify($path = null)
|
110 |
+
{
|
111 |
+
$content = $this->execute($path);
|
112 |
+
|
113 |
+
// save to path
|
114 |
+
if ($path !== null) {
|
115 |
+
$this->save($content, $path);
|
116 |
+
}
|
117 |
+
|
118 |
+
return $content;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Minify & gzip the data & (optionally) saves it to a file.
|
123 |
+
*
|
124 |
+
* @param string[optional] $path Path to write the data to
|
125 |
+
* @param int[optional] $level Compression level, from 0 to 9
|
126 |
+
*
|
127 |
+
* @return string The minified & gzipped data
|
128 |
+
*/
|
129 |
+
public function gzip($path = null, $level = 9)
|
130 |
+
{
|
131 |
+
$content = $this->execute($path);
|
132 |
+
$content = gzencode($content, $level, FORCE_GZIP);
|
133 |
+
|
134 |
+
// save to path
|
135 |
+
if ($path !== null) {
|
136 |
+
$this->save($content, $path);
|
137 |
+
}
|
138 |
+
|
139 |
+
return $content;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Minify the data & write it to a CacheItemInterface object.
|
144 |
+
*
|
145 |
+
* @param CacheItemInterface $item Cache item to write the data to
|
146 |
+
*
|
147 |
+
* @return CacheItemInterface Cache item with the minifier data
|
148 |
+
*/
|
149 |
+
public function cache(CacheItemInterface $item)
|
150 |
+
{
|
151 |
+
$content = $this->execute();
|
152 |
+
$item->set($content);
|
153 |
+
|
154 |
+
return $item;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Minify the data.
|
159 |
+
*
|
160 |
+
* @param string[optional] $path Path to write the data to
|
161 |
+
*
|
162 |
+
* @return string The minified data
|
163 |
+
*/
|
164 |
+
abstract public function execute($path = null);
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Load data.
|
168 |
+
*
|
169 |
+
* @param string $data Either a path to a file or the content itself
|
170 |
+
*
|
171 |
+
* @return string
|
172 |
+
*/
|
173 |
+
protected function load($data)
|
174 |
+
{
|
175 |
+
// check if the data is a file
|
176 |
+
if ($this->canImportFile($data)) {
|
177 |
+
$data = file_get_contents($data);
|
178 |
+
|
179 |
+
// strip BOM, if any
|
180 |
+
if (substr($data, 0, 3) == "\xef\xbb\xbf") {
|
181 |
+
$data = substr($data, 3);
|
182 |
+
}
|
183 |
+
}
|
184 |
+
|
185 |
+
return $data;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Save to file.
|
190 |
+
*
|
191 |
+
* @param string $content The minified data
|
192 |
+
* @param string $path The path to save the minified data to
|
193 |
+
*
|
194 |
+
* @throws IOException
|
195 |
+
*/
|
196 |
+
protected function save($content, $path)
|
197 |
+
{
|
198 |
+
$handler = $this->openFileForWriting($path);
|
199 |
+
|
200 |
+
$this->writeToFile($handler, $content);
|
201 |
+
|
202 |
+
@fclose($handler);
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Register a pattern to execute against the source content.
|
207 |
+
*
|
208 |
+
* @param string $pattern PCRE pattern
|
209 |
+
* @param string|callable $replacement Replacement value for matched pattern
|
210 |
+
*/
|
211 |
+
protected function registerPattern($pattern, $replacement = '')
|
212 |
+
{
|
213 |
+
// study the pattern, we'll execute it more than once
|
214 |
+
$pattern .= 'S';
|
215 |
+
|
216 |
+
$this->patterns[] = array($pattern, $replacement);
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* We can't "just" run some regular expressions against JavaScript: it's a
|
221 |
+
* complex language. E.g. having an occurrence of // xyz would be a comment,
|
222 |
+
* unless it's used within a string. Of you could have something that looks
|
223 |
+
* like a 'string', but inside a comment.
|
224 |
+
* The only way to accurately replace these pieces is to traverse the JS one
|
225 |
+
* character at a time and try to find whatever starts first.
|
226 |
+
*
|
227 |
+
* @param string $content The content to replace patterns in
|
228 |
+
*
|
229 |
+
* @return string The (manipulated) content
|
230 |
+
*/
|
231 |
+
protected function replace($content)
|
232 |
+
{
|
233 |
+
$processed = '';
|
234 |
+
$positions = array_fill(0, count($this->patterns), -1);
|
235 |
+
$matches = array();
|
236 |
+
|
237 |
+
while ($content) {
|
238 |
+
// find first match for all patterns
|
239 |
+
foreach ($this->patterns as $i => $pattern) {
|
240 |
+
list($pattern, $replacement) = $pattern;
|
241 |
+
|
242 |
+
// we can safely ignore patterns for positions we've unset earlier,
|
243 |
+
// because we know these won't show up anymore
|
244 |
+
if (array_key_exists($i, $positions) == false) {
|
245 |
+
continue;
|
246 |
+
}
|
247 |
+
|
248 |
+
// no need to re-run matches that are still in the part of the
|
249 |
+
// content that hasn't been processed
|
250 |
+
if ($positions[$i] >= 0) {
|
251 |
+
continue;
|
252 |
+
}
|
253 |
+
|
254 |
+
$match = null;
|
255 |
+
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) {
|
256 |
+
$matches[$i] = $match;
|
257 |
+
|
258 |
+
// we'll store the match position as well; that way, we
|
259 |
+
// don't have to redo all preg_matches after changing only
|
260 |
+
// the first (we'll still know where those others are)
|
261 |
+
$positions[$i] = $match[0][1];
|
262 |
+
} else {
|
263 |
+
// if the pattern couldn't be matched, there's no point in
|
264 |
+
// executing it again in later runs on this same content;
|
265 |
+
// ignore this one until we reach end of content
|
266 |
+
unset($matches[$i], $positions[$i]);
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
// no more matches to find: everything's been processed, break out
|
271 |
+
if (!$matches) {
|
272 |
+
$processed .= $content;
|
273 |
+
break;
|
274 |
+
}
|
275 |
+
|
276 |
+
// see which of the patterns actually found the first thing (we'll
|
277 |
+
// only want to execute that one, since we're unsure if what the
|
278 |
+
// other found was not inside what the first found)
|
279 |
+
$discardLength = min($positions);
|
280 |
+
$firstPattern = array_search($discardLength, $positions);
|
281 |
+
$match = $matches[$firstPattern][0][0];
|
282 |
+
|
283 |
+
// execute the pattern that matches earliest in the content string
|
284 |
+
list($pattern, $replacement) = $this->patterns[$firstPattern];
|
285 |
+
$replacement = $this->replacePattern($pattern, $replacement, $content);
|
286 |
+
|
287 |
+
// figure out which part of the string was unmatched; that's the
|
288 |
+
// part we'll execute the patterns on again next
|
289 |
+
$content = (string) substr($content, $discardLength);
|
290 |
+
$unmatched = (string) substr($content, strpos($content, $match) + strlen($match));
|
291 |
+
|
292 |
+
// move the replaced part to $processed and prepare $content to
|
293 |
+
// again match batch of patterns against
|
294 |
+
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
|
295 |
+
$content = $unmatched;
|
296 |
+
|
297 |
+
// first match has been replaced & that content is to be left alone,
|
298 |
+
// the next matches will start after this replacement, so we should
|
299 |
+
// fix their offsets
|
300 |
+
foreach ($positions as $i => $position) {
|
301 |
+
$positions[$i] -= $discardLength + strlen($match);
|
302 |
+
}
|
303 |
+
}
|
304 |
+
|
305 |
+
return $processed;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* This is where a pattern is matched against $content and the matches
|
310 |
+
* are replaced by their respective value.
|
311 |
+
* This function will be called plenty of times, where $content will always
|
312 |
+
* move up 1 character.
|
313 |
+
*
|
314 |
+
* @param string $pattern Pattern to match
|
315 |
+
* @param string|callable $replacement Replacement value
|
316 |
+
* @param string $content Content to match pattern against
|
317 |
+
*
|
318 |
+
* @return string
|
319 |
+
*/
|
320 |
+
protected function replacePattern($pattern, $replacement, $content)
|
321 |
+
{
|
322 |
+
if (is_callable($replacement)) {
|
323 |
+
return preg_replace_callback($pattern, $replacement, $content, 1, $count);
|
324 |
+
} else {
|
325 |
+
return preg_replace($pattern, $replacement, $content, 1, $count);
|
326 |
+
}
|
327 |
+
}
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Strings are a pattern we need to match, in order to ignore potential
|
331 |
+
* code-like content inside them, but we just want all of the string
|
332 |
+
* content to remain untouched.
|
333 |
+
*
|
334 |
+
* This method will replace all string content with simple STRING#
|
335 |
+
* placeholder text, so we've rid all strings from characters that may be
|
336 |
+
* misinterpreted. Original string content will be saved in $this->extracted
|
337 |
+
* and after doing all other minifying, we can restore the original content
|
338 |
+
* via restoreStrings().
|
339 |
+
*
|
340 |
+
* @param string[optional] $chars
|
341 |
+
* @param string[optional] $placeholderPrefix
|
342 |
+
*/
|
343 |
+
protected function extractStrings($chars = '\'"', $placeholderPrefix = '')
|
344 |
+
{
|
345 |
+
// PHP only supports $this inside anonymous functions since 5.4
|
346 |
+
$minifier = $this;
|
347 |
+
$callback = function ($match) use ($minifier, $placeholderPrefix) {
|
348 |
+
// check the second index here, because the first always contains a quote
|
349 |
+
if ($match[2] === '') {
|
350 |
+
/*
|
351 |
+
* Empty strings need no placeholder; they can't be confused for
|
352 |
+
* anything else anyway.
|
353 |
+
* But we still needed to match them, for the extraction routine
|
354 |
+
* to skip over this particular string.
|
355 |
+
*/
|
356 |
+
return $match[0];
|
357 |
+
}
|
358 |
+
|
359 |
+
$count = count($minifier->extracted);
|
360 |
+
$placeholder = $match[1].$placeholderPrefix.$count.$match[1];
|
361 |
+
$minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
|
362 |
+
|
363 |
+
return $placeholder;
|
364 |
+
};
|
365 |
+
|
366 |
+
/*
|
367 |
+
* The \\ messiness explained:
|
368 |
+
* * Don't count ' or " as end-of-string if it's escaped (has backslash
|
369 |
+
* in front of it)
|
370 |
+
* * Unless... that backslash itself is escaped (another leading slash),
|
371 |
+
* in which case it's no longer escaping the ' or "
|
372 |
+
* * So there can be either no backslash, or an even number
|
373 |
+
* * multiply all of that times 4, to account for the escaping that has
|
374 |
+
* to be done to pass the backslash into the PHP string without it being
|
375 |
+
* considered as escape-char (times 2) and to get it in the regex,
|
376 |
+
* escaped (times 2)
|
377 |
+
*/
|
378 |
+
$this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
|
379 |
+
}
|
380 |
+
|
381 |
+
/**
|
382 |
+
* This method will restore all extracted data (strings, regexes) that were
|
383 |
+
* replaced with placeholder text in extract*(). The original content was
|
384 |
+
* saved in $this->extracted.
|
385 |
+
*
|
386 |
+
* @param string $content
|
387 |
+
*
|
388 |
+
* @return string
|
389 |
+
*/
|
390 |
+
protected function restoreExtractedData($content)
|
391 |
+
{
|
392 |
+
if (!$this->extracted) {
|
393 |
+
// nothing was extracted, nothing to restore
|
394 |
+
return $content;
|
395 |
+
}
|
396 |
+
|
397 |
+
$content = strtr($content, $this->extracted);
|
398 |
+
|
399 |
+
$this->extracted = array();
|
400 |
+
|
401 |
+
return $content;
|
402 |
+
}
|
403 |
+
|
404 |
+
/**
|
405 |
+
* Check if the path is a regular file and can be read.
|
406 |
+
*
|
407 |
+
* @param string $path
|
408 |
+
*
|
409 |
+
* @return bool
|
410 |
+
*/
|
411 |
+
protected function canImportFile($path)
|
412 |
+
{
|
413 |
+
$parsed = parse_url($path);
|
414 |
+
if (
|
415 |
+
// file is elsewhere
|
416 |
+
isset($parsed['host']) ||
|
417 |
+
// file responds to queries (may change, or need to bypass cache)
|
418 |
+
isset($parsed['query'])
|
419 |
+
) {
|
420 |
+
return false;
|
421 |
+
}
|
422 |
+
|
423 |
+
return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
|
424 |
+
}
|
425 |
+
|
426 |
+
/**
|
427 |
+
* Attempts to open file specified by $path for writing.
|
428 |
+
*
|
429 |
+
* @param string $path The path to the file
|
430 |
+
*
|
431 |
+
* @return resource Specifier for the target file
|
432 |
+
*
|
433 |
+
* @throws IOException
|
434 |
+
*/
|
435 |
+
protected function openFileForWriting($path)
|
436 |
+
{
|
437 |
+
if (($handler = @fopen($path, 'w')) === false) {
|
438 |
+
throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.');
|
439 |
+
}
|
440 |
+
|
441 |
+
return $handler;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
|
446 |
+
*
|
447 |
+
* @param resource $handler The resource to write to
|
448 |
+
* @param string $content The content to write
|
449 |
+
* @param string $path The path to the file (for exception printing only)
|
450 |
+
*
|
451 |
+
* @throws IOException
|
452 |
+
*/
|
453 |
+
protected function writeToFile($handler, $content, $path = '')
|
454 |
+
{
|
455 |
+
if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) {
|
456 |
+
throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.');
|
457 |
+
}
|
458 |
+
}
|
459 |
+
}
|
libs/matthiasmullie/path-converter/src/Converter.php
CHANGED
@@ -1,196 +1,196 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace MatthiasMullie\PathConverter;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Convert paths relative from 1 file to another.
|
7 |
-
*
|
8 |
-
* E.g.
|
9 |
-
* ../../images/icon.jpg relative to /css/imports/icons.css
|
10 |
-
* becomes
|
11 |
-
* ../images/icon.jpg relative to /css/minified.css
|
12 |
-
*
|
13 |
-
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
14 |
-
*
|
15 |
-
* @author Matthias Mullie <pathconverter@mullie.eu>
|
16 |
-
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
17 |
-
* @license MIT License
|
18 |
-
*/
|
19 |
-
class Converter implements ConverterInterface
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* @var string
|
23 |
-
*/
|
24 |
-
protected $from;
|
25 |
-
|
26 |
-
/**
|
27 |
-
* @var string
|
28 |
-
*/
|
29 |
-
protected $to;
|
30 |
-
|
31 |
-
/**
|
32 |
-
* @param string $from The original base path (directory, not file!)
|
33 |
-
* @param string $to The new base path (directory, not file!)
|
34 |
-
* @param string $root Root directory (defaults to `getcwd`)
|
35 |
-
*/
|
36 |
-
public function __construct($from, $to, $root = '')
|
37 |
-
{
|
38 |
-
$shared = $this->shared($from, $to);
|
39 |
-
if ($shared === '') {
|
40 |
-
// when both paths have nothing in common, one of them is probably
|
41 |
-
// absolute while the other is relative
|
42 |
-
$root = $root ?: getcwd();
|
43 |
-
$from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);
|
44 |
-
$to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);
|
45 |
-
|
46 |
-
// or traveling the tree via `..`
|
47 |
-
// attempt to resolve path, or assume it's fine if it doesn't exist
|
48 |
-
$from = @realpath($from) ?: $from;
|
49 |
-
$to = @realpath($to) ?: $to;
|
50 |
-
}
|
51 |
-
|
52 |
-
$from = $this->dirname($from);
|
53 |
-
$to = $this->dirname($to);
|
54 |
-
|
55 |
-
$from = $this->normalize($from);
|
56 |
-
$to = $this->normalize($to);
|
57 |
-
|
58 |
-
$this->from = $from;
|
59 |
-
$this->to = $to;
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Normalize path.
|
64 |
-
*
|
65 |
-
* @param string $path
|
66 |
-
*
|
67 |
-
* @return string
|
68 |
-
*/
|
69 |
-
protected function normalize($path)
|
70 |
-
{
|
71 |
-
// deal with different operating systems' directory structure
|
72 |
-
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
|
73 |
-
|
74 |
-
/*
|
75 |
-
* Example:
|
76 |
-
* /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
|
77 |
-
* to
|
78 |
-
* /home/forkcms/frontend/core/layout/images/img.gif
|
79 |
-
*/
|
80 |
-
do {
|
81 |
-
$path = preg_replace('/[^\/]+(?<!\.\.)\/\.\.\//', '', $path, -1, $count);
|
82 |
-
} while ($count);
|
83 |
-
|
84 |
-
return $path;
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Figure out the shared path of 2 locations.
|
89 |
-
*
|
90 |
-
* Example:
|
91 |
-
* /home/forkcms/frontend/core/layout/images/img.gif
|
92 |
-
* and
|
93 |
-
* /home/forkcms/frontend/cache/minified_css
|
94 |
-
* share
|
95 |
-
* /home/forkcms/frontend
|
96 |
-
*
|
97 |
-
* @param string $path1
|
98 |
-
* @param string $path2
|
99 |
-
*
|
100 |
-
* @return string
|
101 |
-
*/
|
102 |
-
protected function shared($path1, $path2)
|
103 |
-
{
|
104 |
-
// $path could theoretically be empty (e.g. no path is given), in which
|
105 |
-
// case it shouldn't expand to array(''), which would compare to one's
|
106 |
-
// root /
|
107 |
-
$path1 = $path1 ? explode('/', $path1) : array();
|
108 |
-
$path2 = $path2 ? explode('/', $path2) : array();
|
109 |
-
|
110 |
-
$shared = array();
|
111 |
-
|
112 |
-
// compare paths & strip identical ancestors
|
113 |
-
foreach ($path1 as $i => $chunk) {
|
114 |
-
if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
|
115 |
-
$shared[] = $chunk;
|
116 |
-
} else {
|
117 |
-
break;
|
118 |
-
}
|
119 |
-
}
|
120 |
-
|
121 |
-
return implode('/', $shared);
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Convert paths relative from 1 file to another.
|
126 |
-
*
|
127 |
-
* E.g.
|
128 |
-
* ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
|
129 |
-
* should become:
|
130 |
-
* ../../core/layout/images/img.gif relative to
|
131 |
-
* /home/forkcms/frontend/cache/minified_css
|
132 |
-
*
|
133 |
-
* @param string $path The relative path that needs to be converted
|
134 |
-
*
|
135 |
-
* @return string The new relative path
|
136 |
-
*/
|
137 |
-
public function convert($path)
|
138 |
-
{
|
139 |
-
// quit early if conversion makes no sense
|
140 |
-
if ($this->from === $this->to) {
|
141 |
-
return $path;
|
142 |
-
}
|
143 |
-
|
144 |
-
$path = $this->normalize($path);
|
145 |
-
// if we're not dealing with a relative path, just return absolute
|
146 |
-
if (strpos($path, '/') === 0) {
|
147 |
-
return $path;
|
148 |
-
}
|
149 |
-
|
150 |
-
// normalize paths
|
151 |
-
$path = $this->normalize($this->from.'/'.$path);
|
152 |
-
|
153 |
-
// strip shared ancestor paths
|
154 |
-
$shared = $this->shared($path, $this->to);
|
155 |
-
$path = mb_substr($path, mb_strlen($shared));
|
156 |
-
$to = mb_substr($this->to, mb_strlen($shared));
|
157 |
-
|
158 |
-
// add .. for every directory that needs to be traversed to new path
|
159 |
-
$to = str_repeat('../', count(array_filter(explode('/', $to))));
|
160 |
-
|
161 |
-
return $to.ltrim($path, '/');
|
162 |
-
}
|
163 |
-
|
164 |
-
/**
|
165 |
-
* Attempt to get the directory name from a path.
|
166 |
-
*
|
167 |
-
* @param string $path
|
168 |
-
*
|
169 |
-
* @return string
|
170 |
-
*/
|
171 |
-
protected function dirname($path)
|
172 |
-
{
|
173 |
-
if (@is_file($path)) {
|
174 |
-
return dirname($path);
|
175 |
-
}
|
176 |
-
|
177 |
-
if (@is_dir($path)) {
|
178 |
-
return rtrim($path, '/');
|
179 |
-
}
|
180 |
-
|
181 |
-
// no known file/dir, start making assumptions
|
182 |
-
|
183 |
-
// ends in / = dir
|
184 |
-
if (mb_substr($path, -1) === '/') {
|
185 |
-
return rtrim($path, '/');
|
186 |
-
}
|
187 |
-
|
188 |
-
// has a dot in the name, likely a file
|
189 |
-
if (preg_match('/.*\..*$/', basename($path)) !== 0) {
|
190 |
-
return dirname($path);
|
191 |
-
}
|
192 |
-
|
193 |
-
// you're on your own here!
|
194 |
-
return $path;
|
195 |
-
}
|
196 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Convert paths relative from 1 file to another.
|
7 |
+
*
|
8 |
+
* E.g.
|
9 |
+
* ../../images/icon.jpg relative to /css/imports/icons.css
|
10 |
+
* becomes
|
11 |
+
* ../images/icon.jpg relative to /css/minified.css
|
12 |
+
*
|
13 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
14 |
+
*
|
15 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
16 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
17 |
+
* @license MIT License
|
18 |
+
*/
|
19 |
+
class Converter implements ConverterInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
protected $from;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
protected $to;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $from The original base path (directory, not file!)
|
33 |
+
* @param string $to The new base path (directory, not file!)
|
34 |
+
* @param string $root Root directory (defaults to `getcwd`)
|
35 |
+
*/
|
36 |
+
public function __construct($from, $to, $root = '')
|
37 |
+
{
|
38 |
+
$shared = $this->shared($from, $to);
|
39 |
+
if ($shared === '') {
|
40 |
+
// when both paths have nothing in common, one of them is probably
|
41 |
+
// absolute while the other is relative
|
42 |
+
$root = $root ?: getcwd();
|
43 |
+
$from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);
|
44 |
+
$to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);
|
45 |
+
|
46 |
+
// or traveling the tree via `..`
|
47 |
+
// attempt to resolve path, or assume it's fine if it doesn't exist
|
48 |
+
$from = @realpath($from) ?: $from;
|
49 |
+
$to = @realpath($to) ?: $to;
|
50 |
+
}
|
51 |
+
|
52 |
+
$from = $this->dirname($from);
|
53 |
+
$to = $this->dirname($to);
|
54 |
+
|
55 |
+
$from = $this->normalize($from);
|
56 |
+
$to = $this->normalize($to);
|
57 |
+
|
58 |
+
$this->from = $from;
|
59 |
+
$this->to = $to;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Normalize path.
|
64 |
+
*
|
65 |
+
* @param string $path
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
protected function normalize($path)
|
70 |
+
{
|
71 |
+
// deal with different operating systems' directory structure
|
72 |
+
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
|
73 |
+
|
74 |
+
/*
|
75 |
+
* Example:
|
76 |
+
* /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
|
77 |
+
* to
|
78 |
+
* /home/forkcms/frontend/core/layout/images/img.gif
|
79 |
+
*/
|
80 |
+
do {
|
81 |
+
$path = preg_replace('/[^\/]+(?<!\.\.)\/\.\.\//', '', $path, -1, $count);
|
82 |
+
} while ($count);
|
83 |
+
|
84 |
+
return $path;
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Figure out the shared path of 2 locations.
|
89 |
+
*
|
90 |
+
* Example:
|
91 |
+
* /home/forkcms/frontend/core/layout/images/img.gif
|
92 |
+
* and
|
93 |
+
* /home/forkcms/frontend/cache/minified_css
|
94 |
+
* share
|
95 |
+
* /home/forkcms/frontend
|
96 |
+
*
|
97 |
+
* @param string $path1
|
98 |
+
* @param string $path2
|
99 |
+
*
|
100 |
+
* @return string
|
101 |
+
*/
|
102 |
+
protected function shared($path1, $path2)
|
103 |
+
{
|
104 |
+
// $path could theoretically be empty (e.g. no path is given), in which
|
105 |
+
// case it shouldn't expand to array(''), which would compare to one's
|
106 |
+
// root /
|
107 |
+
$path1 = $path1 ? explode('/', $path1) : array();
|
108 |
+
$path2 = $path2 ? explode('/', $path2) : array();
|
109 |
+
|
110 |
+
$shared = array();
|
111 |
+
|
112 |
+
// compare paths & strip identical ancestors
|
113 |
+
foreach ($path1 as $i => $chunk) {
|
114 |
+
if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
|
115 |
+
$shared[] = $chunk;
|
116 |
+
} else {
|
117 |
+
break;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
return implode('/', $shared);
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Convert paths relative from 1 file to another.
|
126 |
+
*
|
127 |
+
* E.g.
|
128 |
+
* ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
|
129 |
+
* should become:
|
130 |
+
* ../../core/layout/images/img.gif relative to
|
131 |
+
* /home/forkcms/frontend/cache/minified_css
|
132 |
+
*
|
133 |
+
* @param string $path The relative path that needs to be converted
|
134 |
+
*
|
135 |
+
* @return string The new relative path
|
136 |
+
*/
|
137 |
+
public function convert($path)
|
138 |
+
{
|
139 |
+
// quit early if conversion makes no sense
|
140 |
+
if ($this->from === $this->to) {
|
141 |
+
return $path;
|
142 |
+
}
|
143 |
+
|
144 |
+
$path = $this->normalize($path);
|
145 |
+
// if we're not dealing with a relative path, just return absolute
|
146 |
+
if (strpos($path, '/') === 0) {
|
147 |
+
return $path;
|
148 |
+
}
|
149 |
+
|
150 |
+
// normalize paths
|
151 |
+
$path = $this->normalize($this->from.'/'.$path);
|
152 |
+
|
153 |
+
// strip shared ancestor paths
|
154 |
+
$shared = $this->shared($path, $this->to);
|
155 |
+
$path = mb_substr($path, mb_strlen($shared));
|
156 |
+
$to = mb_substr($this->to, mb_strlen($shared));
|
157 |
+
|
158 |
+
// add .. for every directory that needs to be traversed to new path
|
159 |
+
$to = str_repeat('../', count(array_filter(explode('/', $to))));
|
160 |
+
|
161 |
+
return $to.ltrim($path, '/');
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Attempt to get the directory name from a path.
|
166 |
+
*
|
167 |
+
* @param string $path
|
168 |
+
*
|
169 |
+
* @return string
|
170 |
+
*/
|
171 |
+
protected function dirname($path)
|
172 |
+
{
|
173 |
+
if (@is_file($path)) {
|
174 |
+
return dirname($path);
|
175 |
+
}
|
176 |
+
|
177 |
+
if (@is_dir($path)) {
|
178 |
+
return rtrim($path, '/');
|
179 |
+
}
|
180 |
+
|
181 |
+
// no known file/dir, start making assumptions
|
182 |
+
|
183 |
+
// ends in / = dir
|
184 |
+
if (mb_substr($path, -1) === '/') {
|
185 |
+
return rtrim($path, '/');
|
186 |
+
}
|
187 |
+
|
188 |
+
// has a dot in the name, likely a file
|
189 |
+
if (preg_match('/.*\..*$/', basename($path)) !== 0) {
|
190 |
+
return dirname($path);
|
191 |
+
}
|
192 |
+
|
193 |
+
// you're on your own here!
|
194 |
+
return $path;
|
195 |
+
}
|
196 |
+
}
|
libs/matthiasmullie/path-converter/src/ConverterInterface.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace MatthiasMullie\PathConverter;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Convert file paths.
|
7 |
-
*
|
8 |
-
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
-
*
|
10 |
-
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
-
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
-
* @license MIT License
|
13 |
-
*/
|
14 |
-
interface ConverterInterface
|
15 |
-
{
|
16 |
-
/**
|
17 |
-
* Convert file paths.
|
18 |
-
*
|
19 |
-
* @param string $path The path to be converted
|
20 |
-
*
|
21 |
-
* @return string The new path
|
22 |
-
*/
|
23 |
-
public function convert($path);
|
24 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Convert file paths.
|
7 |
+
*
|
8 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
+
*
|
10 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
+
* @license MIT License
|
13 |
+
*/
|
14 |
+
interface ConverterInterface
|
15 |
+
{
|
16 |
+
/**
|
17 |
+
* Convert file paths.
|
18 |
+
*
|
19 |
+
* @param string $path The path to be converted
|
20 |
+
*
|
21 |
+
* @return string The new path
|
22 |
+
*/
|
23 |
+
public function convert($path);
|
24 |
+
}
|
libs/matthiasmullie/path-converter/src/NoConverter.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace MatthiasMullie\PathConverter;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Don't convert paths.
|
7 |
-
*
|
8 |
-
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
-
*
|
10 |
-
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
-
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
-
* @license MIT License
|
13 |
-
*/
|
14 |
-
class NoConverter implements ConverterInterface
|
15 |
-
{
|
16 |
-
/**
|
17 |
-
* {@inheritdoc}
|
18 |
-
*/
|
19 |
-
public function convert($path)
|
20 |
-
{
|
21 |
-
return $path;
|
22 |
-
}
|
23 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace MatthiasMullie\PathConverter;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Don't convert paths.
|
7 |
+
*
|
8 |
+
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
|
9 |
+
*
|
10 |
+
* @author Matthias Mullie <pathconverter@mullie.eu>
|
11 |
+
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
|
12 |
+
* @license MIT License
|
13 |
+
*/
|
14 |
+
class NoConverter implements ConverterInterface
|
15 |
+
{
|
16 |
+
/**
|
17 |
+
* {@inheritdoc}
|
18 |
+
*/
|
19 |
+
public function convert($path)
|
20 |
+
{
|
21 |
+
return $path;
|
22 |
+
}
|
23 |
+
}
|
readme.txt
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
=== Fast Velocity Minify ===
|
2 |
Contributors: Alignak
|
3 |
-
Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, CSS Merging, JS Merging, CSS Minification, JS Minification, Speed Optimization, HTML Minification, Performance, Optimization,
|
4 |
-
Requires at least: 4.
|
5 |
-
Requires PHP: 5.
|
6 |
-
Stable tag: 2.7.
|
7 |
-
Tested up to: 5.
|
8 |
License: GPLv3 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
10 |
|
@@ -198,8 +198,23 @@ Please backup your site before updating. Version 3.0 will have a major code rewr
|
|
198 |
|
199 |
== Changelog ==
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
= 2.7.4 [2019.08.18] =
|
202 |
-
*
|
203 |
|
204 |
= 2.7.3 [2019.07.29] =
|
205 |
* Beaver Builder compatibility fix
|
@@ -256,297 +271,8 @@ Please backup your site before updating. Version 3.0 will have a major code rewr
|
|
256 |
* improved compatibility with page cache plugins and servers (purging FVM without purging the page cache should be fine now)
|
257 |
* added a daily cronjob, to delete public invalid cache files that are older than 3 months (your page cache should expire before this)
|
258 |
|
259 |
-
= 2.5.9 [2019.02.19] =
|
260 |
-
* fixed some PHP notices, when wordpress fails to download a missing js/css file
|
261 |
-
|
262 |
-
= 2.5.8 [2019.02.06] =
|
263 |
-
* minor bug fix with the defer for pagespeed option
|
264 |
-
|
265 |
-
= 2.5.7 [2019.02.04] =
|
266 |
-
* reverted back the css merging method to version 2.5.2 due to some compatibility issues
|
267 |
-
|
268 |
-
= 2.5.6 [2019.01.18] =
|
269 |
-
* fixed some php notices
|
270 |
-
* disabled FVM on amp pages
|
271 |
-
* expected to be the last update on the 2.x branch, before 3.0 major release
|
272 |
-
|
273 |
-
= 2.5.5 [2019.01.12] =
|
274 |
-
* fixed the dynamic urls being forced as http://
|
275 |
-
* fixed the inlined styles being stripped when the inline all CSS option is enabled
|
276 |
-
* added option to disable merging of inlined css code (for when you have dynamic inline css code)
|
277 |
-
* other minor bug fixes
|
278 |
-
|
279 |
-
= 2.5.4 [2019.01.11] =
|
280 |
-
* css merging bug fixes
|
281 |
-
|
282 |
-
= 2.5.3 [2019.01.11] =
|
283 |
-
* fixed inlined css code being minified, even when minification is off
|
284 |
-
* compatibility and performance improvements for the CSS merging and inlining functionality
|
285 |
-
|
286 |
-
= 2.5.2 [2019.01.11] =
|
287 |
-
* removed CURL as a fallback method (CURL is already a fallback on the WP HTTP API) as per WP recommendation
|
288 |
-
* fixed a query monitor notice about mkdir
|
289 |
-
* removed some legacy code + some minor performance improvements on the code
|
290 |
-
* improvement for the defer for pagespeed option and ignore list
|
291 |
-
* improvement for the loadCSS functionality
|
292 |
-
* improvements for merging the google fonts option
|
293 |
-
|
294 |
-
= 2.5.1 [2018.12.17] =
|
295 |
-
* minor bug fix related to the font awesome option
|
296 |
-
* added cache purging support to Breeze (Cloudways)
|
297 |
-
|
298 |
-
= 2.5.0 [2018.12.13] =
|
299 |
-
* bug fixes with the google fonts merging option
|
300 |
-
* better default settings
|
301 |
-
|
302 |
-
= 2.4.9 [2018.12.13] =
|
303 |
-
* improved the google fonts merging to only allow existing google fonts (no more google fonts 404 errors due to the merging of the fonts)
|
304 |
-
* downgraded PHP Minify to version 1.3.60 due to someone reporting a server error with the new version
|
305 |
-
|
306 |
-
= 2.4.8 [2018.12.07] =
|
307 |
-
* changed the file permissions for the generated cache directory and files, to match the uploads directory
|
308 |
-
* added some extra checks for when PHP is running in safe mode
|
309 |
-
|
310 |
-
= 2.4.7 [2018.12.06] =
|
311 |
-
* added better default options after new install
|
312 |
-
* added option to preserve FVM settings on deactivation
|
313 |
-
* added an HTML comment to the frontend with the path and notification, when FVM cannot generate the cache files (ie: wrong file permissions)
|
314 |
-
* added a notification on wp-admin when FVM cannot generate the cache files due to wrong permissions
|
315 |
-
* added an option to force "chmod 0777" on FVM cache files, to avoid errors on servers that need more than "chmod 0755"
|
316 |
-
* improved the google fonts merging option when the enqueue is faulty (ie: incomplete google font urls )
|
317 |
-
* fixed the cache purge notifications not showing on wp-admin
|
318 |
-
|
319 |
-
= 2.4.6 [2018.12.05] =
|
320 |
-
* fixed a bug that could cause an error 500 if an enqueued CSS or JS file was not found
|
321 |
-
* added brotli_static support, if you have the php-ext-brotli extension installed - https://github.com/kjdev/php-ext-brotli
|
322 |
-
|
323 |
-
= 2.4.5 [2018.12.04] =
|
324 |
-
* fixed a bug, where it may show a warning during cache purge on wp-admin
|
325 |
-
* exclude footer FVM generated files from the HTTP header preload option (footer files are not in the critical path)
|
326 |
-
|
327 |
-
= 2.4.4 [2018.12.03] =
|
328 |
-
* added option to inline CSS in the footer, while still preserving the merged file in the header
|
329 |
-
* improvements for the google fonts merging option
|
330 |
-
* fixed double notification, when purging caches without a cache plugin
|
331 |
-
|
332 |
-
= 2.4.3 [2018.12.03] =
|
333 |
-
* added font-display, to ensure text remains visible during webfont load for inlined google fonts and font-awesome
|
334 |
-
* added automatic removal of "source mappings" from JS files during merging or minification
|
335 |
-
* added font awesome async and exclusion from PSI options, as well as merging and inlining when the url matches "font-awesome" (ie: cdnjs)
|
336 |
-
* added automatically inline of small CSS code (up to 20KB) for any FVM CSS files in the footer (requests reduction)
|
337 |
-
* added automatically inline of small CSS code (up to 20KB) for any FVM CSS files in the header, which are not of mediatype "all"
|
338 |
-
* improved the cache purge button (no more redirect from frontend to backend)
|
339 |
-
* updated PHP Minify and Path Converter from master
|
340 |
-
* bug fixes related to "Exclude JS files from PSI" option
|
341 |
-
|
342 |
-
= 2.4.2 [2018.11.29] =
|
343 |
-
* fixed a bug with the "Exclude JS files in the ignore list from PSI" option (it wasn't excluding properly)
|
344 |
-
* improved functionality with the "Exclude CSS files from PSI" option (now works with both inline and link stylesheets)
|
345 |
-
* added an option to automatically preload the CSS and JS files generated by FVM (beware that some server caches like Pantheon may push old css and js files even after purging caches on FVM)
|
346 |
-
* improved JavaScript minification
|
347 |
-
|
348 |
-
= 2.4.1 [2018.11.27] =
|
349 |
-
* better FVM default settings
|
350 |
-
|
351 |
-
= 2.4.0 [2018.11.26] =
|
352 |
-
* bug fixes related to the inline css option
|
353 |
-
* changed a few options and added better descriptions to the admin options
|
354 |
-
|
355 |
-
= 2.3.9 [2018.11.24] =
|
356 |
-
* there was an error on my end while pushing 2.3.8... this is a version bump
|
357 |
-
|
358 |
-
= 2.3.8 [2018.11.24] =
|
359 |
-
* removed the dynamic protocol in favour of auto detecting HTTP(s)
|
360 |
-
* fixed a bug where some CSS files were being removed with the latest CSS inline method
|
361 |
-
* fixed a bug where the wrong file path was being generated for fonts and some static assets (when the plugin or theme, uses relative paths and the Inline CSS option is enabled)
|
362 |
-
|
363 |
-
= 2.3.7 [2018.11.24] =
|
364 |
-
* bug fixes and performance improvements
|
365 |
-
* changed a few "options" location to other tabs
|
366 |
-
* changed the "Inline CSS" method to inline each file right separatly, instead of merging it and then inline it (also improves compatibility)
|
367 |
-
* added option to exclude JS and CSS files from PSI separatly (will load them Async, so make sure to read the instructions for each)
|
368 |
-
* added a dedicated Critical Path CSS for "is_front_page" (more conditionals on the roadmap)
|
369 |
-
* renamed some labels to be more explicit regardless of what they do
|
370 |
-
|
371 |
-
= 2.3.6 [2018.11.20] =
|
372 |
-
* added better header preloader and preconnect headers for css and js files
|
373 |
-
* added support to automatically purge the cache enabler plugin
|
374 |
-
* added option to reload the cache, while preserving the old static files
|
375 |
-
* added better default options after first install
|
376 |
-
* added and reorganized some options
|
377 |
-
* added a new developers tab
|
378 |
-
* removed the YUI compressor option (defaults to PHP Minify)
|
379 |
-
* readme and screenshots update
|
380 |
-
* tested up to WP 5.0 tag
|
381 |
-
|
382 |
-
= 2.3.5 [2018.08.27] =
|
383 |
-
* added thinkwithgoogle support for the defer for insights option
|
384 |
-
* added HyperCache support, thanks to @erich_k4wp
|
385 |
-
* added suport for wp_add_inline_script, thanks to @yuriipavlov
|
386 |
-
* fixed a bug where some inlined css was missing if not attached to a parent css file
|
387 |
-
* the ignore list now also supports CSS handle names (no JS yet)
|
388 |
-
* updated PHP Minify from master on github
|
389 |
-
* improved performance for gtmetrix tests
|
390 |
-
|
391 |
-
= 2.3.4 [2018.06.30] =
|
392 |
-
* bug fix
|
393 |
-
|
394 |
-
= 2.3.3 [2018.06.30] =
|
395 |
-
* added a check to prevent creating an empty js or css file
|
396 |
-
* added an option to force the CDN option when using the defer for insights option
|
397 |
-
* removed the alternative HTML minification method
|
398 |
-
* minor performance and bug fixes
|
399 |
-
|
400 |
-
= 2.3.2 [2018.06.03] =
|
401 |
-
* added some compatibility fixes when merging and minifying JS files
|
402 |
-
* added an option to enable an "FVM Purge" button on the admin bar
|
403 |
-
* moved all large transients (cached css or js code) to temporary disk files to reduce the database load
|
404 |
-
|
405 |
-
= 2.3.1 [2018.06.01] =
|
406 |
-
* bug fixes and performance tweaks for the "fix page editors" option
|
407 |
-
|
408 |
-
= 2.3.0 [2018.05.24] =
|
409 |
-
* added wp cli support for purge cache (usage: wp fvm purge)
|
410 |
-
* added wp cli support for getting the cache size (usage: wp fvm stats)
|
411 |
-
|
412 |
-
= 2.2.9 [2018.05.23] =
|
413 |
-
* fixed several bugs related to notices, css minification and file paths
|
414 |
-
* added more pcre.backtrack_limit and pcre.recursion_limit to avoid blank pages on some servers
|
415 |
-
* added new option to defer the ignore list for pagespeed
|
416 |
-
|
417 |
-
= 2.2.8 [2018.01.21] =
|
418 |
-
* rollback to 2.2.6 + bugfixes
|
419 |
-
|
420 |
-
= 2.2.7 [2018.02.19] =
|
421 |
-
* fixed a bug with the blacklist functionality
|
422 |
-
* replaced PHP Minify with JSMin as the default JS minification
|
423 |
-
* replaced PHP Minify with CSSTidy as the default CSS minification
|
424 |
-
* replaced PHP Minify with Minify HTML as the default HTML minification
|
425 |
-
* moved the intermediary cache from transients to disk files
|
426 |
-
|
427 |
-
= 2.2.6 [2018.01.06] =
|
428 |
-
* fixed a bug with html minification on some files that should not be minified
|
429 |
-
* fixed a bug with the defer for pagespeed insights
|
430 |
-
* updated the default blacklist (delete all entries and save again, to restore)
|
431 |
-
|
432 |
-
= 2.2.5 [2017.12.18] =
|
433 |
-
* fixed a fatal error reported on the support forum
|
434 |
-
|
435 |
-
= 2.2.4 [2017.12.17] =
|
436 |
-
* added custom cache directory and url support
|
437 |
-
* cleaned up some old unused code
|
438 |
-
* updated to the latest PHP Minify version
|
439 |
-
* added better descriptions and labels for some options
|
440 |
-
* added auto exclusion for js and css files when defer for pagespeed is enabled
|
441 |
-
|
442 |
-
= 2.2.3 [2017.12.16] =
|
443 |
-
* added robots.txt and ajax requests to the exclusion list
|
444 |
-
* added some cdn fixes
|
445 |
-
* added a new Pro tab
|
446 |
-
* added a global critical path css section
|
447 |
-
* added an option to dequeue all css files
|
448 |
-
* added an option to load CSS Async with LoadCSS (experimental)
|
449 |
-
* added an option to merge external resources together
|
450 |
-
* added the possibility to manage the default ignore list (reported files that cause conflicts when merged)
|
451 |
-
* added the possibility to manage the blacklist (files that cannot be merged with normal files)
|
452 |
-
* added better descriptions and labels for some options
|
453 |
-
|
454 |
-
= 2.2.2 [2017.11.12] =
|
455 |
-
* fixed the current cdn option box
|
456 |
-
* fixed some other minor bugs and notices
|
457 |
-
* added option to remove all enqueued google fonts (so you can use your own CSS @fontfaces manually)
|
458 |
-
* added font hinting for the "Inline Google Fonts CSS" option, so it looks better on Windows
|
459 |
-
|
460 |
-
= 2.2.1 [2017.08.21] =
|
461 |
-
* added unicode support to the alternative html minification option
|
462 |
-
* improved some options description
|
463 |
-
|
464 |
-
= 2.2.0 [2017.08.13] =
|
465 |
-
* fixed some debug notices
|
466 |
-
* fixed the alternative html minification option
|
467 |
-
|
468 |
-
= 2.1.9 [2017.08.11] =
|
469 |
-
* fixed a development bug
|
470 |
-
|
471 |
-
= 2.1.8 [2017.08.11] =
|
472 |
-
* fixed the html minification not working
|
473 |
-
* added support for the cdn enabler plugin (force http or https method)
|
474 |
-
|
475 |
-
= 2.1.7 [2017.07.17] =
|
476 |
-
* improved html minification speed and response time to the first byte
|
477 |
-
* fixed a random bug with the html minification library on large html pages (white pages)
|
478 |
-
* added support for the "Nginx Cache" plugin purge, by Till Krüss
|
479 |
-
|
480 |
-
= 2.1.6 [2017.07.17] =
|
481 |
-
* fixed a php notice in debug mode
|
482 |
-
* children styles (added with wp_add_inline_style) are now kept in order and merged together in place
|
483 |
-
* added faqs for possible "visual composer" issues
|
484 |
-
|
485 |
-
= 2.1.5 [2017.07.17] =
|
486 |
-
* css bug fixes and performance improvements
|
487 |
-
* added support for auto purging on WP Engine
|
488 |
-
|
489 |
-
= 2.1.4 [2017.07.14] =
|
490 |
-
* added compatibility with WP Engine.com and other providers that use a CNAME with their own subdomain
|
491 |
-
|
492 |
-
= 2.1.3 [2017.07.11] =
|
493 |
-
* updated PHP Minify for better compatibility
|
494 |
-
* added an alternative mode for html minification (because PHP Minify sometimes breaks things)
|
495 |
-
* css bug fixes and performance improvements
|
496 |
-
|
497 |
-
= 2.1.2 [2017.06.27] =
|
498 |
-
* fixed another error notice when debug mode is on
|
499 |
-
|
500 |
-
= 2.1.1 [2017.06.24] =
|
501 |
-
* fixed an error notice
|
502 |
-
|
503 |
-
= 2.1.0 [2017.06.21] =
|
504 |
-
* some performance improvements
|
505 |
-
|
506 |
-
= 2.0.9 [2017.06.01] =
|
507 |
-
* several bug and compatibility fixes
|
508 |
-
|
509 |
-
= 2.0.8 [2017.05.28] =
|
510 |
-
* fixed a notice alert on php for undefined function
|
511 |
-
|
512 |
-
= 2.0.7 [2017.05.28] =
|
513 |
-
* added support for auto purging of LiteSpeed Cache
|
514 |
-
* added support for auto purging on Godaddy Managed WordPress Hosting
|
515 |
-
* added the ie only blacklist, wich doesn't split merged files anymore, like the ignore list does
|
516 |
-
* added auto updates for the default ignore list and blacklist from our api once every 24 hours
|
517 |
-
* added cdn rewrite support for generated css and js files only
|
518 |
-
* removed url protocol rewrites and set default to dynamic "//" protocols
|
519 |
-
* updated the faqs
|
520 |
-
|
521 |
-
= 2.0.6 [2017.05.22] =
|
522 |
-
* added a "Troubleshooting" option to fix frontend editors for admin and editor level users
|
523 |
-
* updated the faqs
|
524 |
-
|
525 |
-
= 2.0.5 [2017.05.15] =
|
526 |
-
* fixed preserving the SVG namespace definition "http://www.w3.org/2000/svg" used on Bootstrap 4
|
527 |
-
* added some exclusions for Thrive and Visual Composer frontend preview and editors
|
528 |
-
|
529 |
-
= 2.0.4 [2017.05.15] =
|
530 |
-
* improved compatibility with Windows operating systems
|
531 |
-
|
532 |
-
= 2.0.3 [2017.05.15] =
|
533 |
-
* fixed an "undefined" notice
|
534 |
-
|
535 |
-
= 2.0.2 [2017.05.14] =
|
536 |
-
* improved compatibility on JS merging and minification
|
537 |
-
|
538 |
-
= 2.0.1 [2017.05.11] =
|
539 |
-
* fixed missing file that caused some errors on new installs
|
540 |
-
|
541 |
= 2.0.0 [2017.05.11] =
|
542 |
-
*
|
543 |
-
* removed the font awesome optimization tweaks because people have multiple versions and requirements (but duplicate css and js files are always removed)
|
544 |
-
* added all usable improvements and features up to 1.5.2, except for the "Defer CSS" and "Critical Path" features (will consider for the future)
|
545 |
-
* added info to the FAQ's about our internal blacklist for known CSS or JS files that are always ignored by the plugin
|
546 |
-
* changed the way CSS and JS files are fetched and merged to make use of the new improvements that were supposed to be on 1.4.4+
|
547 |
-
* changed the advanced settings tab back to the settings page for quicker selection of options by the advanced users
|
548 |
-
* changed the cache purging option to also delete our plugin transients via the API, rather than just let them expire
|
549 |
-
* changed the "Inline all CSS" option into header and footer separately
|
550 |
|
551 |
= 1.0 [2016.06.19] =
|
552 |
* Initial Release
|
1 |
=== Fast Velocity Minify ===
|
2 |
Contributors: Alignak
|
3 |
+
Tags: PHP Minify, Lighthouse, GTmetrix, Pingdom, Pagespeed, CSS Merging, JS Merging, CSS Minification, JS Minification, Speed Optimization, HTML Minification, Performance, Optimization, FVM
|
4 |
+
Requires at least: 4.7
|
5 |
+
Requires PHP: 5.6
|
6 |
+
Stable tag: 2.7.8
|
7 |
+
Tested up to: 5.3
|
8 |
License: GPLv3 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
10 |
|
198 |
|
199 |
== Changelog ==
|
200 |
|
201 |
+
= 2.7.8 [2020.02.06] =
|
202 |
+
* updated PHP Minify with full support for PHP 7.4
|
203 |
+
* added try, catch wrappers for merged javacript files with console log errors (instead of letting the browser stop execution on error)
|
204 |
+
* improved compatibility with windows servers
|
205 |
+
* improved compatibility for font paths with some themes
|
206 |
+
|
207 |
+
= 2.7.7 [2019.10.15] =
|
208 |
+
* added a capability check on the status page ajax request, which could show the cache file path when debug mode is enabled to subscribers
|
209 |
+
|
210 |
+
= 2.7.6 [2019.10.10] =
|
211 |
+
* bug fix release
|
212 |
+
|
213 |
+
= 2.7.5 [2019.10.09] =
|
214 |
+
* added support to "after" scripts added via wp_add_inline_script
|
215 |
+
|
216 |
= 2.7.4 [2019.08.18] =
|
217 |
+
* change to open JS/CSS files suspected of having PHP code via HTTP request, instead of reading the file directly from disk
|
218 |
|
219 |
= 2.7.3 [2019.07.29] =
|
220 |
* Beaver Builder compatibility fix
|
271 |
* improved compatibility with page cache plugins and servers (purging FVM without purging the page cache should be fine now)
|
272 |
* added a daily cronjob, to delete public invalid cache files that are older than 3 months (your page cache should expire before this)
|
273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
= 2.0.0 [2017.05.11] =
|
275 |
+
* version 2.x branch release
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
|
277 |
= 1.0 [2016.06.19] =
|
278 |
* Initial Release
|