From 0918e156a05dcf2fa4db5bc14318d1f944dfdbdd Mon Sep 17 00:00:00 2001 From: Mathew May Date: Tue, 11 Jun 2019 13:02:45 +0800 Subject: [PATCH 1/4] MDL-65744 lib: Update minify minify lib --- lib/minify/matthiasmullie-minify/LICENSE | 18 ++ lib/minify/matthiasmullie-minify/src/CSS.php | 125 ++++++++---- .../matthiasmullie-minify/src/Exception.php | 10 +- .../src/Exceptions/BasicException.php | 13 +- .../src/Exceptions/FileImportException.php | 13 +- .../src/Exceptions/IOException.php | 13 +- lib/minify/matthiasmullie-minify/src/JS.php | 187 +++++++++--------- .../matthiasmullie-minify/src/Minify.php | 38 +++- lib/thirdpartylibs.xml | 2 +- 9 files changed, 282 insertions(+), 137 deletions(-) create mode 100755 lib/minify/matthiasmullie-minify/LICENSE diff --git a/lib/minify/matthiasmullie-minify/LICENSE b/lib/minify/matthiasmullie-minify/LICENSE new file mode 100755 index 00000000000..0c0d08a79bd --- /dev/null +++ b/lib/minify/matthiasmullie-minify/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2012 Matthias Mullie + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/minify/matthiasmullie-minify/src/CSS.php b/lib/minify/matthiasmullie-minify/src/CSS.php index ec96ebc8a4f..e5a4669074c 100644 --- a/lib/minify/matthiasmullie-minify/src/CSS.php +++ b/lib/minify/matthiasmullie-minify/src/CSS.php @@ -1,4 +1,13 @@ + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ namespace MatthiasMullie\Minify; @@ -7,10 +16,11 @@ use MatthiasMullie\PathConverter\ConverterInterface; use MatthiasMullie\PathConverter\Converter; /** - * CSS minifier. + * CSS minifier * * Please report bugs on https://github.com/matthiasmullie/minify/issues * + * @package Minify * @author Matthias Mullie * @author Tijs Verkoyen * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved @@ -19,12 +29,12 @@ use MatthiasMullie\PathConverter\Converter; class CSS extends Minify { /** - * @var int + * @var int maximum inport size in kB */ protected $maxImportSize = 5; /** - * @var string[] + * @var string[] valid import extensions */ protected $importExtensions = array( 'gif' => 'data:image/gif', @@ -76,14 +86,14 @@ class CSS extends Minify */ protected function moveImportsToTop($content) { - if (preg_match_all('/@import[^;]+;/', $content, $matches)) { + if (preg_match_all('/(;?)(@import (?url\()?(?P["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) { // remove from content foreach ($matches[0] as $import) { $content = str_replace($import, '', $content); } // add to top - $content = implode('', $matches[0]).$content; + $content = implode(';', $matches[2]).';'.trim($content, ';'); } return $content; @@ -207,6 +217,8 @@ class CSS extends Minify // grab referenced file & minify it (which may include importing // yet other @import statements recursively) $minifier = new static($importPath); + $minifier->setMaxImportSize($this->maxImportSize); + $minifier->setImportExtensions($this->importExtensions); $importContent = $minifier->execute($source, $parents); // check if this is only valid for certain media @@ -295,10 +307,11 @@ class CSS extends Minify */ $this->extractStrings(); $this->stripComments(); + $this->extractCalcs(); $css = $this->replace($css); $css = $this->stripWhitespace($css); - $css = $this->shortenHex($css); + $css = $this->shortenColors($css); $css = $this->shortenZeroes($css); $css = $this->shortenFontWeights($css); $css = $this->stripEmptyTags($css); @@ -469,12 +482,16 @@ class CSS extends Minify * * @return string */ - protected function shortenHex($content) + protected function shortenColors($content) { - $content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?=[; }])/i', '#$1$2$3', $content); + $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); + + // remove alpha channel if it's pointless... + $content = preg_replace('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i', '#$1', $content); + $content = preg_replace('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i', '#$1', $content); - // we can shorten some even more by replacing them with their color name $colors = array( + // we can shorten some even more by replacing them with their color name '#F0FFFF' => 'azure', '#F5F5DC' => 'beige', '#A52A2A' => 'brown', @@ -502,6 +519,9 @@ class CSS extends Minify '#FF6347' => 'tomato', '#EE82EE' => 'violet', '#F5DEB3' => 'wheat', + // or the other way around + 'WHITE' => '#fff', + 'BLACK' => '#000', ); return preg_replace_callback( @@ -543,6 +563,12 @@ class CSS extends Minify */ protected function shortenZeroes($content) { + // we don't want to strip units in `calc()` expressions: + // `5px - 0px` is valid, but `5px - 0` is not + // `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but + // `10 * 0` is invalid + // we've extracted calcs earlier, so we don't need to worry about this + // reusable bits of code throughout these regexes: // before & after are used to make sure we don't match lose unintended // 0-like values (e.g. in #000, or in http://url/1.0) @@ -571,28 +597,11 @@ class CSS extends Minify // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0) $content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content); - // remove zeroes where they make no sense in calc: e.g. calc(100px - 0) - // the 0 doesn't have any effect, and this isn't even valid without unit - // strip all `+ 0` or `- 0` occurrences: calc(10% + 0) -> calc(10%) - // looped because there may be multiple 0s inside 1 group of parentheses - do { - $previous = $content; - $content = preg_replace('/\(([^\(\)]+) [\+\-] 0( [^\(\)]+)?\)/', '(\\1\\2)', $content); - } while ($content !== $previous); - // strip all `0 +` occurrences: calc(0 + 10%) -> calc(10%) - $content = preg_replace('/\(0 \+ ([^\(\)]+)\)/', '(\\1)', $content); - // strip all `0 -` occurrences: calc(0 - 10%) -> calc(-10%) - $content = preg_replace('/\(0 \- ([^\(\)]+)\)/', '(-\\1)', $content); - // I'm not going to attempt to optimize away `x * 0` instances: - // it's dumb enough code already that it likely won't occur, and it's - // too complex to do right (order of operations would have to be - // respected etc) - // what I cared about most here was fixing incorrectly truncated units - - // IE doesn't seem to understand a unitless flex-basis value, so let's - // add it in again (make it `%`, which is only 1 char: 0%, 0px, 0 - // anything, it's all just the same) - $content = preg_replace('/flex:([^ ]+ [^ ]+ )0([;\}])/', 'flex:${1}0%${2}', $content); + // IE doesn't seem to understand a unitless flex-basis value (correct - + // it goes against the spec), so let's add it in again (make it `%`, + // which is only 1 char: 0%, 0px, 0 anything, it's all just the same) + // @see https://developer.mozilla.org/nl/docs/Web/CSS/flex + $content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content); $content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content); return $content; @@ -607,7 +616,10 @@ class CSS extends Minify */ protected function stripEmptyTags($content) { - return preg_replace('/(^|\}|;)[^\{\};]+\{\s*\}/', '\\1', $content); + $content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content); + $content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content); + + return $content; } /** @@ -615,6 +627,17 @@ class CSS extends Minify */ protected function stripComments() { + // PHP only supports $this inside anonymous functions since 5.4 + $minifier = $this; + $callback = function ($match) use ($minifier) { + $count = count($minifier->extracted); + $placeholder = '/*'.$count.'*/'; + $minifier->extracted[$placeholder] = $match[0]; + + return $placeholder; + }; + $this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback); + $this->registerPattern('/\/\*.*?\*\//s', ''); } @@ -637,8 +660,8 @@ class CSS extends Minify // remove whitespace around meta characters // inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex $content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content); - $content = preg_replace('/([\[(:])\s+/', '$1', $content); - $content = preg_replace('/\s+([\]\)])/', '$1', $content); + $content = preg_replace('/([\[(:>\+])\s+/', '$1', $content); + $content = preg_replace('/\s+([\]\)>\+])/', '$1', $content); $content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content); // whitespace around + and - can only be stripped inside some pseudo- @@ -654,6 +677,40 @@ class CSS extends Minify return trim($content); } + /** + * Replace all `calc()` occurrences. + */ + protected function extractCalcs() + { + // PHP only supports $this inside anonymous functions since 5.4 + $minifier = $this; + $callback = function ($match) use ($minifier) { + $length = strlen($match[1]); + $expr = ''; + $opened = 0; + + for ($i = 0; $i < $length; $i++) { + $char = $match[1][$i]; + $expr .= $char; + if ($char === '(') { + $opened++; + } elseif ($char === ')' && --$opened === 0) { + break; + } + } + $rest = str_replace($expr, '', $match[1]); + $expr = trim(substr($expr, 1, -1)); + + $count = count($minifier->extracted); + $placeholder = 'calc('.$count.')'; + $minifier->extracted[$placeholder] = 'calc('.$expr.')'; + + return $placeholder.$rest; + }; + + $this->registerPattern('/calc(\(.+?)(?=$|;|calc\()/', $callback); + } + /** * Check if file is small enough to be imported. * diff --git a/lib/minify/matthiasmullie-minify/src/Exception.php b/lib/minify/matthiasmullie-minify/src/Exception.php index 0cb3fab5eb4..d03898f0437 100644 --- a/lib/minify/matthiasmullie-minify/src/Exception.php +++ b/lib/minify/matthiasmullie-minify/src/Exception.php @@ -1,10 +1,18 @@ + */ namespace MatthiasMullie\Minify; /** + * Base Exception Class * @deprecated Use Exceptions\BasicException instead * + * @package Minify * @author Matthias Mullie */ abstract class Exception extends \Exception diff --git a/lib/minify/matthiasmullie-minify/src/Exceptions/BasicException.php b/lib/minify/matthiasmullie-minify/src/Exceptions/BasicException.php index a6328f4e46a..af5e81bc084 100644 --- a/lib/minify/matthiasmullie-minify/src/Exceptions/BasicException.php +++ b/lib/minify/matthiasmullie-minify/src/Exceptions/BasicException.php @@ -1,10 +1,21 @@ + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ namespace MatthiasMullie\Minify\Exceptions; use MatthiasMullie\Minify\Exception; /** + * Basic Exception Class + * + * @package Minify\Exception * @author Matthias Mullie */ abstract class BasicException extends Exception diff --git a/lib/minify/matthiasmullie-minify/src/Exceptions/FileImportException.php b/lib/minify/matthiasmullie-minify/src/Exceptions/FileImportException.php index 98fc341ccd0..912a2c908dc 100644 --- a/lib/minify/matthiasmullie-minify/src/Exceptions/FileImportException.php +++ b/lib/minify/matthiasmullie-minify/src/Exceptions/FileImportException.php @@ -1,8 +1,19 @@ + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ namespace MatthiasMullie\Minify\Exceptions; /** + * File Import Exception Class + * + * @package Minify\Exception * @author Matthias Mullie */ class FileImportException extends BasicException diff --git a/lib/minify/matthiasmullie-minify/src/Exceptions/IOException.php b/lib/minify/matthiasmullie-minify/src/Exceptions/IOException.php index 9b590742c5d..b172eb48f37 100644 --- a/lib/minify/matthiasmullie-minify/src/Exceptions/IOException.php +++ b/lib/minify/matthiasmullie-minify/src/Exceptions/IOException.php @@ -1,8 +1,19 @@ + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ namespace MatthiasMullie\Minify\Exceptions; /** + * IO Exception Class + * + * @package Minify\Exception * @author Matthias Mullie */ class IOException extends BasicException diff --git a/lib/minify/matthiasmullie-minify/src/JS.php b/lib/minify/matthiasmullie-minify/src/JS.php index 042f5429f2d..92389cdd5d0 100644 --- a/lib/minify/matthiasmullie-minify/src/JS.php +++ b/lib/minify/matthiasmullie-minify/src/JS.php @@ -1,13 +1,22 @@ + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ +namespace MatthiasMullie\Minify; + +/** + * JavaScript Minifier Class + * + * Please report bugs on https://github.com/matthiasmullie/minify/issues + * + * @package Minify + * @author Matthias Mullie * @author Tijs Verkoyen * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved * @license MIT License @@ -110,11 +119,6 @@ class JS extends Minify */ protected $operatorsAfter = array(); - /** - * @var array - */ - protected $nestedExtracted = array(); - /** * {@inheritdoc} */ @@ -144,19 +148,6 @@ class JS extends Minify { $content = ''; - // loop files - foreach ($this->data as $source => $js) { - /* - * Combine js: separating the scripts by a ; - * I'm also adding a newline: it will be eaten when whitespace is - * stripped, but we need to make sure we're not just appending - * a new script right after a previous script that ended with a - * singe-line comment on the last line (in which case it would also - * be seen as part of that comment) - */ - $content .= $js."\n;"; - } - /* * Let's first take out strings, comments and regular expressions. * All of these can contain JS code-like characters, and we should make @@ -171,11 +162,24 @@ class JS extends Minify $this->extractStrings('\'"`'); $this->stripComments(); $this->extractRegex(); - $content = $this->replace($content); - $content = $this->propertyNotation($content); - $content = $this->shortenBools($content); - $content = $this->stripWhitespace($content); + // loop files + foreach ($this->data as $source => $js) { + // take out strings, comments & regex (for which we've registered + // the regexes just a few lines earlier) + $js = $this->replace($js); + + $js = $this->propertyNotation($js); + $js = $this->shortenBools($js); + $js = $this->stripWhitespace($js); + + // combine js: separating the scripts by a ; + $content .= $js.";"; + } + + // clean up leftover `;`s from the combination of multiple scripts + $content = ltrim($content, ';'); + $content = (string) substr($content, 0, -1); /* * Earlier, we extracted strings & regular expressions and replaced them @@ -191,11 +195,21 @@ class JS extends Minify */ protected function stripComments() { + // PHP only supports $this inside anonymous functions since 5.4 + $minifier = $this; + $callback = function ($match) use ($minifier) { + $count = count($minifier->extracted); + $placeholder = '/*'.$count.'*/'; + $minifier->extracted[$placeholder] = $match[0]; + + return $placeholder; + }; + // multi-line comments + $this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback); + $this->registerPattern('/\/\*.*?\*\//s', ''); + // single-line comments $this->registerPattern('/\/\/.*$/m', ''); - - // multi-line comments - $this->registerPattern('/\/\*.*?\*\//s', ''); } /** @@ -222,38 +236,26 @@ class JS extends Minify $callback = function ($match) use ($minifier) { $count = count($minifier->extracted); $placeholder = '"'.$count.'"'; - $minifier->extracted[$placeholder] = $match['regex']; + $minifier->extracted[$placeholder] = $match[0]; - // because we're also trying to find regular expressions that follow - // if/when/for statements, we should also make sure that the content - // within these statements is also minified... - // e.g. `if("some string"/* or comment */)` should become - // `if("some string")` - if (isset($match['before'])) { - $other = new static(); - $other->extractStrings('\'"`', "$count-"); - $other->stripComments(); - $match['before'] = $other->replace($match['before']); - $this->nestedExtracted += $other->extracted; - } - - return (isset($match['before']) ? $match['before'] : ''). - $placeholder. - (isset($match['after']) ? $match['after'] : ''); + return $placeholder; }; - $pattern = '(?P\/.+?((?[=:,;\}\(\{&\|!]|^|'.implode('|', $keywords).')'; + $before = '([=:,;\+\-\*\/\}\(\{\[&\|!]|^|'.implode('|', $keywords).')\s*'; $propertiesAndMethods = array( - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties - 'prototype', - 'length', - 'lastIndex', // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2 'constructor', 'flags', @@ -267,29 +269,28 @@ class JS extends Minify 'compile(', 'exec(', 'test(', - 'match', - 'replace(', - 'search(', - 'split(', 'toSource(', 'toString(', ); $delimiters = array_fill(0, count($propertiesAndMethods), '/'); $propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters); - $after = '(?P[\.,;\)\}&\|+]|$|\.('.implode('|', $propertiesAndMethods).'))'; - $this->registerPattern('/'.$before.'\s*'.$pattern.'\s*'.$after.'/', $callback); + $after = '(?=\s*([\.,;\)\}&\|+]|\/\/|$|\.('.implode('|', $propertiesAndMethods).')))'; + $this->registerPattern('/'.$before.'\K'.$pattern.$after.'/', $callback); - // we didn't check for regular expressions after `)`, because that is - // more often than not not a character where a regex can follow (e.g. - // (1+2)/3/4 -> /3/ could be considered a regex, but it's not) - // however, after single-line if/while/for, there could very well be a - // regex after `)` (e.g. if(true)/regex/) - // there is one problem, though: it's (near) impossible to check for - // when the if/while/for statement is closed (same amount of closing - // brackets as there were opened), so I'll ignore single-line statements - // with nested brackets followed by a regex for now... - $before = '(?P\b(if|while|for)\s*\((?P[^\(]+?)\))'; - $this->registerPattern('/'.$before.'\s*'.$pattern.'\s*'.$after.'/', $callback); + // regular expressions following a `)` are rather annoying to detect... + // quite often, `/` after `)` is a division operator & if it happens to + // be followed by another one (or a comment), it is likely to be + // confused for a regular expression + // however, it's perfectly possible for a regex to follow a `)`: after + // a single-line `if()`, `while()`, ... statement, for example + // since, when they occur like that, they're always the start of a + // statement, there's only a limited amount of ways they can be useful: + // by calling the regex methods directly + // if a regex following `)` is not followed by `.`, + // it's quite likely not a regex + $before = '\)\s*'; + $after = '(?=\s*\.('.implode('|', $propertiesAndMethods).'))'; + $this->registerPattern('/'.$before.'\K'.$pattern.$after.'/', $callback); // 1 more edge case: a regex can be followed by a lot more operators or // keywords if there's a newline (ASI) in between, where the operator @@ -297,25 +298,8 @@ class JS extends Minify // (https://github.com/matthiasmullie/minify/issues/56) $operators = $this->getOperatorsForRegex($this->operatorsBefore, '/'); $operators += $this->getOperatorsForRegex($this->keywordsReserved, '/'); - $after = '(?P\n\s*('.implode('|', $operators).'))'; - $this->registerPattern('/'.$pattern.'\s*'.$after.'/', $callback); - } - - /** - * In addition to the regular restore routine, we also need to restore a few - * more things that have been extracted as part of the regex extraction... - * - * {@inheritdoc} - */ - protected function restoreExtractedData($content) - { - // restore regular extracted stuff - $content = parent::restoreExtractedData($content); - - // restore nested stuff from within regex extraction - $content = strtr($content, $this->nestedExtracted); - - return $content; + $after = '(?=\s*\n\s*('.implode('|', $operators).'))'; + $this->registerPattern('/'.$pattern.$after.'/', $callback); } /** @@ -361,7 +345,9 @@ class JS extends Minify array( '/('.implode('|', $operatorsBefore).')\s+/', '/\s+('.implode('|', $operatorsAfter).')/', - ), '\\1', $content + ), + '\\1', + $content ); // make sure + and - can't be mistaken for, or joined into ++ and -- @@ -369,7 +355,9 @@ class JS extends Minify array( '/(? + * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved + * @license MIT License + */ namespace MatthiasMullie\Minify; use MatthiasMullie\Minify\Exceptions\IOException; @@ -10,6 +18,7 @@ use Psr\Cache\CacheItemInterface; * * Please report bugs on https://github.com/matthiasmullie/minify/issues * + * @package Minify * @author Matthias Mullie * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved * @license MIT License @@ -230,6 +239,12 @@ abstract class Minify foreach ($this->patterns as $i => $pattern) { list($pattern, $replacement) = $pattern; + // we can safely ignore patterns for positions we've unset earlier, + // because we know these won't show up anymore + if (array_key_exists($i, $positions) == false) { + continue; + } + // no need to re-run matches that are still in the part of the // content that hasn't been processed if ($positions[$i] >= 0) { @@ -237,19 +252,18 @@ abstract class Minify } $match = null; - if (preg_match($pattern, $content, $match)) { + if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) { $matches[$i] = $match; // we'll store the match position as well; that way, we // don't have to redo all preg_matches after changing only // the first (we'll still know where those others are) - $positions[$i] = strpos($content, $match[0]); + $positions[$i] = $match[0][1]; } else { // if the pattern couldn't be matched, there's no point in // executing it again in later runs on this same content; // ignore this one until we reach end of content - unset($matches[$i]); - $positions[$i] = strlen($content); + unset($matches[$i], $positions[$i]); } } @@ -264,7 +278,7 @@ abstract class Minify // other found was not inside what the first found) $discardLength = min($positions); $firstPattern = array_search($discardLength, $positions); - $match = $matches[$firstPattern][0]; + $match = $matches[$firstPattern][0][0]; // execute the pattern that matches earliest in the content string list($pattern, $replacement) = $this->patterns[$firstPattern]; @@ -272,7 +286,7 @@ abstract class Minify // figure out which part of the string was unmatched; that's the // part we'll execute the patterns on again next - $content = substr($content, $discardLength); + $content = (string) substr($content, $discardLength); $unmatched = (string) substr($content, strpos($content, $match) + strlen($match)); // move the replaced part to $processed and prepare $content to @@ -396,6 +410,16 @@ abstract class Minify */ protected function canImportFile($path) { + $parsed = parse_url($path); + if ( + // file is elsewhere + isset($parsed['host']) || + // file responds to queries (may change, or need to bypass cache) + isset($parsed['query']) + ) { + return false; + } + return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path); } diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index 8623c2ee04e..a7d4d9c3e4e 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -53,7 +53,7 @@ minify/matthiasmullie-minify MatthiasMullie\Minify MIT - 1.3.51 + 1.3.61 From b4e39ff24e5e834b376066bf5459318dfa075a36 Mon Sep 17 00:00:00 2001 From: Mathew May Date: Tue, 11 Jun 2019 13:05:44 +0800 Subject: [PATCH 2/4] MDL-65744 lib: Update minify pathconverter lib --- .../matthiasmullie-pathconverter/LICENSE | 18 ++++++++++++++++++ .../src/Converter.php | 19 ++++++++++--------- lib/thirdpartylibs.xml | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 lib/minify/matthiasmullie-pathconverter/LICENSE diff --git a/lib/minify/matthiasmullie-pathconverter/LICENSE b/lib/minify/matthiasmullie-pathconverter/LICENSE new file mode 100644 index 00000000000..491295ad30e --- /dev/null +++ b/lib/minify/matthiasmullie-pathconverter/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2015 Matthias Mullie + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/minify/matthiasmullie-pathconverter/src/Converter.php b/lib/minify/matthiasmullie-pathconverter/src/Converter.php index c8b0c696a99..519d3c84ff5 100644 --- a/lib/minify/matthiasmullie-pathconverter/src/Converter.php +++ b/lib/minify/matthiasmullie-pathconverter/src/Converter.php @@ -31,21 +31,22 @@ class Converter implements ConverterInterface /** * @param string $from The original base path (directory, not file!) * @param string $to The new base path (directory, not file!) + * @param string $root Root directory (defaults to `getcwd`) */ - public function __construct($from, $to) + public function __construct($from, $to, $root = '') { $shared = $this->shared($from, $to); if ($shared === '') { // when both paths have nothing in common, one of them is probably // absolute while the other is relative - $cwd = getcwd(); - $from = strpos($from, $cwd) === 0 ? $from : $cwd.'/'.$from; - $to = strpos($to, $cwd) === 0 ? $to : $cwd.'/'.$to; + $root = $root ?: getcwd(); + $from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from); + $to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to); // or traveling the tree via `..` // attempt to resolve path, or assume it's fine if it doesn't exist - $from = realpath($from) ?: $from; - $to = realpath($to) ?: $to; + $from = @realpath($from) ?: $from; + $to = @realpath($to) ?: $to; } $from = $this->dirname($from); @@ -155,7 +156,7 @@ class Converter implements ConverterInterface $to = mb_substr($this->to, mb_strlen($shared)); // add .. for every directory that needs to be traversed to new path - $to = str_repeat('../', mb_substr_count($to, '/')); + $to = str_repeat('../', count(array_filter(explode('/', $to)))); return $to.ltrim($path, '/'); } @@ -169,11 +170,11 @@ class Converter implements ConverterInterface */ protected function dirname($path) { - if (is_file($path)) { + if (@is_file($path)) { return dirname($path); } - if (is_dir($path)) { + if (@is_dir($path)) { return rtrim($path, '/'); } diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index a7d4d9c3e4e..a7c79f64f23 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -60,7 +60,7 @@ minify/matthiasmullie-pathconverter MatthiasMullie\PathConverter MIT - 1.1.0 + 1.1.2 From ad4d9cf7453e10340afeebc0ab957e2b58f6e885 Mon Sep 17 00:00:00 2001 From: Mathew May Date: Wed, 12 Jun 2019 07:33:22 +0800 Subject: [PATCH 3/4] MDL-65744 lib: Modify minify test to check properly --- lib/tests/minify_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tests/minify_test.php b/lib/tests/minify_test.php index 6eacf71940c..2e3f9f87b1c 100644 --- a/lib/tests/minify_test.php +++ b/lib/tests/minify_test.php @@ -83,7 +83,7 @@ function hm() } "; - $this->assertSame("function hm()\n{}", core_minify::js($js)); + $this->assertSame("function hm(){}", core_minify::js($js)); $js = "function hm{}"; $result = core_minify::js($js); From f305ffc93373cfc694ae1cb39f791b08ddc05d53 Mon Sep 17 00:00:00 2001 From: Mathew May Date: Tue, 16 Jul 2019 17:01:05 +0800 Subject: [PATCH 4/4] MDL-65744 lib: Modify minify test to check properly --- lib/tests/minify_test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tests/minify_test.php b/lib/tests/minify_test.php index 2e3f9f87b1c..cde85a5ac0c 100644 --- a/lib/tests/minify_test.php +++ b/lib/tests/minify_test.php @@ -110,11 +110,11 @@ function hm() $files = array($testfile1, $testfile2); - $this->assertSame("function hm()\n{};\nfunction oh(){}", core_minify::js_files($files)); + $this->assertSame("function hm(){};\nfunction oh(){}", core_minify::js_files($files)); $files = array($testfile1, $testfile2, $testfile3); - $this->assertStringStartsWith("function hm()\n{};\nfunction oh(){};\n\n\n// Cannot read JS file ", + $this->assertStringStartsWith("function hm(){};\nfunction oh(){};\n\n\n// Cannot read JS file ", @core_minify::js_files($files)); unlink($testfile1);