PluginProbe
Autoptimize / trunk
Autoptimize vtrunk
3.1.16 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 All 108 releases
← All changes | classes/autoptimizeCache.php +206 -14 2.4.2 → trunk View file →
@@ -39,17 +39,22 @@
39 39 * @param string $ext Extension.
40 40 */
41 41 public function __construct( $md5, $ext = 'php' )
42 42 {
43 + $_min_ext = '';
44 + if ( apply_filters( 'autoptimize_filter_cache_url_add_min_ext', false ) ) {
45 + $_min_ext = '.min';
46 + }
47 +
43 48 $this->cachedir = AUTOPTIMIZE_CACHE_DIR;
44 49 $this->nogzip = AUTOPTIMIZE_CACHE_NOGZIP;
45 50 if ( ! $this->nogzip ) {
46 - $this->filename = AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . '.php';
51 + $this->filename = AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . $_min_ext . '.php';
47 52 } else {
48 53 if ( in_array( $ext, array( 'js', 'css' ) ) ) {
49 - $this->filename = $ext . '/' . AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . '.' . $ext;
54 + $this->filename = $ext . '/' . AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . $_min_ext . '.' . $ext;
50 55 } else {
51 - $this->filename = AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . '.' . $ext;
56 + $this->filename = AUTOPTIMIZE_CACHEFILE_PREFIX . $md5 . $_min_ext . '.' . $ext;
52 57 }
53 58 }
54 59 }
55 60
@@ -85,12 +90,25 @@
85 90 *
86 91 * @param string $data Data to cache.
87 92 * @param string $mime Mimetype.
88 93 *
89 - * @return void
94 + * @return void|bool
90 95 */
91 96 public function cache( $data, $mime )
92 97 {
98 + // readonly FS explicitly OK'ed by developer, so just pretend all is OK.
99 + if ( defined( 'AUTOPTIMIZE_CACHE_READONLY' ) ) {
100 + return true;
101 + }
102 +
103 + // off by default; check if cachedirs exist every time before caching
104 + //
105 + // to be activated for users that experience these ugly errors;
106 + // PHP Warning: file_put_contents failed to open stream: No such file or directory.
107 + if ( apply_filters( 'autoptimize_filter_cache_checkdirs_on_write', false ) ) {
108 + $this->check_and_create_dirs();
109 + }
110 +
93 111 if ( false === $this->nogzip ) {
94 112 // We handle gzipping ourselves.
95 113 $file = 'default.php';
96 114 $phpcode = file_get_contents( AUTOPTIMIZE_PLUGIN_DIR . 'config/' . $file );
@@ -100,13 +118,31 @@
100 118 file_put_contents( $this->cachedir . $this->filename . '.none', $data );
101 119 } else {
102 120 // Write code to cache without doing anything else.
103 121 file_put_contents( $this->cachedir . $this->filename, $data );
122 +
123 + // save fallback .js or .css file if filter true (to be false by default) but not if snippet or single.
124 + if ( self::do_fallback() && strpos( $this->filename, '_snippet_' ) === false && strpos( $this->filename, '_single_' ) === false ) {
125 + $_extension = pathinfo( $this->filename, PATHINFO_EXTENSION );
126 + $_fallback_file = AUTOPTIMIZE_CACHEFILE_PREFIX . 'fallback.' . $_extension;
127 + if ( ( 'css' === $_extension || 'js' === $_extension ) && ! file_exists( $this->cachedir . $_extension . '/' . $_fallback_file ) ) {
128 + file_put_contents( $this->cachedir . $_extension . '/' . $_fallback_file, $data );
129 + }
130 + }
131 +
104 132 if ( apply_filters( 'autoptimize_filter_cache_create_static_gzip', false ) ) {
105 133 // Create an additional cached gzip file.
106 134 file_put_contents( $this->cachedir . $this->filename . '.gz', gzencode( $data, 9, FORCE_GZIP ) );
135 + // If PHP Brotli extension is installed, create an additional cached Brotli file.
136 + if ( function_exists( 'brotli_compress' ) ) {
137 + file_put_contents( $this->cachedir . $this->filename . '.br', brotli_compress( $data, 11, BROTLI_GENERIC ) );
138 + }
107 139 }
108 140 }
141 +
142 + // Provide 3rd party action hook for every cache file that is created.
143 + // This hook can for example be used to inject a copy of the created cache file to a other domain.
144 + do_action( 'autoptimize_action_cache_file_created', $this->cachedir . $this->filename );
109 145 }
110 146
111 147 /**
112 148 * Get cache filename.
@@ -194,8 +230,12 @@
194 230 * Clears contents of AUTOPTIMIZE_CACHE_DIR by renaming the current
195 231 * cache directory into a new one with a unique name and then
196 232 * re-creating the default (empty) cache directory.
197 233 *
234 + * Important/ Fixme: this does not take multisite into account, so
235 + * if advanced_cache_clear_enabled is true (it is not by default)
236 + * then the content for all subsites is zapped!
237 + *
198 238 * @return bool Returns true when everything is done successfully, false otherwise.
199 239 */
200 240 protected static function clear_cache_via_rename()
201 241 {
@@ -247,9 +287,9 @@
247 287 protected static function get_advanced_cache_clear_prefix()
248 288 {
249 289 $pathname = self::get_pathname_base();
250 290 $basename = basename( $pathname );
251 - $prefix = $basename . '-';
291 + $prefix = $basename . '-artifact-';
252 292
253 293 return $prefix;
254 294 }
255 295
@@ -274,8 +314,13 @@
274 314 * @return bool
275 315 */
276 316 public static function delete_advanced_cache_clear_artifacts()
277 317 {
318 + // Don't go through these motions (called from the cachechecker) if advanced cache clear isn't even active.
319 + if ( ! self::advanced_cache_clear_enabled() ) {
320 + return false;
321 + }
322 +
278 323 $dir = self::get_pathname_base();
279 324 $prefix = self::get_advanced_cache_clear_prefix();
280 325 $parent = dirname( $dir );
281 326 $ok = false;
@@ -336,9 +381,21 @@
336 381 * @return bool
337 382 */
338 383 public static function clearall( $propagate = true )
339 384 {
340 - if ( ! self::cacheavail() ) {
385 + if ( defined( 'ET_CORE_VERSION' ) && 'Divi' === get_template() ) {
386 + // see https://blog.futtta.be/2018/11/17/warning-divi-purging-autoptimizes-cache/ .
387 + $dbt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
388 + $caller = isset( $dbt[1]['function'] ) ? $dbt[1]['function'] : null;
389 + if ( 'et_core_clear_wp_cache' === $caller ) {
390 + if ( apply_filters( 'autoptimize_filter_cache_divi_wrong_complain', true ) ) {
391 + _doing_it_wrong( 'autoptimizeCache::clearall', 'Divi devs: please don\'t clear Autoptimize\'s cache, it is unneeded and can break sites. You can contact me at [email protected] to discuss.', 'Autoptimize 2.9.6' );
392 + }
393 + return false;
394 + }
395 + }
396 +
397 + if ( ! self::cacheavail() || true === apply_filters( 'autoptimize_filter_cache_clearall_disabled', false ) ) {
341 398 return false;
342 399 }
343 400
344 401 // TODO/FIXME: If cache is big, switch to advanced/new cache clearing automatically?
@@ -347,8 +404,14 @@
347 404 } else {
348 405 self::clear_cache_classic();
349 406 }
350 407
408 + // Remove 404 handler if required.
409 + if ( self::do_fallback() ) {
410 + $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . 'autoptimize_404_handler.php';
411 + @unlink( $_fallback_php ); // @codingStandardsIgnoreLine
412 + }
413 +
351 414 // Remove the transient so it gets regenerated...
352 415 delete_transient( 'autoptimize_stats' );
353 416
354 417 // Cache was just purged, clear page cache and allow others to hook into our purging...
@@ -362,10 +425,12 @@
362 425 add_action( 'autoptimize_action_cachepurged', array( 'autoptimizeCache', 'flushPageCache' ), 10, 0 );
363 426 }
364 427
365 428 // Warm cache (part of speedupper)!
366 - if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) {
429 + if ( apply_filters( 'autoptimize_filter_speedupper', true ) && false == get_transient( 'autoptimize_cache_warmer_protector' ) ) {
430 + set_transient( 'autoptimize_cache_warmer_protector', 'I shall not warm cache for another 10 minutes.', 60 * 10 );
367 431 $url = site_url() . '/?ao_speedup_cachebuster=' . rand( 1, 100000 );
432 + $url = apply_filters( 'autoptimize_filter_cache_warmer_url', $url );
368 433 $cache = @wp_remote_get( $url ); // @codingStandardsIgnoreLine
369 434 unset( $cache );
370 435 }
371 436
@@ -480,17 +545,15 @@
480 545 * @return bool
481 546 */
482 547 public static function cacheavail()
483 548 {
484 - if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) {
485 - // We didn't set a cache.
486 - return false;
549 + // readonly FS explicitly OK'ed by dev, let's assume the cache dirs are there!
550 + if ( defined( 'AUTOPTIMIZE_CACHE_READONLY' ) ) {
551 + return true;
487 552 }
488 553
489 - foreach ( array( '', 'js', 'css' ) as $dir ) {
490 - if ( ! self::check_cache_dir( AUTOPTIMIZE_CACHE_DIR . $dir ) ) {
491 - return false;
492 - }
554 + if ( false === autoptimizeCache::check_and_create_dirs() ) {
555 + return false;
493 556 }
494 557
495 558 // Using .htaccess inside our cache folder to overrule wp-super-cache.
496 559 $htaccess = AUTOPTIMIZE_CACHE_DIR . '/.htaccess';
@@ -555,16 +618,124 @@
555 618 Deny from all
556 619 </Files>
557 620 </IfModule>';
558 621 }
622 +
623 + if ( self::do_fallback() === true ) {
624 + $content .= "\nErrorDocument 404 " . trailingslashit( parse_url( content_url(), PHP_URL_PATH ) ) . 'autoptimize_404_handler.php';
625 + }
559 626 @file_put_contents( $htaccess, $content ); // @codingStandardsIgnoreLine
560 627 }
561 628
629 + if ( self::do_fallback() ) {
630 + self::check_fallback_php();
631 + }
632 +
562 633 // All OK!
563 634 return true;
564 635 }
565 636
566 637 /**
638 + * Checks if fallback-php file exists and create it if not.
639 + *
640 + * Return bool
641 + */
642 + public static function check_fallback_php() {
643 + $_fallback_filename = 'autoptimize_404_handler.php';
644 + $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . $_fallback_filename;
645 + $_fallback_status = true;
646 +
647 + if ( ! file_exists( $_fallback_php ) && is_writable( WP_CONTENT_DIR ) ) {
648 + $_fallback_php_contents = file_get_contents( AUTOPTIMIZE_PLUGIN_DIR . 'config/' . $_fallback_filename );
649 + $_fallback_php_contents = str_replace( '<?php exit;', '<?php', $_fallback_php_contents );
650 + $_fallback_php_contents = str_replace( '<!--ao-cache-dir-->', AUTOPTIMIZE_CACHE_DIR, $_fallback_php_contents );
651 + $_fallback_php_contents = str_replace( '<!--ao-cachefile-prefix-->', AUTOPTIMIZE_CACHEFILE_PREFIX, $_fallback_php_contents );
652 + if ( is_multisite() ) {
653 + $_fallback_php_contents = str_replace( '$multisite = false;', '$multisite = true;', $_fallback_php_contents );
654 + }
655 + if ( apply_filters( 'autoptimize_filter_cache_fallback_log_errors', false ) ) {
656 + $_fallback_php_contents = str_replace( '// error_log', 'error_log', $_fallback_php_contents );
657 + }
658 + $_fallback_status = file_put_contents( $_fallback_php, $_fallback_php_contents );
659 + }
660 +
661 + return $_fallback_status;
662 + }
663 +
664 + /**
665 + * Tells if AO should try to avoid 404's by creating fallback filesize
666 + * and create a php 404 handler and tell .htaccess to redirect to said handler
667 + * and hook into WordPress to redirect 404 to said handler as well. NGINX users
668 + * are smart enough to get this working, no? ;-)
669 + *
670 + * Return bool
671 + */
672 + public static function do_fallback() {
673 + static $_do_fallback = null;
674 +
675 + if ( null === $_do_fallback ) {
676 + $_do_fallback = (bool) apply_filters( 'autoptimize_filter_cache_do_fallback', autoptimizeOptionWrapper::get_option( 'autoptimize_cache_fallback', '1' ) );
677 + }
678 +
679 + return $_do_fallback;
680 + }
681 +
682 + /**
683 + * Hooks into template_redirect, will act on 404-ing requests for
684 + * Autoptimized files and redirects to the fallback CSS/ JS if available
685 + * and 410'ing ("Gone") if fallback not available.
686 + */
687 + public static function wordpress_notfound_fallback() {
688 + $original_request = strtok( $_SERVER['REQUEST_URI'], '?' );
689 + if ( strpos( $original_request, wp_basename( WP_CONTENT_DIR ) . AUTOPTIMIZE_CACHE_CHILD_DIR ) !== false && is_404() ) {
690 + // make sure this is not considered a 404.
691 + global $wp_query;
692 + $wp_query->is_404 = false;
693 +
694 + // set fallback path.
695 + $js_or_css = pathinfo( $original_request, PATHINFO_EXTENSION );
696 + $fallback_path = AUTOPTIMIZE_CACHE_DIR . $js_or_css . '/autoptimize_fallback.' . $js_or_css;
697 +
698 + // prepare for Shakeeb's Unused CSS files to be 404-handled as well.
699 + if ( strpos( $original_request, 'uucss/uucss-' ) !== false ) {
700 + $original_request = preg_replace( '/uucss\/uucss-[a-z0-9]{32}-/', 'css/', $original_request );
701 + }
702 +
703 + // set fallback URL.
704 + $fallback_target = preg_replace( '/(.*)_(?:[a-z0-9]{32})\.(js|css)$/', '${1}_fallback.${2}', $original_request );
705 +
706 + // redirect to fallback if possible.
707 + if ( $original_request !== $fallback_target && file_exists( $fallback_path ) ) {
708 + // redirect to fallback.
709 + wp_redirect( $fallback_target, 302 );
710 + } else {
711 + // return HTTP 410 (gone) reponse.
712 + status_header( 410 );
713 + }
714 + }
715 + }
716 +
717 + /**
718 + * Checks if cache dirs exist and create if not.
719 + * Returns false if not succesful.
720 + *
721 + * @return bool
722 + */
723 + public static function check_and_create_dirs() {
724 + if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) {
725 + // We didn't set a cache.
726 + return false;
727 + }
728 +
729 + foreach ( array( '', 'js', 'css' ) as $dir ) {
730 + if ( ! self::check_cache_dir( AUTOPTIMIZE_CACHE_DIR . $dir ) ) {
731 + return false;
732 + }
733 + }
734 + return true;
735 + }
736 +
737 + /**
567 738 * Ensures the specified `$dir` exists and is writeable.
568 739 * Returns false if that's not the case.
569 740 *
570 741 * @param string $dir Directory to check/create.
@@ -615,8 +786,12 @@
615 786 } elseif ( function_exists( 'w3tc_pgcache_flush' ) ) {
616 787 w3tc_pgcache_flush();
617 788 } elseif ( function_exists( 'wp_fast_cache_bulk_delete_all' ) ) {
618 789 wp_fast_cache_bulk_delete_all();
790 + } elseif ( function_exists( 'rapidcache_clear_cache' ) ) {
791 + rapidcache_clear_cache();
792 + } elseif ( class_exists( 'Swift_Performance_Cache' ) ) {
793 + Swift_Performance_Cache::clear_all_cache();
619 794 } elseif ( class_exists( 'WpFastestCache' ) ) {
620 795 $wpfc = new WpFastestCache();
621 796 $wpfc->deleteCache();
622 797 } elseif ( class_exists( 'c_ws_plugin__qcache_purging_routines' ) ) {
@@ -645,8 +820,22 @@
645 820 }
646 821 }
647 822 } elseif ( function_exists( 'sg_cachepress_purge_cache' ) ) {
648 823 sg_cachepress_purge_cache();
824 + } elseif ( array_key_exists( 'KINSTA_CACHE_ZONE', $_SERVER ) ) {
825 + $_kinsta_clear_cache_url = 'https://localhost/kinsta-clear-cache-all';
826 + $_kinsta_response = wp_remote_get(
827 + $_kinsta_clear_cache_url,
828 + array(
829 + 'sslverify' => false,
830 + 'timeout' => 5,
831 + )
832 + );
833 + } elseif ( class_exists( 'RaidboxesNginxCacheFunctions' ) ) {
834 + $rb_cache_helper = new RaidboxesNginxCacheFunctions();
835 + $rb_cache_helper->purge_cache();
836 + } elseif ( defined('NGINX_HELPER_BASENAME') ) {
837 + do_action( 'rt_nginx_helper_purge_all' );
649 838 } elseif ( file_exists( WP_CONTENT_DIR . '/wp-cache-config.php' ) && function_exists( 'prune_super_cache' ) ) {
650 839 // fallback for WP-Super-Cache
651 840 global $cache_path;
652 841 if ( is_multisite() ) {
@@ -656,8 +845,11 @@
656 845 } else {
657 846 prune_super_cache( $cache_path . 'supercache/', true );
658 847 prune_super_cache( $cache_path, true );
659 848 }
849 + } elseif ( class_exists( 'NginxCache' ) ) {
850 + $nginx_cache = new NginxCache();
851 + $nginx_cache->purge_zone_once();
660 852 }
661 853 }
662 854 // @codingStandardsIgnoreEnd
663 855 }