PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.2
1.4.2 1.4.1 1.4.0 1.3.7 1.3.6 1.3.5 1.3.4 1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 36 releases
← All changes | includes/class-cache-gc.php +30 -23 1.4.0 → 1.4.2 View file →
@@ -389,9 +389,9 @@
389 389 // lifetime, and this tree is served without PHP so nothing else
390 390 // can enforce it. A site caching for a week would otherwise hand
391 391 // out a dead nonce for six and a half days of it, breaking every
392 392 // anonymous form on the page.
393 - $expires_file = dirname( $path ) . '/.xspeed-expires';
393 + $expires_file = dirname( $path ) . '/' . Cache::EXPIRES_MARKER;
394 394 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- sidecar read on a cron sweep; WP_Filesystem is not loaded here.
395 395 $expires = is_readable( $expires_file ) ? (int) @file_get_contents( $expires_file ) : 0; // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- file may vanish between the check and the read.
396 396 if ( $expires > 0 ) {
397 397 $mtime = @filemtime( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- false is handled below.
@@ -519,29 +519,14 @@
519 519 }
520 520
521 521 /**
522 522 * Delete a cache entry and every sibling that only exists because of it,
523 - * so the sweep never creates the orphans it is there to remove:
524 - *
525 - * <md5>.html → <md5>.meta, <md5>.html.br
526 - * index.html → index.html.br
527 - * <key>.css/js → (none)
523 + * so the sweep never creates the orphans it is there to remove.
528 524 */
529 525 private static function delete_entry( string $path ): void {
530 526 wp_delete_file( $path );
527 + self::delete_siblings( $path );
531 528
532 - $br = $path . '.br';
533 - if ( file_exists( $br ) ) {
534 - wp_delete_file( $br );
535 - }
536 -
537 - if ( '.html' === substr( $path, -5 ) ) {
538 - $meta = substr( $path, 0, -5 ) . '.meta';
539 - if ( file_exists( $meta ) ) {
540 - wp_delete_file( $meta );
541 - }
542 - }
543 -
544 529 // Deleting an asset and invalidating the pages that embed it are ONE
545 530 // operation, so the two caches can never disagree. is_referenced()
546 531 // already keeps a linked asset alive, so this is the belt to that
547 532 // braces: it covers the races the index cannot see — a page written
@@ -554,8 +539,34 @@
554 539 }
555 540 }
556 541
557 542 /**
543 + * The files that exist only because of $path:
544 + *
545 + * <md5>.html → <md5>.meta, <md5>.html.br, <md5>.html.br.size
546 + * index.html → index.html.br, index.html.br.size, the expires marker
547 + * <key>.css/js → its .br and .br.size, if any
548 + *
549 + * The marker and the size record were missed once, which left every
550 + * nonce page's folder non-empty so prune_empty_dirs() could never remove
551 + * it (#636).
552 + */
553 + private static function delete_siblings( string $path ): void {
554 + $siblings = array( $path . '.br', $path . '.br.size' );
555 + if ( '.html' === substr( $path, -5 ) ) {
556 + $siblings[] = substr( $path, 0, -5 ) . '.meta';
557 + }
558 + if ( 'index.html' === basename( $path ) ) {
559 + $siblings[] = dirname( $path ) . '/' . Cache::EXPIRES_MARKER;
560 + }
561 + foreach ( $siblings as $sibling ) {
562 + if ( file_exists( $sibling ) ) {
563 + wp_delete_file( $sibling );
564 + }
565 + }
566 + }
567 +
568 + /**
558 569 * Remove every cached page that links to the given asset.
559 570 *
560 571 * Walks both trees: the static one is served by nginx without PHP, so a
561 572 * page left there keeps serving the dead link no matter what the flat
@@ -583,13 +594,9 @@
583 594 continue;
584 595 }
585 596
586 597 wp_delete_file( $file );
587 - foreach ( array( $file . '.br', substr( $file, 0, -5 ) . '.meta' ) as $sibling ) {
588 - if ( file_exists( $sibling ) ) {
589 - wp_delete_file( $sibling );
590 - }
591 - }
598 + self::delete_siblings( $file );
592 599 }
593 600 }
594 601 }
595 602