PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
← All changes | vendor/matthiasmullie/minify/src/Minify.php +94 -20 3.2.9 → 4.7.0 View file →
@@ -1,7 +1,8 @@
1 1 <?php
2 +
2 3 /**
3 - * Abstract minifier class
4 + * Abstract minifier class.
4 5 *
5 6 * Please report bugs on https://github.com/matthiasmullie/minify/issues
6 7 *
7 8 * @author Matthias Mullie <[email protected]>
@@ -7,11 +8,13 @@
7 8 * @author Matthias Mullie <[email protected]>
8 9 * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
9 10 * @license MIT License
10 11 */
12 +
11 13 namespace MatthiasMullie\Minify;
12 14
13 15 use MatthiasMullie\Minify\Exceptions\IOException;
16 +use MatthiasMullie\Minify\Exceptions\PatternMatchException;
14 17 use Psr\Cache\CacheItemInterface;
15 18
16 19 /**
17 20 * Abstract minifier class.
@@ -17,9 +20,8 @@
17 20 * Abstract minifier class.
18 21 *
19 22 * Please report bugs on https://github.com/matthiasmullie/minify/issues
20 23 *
21 - * @package Minify
22 24 * @author Matthias Mullie <[email protected]>
23 25 * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
24 26 * @license MIT License
25 27 */
@@ -43,8 +45,10 @@
43 45 * This array will hold content of strings and regular expressions that have
44 46 * been extracted from the JS source code, so we can reliably match "code",
45 47 * without having to worry about potential "code-like" characters inside.
46 48 *
49 + * @internal
50 + *
47 51 * @var string[]
48 52 */
49 53 public $extracted = array();
50 54
@@ -127,9 +131,9 @@
127 131 $path = (string) $path;
128 132
129 133 // check if we can read the file
130 134 if (!$this->canImportFile($path)) {
131 - throw new IOException('The file "'.$path.'" could not be opened for reading. Check if PHP has enough permissions.');
135 + throw new IOException('The file "' . $path . '" could not be opened for reading. Check if PHP has enough permissions.');
132 136 }
133 137
134 138 $this->add($path);
135 139 }
@@ -226,9 +230,9 @@
226 230 /**
227 231 * Save to file.
228 232 *
229 233 * @param string $content The minified data
230 - * @param string $path The path to save the minified data to
234 + * @param string $path The path to save the minified data to
231 235 *
232 236 * @throws IOException
233 237 */
234 238 protected function save($content, $path)
@@ -245,9 +249,9 @@
245 249 *
246 250 * If $replacement is a string, it must be plain text. Placeholders like $1 or \2 don't work.
247 251 * If you need that functionality, use a callback instead.
248 252 *
249 - * @param string $pattern PCRE pattern
253 + * @param string $pattern PCRE pattern
250 254 * @param string|callable $replacement Replacement value for matched pattern
251 255 */
252 256 protected function registerPattern($pattern, $replacement = '')
253 257 {
@@ -257,8 +261,47 @@
257 261 $this->patterns[] = array($pattern, $replacement);
258 262 }
259 263
260 264 /**
265 + * Both JS and CSS use the same form of multi-line comment, so putting the common code here.
266 + */
267 + protected function stripMultilineComments()
268 + {
269 + $minifier = $this;
270 + // Pattern for matching comments that we want to preserve
271 + $keepPattern = '/^
272 + # comment content
273 + (?:
274 + # either starts with an !
275 + !
276 + |
277 + # or, after some number of characters which do not end the comment
278 + (?:(?!\*\/).)*?
279 +
280 + # there is either a @license or @preserve tag
281 + @(?:license|preserve)
282 + )
283 + /ixs';
284 + $callback = function ($match) use ($minifier, $keepPattern) {
285 + if (preg_match($keepPattern, $match[1])) {
286 + // Preserve the comment
287 + $count = count($minifier->extracted);
288 + $placeholder = '/*' . $count . '*/';
289 + $minifier->extracted[$placeholder] = $match[0];
290 + } else {
291 + // Discard the comment but keep any single line feed
292 + $placeholder = strncmp($match[0], "\n", 1) === 0 || substr($match[0], -1) === "\n"
293 + ? "\n"
294 + : '';
295 + }
296 +
297 + return $placeholder;
298 + };
299 +
300 + $this->registerPattern('/\n?\/\*(.*?)\*\/\n?/s', $callback);
301 + }
302 +
303 + /**
261 304 * We can't "just" run some regular expressions against JavaScript: it's a
262 305 * complex language. E.g. having an occurrence of // xyz would be a comment,
263 306 * unless it's used within a string. Of you could have something that looks
264 307 * like a 'string', but inside a comment.
@@ -267,8 +310,10 @@
267 310 *
268 311 * @param string $content The content to replace patterns in
269 312 *
270 313 * @return string The (manipulated) content
314 + *
315 + * @throws PatternMatchException
271 316 */
272 317 protected function replace($content)
273 318 {
274 319 $contentLength = strlen($content);
@@ -294,9 +339,10 @@
294 339 continue;
295 340 }
296 341
297 342 $match = null;
298 - if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) {
343 + $matchResult = preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset);
344 + if ($matchResult) {
299 345 $matches[$i] = $match;
300 346
301 347 // we'll store the match position as well; that way, we
302 348 // don't have to redo all preg_matches after changing only
@@ -302,8 +348,13 @@
302 348 // don't have to redo all preg_matches after changing only
303 349 // the first (we'll still know where those others are)
304 350 $positions[$i] = $match[0][1];
305 351 } else {
352 + if ($matchResult === false) {
353 + throw PatternMatchException::fromLastError(
354 + "Failed to match pattern '$pattern' at $processedOffset"
355 + );
356 + }
306 357 // if the pattern couldn't be matched, there's no point in
307 358 // executing it again in later runs on this same content;
308 359 // ignore this one until we reach end of content
309 360 unset($matches[$i], $positions[$i]);
@@ -343,9 +394,9 @@
343 394 * If $replacement is a callback, execute it, passing in the match data.
344 395 * If it's a string, just pass it through.
345 396 *
346 397 * @param string|callable $replacement Replacement value
347 - * @param array $match Match data, in PREG_OFFSET_CAPTURE form
398 + * @param array $match Match data, in PREG_OFFSET_CAPTURE form
348 399 *
349 400 * @return string
350 401 */
351 402 protected function executeReplacement($replacement, $match)
@@ -356,8 +407,9 @@
356 407 // convert $match from the PREG_OFFSET_CAPTURE form to the form the callback expects
357 408 foreach ($match as &$matchItem) {
358 409 $matchItem = $matchItem[0];
359 410 }
411 +
360 412 return $replacement($match);
361 413 }
362 414
363 415 /**
@@ -390,15 +442,20 @@
390 442 return $match[0];
391 443 }
392 444
393 445 $count = count($minifier->extracted);
394 - $placeholder = $match[1].$placeholderPrefix.$count.$match[1];
395 - $minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
446 + $placeholder = $match[1] . $placeholderPrefix . $count . $match[1];
447 + $minifier->extracted[$placeholder] = $match[1] . $match[2] . $match[1];
396 448
397 449 return $placeholder;
398 450 };
399 451
400 452 /*
453 + * Quantifier {0,65535} is used instead of *? to avoid exceeding
454 + * backtrack limit with large strings. 65535 is the maximum allowed
455 + * (see https://www.php.net/manual/en/regexp.reference.repetition.php)
456 + * and should be well sufficient for string representations here.
457 + *
401 458 * The \\ messiness explained:
402 459 * * Don't count ' or " as end-of-string if it's escaped (has backslash
403 460 * in front of it)
404 461 * * Unless... that backslash itself is escaped (another leading slash),
@@ -408,9 +465,10 @@
408 465 * to be done to pass the backslash into the PHP string without it being
409 466 * considered as escape-char (times 2) and to get it in the regex,
410 467 * escaped (times 2)
411 468 */
412 - $this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
469 +
470 + $this->registerPattern('/([' . $chars . '])(.{0,65535}?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
413 471 }
414 472
415 473 /**
416 474 * This method will restore all extracted data (strings, regexes) that were
@@ -446,16 +504,22 @@
446 504 {
447 505 $parsed = parse_url($path);
448 506 if (
449 507 // file is elsewhere
450 - isset($parsed['host']) ||
508 + isset($parsed['host'])
451 509 // file responds to queries (may change, or need to bypass cache)
452 - isset($parsed['query'])
510 + || isset($parsed['query'])
453 511 ) {
454 512 return false;
455 513 }
456 514
457 - return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
515 + try {
516 + return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
517 + }
518 + // catch openbasedir exceptions which are not caught by @ on is_file()
519 + catch (\Exception $e) {
520 + return false;
521 + }
458 522 }
459 523
460 524 /**
461 525 * Attempts to open file specified by $path for writing.
@@ -468,9 +532,9 @@
468 532 */
469 533 protected function openFileForWriting($path)
470 534 {
471 535 if ($path === '' || ($handler = @fopen($path, 'w')) === false) {
472 - throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.');
536 + throw new IOException('The file "' . $path . '" could not be opened for writing. Check if PHP has enough permissions.');
473 537 }
474 538
475 539 return $handler;
476 540 }
@@ -478,10 +542,10 @@
478 542 /**
479 543 * Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
480 544 *
481 545 * @param resource $handler The resource to write to
482 - * @param string $content The content to write
483 - * @param string $path The path to the file (for exception printing only)
546 + * @param string $content The content to write
547 + * @param string $path The path to the file (for exception printing only)
484 548 *
485 549 * @throws IOException
486 550 */
487 551 protected function writeToFile($handler, $content, $path = '')
@@ -486,12 +550,22 @@
486 550 */
487 551 protected function writeToFile($handler, $content, $path = '')
488 552 {
489 553 if (
490 - !is_resource($handler) ||
491 - ($result = @fwrite($handler, $content)) === false ||
492 - ($result < strlen($content))
554 + !is_resource($handler)
555 + || ($result = @fwrite($handler, $content)) === false
556 + || ($result < strlen($content))
493 557 ) {
494 - throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.');
558 + throw new IOException('The file "' . $path . '" could not be written to. Check your disk space and file permissions.');
495 559 }
560 + }
561 +
562 + protected static function str_replace_first($search, $replace, $subject)
563 + {
564 + $pos = strpos($subject, $search);
565 + if ($pos !== false) {
566 + return substr_replace($subject, $replace, $pos, strlen($search));
567 + }
568 +
569 + return $subject;
496 570 }
497 571 }