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 +172 -6 2.5.1 → 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,17 @@
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 +
93 103 // off by default; check if cachedirs exist every time before caching
94 104 //
95 105 // to be activated for users that experience these ugly errors;
96 106 // PHP Warning: file_put_contents failed to open stream: No such file or directory.
@@ -108,8 +118,18 @@
108 118 file_put_contents( $this->cachedir . $this->filename . '.none', $data );
109 119 } else {
110 120 // Write code to cache without doing anything else.
111 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 +
112 132 if ( apply_filters( 'autoptimize_filter_cache_create_static_gzip', false ) ) {
113 133 // Create an additional cached gzip file.
114 134 file_put_contents( $this->cachedir . $this->filename . '.gz', gzencode( $data, 9, FORCE_GZIP ) );
115 135 // If PHP Brotli extension is installed, create an additional cached Brotli file.
@@ -117,8 +137,12 @@
117 137 file_put_contents( $this->cachedir . $this->filename . '.br', brotli_compress( $data, 11, BROTLI_GENERIC ) );
118 138 }
119 139 }
120 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 );
121 145 }
122 146
123 147 /**
124 148 * Get cache filename.
@@ -206,8 +230,12 @@
206 230 * Clears contents of AUTOPTIMIZE_CACHE_DIR by renaming the current
207 231 * cache directory into a new one with a unique name and then
208 232 * re-creating the default (empty) cache directory.
209 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 + *
210 238 * @return bool Returns true when everything is done successfully, false otherwise.
211 239 */
212 240 protected static function clear_cache_via_rename()
213 241 {
@@ -259,9 +287,9 @@
259 287 protected static function get_advanced_cache_clear_prefix()
260 288 {
261 289 $pathname = self::get_pathname_base();
262 290 $basename = basename( $pathname );
263 - $prefix = $basename . '-';
291 + $prefix = $basename . '-artifact-';
264 292
265 293 return $prefix;
266 294 }
267 295
@@ -286,8 +314,13 @@
286 314 * @return bool
287 315 */
288 316 public static function delete_advanced_cache_clear_artifacts()
289 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 +
290 323 $dir = self::get_pathname_base();
291 324 $prefix = self::get_advanced_cache_clear_prefix();
292 325 $parent = dirname( $dir );
293 326 $ok = false;
@@ -348,9 +381,21 @@
348 381 * @return bool
349 382 */
350 383 public static function clearall( $propagate = true )
351 384 {
352 - 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 ) ) {
353 398 return false;
354 399 }
355 400
356 401 // TODO/FIXME: If cache is big, switch to advanced/new cache clearing automatically?
@@ -359,8 +404,14 @@
359 404 } else {
360 405 self::clear_cache_classic();
361 406 }
362 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 +
363 414 // Remove the transient so it gets regenerated...
364 415 delete_transient( 'autoptimize_stats' );
365 416
366 417 // Cache was just purged, clear page cache and allow others to hook into our purging...
@@ -377,8 +428,9 @@
377 428 // Warm cache (part of speedupper)!
378 429 if ( apply_filters( 'autoptimize_filter_speedupper', true ) && false == get_transient( 'autoptimize_cache_warmer_protector' ) ) {
379 430 set_transient( 'autoptimize_cache_warmer_protector', 'I shall not warm cache for another 10 minutes.', 60 * 10 );
380 431 $url = site_url() . '/?ao_speedup_cachebuster=' . rand( 1, 100000 );
432 + $url = apply_filters( 'autoptimize_filter_cache_warmer_url', $url );
381 433 $cache = @wp_remote_get( $url ); // @codingStandardsIgnoreLine
382 434 unset( $cache );
383 435 }
384 436
@@ -493,8 +545,13 @@
493 545 * @return bool
494 546 */
495 547 public static function cacheavail()
496 548 {
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;
552 + }
553 +
497 554 if ( false === autoptimizeCache::check_and_create_dirs() ) {
498 555 return false;
499 556 }
500 557
@@ -561,16 +618,104 @@
561 618 Deny from all
562 619 </Files>
563 620 </IfModule>';
564 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 + }
565 626 @file_put_contents( $htaccess, $content ); // @codingStandardsIgnoreLine
566 627 }
567 628
629 + if ( self::do_fallback() ) {
630 + self::check_fallback_php();
631 + }
632 +
568 633 // All OK!
569 634 return true;
570 635 }
571 636
572 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 + /**
573 718 * Checks if cache dirs exist and create if not.
574 719 * Returns false if not succesful.
575 720 *
576 721 * @return bool
@@ -641,8 +786,12 @@
641 786 } elseif ( function_exists( 'w3tc_pgcache_flush' ) ) {
642 787 w3tc_pgcache_flush();
643 788 } elseif ( function_exists( 'wp_fast_cache_bulk_delete_all' ) ) {
644 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();
645 794 } elseif ( class_exists( 'WpFastestCache' ) ) {
646 795 $wpfc = new WpFastestCache();
647 796 $wpfc->deleteCache();
648 797 } elseif ( class_exists( 'c_ws_plugin__qcache_purging_routines' ) ) {
@@ -671,8 +820,22 @@
671 820 }
672 821 }
673 822 } elseif ( function_exists( 'sg_cachepress_purge_cache' ) ) {
674 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' );
675 838 } elseif ( file_exists( WP_CONTENT_DIR . '/wp-cache-config.php' ) && function_exists( 'prune_super_cache' ) ) {
676 839 // fallback for WP-Super-Cache
677 840 global $cache_path;
678 841 if ( is_multisite() ) {
@@ -682,8 +845,11 @@
682 845 } else {
683 846 prune_super_cache( $cache_path . 'supercache/', true );
684 847 prune_super_cache( $cache_path, true );
685 848 }
849 + } elseif ( class_exists( 'NginxCache' ) ) {
850 + $nginx_cache = new NginxCache();
851 + $nginx_cache->purge_zone_once();
686 852 }
687 853 }
688 854 // @codingStandardsIgnoreEnd
689 855 }