Comet Cache - Version 160416

Version Description

= v160416 =

Requires WordPress v4.2+.

Download this release

Release Info

Developer raamdev
Plugin Icon 128x128 Comet Cache
Version 160416
Comparing to
See all releases

Code changes from version 160227 to 160416

Files changed (161) hide show
  1. CHANGELOG.md +18 -0
  2. comet-cache.php +2 -2
  3. plugin.php +17 -11
  4. readme.txt +24 -64
  5. src/client-s/css/admin-bar.min.css +1 -1
  6. src/client-s/css/menu-pages.min.css +1 -1
  7. src/includes/api.php +4 -2
  8. src/includes/classes/AbsBase.php +10 -8
  9. src/includes/classes/AbsBaseAp.php +28 -12
  10. src/includes/classes/Actions.php +7 -7
  11. src/includes/classes/AdvCacheBackCompat.php +4 -4
  12. src/includes/classes/AdvancedCache.php +13 -11
  13. src/includes/classes/ApiBase.php +2 -1
  14. src/includes/classes/Conflicts.php +11 -9
  15. src/includes/classes/FeedUtils.php +15 -15
  16. src/includes/classes/MenuPage.php +4 -2
  17. src/includes/classes/MenuPageOptions.php +13 -13
  18. src/includes/classes/Plugin.php +93 -67
  19. src/includes/classes/VsUpgrades.php +6 -7
  20. src/includes/closures/Ac/AbortUtils.php +0 -11
  21. src/includes/closures/Ac/AcPluginUtils.php +0 -25
  22. src/includes/closures/Ac/BrowserUtils.php +0 -34
  23. src/includes/closures/Ac/NcDebugConsts.php +0 -293
  24. src/includes/closures/Ac/NcDebugUtils.php +0 -209
  25. src/includes/closures/Ac/ObUtils.php +0 -353
  26. src/includes/closures/Ac/PostloadUtils.php +0 -187
  27. src/includes/closures/Ac/ShutdownUtils.php +0 -18
  28. src/includes/closures/Plugin/ActionUtils.php +0 -16
  29. src/includes/closures/Plugin/BbPressUtils.php +0 -61
  30. src/includes/closures/Plugin/CleanupUtils.php +0 -19
  31. src/includes/closures/Plugin/CondUtils.php +0 -13
  32. src/includes/closures/Plugin/CronUtils.php +0 -80
  33. src/includes/closures/Plugin/DbUtils.php +0 -13
  34. src/includes/closures/Plugin/DirUtils.php +0 -79
  35. src/includes/closures/Plugin/HtaccessUtils.php +0 -273
  36. src/includes/closures/Plugin/InstallUtils.php +0 -535
  37. src/includes/closures/Plugin/MenuPageUtils.php +0 -219
  38. src/includes/closures/Plugin/NoticeUtils.php +0 -296
  39. src/includes/closures/Plugin/OptionUtils.php +0 -70
  40. src/includes/closures/Plugin/PostUtils.php +0 -42
  41. src/includes/closures/Plugin/UpdateUtils.php +0 -46
  42. src/includes/closures/Plugin/UrlUtils.php +0 -22
  43. src/includes/closures/Plugin/UserUtils.php +0 -118
  44. src/includes/closures/Plugin/WcpAuthorUtils.php +0 -92
  45. src/includes/closures/Plugin/WcpCommentUtils.php +0 -96
  46. src/includes/closures/Plugin/WcpFeedUtils.php +0 -116
  47. src/includes/closures/Plugin/WcpHomeBlogUtils.php +0 -101
  48. src/includes/closures/Plugin/WcpJetpackUtils.php +0 -24
  49. src/includes/closures/Plugin/WcpOpcacheUtils.php +0 -69
  50. src/includes/closures/Plugin/WcpPluginUtils.php +0 -22
  51. src/includes/closures/Plugin/WcpPostTypeUtils.php +0 -66
  52. src/includes/closures/Plugin/WcpPostUtils.php +0 -176
  53. src/includes/closures/Plugin/WcpSettingUtils.php +0 -31
  54. src/includes/closures/Plugin/WcpSitemapUtils.php +0 -47
  55. src/includes/closures/Plugin/WcpTermUtils.php +0 -139
  56. src/includes/closures/Plugin/WcpUpdaterUtils.php +0 -99
  57. src/includes/closures/Plugin/WcpUtils.php +0 -341
  58. src/includes/closures/Plugin/WcpWooCommerceUtils.php +0 -24
  59. src/includes/closures/Shared/BlogUtils.php +0 -31
  60. src/includes/closures/Shared/CacheDirUtils.php +0 -643
  61. src/includes/closures/Shared/CacheLockUtils.php +0 -80
  62. src/includes/closures/Shared/CachePathConsts.php +0 -140
  63. src/includes/closures/Shared/CachePathUtils.php +0 -351
  64. src/includes/closures/Shared/ConditionalUtils.php +0 -358
  65. src/includes/closures/Shared/DomainMappingUtils.php +0 -264
  66. src/includes/closures/Shared/EscapeUtils.php +0 -17
  67. src/includes/closures/Shared/FsUtils.php +0 -323
  68. src/includes/closures/Shared/HookUtils.php +0 -249
  69. src/includes/closures/Shared/HttpUtils.php +0 -166
  70. src/includes/closures/Shared/I18nUtils.php +0 -44
  71. src/includes/closures/Shared/IpAddrUtils.php +0 -83
  72. src/includes/closures/Shared/PatternUtils.php +0 -48
  73. src/includes/closures/Shared/ReplaceUtils.php +0 -43
  74. src/includes/closures/Shared/ServerUtils.php +0 -65
  75. src/includes/closures/Shared/StringUtils.php +0 -87
  76. src/includes/closures/Shared/SysUtils.php +0 -92
  77. src/includes/closures/Shared/TokenUtils.php +0 -300
  78. src/includes/closures/Shared/TrimUtils.php +0 -36
  79. src/includes/closures/Shared/UrlUtils.php +0 -131
  80. src/includes/functions/i18n-utils.php +32 -17
  81. src/includes/functions/wp-cache-postload.php +1 -1
  82. src/includes/interfaces/Shared/CachePathConsts.php +140 -0
  83. src/includes/interfaces/Shared/NcDebugConsts.php +293 -0
  84. src/includes/plugin.php +8 -6
  85. src/includes/stub.php +22 -6
  86. src/includes/templates/advanced-cache.txt +9 -3
  87. src/includes/traits/Ac/AbortUtils.php +17 -0
  88. src/includes/traits/Ac/AcPluginUtils.php +31 -0
  89. src/includes/traits/Ac/BrowserUtils.php +40 -0
  90. src/includes/traits/Ac/NcDebugUtils.php +217 -0
  91. src/includes/traits/Ac/ObUtils.php +356 -0
  92. src/includes/traits/Ac/PostloadUtils.php +193 -0
  93. src/includes/traits/Ac/ShutdownUtils.php +26 -0
  94. src/includes/traits/Plugin/ActionUtils.php +22 -0
  95. src/includes/traits/Plugin/BbPressUtils.php +69 -0
  96. src/includes/traits/Plugin/CleanupUtils.php +25 -0
  97. src/includes/traits/Plugin/CondUtils.php +19 -0
  98. src/includes/traits/Plugin/CronUtils.php +87 -0
  99. src/includes/traits/Plugin/DbUtils.php +19 -0
  100. src/includes/traits/Plugin/DirUtils.php +87 -0
  101. src/includes/traits/Plugin/HtaccessUtils.php +284 -0
  102. src/includes/traits/Plugin/InstallUtils.php +553 -0
  103. src/includes/traits/Plugin/MenuPageUtils.php +236 -0
  104. src/includes/traits/Plugin/NoticeUtils.php +337 -0
  105. src/includes/traits/Plugin/OptionUtils.php +81 -0
  106. src/includes/traits/Plugin/PostUtils.php +49 -0
  107. src/includes/traits/Plugin/UpdateUtils.php +52 -0
  108. src/includes/traits/Plugin/UrlUtils.php +52 -0
  109. src/includes/traits/Plugin/UserUtils.php +172 -0
  110. src/includes/traits/Plugin/WcpAuthorUtils.php +97 -0
  111. src/includes/traits/Plugin/WcpCommentUtils.php +103 -0
  112. src/includes/traits/Plugin/WcpFeedUtils.php +121 -0
  113. src/includes/traits/Plugin/WcpHomeBlogUtils.php +106 -0
  114. src/includes/traits/Plugin/WcpJetpackUtils.php +30 -0
  115. src/includes/traits/Plugin/WcpOpcacheUtils.php +77 -0
  116. src/includes/traits/Plugin/WcpPluginUtils.php +28 -0
  117. src/includes/traits/Plugin/WcpPostTypeUtils.php +71 -0
  118. src/includes/traits/Plugin/WcpPostUtils.php +190 -0
  119. src/includes/traits/Plugin/WcpSettingUtils.php +37 -0
  120. src/includes/traits/Plugin/WcpSitemapUtils.php +52 -0
  121. src/includes/traits/Plugin/WcpTermUtils.php +144 -0
  122. src/includes/traits/Plugin/WcpUpdaterUtils.php +103 -0
  123. src/includes/traits/Plugin/WcpUtils.php +383 -0
  124. src/includes/traits/Plugin/WcpWooCommerceUtils.php +30 -0
  125. src/includes/traits/Shared/BlogUtils.php +37 -0
  126. src/includes/traits/Shared/CacheDirUtils.php +651 -0
  127. src/includes/traits/Shared/CacheLockUtils.php +87 -0
  128. src/includes/traits/Shared/CachePathUtils.php +358 -0
  129. src/includes/traits/Shared/ConditionalUtils.php +380 -0
  130. src/includes/traits/Shared/DomainMappingUtils.php +277 -0
  131. src/includes/traits/Shared/EscapeUtils.php +23 -0
  132. src/includes/traits/Shared/FsUtils.php +335 -0
  133. src/includes/traits/Shared/HookUtils.php +281 -0
  134. src/includes/traits/Shared/HttpUtils.php +177 -0
  135. src/includes/traits/Shared/I18nUtils.php +52 -0
  136. src/includes/traits/Shared/IpAddrUtils.php +90 -0
  137. src/includes/traits/Shared/PatternUtils.php +55 -0
  138. src/includes/traits/Shared/ReplaceUtils.php +49 -0
  139. src/includes/traits/Shared/ServerUtils.php +73 -0
  140. src/includes/traits/Shared/StringUtils.php +94 -0
  141. src/includes/traits/Shared/SysUtils.php +100 -0
  142. src/includes/traits/Shared/TokenUtils.php +297 -0
  143. src/includes/traits/Shared/TrimUtils.php +40 -0
  144. src/includes/traits/Shared/UrlUtils.php +140 -0
  145. src/includes/translations/comet-cache.pot +0 -1927
  146. src/includes/uninstall.php +5 -3
  147. src/vendor/autoload.php +1 -1
  148. src/vendor/composer/ClassLoader.php +4 -4
  149. src/vendor/composer/LICENSE +1 -1
  150. src/vendor/composer/autoload_psr4.php +3 -1
  151. src/vendor/composer/autoload_real.php +3 -8
  152. src/vendor/composer/installed.json +70 -70
  153. src/vendor/websharks/sharkicons/src/long-classes.min.css +0 -1
  154. src/vendor/websharks/sharkicons/src/short-classes.min.css +0 -1
  155. src/vendor/websharks/wp-i18n-tools/CHANGELOG.md +3 -0
  156. src/vendor/websharks/wp-i18n-tools/README.md +14 -0
  157. src/vendor/websharks/wp-i18n-tools/add-textdomain.php +110 -0
  158. src/vendor/websharks/wp-i18n-tools/cron-svn-pots.php +117 -0
  159. src/vendor/websharks/wp-i18n-tools/extract/ExtractTest.php +160 -0
  160. src/vendor/websharks/wp-i18n-tools/extract/TODO +1 -0
  161. src/vendor/websharks/wp-i18n-tools/extract/extract.php +163 -0
CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = v160227 =
2
 
3
  - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing calls to `$GLOBALS['zencache']` from working properly with Comet Cache. See [Issue #689](https://github.com/websharks/comet-cache/issues/689)
1
+ = v160416 =
2
+
3
+ - **Enhancement**: Several PHP 5.4+ enhancements, most notably a conversion from PHP Closures to PHP Traits. See [Issue #635](https://github.com/websharks/comet-cache/issues/635).
4
+ - **Enhancement**: Dashboard notices generated by Comet Cache now use the WordPress-style dismiss button to keep things consistent. See [Issue #719](https://github.com/websharks/comet-cache/issues/719).
5
+ - **Enhancement**: Dashboard notices generated by Comet Cache are now compacted into a single notice that can be expanded to view details. This helps reduce the number of messages that appear when, for example, a Post is published or updated and several cache files are automatically cleared. Instead of showing a separate notice for each type of cache file that was cleared, a single notice is shown with a link to toggle the details. See [Issue #118](https://github.com/websharks/comet-cache/issues/118).
6
+ - **Enhancement** (Pro): Improved the way the Auto-Cache Engine figures out the URL scheme (`http` vs `https`) that should be used when fetching the XML Sitemap. Instead of forcing `http`, whatever scheme is configured with the Home URL is now used. See [Issue #715](https://github.com/websharks/comet-cache/issues/715).
7
+ - **Enhancement** (Pro): The Pro Plugin Updater page now includes a "Save All Changes" button at the bottom, allowing you to save changes to the updater configuration without actually running the plugin updater. Props @bridgeport @NoahjChampion @1wdtv. See [Issue #681](https://github.com/websharks/comet-cache/issues/681).
8
+ - **Bug Fix**: Fixed a duplicated row of links on the Pro Plugin Updater page. See [Issue #696](https://github.com/websharks/comet-cache/issues/696).
9
+ - **Bug Fix**: Fixed an issue where some browsers would report "Failed to parse SourceMap" errors in their console when browsing the Comet Cache Options page. This was related to `sourceMappingURL` comments in the minified JS/CSS files that were intended for development purposes. Props to @1wdtv for reporting. See [#732](https://github.com/websharks/comet-cache/issues/732).
10
+ - **Bug Fix**: Fixed a UI bug in the Pro Preview that was causing the Manual Cache Clearing panel to not appear as part of the Pro Preview. Props @renzms. See [Issue #711](https://github.com/websharks/comet-cache/issues/711).
11
+ - **Bug Fix** (Pro): Fixed a bug related to the Pro Updater where some users who had migrated from ZenCache Pro to Comet Cache Pro were seeing an invalid new version message. Props @renzms @jaswsinc. See [Issue #727](https://github.com/websharks/comet-cache/issues/727)
12
+ - **Bug Fix** (Pro): Fixed a bug with the Pro Plugin Updater that resulted in "Unknown error. Please wait 15 minutes and try again." when attempting to update Comet Cache Pro. The issue affected sites on servers running an old version of cURL (< v7.36) and/or an old version of OpenSSL, which made them unable to connect to the Comet Cache Pro update server. The Pro Plugin Updater now attempts to connect to a secondary update server that is more compatible with older versions of cURL and OpenSSL. See [Issue #678](https://github.com/websharks/comet-cache/issues/678).
13
+ - **Hooks/Filters**: Comet Cache now hooks into `plugins_loaded` instead of `after_setup_theme` when calling its own setup routine. This improves integration with other plugins that may be expecting the Comet Cache API functions to be available after `plugins_loaded`. Props to Frank Goossens (@futtta) from Autoptimize for helping with this. See [Issue #716](https://github.com/websharks/comet-cache/issues/716).
14
+ - **Compatibility**: Fixed a compatibility issue for some themes and plugins that were using old AC Plugin code designed to work with Quick Cache. This fix adds some backwards compatibility support for Quick Cache, but note that the first release of Comet Cache dropped support for Quick Cache backwards compatibility in favor of ZenCache backwards compatibility. See [Issue #710](https://github.com/websharks/comet-cache/issues/710).
15
+ - **Compatibility: Query Monitor.** The Query Monitor plugin was reporting false-positive errors indicating that many Comet Cache methods did not exist. This was due to how the Comet Cache codebase was utilizing PHP Closures, which Query Monitor had a hard time handling. The codebase has been refactored to use PHP Traits instead of Closures and now the Query Monitor plugin has no problem recognizing Comet Cache methods. Props to @NoahjChampion for reporting. See [Issue #686](https://github.com/websharks/comet-cache/issues/686).
16
+ - **Compatibility: WP-CLI.** When installing Comet Cache via WP-CLI, Comet Cache is now automatically enabled. There's no need to manually enable Comet Cache from within the plugin options after installing. Props @jaswsinc. See [Issue #464](https://github.com/websharks/comet-cache/issues/464).
17
+ - **Required WordPress Version is now v4.2.** The minimum required WordPress version has been bumped from v4.1 to v4.2. See [Issue #706](https://github.com/websharks/comet-cache/issues/706).
18
+
19
  = v160227 =
20
 
21
  - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing calls to `$GLOBALS['zencache']` from working properly with Comet Cache. See [Issue #689](https://github.com/websharks/comet-cache/issues/689)
comet-cache.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Version: 160227
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
@@ -14,4 +14,4 @@ Description: Comet Cache is an advanced WordPress caching plugin inspired by sim
14
  if (!defined('WPINC')) {
15
  exit('Do NOT access this file directly: '.basename(__FILE__));
16
  }
17
- require_once dirname(__FILE__).'/plugin.php';
1
  <?php
2
  /*
3
+ Version: 160416
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
14
  if (!defined('WPINC')) {
15
  exit('Do NOT access this file directly: '.basename(__FILE__));
16
  }
17
+ require_once __DIR__.'/plugin.php';
plugin.php CHANGED
@@ -4,12 +4,12 @@ if (!defined('WPINC')) {
4
  }
5
  $GLOBALS['wp_php_rv'] = '5.3.2'; //php-required-version// // Leaving this at v5.3.2 so that we can have more control over Dashboard messages below.
6
 
7
- if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/check.php')) {
8
  if (!empty($_REQUEST['comet_cache_mbstring_deprecated_warning_bypass']) && is_admin()) {
9
  update_site_option('comet_cache_mbstring_deprecated_warning_bypass', time());
10
  }
11
 
12
- ${__FILE__}['apc_enabled'] = (extension_loaded('apc') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.cache_by_default'), FILTER_VALIDATE_BOOLEAN) && stripos((string)ini_get('apc.filters'), 'comet-cache') === false) ? true : false;
13
 
14
  if ((!version_compare(PHP_VERSION, '5.4', '>=') || ${__FILE__}['apc_enabled'])) { // If PHP <= 5.4 or APC is enabled
15
 
@@ -22,8 +22,10 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
22
  }
23
 
24
  add_action(
25
- 'all_admin_notices', create_function(
26
- '', 'if(!current_user_can(\'activate_plugins\'))'.
 
 
27
  ' return;'."\n".// User missing capability.
28
 
29
  'echo \''.// Wrap `$notice` inside a WordPress error.
@@ -33,7 +35,7 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
33
  '</div>'.
34
 
35
  '\';'
36
- )
37
  );
38
  } elseif (${__FILE__}['apc_enabled'] && is_admin()) {
39
  ${__FILE__}['apc_deprecated_notice'] = '<h3 style="margin:.5em 0 .25em 0;">'.__('<strong>NOTICE: Comet Cache + PHP APC Extension</strong></h3>', 'comet-cache');
@@ -46,8 +48,10 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
46
  ${__FILE__}['apc_deprecated_notice'] .= '<p style="margin-top:0;">'.__('To learn more about this change, please see the announcement: <a href="http://cometcache.com/r/php-apc-extension-no-longer-supported/" target="_blank">PHP APC Extension No Longer Supported</a>', 'comet-cache').'</p>';
47
 
48
  add_action(
49
- 'all_admin_notices', create_function(
50
- '', 'if(!current_user_can(\'activate_plugins\'))'.
 
 
51
  ' return;'."\n".// User missing capability.
52
 
53
  'echo \''.// Wrap `$notice` inside a WordPress error.
@@ -57,7 +61,7 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
57
  '</div>'.
58
 
59
  '\';'
60
- )
61
  );
62
  }
63
  } else { // Load the plugin
@@ -68,8 +72,10 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
68
  ${__FILE__}['mbstring_deprecated_warning'] .= '<p style="margin-top:0;">'.__('The <code>mbstring</code> extension provides Multibyte String support to PHP and is required to properly handle UTF-8 characters, which many sites now use. Without Multibyte String support, Comet Cache will be unstable. For that reason we are requiring the <code>mbstring</code> extension to improve reliablity when caching and to prevent your site from experiencing unforeseen issues in the future.', 'comet-cache').'</p>';
69
  ${__FILE__}['mbstring_deprecated_warning'] .= '<p style="margin-bottom:.5em;">'.__('<a href="'.esc_attr(add_query_arg('comet_cache_mbstring_deprecated_warning_bypass', '1')).'" onclick="if(!confirm(\'Are you sure? Press OK to continue, or Cancel to stop and read carefully.\')) return false;">Dismiss this notice.</a>', 'comet-cache').'</p>';
70
  add_action(
71
- 'all_admin_notices', create_function(
72
- '', 'if(!current_user_can(\'activate_plugins\'))'.
 
 
73
  ' return;'."\n".// User missing capability.
74
  'echo \''.// Wrap `$notice` inside a WordPress error.
75
  '<div class="notice notice-warning">'.
@@ -80,7 +86,7 @@ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/chec
80
  );
81
  }
82
 
83
- require_once dirname(__FILE__).'/src/includes/plugin.php';
84
  }
85
  } else {
86
  wp_php_rv_notice('Comet Cache');
4
  }
5
  $GLOBALS['wp_php_rv'] = '5.3.2'; //php-required-version// // Leaving this at v5.3.2 so that we can have more control over Dashboard messages below.
6
 
7
+ if (require(__DIR__.'/src/vendor/websharks/wp-php-rv/src/includes/check.php')) {
8
  if (!empty($_REQUEST['comet_cache_mbstring_deprecated_warning_bypass']) && is_admin()) {
9
  update_site_option('comet_cache_mbstring_deprecated_warning_bypass', time());
10
  }
11
 
12
+ ${__FILE__}['apc_enabled'] = (extension_loaded('apc') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.cache_by_default'), FILTER_VALIDATE_BOOLEAN) && stripos((string) ini_get('apc.filters'), 'comet-cache') === false) ? true : false;
13
 
14
  if ((!version_compare(PHP_VERSION, '5.4', '>=') || ${__FILE__}['apc_enabled'])) { // If PHP <= 5.4 or APC is enabled
15
 
22
  }
23
 
24
  add_action(
25
+ 'all_admin_notices',
26
+ create_function(
27
+ '',
28
+ 'if(!current_user_can(\'activate_plugins\'))'.
29
  ' return;'."\n".// User missing capability.
30
 
31
  'echo \''.// Wrap `$notice` inside a WordPress error.
35
  '</div>'.
36
 
37
  '\';'
38
+ )
39
  );
40
  } elseif (${__FILE__}['apc_enabled'] && is_admin()) {
41
  ${__FILE__}['apc_deprecated_notice'] = '<h3 style="margin:.5em 0 .25em 0;">'.__('<strong>NOTICE: Comet Cache + PHP APC Extension</strong></h3>', 'comet-cache');
48
  ${__FILE__}['apc_deprecated_notice'] .= '<p style="margin-top:0;">'.__('To learn more about this change, please see the announcement: <a href="http://cometcache.com/r/php-apc-extension-no-longer-supported/" target="_blank">PHP APC Extension No Longer Supported</a>', 'comet-cache').'</p>';
49
 
50
  add_action(
51
+ 'all_admin_notices',
52
+ create_function(
53
+ '',
54
+ 'if(!current_user_can(\'activate_plugins\'))'.
55
  ' return;'."\n".// User missing capability.
56
 
57
  'echo \''.// Wrap `$notice` inside a WordPress error.
61
  '</div>'.
62
 
63
  '\';'
64
+ )
65
  );
66
  }
67
  } else { // Load the plugin
72
  ${__FILE__}['mbstring_deprecated_warning'] .= '<p style="margin-top:0;">'.__('The <code>mbstring</code> extension provides Multibyte String support to PHP and is required to properly handle UTF-8 characters, which many sites now use. Without Multibyte String support, Comet Cache will be unstable. For that reason we are requiring the <code>mbstring</code> extension to improve reliablity when caching and to prevent your site from experiencing unforeseen issues in the future.', 'comet-cache').'</p>';
73
  ${__FILE__}['mbstring_deprecated_warning'] .= '<p style="margin-bottom:.5em;">'.__('<a href="'.esc_attr(add_query_arg('comet_cache_mbstring_deprecated_warning_bypass', '1')).'" onclick="if(!confirm(\'Are you sure? Press OK to continue, or Cancel to stop and read carefully.\')) return false;">Dismiss this notice.</a>', 'comet-cache').'</p>';
74
  add_action(
75
+ 'all_admin_notices',
76
+ create_function(
77
+ '',
78
+ 'if(!current_user_can(\'activate_plugins\'))'.
79
  ' return;'."\n".// User missing capability.
80
  'echo \''.// Wrap `$notice` inside a WordPress error.
81
  '<div class="notice notice-warning">'.
86
  );
87
  }
88
 
89
+ require_once __DIR__.'/src/includes/plugin.php';
90
  }
91
  } else {
92
  wp_php_rv_notice('Comet Cache');
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Comet Cache ===
2
 
3
- Stable tag: 160227
4
- Requires at least: 4.1
5
- Tested up to: 4.5-alpha
6
  Text Domain: comet-cache
7
 
8
  License: GPLv2 or later
@@ -330,12 +330,30 @@ Released under the terms of the [GNU General Public License](http://www.gnu.org/
330
 
331
  == Upgrade Notice ==
332
 
333
- = v160211 =
334
 
335
- Requires PHP v5.4+. The latest version of Comet Cache is a complete rewrite (OOP design). Faster! and even more dependable. For further details, please see http://cometcache.com/new-minimum-php-version-php-5-4/
336
 
337
  == Changelog ==
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  = v160227 =
340
 
341
  - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing calls to `$GLOBALS['zencache']` from working properly with Comet Cache. See [Issue #689](https://github.com/websharks/comet-cache/issues/689)
@@ -356,62 +374,4 @@ Requires PHP v5.4+. The latest version of Comet Cache is a complete rewrite (OOP
356
  - **Bug Fix (Multisite)**: Fixed a bug where when Comet Cache was Network Activated the plugin settings link would show up in the plugins list for the Main Site and would lead to a 404 error. The settings link is now only shown when viewing the plugins list from the Network Admin. Props @jaswsinc. See [Issue #675](https://github.com/websharks/zencache/issues/675).
357
  - **Enhancement**: Added support-related links to the plugin options page. Props @renzms. See [Issue #612](https://github.com/websharks/zencache/issues/612#issuecomment-186827661).
358
 
359
- = v160222 =
360
-
361
- - **Announcement: ZenCache is changing its name to Comet Cache!** Learn more about this upcoming change [here](https://cometcache.com/r/announcing-comet-cache-formerly-zencache/).
362
- - **Announcement: This version of ZenCache requires PHP 5.4+.** As announced in the previous release, the minimum PHP version required to run ZenCache / Comet Cache has changed to PHP 5.4+ as of December 1st, 2015. Please see announcement with further details: [New Minimum PHP Version: PHP 5.4](http://zencache.com/r/new-minimum-php-version-php-5-4/)
363
- - **Announcement: This version of ZenCache does not support the PHP APC Extension**. As announced in the previous release, ZenCache / Comet Cache no longer runs with the PHP APC extension enabled as of December 1st, 2015. Please see announcement with further details: [PHP APC Extension No Longer Supported](http://zencache.com/r/php-apc-extension-no-longer-supported/)
364
- - **Announcement: After March 1st, 2016 ZenCache / Comet Cache will require PHP Multibyte String support.** The `mbstring` extension provides Multibyte String support to PHP and is required to properly handle UTF-8 characters, which many sites now use. Without Multibyte String support, caching will be unstable. For that reason we are requiring the `mbstring` extension to improve reliability when caching and to prevent your site from experiencing unforeseen issues in the future.
365
- - **Announcement: Restructured Codebase**. The entire ZenCache Lite codebase has been restructured to improve performance, enhance flexibility, and make it easier to build in new features! This release of ZenCache Lite has been built from the ZenCache Pro codebase, which is more polished and up-to-date. This release includes many changes and improvements that were released as part of ZenCache Pro releases over the past 6 months and are now being included in the Lite version. See the full changelog below for a complete list of changes.
366
- - **New Feature!** A new watered-down Regular Expression syntax is now supported in several existing ZenCache features, including XML Sitemap Patterns, URI Exclusion Patterns, HTTP Referrer Exclusion Patterns, and User-Agent Exclusion Patterns. (It is also supported in the Pro-only Custom URLs to Auto-Clear, and the HTML Compressor CSS Exclusion Patterns and JavaScript Exclusion Patterns.) This new syntax greatly increases the power and flexibility of each of these features and makes things possible like the much-requested ability to Auto-Clear the Home Page or Posts Page of a site whenever a post cache is cleared. For more information on this new watered-down Regular Expression syntax, [this KB Article](http://zencache.com/r/watered-down-regex-syntax/). Props @kristineds @jaswsinc. See [Issue #191](https://github.com/websharks/zencache/issues/191).
367
- - **Bug Fix**: Fixed a bug with clearing cache files for paginated pages where the `pagination_base` had been changed from the default `page` to something else (e.g., a translated string). The WP Rewrite API is now used to include `pagination_base` and `comments_pagination_base` when building paths to cache files to determine which cache files should be cleared. Props @renzms. See [Issue #607](https://github.com/websharks/zencache/issues/607).
368
- - **Bug Fix**: This release attempts to resolve reports of Error 500 and Internal Server Error issues when running with PHP 5.6 + OPcache. Instead of clearing the entire Opcode cache whenever the plugin options are saved, we only invalidate the `advanced-cache.php` file, which is rebuilt each time you update your configuration options. Props @jaswsinc. Also props to @MarioKnight and @CotswoldPhoto for helping us narrow this down. See [Issue #624](https://github.com/websharks/zencache/issues/624).
369
- - **Bug Fix**: Fixed an issue where a PHP Notice was generated when an inactive WordPress component was being upgraded. This issue did not have any adverse affect on the site, but this fix resolves the issue so that the notice won't appear in PHP logs. See [Issue #589](https://github.com/websharks/zencache/issues/589).
370
- - **Bug Fix**: Fixed a bug where a commented-out `WP_CACHE` definition in `wp-config.php` (such as what WP Super Cache leaves behind) was being incorrectly ignored and resulted in caching being silently disabled. Props @davidfavor. See [Issue #591](https://github.com/websharks/zencache/issues/591).
371
- - **Bug Fix**: Fixed a bug where in some scenarios a page might not be cached due to a stray `AUTH_COOKIE` or `SECURE_AUTH_COOKIE` cookie, even when the user is not logged in. Props @jaswsinc @renzms. See [Issue #592](https://github.com/websharks/zencache/issues/592).
372
- - **Bug Fix**: Fixed an issue related to a popular NGINX server configuration (`try_files $uri $uri/ /index.php?q=$uri&$args;`) that was preventing the entire site from being cached. ZenCache disables caching by default for all requests that include a query string (see _Dashboard → ZenCache → Plugin Options → GET Requests_) and this particular NGINX configuration passes _all_ requests to WordPress with a `?q=` query variable, which was resulting in ZenCache disabling caching on all pages. This release implements better detection for NGINX and works around this scenario. Props @jaswsinc. See [Issue #561](https://github.com/websharks/zencache/issues/561).
373
- - **Bug Fix**: Fixed a bug where, in some rare cases, `wp-config.php` would end up with two `WP_CACHE` definitions. Props @jaswsinc. See [Issue #509](https://github.com/websharks/zencache/issues/509).
374
- - **Bug Fix**: Saving a Post as a Draft was incorrectly purging XML Sitemap cache files. Props @jaswsinc. See [Issue #368](https://github.com/websharks/zencache/issues/368).
375
- - **Bug Fix**: Fixed a bug in the Dynamic Version Salt filter that was generating PHP notices and warnings. See [Issue #522](https://github.com/websharks/zencache/issues/522).
376
- - **Bug Fix**: Fixed an issue with backwards compatibility that was preventing some AC Plugins from working properly. See [Issue #514](https://github.com/websharks/zencache/issues/514).
377
- - **Bug Fix**: Fixed a bug where saving a Post/Page as a Draft as a user with an Editor role would unnecessarily clear the Home Page cache. See [Issue #625](https://github.com/websharks/zencache/issues/625).
378
- - **Multisite Bug Fix**: Fixed a bug where the Clear Cache button wouldn't clear Child-Site Logged-In User Home Page cache files on WordPress Multisite Networks. Props @jaswsinc. See [Issue #409](https://github.com/websharks/zencache/issues/409)
379
- - **Multisite Bug Fix**: Fixed a bug where the Home Page cache was not clearing on Child Sites in a Multisite Network. Props @jaswsinc. See [Issue #409](https://github.com/websharks/zencache/issues/409)
380
- - **Multisite Bug Fix**: Fixed a bug with 404 Request caching on Multisite Networks where ZenCache Pro was not considering that each child blog in a multisite network will have its own 404 error page. Props @jaswsinc. See [Issue #539](https://github.com/websharks/zencache/issues/539).
381
- - **Multisite Bug Fix**: Fixed a bug where clearing the cache from the main site of a multisite network, when there are child blogs in sub-directories, resulted in all child blogs being cleared from the cache, not just the main site as would be expected. This has been resolved and only the main site is cleared when clicking the Clear Cache button. Note that the Wipe Cache button can still be used to clear the cache for all sites in a Multisite Network. Props @jaswsinc. See [Issue #540](https://github.com/websharks/zencache/issues/540).
382
- - **Multisite Bug Fix**: Fixed a bug where Wiping the cache on a multisite network resulted in the very next page view being cached incorrectly. Props @jaswsinc. See [Issue #541](https://github.com/websharks/zencache/issues/541).
383
- - **Multisite Bug Fix**: Fixed a bug where when ZenCache was Network Activated the plugin settings link would show up in the plugins list for the Main Site and would lead to a 404 error. The settings link is now only shown when viewing the plugins list from the Network Admin. Props @jaswsinc. See [Issue #675](https://github.com/websharks/zencache/issues/675).
384
- - **Enhancement**: Added support-related links to the plugin options page. Props @renzms. See [Issue #612](https://github.com/websharks/zencache/issues/612#issuecomment-186827661).
385
- - **Enhancement**: It's now possible to override the ZenCache Nonce exclusion globally (dangerous) or only for Logged-In Users (safer). Please see [this article](http://zencache.com/r/kb-article-what-are-wordpress-nonces-and-why-are-they-not-cache-compatible/) for full details. [Issue #637](https://github.com/websharks/zencache/issues/637).
386
- - **Enhancement**: Improved WP Cron-related configuration and validation of custom cron schedules. See [PR #197](https://github.com/websharks/zencache-pro/pull/197).
387
- - **Enhancement**: ZenCache now clears the cache whenever a WordPress plugin is activated or deactivated. Many WordPress plugins change content on the front-end of the site, so this enhancement ensures that an old cache file is never served to visitors. If you want to disable this automatic behavior, see [this article](http://zencache.com/kb-article/how-do-i-prevent-zencache-from-clearing-the-cache-upon-plugin-activation-or-deactivation/). Props @renzms. See [Issue #424](https://github.com/websharks/zencache/issues/424).
388
- - **Enhancement**: When activating ZenCache for the first time, a new Dashboard message now includes a helpful link to the options page to enable caching and review the options. Props @kristineds. See [Issue #112](https://github.com/websharks/zencache/issues/112).
389
- - **Enhancement**: The automatic Cache Cleanup schedule that cleans up (deletes) expired/stale cache files has been changed from once every day to once every hour. Running the cleanup hourly makes ZenCache smarter when configured in certain ways and saves disk space. Props @kristineds. See [Issue #472](https://github.com/websharks/zencache/issues/472).
390
- - **Enhancement**: When the Cache Directory location is changed, ZenCache now cleans up the old Cache Directory and any old cache files instead of leaving them behind. Props @clavaque @renzms. See [Issue #580](https://github.com/websharks/zencache/issues/580).
391
- - **Enhancement**: Added a new API Function that allows a site owner to clear the cache for a specific URL via `zencache::clearUrl($url);`. See [this article](http://zencache.com/kb-article/clearing-the-cache-dynamically/#toc-988085ad) for further details. Props @kristineds. See [Issue #590](https://github.com/websharks/zencache/issues/590).
392
- - **Enhancement**: Improved the HTML Notes generated by ZenCache when s2Member (a membership plugin for WordPress) is specifically disabling caching. s2Member automatically disables caching on certain pages that are required to remain dynamic. The HTML Notes generated by ZenCache now explain when this is happening. Props @renzms. See [Issue #504](https://github.com/websharks/zencache/issues/504).
393
- - **Enhancement**: Manual Cache Clearing options have now been separated from Automatic Cache Clearing options inside the ZenCache Plugin Options to improve the differentiation between these.
394
- - **Enhancement**: New icons in the ZenCache Plugin Options help improve the visual representation of each panel.
395
- - **Enhancement**: The installed plugin version is now shown at the top of the ZenCache Options Page. Props @renzms. See [Issue #502](https://github.com/websharks/zencache/issues/502).
396
- - **Enhancement**: New transition in/out effects on the Cache Cleared Dashboard notifications. Props @jaswsinc. See [Issue #538](https://github.com/websharks/zencache/issues/538).
397
- - **Enhancement**: Improved compatibility with any Custom Post Type that uses hierarchies. Props @jaswsinc.
398
- - **Akismet Compatibility:** ZenCache no longer caches pages that contain `akismet_comment_nonce` in the markup. This ensures that a page that contains a time-sensitive `nonce` value does not get cached. Props @kristineds and @jaswsinc. See [Issue #601](https://github.com/websharks/zencache/issues/601).
399
- - **Akismet Compatibility:** ZenCache now automatically disables the Akismet Comment Nonce using [the `akismet_comment_nonce` filter](https://github.com/git-mirror/wordpress-akismet/blob/2.5.6/akismet.php#L333), which improves compatibility between Akismet and the page caching functionality provided by ZenCache. This ensures that pages do not contain time-sensitive `nonce` values that should not be cached. If you'd like to revert this behavior, please see [this article](http://zencache.com/kb-article/how-do-i-prevent-zencache-from-disabling-the-akismet-comment-nonce/). Props @kristineds and @jaswsinc. See [Issue #601](https://github.com/websharks/zencache/issues/601).
400
- - **Akismet Compatibility**: Fixed a bug with Akismet compatibility where ZenCache was not properly disabling the Akismet Comment Nonce, which resulted in pages being unnecessarily excluded from the cache due to the presence of the `akismet_comment_nonce` in the markup. Props @Kalfer. See [Issue #642](https://github.com/websharks/zencache/issues/642).
401
- - **WooCommerce Compatibility:** This release improves compatibility with the WooCommerce Product Stock feature. When the Product Stock changes, ZenCache will now clear the cache file for the associated Product to ensure that the stock quantity that appears on the site remains up-to-date. See [Issue #597](https://github.com/websharks/zencache/issues/597).
402
- - **Multisite Domain Mapping Compatibility**: ZenCache is now fully compatible with the [WordPress MU Domain Mapping plugin](https://wordpress.org/plugins/wordpress-mu-domain-mapping/), including Multisite Networks using domain mapping on top-level domains, sub-domains, and sub-directories. Multiple variations of each site spread across an unlimited number of domain mappings and/or the original blog domain/path is also supported. All Pro-only features, including the Auto-Cache Engine, Static CDN Filters, and HTML Compression, are also now compatible with domain mapping. Props @jaswsinc. See [Issue #339](https://github.com/websharks/zencache/issues/339).
403
- - **bbPress Compatibility**: This release greatly improves compatibility with bbPress. Events like creating a new Forum, creating a new Topic, and posting a reply to a Topic (including threaded replies), now properly clear the necessary cache files to ensure that cached bbPress pages remain up-to-date. Props @jaswsinc. See [Issue #168](https://github.com/websharks/zencache/issues/168).
404
- - **bbPress Compatibility:** This release improves compatibility with bbPress when ZenCache Logged-In User caching is enabled. In this scenario, bbPress may generate links for Admins that contain time-sensitive `_wpnonce` values which could expire if cached and result in certain admin-related actions failing. ZenCache no longer caches pages that contain `_wpnonce` in the markup. This ensures that pages containing time-sensitive `nonce` values are not cached. Props @kristineds, @jaswsinc, and @clavaque. See [Issue #601](https://github.com/websharks/zencache/issues/601).
405
- - **New Pro Features:** This release updates the Pro Preview to include several new Pro features that have been added over the past 6 months, including the ability to clear the PHP OPCache whenever manually clearing the cache (_ZenCache Options → Manual Cache Clearing → Clear the PHP OPCache Too?_), clear the CDN Cache whenever manually clearing the cache (_ZenCache Options → Manual Cache Clearing → CDN Cache Clear the CDN Cache Too?_), disable cache expiration if the server load average is high (_ZenCache Options → Cache Expiration Time → Disable Cache Expiration If Server Load Average is High_), the ability to specify which WordPress Roles/Capabilities are allowed to clear the cache from the WordPress Admin bar (_ZenCache Options → Manual Cache Clearing → Also allow others to clear the cache from their Admin Bar?_), a completely new Cache Statistics feature that allows you to monitor the health and status of your cache (_ZenCache → Stats / Charts_), the ability to specify a list of Custom URLs whose cache files should be cleared whenever ZenCache detects that a Post/Page cache should be cleared (_ZenCache Options → Automatic Cache Clearing → Misc. Auto-Clear Options → Auto-Clear a List of Custom URLs Too?_), a new menu of Clear Cache options in the Admin Bar that allows you to clear the cache for just the Home Page, the Current URL, a Specific URL, PHP's OPCache, or the CDN Cache (_ZenCache Options → Plugin Options → Manual Cache Clearing_), the ability to customize the Cache Cleanup Schedule and set your own schedule (_ZenCache Options → Manual Cache Clearing → Cache Cleanup Schedule_), the ability to configure the Pro Plugin Updater to check for Beta versions, an option to clear Expired WordPress Transients, and URI Exclusion Patterns for Client-Side Caching.
406
-
407
- = v160211.2 =
408
-
409
- - **Minor Fix**: Remove unnecessary `src/client-s/css/.sass-cache` directory.
410
-
411
- = v160211 =
412
-
413
- **Announcing Comet Cache, formerly ZenCache!**
414
-
415
- We are very excited to announce the release of [Comet Cache](http://cometcache.com), an advanced WordPress caching plugin inspired by simplicity. Comet Cache is the successor to ZenCache (and Quick Cache before that), a very popular WordPress caching plugin that has been downloaded over 1 million times and has won acclaim for its speed, simplicity, and ease of configuration. [Read the full announcement here](https://cometcache.com/r/announcing-comet-cache-formerly-zencache/).
416
-
417
- For older Changelog entries, please see the `CHANGELOG.md` file.
1
  === Comet Cache ===
2
 
3
+ Stable tag: 160416
4
+ Requires at least: 4.2
5
+ Tested up to: 4.6-alpha
6
  Text Domain: comet-cache
7
 
8
  License: GPLv2 or later
330
 
331
  == Upgrade Notice ==
332
 
333
+ = v160416 =
334
 
335
+ Requires WordPress v4.2+.
336
 
337
  == Changelog ==
338
 
339
+ = v160416 =
340
+
341
+ - **Enhancement**: Several PHP 5.4+ enhancements, most notably a conversion from PHP Closures to PHP Traits. See [Issue #635](https://github.com/websharks/comet-cache/issues/635).
342
+ - **Enhancement**: Dashboard notices generated by Comet Cache now use the WordPress-style dismiss button to keep things consistent. See [Issue #719](https://github.com/websharks/comet-cache/issues/719).
343
+ - **Enhancement**: Dashboard notices generated by Comet Cache are now compacted into a single notice that can be expanded to view details. This helps reduce the number of messages that appear when, for example, a Post is published or updated and several cache files are automatically cleared. Instead of showing a separate notice for each type of cache file that was cleared, a single notice is shown with a link to toggle the details. See [Issue #118](https://github.com/websharks/comet-cache/issues/118).
344
+ - **Enhancement** (Pro): Improved the way the Auto-Cache Engine figures out the URL scheme (`http` vs `https`) that should be used when fetching the XML Sitemap. Instead of forcing `http`, whatever scheme is configured with the Home URL is now used. See [Issue #715](https://github.com/websharks/comet-cache/issues/715).
345
+ - **Enhancement** (Pro): The Pro Plugin Updater page now includes a "Save All Changes" button at the bottom, allowing you to save changes to the updater configuration without actually running the plugin updater. Props @bridgeport @NoahjChampion @1wdtv. See [Issue #681](https://github.com/websharks/comet-cache/issues/681).
346
+ - **Bug Fix**: Fixed a duplicated row of links on the Pro Plugin Updater page. See [Issue #696](https://github.com/websharks/comet-cache/issues/696).
347
+ - **Bug Fix**: Fixed an issue where some browsers would report "Failed to parse SourceMap" errors in their console when browsing the Comet Cache Options page. This was related to `sourceMappingURL` comments in the minified JS/CSS files that were intended for development purposes. Props to @1wdtv for reporting. See [#732](https://github.com/websharks/comet-cache/issues/732).
348
+ - **Bug Fix**: Fixed a UI bug in the Pro Preview that was causing the Manual Cache Clearing panel to not appear as part of the Pro Preview. Props @renzms. See [Issue #711](https://github.com/websharks/comet-cache/issues/711).
349
+ - **Bug Fix** (Pro): Fixed a bug related to the Pro Updater where some users who had migrated from ZenCache Pro to Comet Cache Pro were seeing an invalid new version message. Props @renzms @jaswsinc. See [Issue #727](https://github.com/websharks/comet-cache/issues/727)
350
+ - **Bug Fix** (Pro): Fixed a bug with the Pro Plugin Updater that resulted in "Unknown error. Please wait 15 minutes and try again." when attempting to update Comet Cache Pro. The issue affected sites on servers running an old version of cURL (< v7.36) and/or an old version of OpenSSL, which made them unable to connect to the Comet Cache Pro update server. The Pro Plugin Updater now attempts to connect to a secondary update server that is more compatible with older versions of cURL and OpenSSL. See [Issue #678](https://github.com/websharks/comet-cache/issues/678).
351
+ - **Hooks/Filters**: Comet Cache now hooks into `plugins_loaded` instead of `after_setup_theme` when calling its own setup routine. This improves integration with other plugins that may be expecting the Comet Cache API functions to be available after `plugins_loaded`. Props to Frank Goossens (@futtta) from Autoptimize for helping with this. See [Issue #716](https://github.com/websharks/comet-cache/issues/716).
352
+ - **Compatibility**: Fixed a compatibility issue for some themes and plugins that were using old AC Plugin code designed to work with Quick Cache. This fix adds some backwards compatibility support for Quick Cache, but note that the first release of Comet Cache dropped support for Quick Cache backwards compatibility in favor of ZenCache backwards compatibility. See [Issue #710](https://github.com/websharks/comet-cache/issues/710).
353
+ - **Compatibility: Query Monitor.** The Query Monitor plugin was reporting false-positive errors indicating that many Comet Cache methods did not exist. This was due to how the Comet Cache codebase was utilizing PHP Closures, which Query Monitor had a hard time handling. The codebase has been refactored to use PHP Traits instead of Closures and now the Query Monitor plugin has no problem recognizing Comet Cache methods. Props to @NoahjChampion for reporting. See [Issue #686](https://github.com/websharks/comet-cache/issues/686).
354
+ - **Compatibility: WP-CLI.** When installing Comet Cache via WP-CLI, Comet Cache is now automatically enabled. There's no need to manually enable Comet Cache from within the plugin options after installing. Props @jaswsinc. See [Issue #464](https://github.com/websharks/comet-cache/issues/464).
355
+ - **Required WordPress Version is now v4.2.** The minimum required WordPress version has been bumped from v4.1 to v4.2. See [Issue #706](https://github.com/websharks/comet-cache/issues/706).
356
+
357
  = v160227 =
358
 
359
  - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing calls to `$GLOBALS['zencache']` from working properly with Comet Cache. See [Issue #689](https://github.com/websharks/comet-cache/issues/689)
374
  - **Bug Fix (Multisite)**: Fixed a bug where when Comet Cache was Network Activated the plugin settings link would show up in the plugins list for the Main Site and would lead to a 404 error. The settings link is now only shown when viewing the plugins list from the Network Admin. Props @jaswsinc. See [Issue #675](https://github.com/websharks/zencache/issues/675).
375
  - **Enhancement**: Added support-related links to the plugin options page. Props @renzms. See [Issue #612](https://github.com/websharks/zencache/issues/612#issuecomment-186827661).
376
 
377
+ For older Changelog entries going back to 2009, please see the `CHANGELOG.md` file.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/client-s/css/admin-bar.min.css CHANGED
@@ -1,2 +1,2 @@
1
  
2
- /*# sourceMappingURL=admin-bar.min.css.map */
1
  
2
+
src/client-s/css/menu-pages.min.css CHANGED
@@ -1,2 +1,2 @@
1
  @font-face{font-family:sharkicons;src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?v160221");src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.ttf?v160221") format("truetype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.woff?v160221") format("woff"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}.plugin-menu-page-animation-spin{-webkit-animation-duration:0.75s;-moz-animation-duration:0.75s;animation-duration:0.75s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-timing-function:linear;-moz-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:plugin-menu-page-animation-spin;-moz-animation-name:plugin-menu-page-animation-spin;animation-name:plugin-menu-page-animation-spin}@-webkit-keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes plugin-menu-page-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(360deg)}}@keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}html{overflow-y:scroll}#wpwrap{position:relative}#wpwrap::after{top:0;right:0;bottom:0;left:0;z-index:-1;position:absolute;content:'';opacity:0.25;background:url("../images/bg.png")}#wpwrap .updated,#wpwrap .error{margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page{min-width:800px;margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page,.plugin-menu-page p{font-size:14px}.plugin-menu-page a{color:#033A63}.plugin-menu-page a:hover,.plugin-menu-page a:active{color:#467629}.plugin-menu-page p:first-child,.plugin-menu-page pre:first-child{margin-top:0}.plugin-menu-page p:last-child,.plugin-menu-page pre:last-child{margin-bottom:0}.plugin-menu-page code{border-radius:3px;padding:0.1em 0.25em;background:rgba(178,178,178,0.25);font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page pre.code{padding:0;background:none}.plugin-menu-page pre.code>code{font-size:90%;overflow-x:auto;max-width:100%;border-radius:4px;padding:1em;display:block;color:#eee;background:#222;box-shadow:0 0 5px 1px #000 inset}.plugin-menu-page img{border:0}.plugin-menu-page img.screenshot{float:right;border-radius:4px;padding:0.5em;margin:0 0 2em 2em;background:#fff;border:1px solid #afafaf;box-shadow:0 0 5px 0 rgba(0,0,0,0.2) inset}.plugin-menu-page hr{border:0;padding:0;height:1px;margin:1em 0;background:linear-gradient(to left, transparent, rgba(0,0,0,0.75), transparent)}.plugin-menu-page label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plugin-menu-page label.switch-primary{font-size:130%;margin:0;padding:0.5em;border-radius:4px;display:inline;color:#000;background:#f1e982;border:1px solid rgba(0,0,0,0.07);box-shadow:-1px -1px 0 0 rgba(0,0,0,0.25) inset,1px 1px 0 0 #fff inset}.plugin-menu-page select,.plugin-menu-page textarea,.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{width:100%;line-height:1.3em;margin:0;padding:0.25em 0.5em;border-radius:4px;box-sizing:border-box;color:#333;background:#e8e8e8;border:1px solid #848484;box-shadow:0 0 2px 0 rgba(132,132,132,0.5) inset}.plugin-menu-page select,.plugin-menu-page select:focus{box-shadow:0 1px 0 0 #fff inset,0 -2px 3px 0 rgba(132,132,132,0.25) inset}.plugin-menu-page select,.plugin-menu-page select:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{height:2em}.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{color:#000;background:#e2e2e2}.plugin-menu-page input[disabled],.plugin-menu-page select[disabled],.plugin-menu-page textarea[disabled]{opacity:0.5}.plugin-menu-page input::-webkit-input-placeholder,.plugin-menu-page textarea::-webkit-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input::-moz-placeholder,.plugin-menu-page textarea::-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-moz-placeholder,.plugin-menu-page textarea:-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-ms-input-placeholder,.plugin-menu-page textarea:-ms-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page table{margin:1em 0}.plugin-menu-page button{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:150%;font-weight:bold;line-height:1em;outline:none;cursor:pointer;border-radius:4px;margin:0;padding:0.25em 0.5em;box-sizing:border-box;color:#fff;background:#033A63;border:1px solid rgba(0,0,0,0.5);box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),-1px -1px 0 0 rgba(0,0,0,0.2) inset,1px 1px 0 0 rgba(255,255,255,0.1) inset}.plugin-menu-page button:hover{background:#467629}.plugin-menu-page button[type='submit']{background:#467629}.plugin-menu-page button[type='submit']:hover{background:#033A63}.plugin-menu-page button:active{-webkit-transform:scale(0.98, 0.98);-moz-transform:scale(0.98, 0.98);-ms-transform:scale(0.98, 0.98);-o-transform:scale(0.98, 0.98);transform:scale(0.98, 0.98)}.plugin-menu-page .info,.plugin-menu-page .notice,.plugin-menu-page .warning,.plugin-menu-page .error{border-radius:4px;padding:0.5em;margin:1em 0}.plugin-menu-page .info{background:#cadfed;border:1px solid #216095}.plugin-menu-page .notice{background:#fffde8;border:1px solid #e6db55}.plugin-menu-page .warning{background:#ffefd3;border:1px solid #e6db55}.plugin-menu-page .error{background:pink;border:1px solid #711e1e}.plugin-menu-page .monospace{font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page textarea.monospace{white-space:pre}.plugin-menu-page .clearfix::before,.plugin-menu-page .clearfix::after{display:table;content:' '}.plugin-menu-page .clearfix::after{clear:both}.plugin-menu-page-heading .plugin-menu-page-restore-defaults,.plugin-menu-page-heading .plugin-menu-page-panel-togglers{float:right;margin:0 1em 0 0}.plugin-menu-page-heading .plugin-menu-page-panel-togglers button{background:#033A63 !important}.plugin-menu-page-heading .plugin-menu-page-upsells{float:right;clear:right;text-align:right;max-width:350px;margin:1em 0 0}.plugin-menu-page-heading .plugin-menu-page-upsells a{text-decoration:none;line-height:1.5em;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-support-links,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}.plugin-menu-page-heading .plugin-menu-page-support-links a,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links a{text-decoration:none;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-version{float:right;clear:right;min-width:350px;margin:0.5em 0 0 0;text-align:right}.plugin-menu-page-body{position:relative}.plugin-menu-page-section-heading{margin:1em 0}.plugin-menu-page-section-heading>small{font-size:65%;font-style:italic;margin:0;display:block;opacity:0.5}.plugin-menu-page-panel{margin:1em 0}.plugin-menu-page-panel:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-heading{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;padding:10px;font-size:150%;line-height:1.125em;font-weight:bold;border-radius:4px;display:block;cursor:pointer;background:#033A63;background:linear-gradient(to right, #033A63, #20669A);color:#eee !important;box-shadow:0 2px 2px 0 rgba(0,0,0,0.25)}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none;content:""}.plugin-menu-page-panel .plugin-menu-page-panel-heading:hover,.plugin-menu-page-panel .plugin-menu-page-panel-heading.open{color:#fff !important}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font-size:80%;float:right;margin:0 0 0 5px}.plugin-menu-page-panel .plugin-menu-page-panel-heading.open::after{content:""}.plugin-menu-page-panel-heading.pro-preview-feature{background:#216095}.pro-preview-feature::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'pro version only' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel-heading.pro-preview-additional-features{background:#216095}.pro-preview-additional-features::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'additional pro version only features' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel .plugin-menu-page-panel-heading>.si{text-align:center;width:1.28571429em;margin-right:.25em}.plugin-menu-page-panel .plugin-menu-page-panel-body{width:99%;margin:0 auto;display:none;padding:1.2em;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-sizing:border-box;color:#222;border:1px solid #848484;background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),0 3px 1px -1px rgba(0,0,0,0.25) inset}.plugin-menu-page-panel .plugin-menu-page-panel-body.open{display:block}.plugin-menu-page-panel .plugin-menu-page-panel-body p{font-size:90%;color:#666}.plugin-menu-page-panel .plugin-menu-page-panel-body p.notice,.plugin-menu-page-panel .plugin-menu-page-panel-body p.info,.plugin-menu-page-panel .plugin-menu-page-panel-body p.warning,.plugin-menu-page-panel .plugin-menu-page-panel-body p.error{color:#000}.plugin-menu-page-panel .plugin-menu-page-panel-body h3{margin:0 0 0.5em}.plugin-menu-page-panel .plugin-menu-page-panel-body h3:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body h3+p{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body a.dotted{text-decoration:none;border-bottom:1px dotted}.plugin-menu-page-panel .plugin-menu-page-panel-body.pro-preview,.plugin-menu-page-panel .plugin-menu-page-panel-body .pro-preview{opacity:0.5}.plugin-menu-page-save{margin-top:2em}.plugin-menu-page-save button{line-height:1.3em;width:100%}
2
- /*# sourceMappingURL=menu-pages.min.css.map */
1
  @font-face{font-family:sharkicons;src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?v160221");src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.ttf?v160221") format("truetype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.woff?v160221") format("woff"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}.plugin-menu-page-animation-spin{-webkit-animation-duration:0.75s;-moz-animation-duration:0.75s;animation-duration:0.75s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-timing-function:linear;-moz-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:plugin-menu-page-animation-spin;-moz-animation-name:plugin-menu-page-animation-spin;animation-name:plugin-menu-page-animation-spin}@-webkit-keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes plugin-menu-page-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(360deg)}}@keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}html{overflow-y:scroll}#wpwrap{position:relative}#wpwrap::after{top:0;right:0;bottom:0;left:0;z-index:-1;position:absolute;content:'';opacity:0.25;background:url("../images/bg.png")}#wpwrap .updated,#wpwrap .error{margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page{min-width:800px;margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page,.plugin-menu-page p{font-size:14px}.plugin-menu-page a{color:#033A63}.plugin-menu-page a:hover,.plugin-menu-page a:active{color:#467629}.plugin-menu-page p:first-child,.plugin-menu-page pre:first-child{margin-top:0}.plugin-menu-page p:last-child,.plugin-menu-page pre:last-child{margin-bottom:0}.plugin-menu-page code{border-radius:3px;padding:0.1em 0.25em;background:rgba(178,178,178,0.25);font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page pre.code{padding:0;background:none}.plugin-menu-page pre.code>code{font-size:90%;overflow-x:auto;max-width:100%;border-radius:4px;padding:1em;display:block;color:#eee;background:#222;box-shadow:0 0 5px 1px #000 inset}.plugin-menu-page img{border:0}.plugin-menu-page img.screenshot{float:right;border-radius:4px;padding:0.5em;margin:0 0 2em 2em;background:#fff;border:1px solid #afafaf;box-shadow:0 0 5px 0 rgba(0,0,0,0.2) inset}.plugin-menu-page hr{border:0;padding:0;height:1px;margin:1em 0;background:linear-gradient(to left, transparent, rgba(0,0,0,0.75), transparent)}.plugin-menu-page label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plugin-menu-page label.switch-primary{font-size:130%;margin:0;padding:0.5em;border-radius:4px;display:inline;color:#000;background:#f1e982;border:1px solid rgba(0,0,0,0.07);box-shadow:-1px -1px 0 0 rgba(0,0,0,0.25) inset,1px 1px 0 0 #fff inset}.plugin-menu-page select,.plugin-menu-page textarea,.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{width:100%;line-height:1.3em;margin:0;padding:0.25em 0.5em;border-radius:4px;box-sizing:border-box;color:#333;background:#e8e8e8;border:1px solid #848484;box-shadow:0 0 2px 0 rgba(132,132,132,0.5) inset}.plugin-menu-page select,.plugin-menu-page select:focus{box-shadow:0 1px 0 0 #fff inset,0 -2px 3px 0 rgba(132,132,132,0.25) inset}.plugin-menu-page select,.plugin-menu-page select:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{height:2em}.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{color:#000;background:#e2e2e2}.plugin-menu-page input[disabled],.plugin-menu-page select[disabled],.plugin-menu-page textarea[disabled]{opacity:0.5}.plugin-menu-page input::-webkit-input-placeholder,.plugin-menu-page textarea::-webkit-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input::-moz-placeholder,.plugin-menu-page textarea::-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-moz-placeholder,.plugin-menu-page textarea:-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-ms-input-placeholder,.plugin-menu-page textarea:-ms-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page table{margin:1em 0}.plugin-menu-page button{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:150%;font-weight:bold;line-height:1em;outline:none;cursor:pointer;border-radius:4px;margin:0;padding:0.25em 0.5em;box-sizing:border-box;color:#fff;background:#033A63;border:1px solid rgba(0,0,0,0.5);box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),-1px -1px 0 0 rgba(0,0,0,0.2) inset,1px 1px 0 0 rgba(255,255,255,0.1) inset}.plugin-menu-page button:hover{background:#467629}.plugin-menu-page button[type='submit']{background:#467629}.plugin-menu-page button[type='submit']:hover{background:#033A63}.plugin-menu-page button:active{-webkit-transform:scale(0.98, 0.98);-moz-transform:scale(0.98, 0.98);-ms-transform:scale(0.98, 0.98);-o-transform:scale(0.98, 0.98);transform:scale(0.98, 0.98)}.plugin-menu-page .info,.plugin-menu-page .notice,.plugin-menu-page .warning,.plugin-menu-page .error{border-radius:4px;padding:0.5em;margin:1em 0}.plugin-menu-page .info{background:#cadfed;border:1px solid #216095}.plugin-menu-page .notice{background:#fffde8;border:1px solid #e6db55}.plugin-menu-page .warning{background:#ffefd3;border:1px solid #e6db55}.plugin-menu-page .error{background:pink;border:1px solid #711e1e}.plugin-menu-page .monospace{font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page textarea.monospace{white-space:pre}.plugin-menu-page .clearfix::before,.plugin-menu-page .clearfix::after{display:table;content:' '}.plugin-menu-page .clearfix::after{clear:both}.plugin-menu-page-heading .plugin-menu-page-restore-defaults,.plugin-menu-page-heading .plugin-menu-page-panel-togglers{float:right;margin:0 1em 0 0}.plugin-menu-page-heading .plugin-menu-page-panel-togglers button{background:#033A63 !important}.plugin-menu-page-heading .plugin-menu-page-upsells{float:right;clear:right;text-align:right;max-width:350px;margin:1em 0 0}.plugin-menu-page-heading .plugin-menu-page-upsells a{text-decoration:none;line-height:1.5em;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-support-links,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}.plugin-menu-page-heading .plugin-menu-page-support-links a,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links a{text-decoration:none;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-version{float:right;clear:right;min-width:350px;margin:0.5em 0 0 0;text-align:right}.plugin-menu-page-body{position:relative}.plugin-menu-page-section-heading{margin:1em 0}.plugin-menu-page-section-heading>small{font-size:65%;font-style:italic;margin:0;display:block;opacity:0.5}.plugin-menu-page-panel{margin:1em 0}.plugin-menu-page-panel:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-heading{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;padding:10px;font-size:150%;line-height:1.125em;font-weight:bold;border-radius:4px;display:block;cursor:pointer;background:#033A63;background:linear-gradient(to right, #033A63, #20669A);color:#eee !important;box-shadow:0 2px 2px 0 rgba(0,0,0,0.25)}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none;content:""}.plugin-menu-page-panel .plugin-menu-page-panel-heading:hover,.plugin-menu-page-panel .plugin-menu-page-panel-heading.open{color:#fff !important}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font-size:80%;float:right;margin:0 0 0 5px}.plugin-menu-page-panel .plugin-menu-page-panel-heading.open::after{content:""}.plugin-menu-page-panel-heading.pro-preview-feature{background:#216095}.pro-preview-feature::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'pro version only' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel-heading.pro-preview-additional-features{background:#216095}.pro-preview-additional-features::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'additional pro version only features' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel .plugin-menu-page-panel-heading>.si{text-align:center;width:1.28571429em;margin-right:.25em}.plugin-menu-page-panel .plugin-menu-page-panel-body{width:99%;margin:0 auto;display:none;padding:1.2em;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-sizing:border-box;color:#222;border:1px solid #848484;background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),0 3px 1px -1px rgba(0,0,0,0.25) inset}.plugin-menu-page-panel .plugin-menu-page-panel-body.open{display:block}.plugin-menu-page-panel .plugin-menu-page-panel-body p{font-size:90%;color:#666}.plugin-menu-page-panel .plugin-menu-page-panel-body p.notice,.plugin-menu-page-panel .plugin-menu-page-panel-body p.info,.plugin-menu-page-panel .plugin-menu-page-panel-body p.warning,.plugin-menu-page-panel .plugin-menu-page-panel-body p.error{color:#000}.plugin-menu-page-panel .plugin-menu-page-panel-body h3{margin:0 0 0.5em}.plugin-menu-page-panel .plugin-menu-page-panel-body h3:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body h3+p{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body a.dotted{text-decoration:none;border-bottom:1px dotted}.plugin-menu-page-panel .plugin-menu-page-panel-body.pro-preview,.plugin-menu-page-panel .plugin-menu-page-panel-body .pro-preview{opacity:0.5}.plugin-menu-page-save{margin-top:2em}.plugin-menu-page-save button{line-height:1.3em;width:100%}
2
+
src/includes/api.php CHANGED
@@ -6,11 +6,13 @@
6
  */
7
  namespace WebSharks\CometCache;
8
 
 
 
9
  if (!defined('WPINC')) {
10
  exit('Do NOT access this file directly: '.basename(__FILE__));
11
  }
12
- class_alias(__NAMESPACE__.'\\ApiBase', GLOBAL_NS);
13
 
14
  if (!class_exists('zencache')) {
15
- class_alias(__NAMESPACE__.'\\ApiBase', 'zencache');
16
  }
6
  */
7
  namespace WebSharks\CometCache;
8
 
9
+ use WebSharks\CometCache\Classes;
10
+
11
  if (!defined('WPINC')) {
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
14
+ class_alias(__NAMESPACE__.'\\Classes\\ApiBase', GLOBAL_NS);
15
 
16
  if (!class_exists('zencache')) {
17
+ class_alias(__NAMESPACE__.'\\Classes\\ApiBase', 'zencache');
18
  }
src/includes/classes/AbsBase.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Abstract Base.
@@ -20,21 +20,21 @@ abstract class AbsBase
20
  *
21
  * @since 150422 Rewrite.
22
  */
23
- protected $cache = array();
24
 
25
  /**
26
  * @type array Global static cache ref.
27
  *
28
  * @since 150422 Rewrite.
29
  */
30
- protected $static = array();
31
 
32
  /**
33
  * @type array Global static cache.
34
  *
35
  * @since 150422 Rewrite.
36
  */
37
- protected static $global_static = array();
38
 
39
  /**
40
  * @type \stdClass Overload properties.
@@ -55,7 +55,7 @@ abstract class AbsBase
55
  $class = get_called_class();
56
 
57
  if (empty(static::$global_static[$class])) {
58
- static::$global_static[$class] = array();
59
  }
60
  $this->static = &static::$global_static[$class];
61
 
@@ -76,7 +76,8 @@ abstract class AbsBase
76
  if (isset($instance)) {
77
  return $instance;
78
  }
79
- return ($instance = new static());
 
80
  }
81
 
82
  /**
@@ -167,7 +168,7 @@ abstract class AbsBase
167
  * @note This function returns by reference. The use of `&` is highly recommended when calling this utility.
168
  * See also: <http://php.net/manual/en/language.references.return.php>
169
  */
170
- public function &cacheKey($function, $args = array(), $___prop = 'cache')
171
  {
172
  $function = (string) $function;
173
  $args = (array) $args;
@@ -210,6 +211,7 @@ abstract class AbsBase
210
  }
211
  $cache_key = &$cache_key[$_key];
212
  }
 
213
  return $cache_key;
214
  }
215
 
@@ -224,7 +226,7 @@ abstract class AbsBase
224
  * @note This function returns by reference. The use of `&` is highly recommended when calling this utility.
225
  * See also: <http://php.net/manual/en/language.references.return.php>
226
  */
227
- public function &staticKey($function, $args = array())
228
  {
229
  $key = &$this->cacheKey($function, $args, 'static');
230
 
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Abstract Base.
20
  *
21
  * @since 150422 Rewrite.
22
  */
23
+ protected $cache = [];
24
 
25
  /**
26
  * @type array Global static cache ref.
27
  *
28
  * @since 150422 Rewrite.
29
  */
30
+ protected $static = [];
31
 
32
  /**
33
  * @type array Global static cache.
34
  *
35
  * @since 150422 Rewrite.
36
  */
37
+ protected static $global_static = [];
38
 
39
  /**
40
  * @type \stdClass Overload properties.
55
  $class = get_called_class();
56
 
57
  if (empty(static::$global_static[$class])) {
58
+ static::$global_static[$class] = [];
59
  }
60
  $this->static = &static::$global_static[$class];
61
 
76
  if (isset($instance)) {
77
  return $instance;
78
  }
79
+
80
+ return $instance = new static();
81
  }
82
 
83
  /**
168
  * @note This function returns by reference. The use of `&` is highly recommended when calling this utility.
169
  * See also: <http://php.net/manual/en/language.references.return.php>
170
  */
171
+ public function &cacheKey($function, $args = [], $___prop = 'cache')
172
  {
173
  $function = (string) $function;
174
  $args = (array) $args;
211
  }
212
  $cache_key = &$cache_key[$_key];
213
  }
214
+
215
  return $cache_key;
216
  }
217
 
226
  * @note This function returns by reference. The use of `&` is highly recommended when calling this utility.
227
  * See also: <http://php.net/manual/en/language.references.return.php>
228
  */
229
+ public function &staticKey($function, $args = [])
230
  {
231
  $key = &$this->cacheKey($function, $args, 'static');
232
 
src/includes/classes/AbsBaseAp.php CHANGED
@@ -1,13 +1,39 @@
1
  <?php
2
- namespace WebSharks\CometCache;
 
 
 
3
 
4
  /**
5
  * Abstract Base for Advanced Cache and Plugin.
6
  *
7
  * @since 150422 Rewrite.
8
  */
9
- abstract class AbsBaseAp extends AbsBase
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * Class constructor.
13
  *
@@ -16,16 +42,6 @@ abstract class AbsBaseAp extends AbsBase
16
  public function __construct()
17
  {
18
  parent::__construct();
19
-
20
- $closures_dir = dirname(dirname(__FILE__)).'/closures/Shared';
21
- $self = $this; // Reference for closures.
22
-
23
- foreach (scandir($closures_dir) as $_closure) {
24
- if (substr($_closure, -4) === '.php') {
25
- require $closures_dir.'/'.$_closure;
26
- }
27
- }
28
- unset($_closure); // Housekeeping.
29
  }
30
 
31
  /**
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
+
4
+ use WebSharks\CometCache\Traits;
5
+ use WebSharks\CometCache\Interfaces;
6
 
7
  /**
8
  * Abstract Base for Advanced Cache and Plugin.
9
  *
10
  * @since 150422 Rewrite.
11
  */
12
+ abstract class AbsBaseAp extends AbsBase implements Interfaces\Shared\NcDebugConsts, Interfaces\Shared\CachePathConsts
13
  {
14
+ /*[.build.php-auto-generate-use-Traits]*/
15
+ use Traits\Shared\BlogUtils;
16
+ use Traits\Shared\CacheDirUtils;
17
+ use Traits\Shared\CacheLockUtils;
18
+ use Traits\Shared\CachePathUtils;
19
+ use Traits\Shared\ConditionalUtils;
20
+ use Traits\Shared\DomainMappingUtils;
21
+ use Traits\Shared\EscapeUtils;
22
+ use Traits\Shared\FsUtils;
23
+ use Traits\Shared\HookUtils;
24
+ use Traits\Shared\HttpUtils;
25
+ use Traits\Shared\I18nUtils;
26
+ use Traits\Shared\IpAddrUtils;
27
+ use Traits\Shared\PatternUtils;
28
+ use Traits\Shared\ReplaceUtils;
29
+ use Traits\Shared\ServerUtils;
30
+ use Traits\Shared\StringUtils;
31
+ use Traits\Shared\SysUtils;
32
+ use Traits\Shared\TokenUtils;
33
+ use Traits\Shared\TrimUtils;
34
+ use Traits\Shared\UrlUtils;
35
+ /*[/.build.php-auto-generate-use-Traits]*/
36
+
37
  /**
38
  * Class constructor.
39
  *
42
  public function __construct()
43
  {
44
  parent::__construct();
 
 
 
 
 
 
 
 
 
 
45
  }
46
 
47
  /**
src/includes/classes/Actions.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Actions.
@@ -13,7 +13,7 @@ class Actions extends AbsBase
13
  *
14
  * @since 150422 Rewrite.
15
  */
16
- protected $allowed_actions = array(
17
  'wipeCache',
18
  'clearCache',
19
 
@@ -37,7 +37,7 @@ class Actions extends AbsBase
37
 
38
 
39
  'dismissNotice',
40
- );
41
 
42
  /**
43
  * Class constructor.
@@ -81,7 +81,7 @@ class Actions extends AbsBase
81
 
82
 
83
  $redirect_to = self_admin_url('/admin.php');
84
- $query_args = array('page' => GLOBAL_NS, GLOBAL_NS.'_cache_wiped' => '1');
85
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
86
 
87
  wp_redirect($redirect_to).exit();
@@ -107,7 +107,7 @@ class Actions extends AbsBase
107
 
108
 
109
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
110
- $query_args = array('page' => GLOBAL_NS, GLOBAL_NS.'_cache_cleared' => '1');
111
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
112
 
113
  wp_redirect($redirect_to).exit();
@@ -167,7 +167,7 @@ class Actions extends AbsBase
167
  delete_transient(GLOBAL_NS.'-'.md5($this->plugin->options['auto_cache_sitemap_url']));
168
 
169
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
170
- $query_args = array('page' => GLOBAL_NS, GLOBAL_NS.'_updated' => '1');
171
 
172
  $this->plugin->autoWipeCache(); // May produce a notice.
173
 
@@ -232,7 +232,7 @@ class Actions extends AbsBase
232
  $this->plugin->restoreDefaultOptions(); // Restore defaults.
233
 
234
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
235
- $query_args = array('page' => GLOBAL_NS, GLOBAL_NS.'_restored' => '1');
236
 
237
  $this->plugin->autoWipeCache(); // May produce a notice.
238
 
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Actions.
13
  *
14
  * @since 150422 Rewrite.
15
  */
16
+ protected $allowed_actions = [
17
  'wipeCache',
18
  'clearCache',
19
 
37
 
38
 
39
  'dismissNotice',
40
+ ];
41
 
42
  /**
43
  * Class constructor.
81
 
82
 
83
  $redirect_to = self_admin_url('/admin.php');
84
+ $query_args = ['page' => GLOBAL_NS, GLOBAL_NS.'_cache_wiped' => '1'];
85
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
86
 
87
  wp_redirect($redirect_to).exit();
107
 
108
 
109
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
110
+ $query_args = ['page' => GLOBAL_NS, GLOBAL_NS.'_cache_cleared' => '1'];
111
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
112
 
113
  wp_redirect($redirect_to).exit();
167
  delete_transient(GLOBAL_NS.'-'.md5($this->plugin->options['auto_cache_sitemap_url']));
168
 
169
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
170
+ $query_args = ['page' => GLOBAL_NS, GLOBAL_NS.'_updated' => '1'];
171
 
172
  $this->plugin->autoWipeCache(); // May produce a notice.
173
 
232
  $this->plugin->restoreDefaultOptions(); // Restore defaults.
233
 
234
  $redirect_to = self_admin_url('/admin.php'); // Redirect preparations.
235
+ $query_args = ['page' => GLOBAL_NS, GLOBAL_NS.'_restored' => '1'];
236
 
237
  $this->plugin->autoWipeCache(); // May produce a notice.
238
 
src/includes/classes/AdvCacheBackCompat.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * AC back compat.
@@ -15,11 +15,11 @@ class AdvCacheBackCompat
15
  */
16
  public static function zcRequestVars()
17
  {
18
- $super_gs = array(
19
  '_GET' => &$_GET,
20
  '_REQUEST' => &$_REQUEST,
21
- );
22
- $zc_suffixes = array('AC', 'ABC');
23
 
24
  foreach ($super_gs as $_super_g_key => &$_super_g_value) {
25
  foreach ($zc_suffixes as $_zc_suffix) {
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * AC back compat.
15
  */
16
  public static function zcRequestVars()
17
  {
18
+ $super_gs = [
19
  '_GET' => &$_GET,
20
  '_REQUEST' => &$_REQUEST,
21
+ ];
22
+ $zc_suffixes = ['AC', 'ABC'];
23
 
24
  foreach ($super_gs as $_super_g_key => &$_super_g_value) {
25
  foreach ($zc_suffixes as $_zc_suffix) {
src/includes/classes/AdvancedCache.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
- namespace WebSharks\CometCache;
 
 
3
 
4
  /**
5
  * Advanced cache.
@@ -8,6 +10,16 @@ namespace WebSharks\CometCache;
8
  */
9
  class AdvancedCache extends AbsBaseAp
10
  {
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * Flagged as `TRUE` if running.
13
  *
@@ -35,16 +47,6 @@ class AdvancedCache extends AbsBaseAp
35
  {
36
  parent::__construct();
37
 
38
- $closures_dir = dirname(dirname(__FILE__)).'/closures/Ac';
39
- $self = $this; // Reference for closures.
40
-
41
- foreach (scandir($closures_dir) as $_closure) {
42
- if (substr($_closure, -4) === '.php') {
43
- require $closures_dir.'/'.$_closure;
44
- }
45
- }
46
- unset($_closure); // Housekeeping.
47
-
48
  if (!defined('WP_CACHE') || !WP_CACHE || !COMET_CACHE_ENABLE) {
49
  return; // Not enabled.
50
  }
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
+
4
+ use WebSharks\CometCache\Traits;
5
 
6
  /**
7
  * Advanced cache.
10
  */
11
  class AdvancedCache extends AbsBaseAp
12
  {
13
+ /*[.build.php-auto-generate-use-Traits]*/
14
+ use Traits\Ac\AbortUtils;
15
+ use Traits\Ac\AcPluginUtils;
16
+ use Traits\Ac\BrowserUtils;
17
+ use Traits\Ac\NcDebugUtils;
18
+ use Traits\Ac\ObUtils;
19
+ use Traits\Ac\PostloadUtils;
20
+ use Traits\Ac\ShutdownUtils;
21
+ /*[/.build.php-auto-generate-use-Traits]*/
22
+
23
  /**
24
  * Flagged as `TRUE` if running.
25
  *
47
  {
48
  parent::__construct();
49
 
 
 
 
 
 
 
 
 
 
 
50
  if (!defined('WP_CACHE') || !WP_CACHE || !COMET_CACHE_ENABLE) {
51
  return; // Not enabled.
52
  }
src/includes/classes/ApiBase.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * API Base Class.
@@ -100,6 +100,7 @@ class ApiBase
100
  public static function clearUrl($url)
101
  {
102
  $regex = $GLOBALS[GLOBAL_NS]->buildCachePathRegexFromWcUrl($url);
 
103
  return $GLOBALS[GLOBAL_NS]->deleteFilesFromCacheDir($regex);
104
  }
105
 
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * API Base Class.
100
  public static function clearUrl($url)
101
  {
102
  $regex = $GLOBALS[GLOBAL_NS]->buildCachePathRegexFromWcUrl($url);
103
+
104
  return $GLOBALS[GLOBAL_NS]->deleteFilesFromCacheDir($regex);
105
  }
106
 
src/includes/classes/Conflicts.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Conflicts.
@@ -18,6 +18,7 @@ class Conflicts
18
  if (static::doCheck()) {
19
  static::maybeEnqueueNotice();
20
  }
 
21
  return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'];
22
  }
23
 
@@ -31,13 +32,13 @@ class Conflicts
31
  if (!empty($GLOBALS[GLOBAL_NS.'_conflicting_plugin'])) {
32
  return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'];
33
  }
34
- $conflicting_plugin_slugs = array(
35
  'zencache', 'zencache-pro', 'quick-cache', 'quick-cache-pro',
36
  str_replace('_', '-', GLOBAL_NS).(IS_PRO ? '' : '-pro'),
37
  'wp-super-cache', 'w3-total-cache', 'hyper-cache', 'wp-rocket',
38
- );
39
- $active_plugins = (array) get_option('active_plugins', array());
40
- $active_sitewide_plugins = is_multisite() ? array_keys((array) get_site_option('active_sitewide_plugins', array())) : array();
41
  $active_plugins = array_unique(array_merge($active_plugins, $active_sitewide_plugins));
42
 
43
  foreach ($active_plugins as $_active_plugin_basename) {
@@ -45,16 +46,17 @@ class Conflicts
45
  continue; // Nothing to check in this case.
46
  }
47
  if (in_array($_active_plugin_slug, $conflicting_plugin_slugs, true)) {
48
- if (empty($GLOBALS[GLOBAL_NS.'_uninstalling']) && is_admin() && in_array($_active_plugin_slug, array('comet-cache', 'comet-cache-pro', 'zencache', 'zencache-pro', 'quick-cache', 'quick-cache-pro'), true)) {
49
  add_action('admin_init', function () use ($_active_plugin_basename) {
50
  deactivate_plugins($_active_plugin_basename, true);
51
- }, -1000);
52
  } else {
53
- return ($GLOBALS[GLOBAL_NS.'_conflicting_plugin'] = $_active_plugin_slug);
54
  }
55
  }
56
  }
57
- return ($GLOBALS[GLOBAL_NS.'_conflicting_plugin'] = ''); // i.e. No conflicting plugins.
 
58
  }
59
 
60
  /**
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Conflicts.
18
  if (static::doCheck()) {
19
  static::maybeEnqueueNotice();
20
  }
21
+
22
  return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'];
23
  }
24
 
32
  if (!empty($GLOBALS[GLOBAL_NS.'_conflicting_plugin'])) {
33
  return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'];
34
  }
35
+ $conflicting_plugin_slugs = [
36
  'zencache', 'zencache-pro', 'quick-cache', 'quick-cache-pro',
37
  str_replace('_', '-', GLOBAL_NS).(IS_PRO ? '' : '-pro'),
38
  'wp-super-cache', 'w3-total-cache', 'hyper-cache', 'wp-rocket',
39
+ ];
40
+ $active_plugins = (array) get_option('active_plugins', []);
41
+ $active_sitewide_plugins = is_multisite() ? array_keys((array) get_site_option('active_sitewide_plugins', [])) : [];
42
  $active_plugins = array_unique(array_merge($active_plugins, $active_sitewide_plugins));
43
 
44
  foreach ($active_plugins as $_active_plugin_basename) {
46
  continue; // Nothing to check in this case.
47
  }
48
  if (in_array($_active_plugin_slug, $conflicting_plugin_slugs, true)) {
49
+ if (empty($GLOBALS[GLOBAL_NS.'_uninstalling']) && is_admin() && in_array($_active_plugin_slug, ['comet-cache', 'comet-cache-pro', 'zencache', 'zencache-pro', 'quick-cache', 'quick-cache-pro'], true)) {
50
  add_action('admin_init', function () use ($_active_plugin_basename) {
51
  deactivate_plugins($_active_plugin_basename, true);
52
+ }, -1000);
53
  } else {
54
+ return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'] = $_active_plugin_slug;
55
  }
56
  }
57
  }
58
+
59
+ return $GLOBALS[GLOBAL_NS.'_conflicting_plugin'] = ''; // i.e. No conflicting plugins.
60
  }
61
 
62
  /**
src/includes/classes/FeedUtils.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Feed Utils.
@@ -48,7 +48,7 @@ class FeedUtils extends AbsBase
48
  $this->home_url = rtrim(home_url(), '/');
49
  $this->default_feed = get_default_feed(); // Default feed type.
50
  $this->seo_friendly_permalinks = (boolean) get_option('permalink_structure');
51
- $this->feed_types = array_unique(array($this->default_feed, 'rdf', 'rss', 'rss2', 'atom'));
52
  }
53
 
54
  /**
@@ -62,7 +62,7 @@ class FeedUtils extends AbsBase
62
  */
63
  public function feedLinkVariations($type_prefix = '')
64
  {
65
- $variations = array(); // Initialize.
66
 
67
  foreach ($this->feed_types as $_feed_type) {
68
  $variations[] = get_feed_link((string) $type_prefix.$_feed_type);
@@ -83,7 +83,7 @@ class FeedUtils extends AbsBase
83
  */
84
  public function postCommentsFeedLinkVariations(\WP_Post $post)
85
  {
86
- $variations = array(); // Initialize.
87
 
88
  foreach ($this->feed_types as $_feed_type) {
89
  $variations[] = get_post_comments_feed_link($post->ID, $_feed_type);
@@ -104,15 +104,15 @@ class FeedUtils extends AbsBase
104
  */
105
  public function postAuthorFeedLinkVariations(\WP_Post $post)
106
  {
107
- $variations = array(); // Initialize.
108
 
109
  foreach ($this->feed_types as $_feed_type) {
110
  $variations[] = get_author_feed_link($post->post_author, $_feed_type);
111
  }
112
  if ($this->seo_friendly_permalinks && ($post_author = get_userdata($post->post_author))) {
113
  foreach ($this->feed_types as $_feed_type) {
114
- $variations[] = add_query_arg(urlencode_deep(array('author' => $post->post_author)), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
115
- $variations[] = add_query_arg(urlencode_deep(array('author' => $post_author->user_nicename)), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
116
  }
117
  }
118
  unset($_feed_type); // Housekeeping.
@@ -131,7 +131,7 @@ class FeedUtils extends AbsBase
131
  */
132
  public function postTypeArchiveFeedLinkVariations(\WP_Post $post)
133
  {
134
- $variations = array(); // Initialize.
135
 
136
  foreach ($this->feed_types as $_feed_type) {
137
  $variations[] = get_post_type_archive_feed_link($post->post_type, $_feed_type);
@@ -158,7 +158,7 @@ class FeedUtils extends AbsBase
158
  */
159
  public function postTermFeedLinkVariations(\WP_Post $post, $include_regex_wildcard_keys = false)
160
  {
161
- $variations = $post_terms = array(); // Initialize.
162
 
163
  if (!is_array($post_taxonomies = get_object_taxonomies($post, 'objects')) || !$post_taxonomies) {
164
  return $variations; // Nothing to do here; post has no terms.
@@ -202,10 +202,10 @@ class FeedUtils extends AbsBase
202
  $_taxonomy_query_var = $_taxonomy->query_var;
203
  }
204
  foreach ($this->feed_types as $_feed_type) {
205
- $variations[] = add_query_arg(urlencode_deep(array($_taxonomy_query_var => $_post_term->term_id)), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
206
  }
207
  foreach ($this->feed_types as $_feed_type) {
208
- $variations[] = add_query_arg(urlencode_deep(array($_taxonomy_query_var => $_post_term->slug)), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
209
  }
210
  }
211
  unset($_taxonomy, $_taxonomy_query_var, $_feed_type); // Housekeeping.
@@ -226,11 +226,11 @@ class FeedUtils extends AbsBase
226
  */
227
  public function convertVariationsToHostCachePathRegexFrags(array $variations)
228
  {
229
- $regex_frags = array();
230
  $is_multisite = is_multisite();
231
  $can_consider_domain_mapping = $is_multisite && $this->plugin->canConsiderDomainMapping();
232
- $flags = CACHE_PATH_NO_SCHEME | CACHE_PATH_NO_HOST // Default flags.
233
- | CACHE_PATH_NO_USER | CACHE_PATH_NO_VSALT | CACHE_PATH_NO_EXT;
234
  // Flags: note that we DO allow for query string data in these regex fragments.
235
 
236
  foreach ($variations as $_key => $_url) {
@@ -252,7 +252,7 @@ class FeedUtils extends AbsBase
252
 
253
  if (is_string($_key) && strpos($_key, '::') !== false && strpos($_url, '*') !== false) {
254
  list($_feed_type, $_wildcard_regex) = explode('::', $_key, 2); // This regex replaces wildcards.
255
- $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags | CACHE_PATH_ALLOW_WILDCARDS);
256
  $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
257
  $_relative_cache_path_regex = preg_replace('/\\\\\*/', $_wildcard_regex, preg_quote($_relative_cache_path, '/'));
258
  } else {
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Feed Utils.
48
  $this->home_url = rtrim(home_url(), '/');
49
  $this->default_feed = get_default_feed(); // Default feed type.
50
  $this->seo_friendly_permalinks = (boolean) get_option('permalink_structure');
51
+ $this->feed_types = array_unique([$this->default_feed, 'rdf', 'rss', 'rss2', 'atom']);
52
  }
53
 
54
  /**
62
  */
63
  public function feedLinkVariations($type_prefix = '')
64
  {
65
+ $variations = []; // Initialize.
66
 
67
  foreach ($this->feed_types as $_feed_type) {
68
  $variations[] = get_feed_link((string) $type_prefix.$_feed_type);
83
  */
84
  public function postCommentsFeedLinkVariations(\WP_Post $post)
85
  {
86
+ $variations = []; // Initialize.
87
 
88
  foreach ($this->feed_types as $_feed_type) {
89
  $variations[] = get_post_comments_feed_link($post->ID, $_feed_type);
104
  */
105
  public function postAuthorFeedLinkVariations(\WP_Post $post)
106
  {
107
+ $variations = []; // Initialize.
108
 
109
  foreach ($this->feed_types as $_feed_type) {
110
  $variations[] = get_author_feed_link($post->post_author, $_feed_type);
111
  }
112
  if ($this->seo_friendly_permalinks && ($post_author = get_userdata($post->post_author))) {
113
  foreach ($this->feed_types as $_feed_type) {
114
+ $variations[] = add_query_arg(urlencode_deep(['author' => $post->post_author]), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
115
+ $variations[] = add_query_arg(urlencode_deep(['author' => $post_author->user_nicename]), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
116
  }
117
  }
118
  unset($_feed_type); // Housekeeping.
131
  */
132
  public function postTypeArchiveFeedLinkVariations(\WP_Post $post)
133
  {
134
+ $variations = []; // Initialize.
135
 
136
  foreach ($this->feed_types as $_feed_type) {
137
  $variations[] = get_post_type_archive_feed_link($post->post_type, $_feed_type);
158
  */
159
  public function postTermFeedLinkVariations(\WP_Post $post, $include_regex_wildcard_keys = false)
160
  {
161
+ $variations = $post_terms = []; // Initialize.
162
 
163
  if (!is_array($post_taxonomies = get_object_taxonomies($post, 'objects')) || !$post_taxonomies) {
164
  return $variations; // Nothing to do here; post has no terms.
202
  $_taxonomy_query_var = $_taxonomy->query_var;
203
  }
204
  foreach ($this->feed_types as $_feed_type) {
205
+ $variations[] = add_query_arg(urlencode_deep([$_taxonomy_query_var => $_post_term->term_id]), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
206
  }
207
  foreach ($this->feed_types as $_feed_type) {
208
+ $variations[] = add_query_arg(urlencode_deep([$_taxonomy_query_var => $_post_term->slug]), $this->home_url.'/feed/'.urlencode($_feed_type).'/');
209
  }
210
  }
211
  unset($_taxonomy, $_taxonomy_query_var, $_feed_type); // Housekeeping.
226
  */
227
  public function convertVariationsToHostCachePathRegexFrags(array $variations)
228
  {
229
+ $regex_frags = [];
230
  $is_multisite = is_multisite();
231
  $can_consider_domain_mapping = $is_multisite && $this->plugin->canConsiderDomainMapping();
232
+ $flags = $this::CACHE_PATH_NO_SCHEME | $this::CACHE_PATH_NO_HOST // Default flags.
233
+ | $this::CACHE_PATH_NO_USER | $this::CACHE_PATH_NO_VSALT | $this::CACHE_PATH_NO_EXT;
234
  // Flags: note that we DO allow for query string data in these regex fragments.
235
 
236
  foreach ($variations as $_key => $_url) {
252
 
253
  if (is_string($_key) && strpos($_key, '::') !== false && strpos($_url, '*') !== false) {
254
  list($_feed_type, $_wildcard_regex) = explode('::', $_key, 2); // This regex replaces wildcards.
255
+ $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags | $this::CACHE_PATH_ALLOW_WILDCARDS);
256
  $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
257
  $_relative_cache_path_regex = preg_replace('/\\\\\*/', $_wildcard_regex, preg_quote($_relative_cache_path, '/'));
258
  } else {
src/includes/classes/MenuPage.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
- namespace WebSharks\CometCache;
 
 
3
 
4
  /**
5
  * Menu Page.
@@ -22,7 +24,7 @@ class MenuPage extends AbsBase
22
  if ($menu_page) {
23
  switch ($menu_page) {
24
  case 'options':
25
- new MenuPageOptions();
26
  break;
27
 
28
 
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
+
4
+ use WebSharks\CometCache\Classes;
5
 
6
  /**
7
  * Menu Page.
24
  if ($menu_page) {
25
  switch ($menu_page) {
26
  case 'options':
27
+ new Classes\MenuPageOptions();
28
  break;
29
 
30
 
src/includes/classes/MenuPageOptions.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Options Page.
@@ -20,7 +20,7 @@ class MenuPageOptions extends MenuPage
20
  global $is_nginx; // WP global for web server checks below.
21
 
22
  echo '<form id="plugin-menu-page" class="plugin-menu-page" method="post" enctype="multipart/form-data"'.
23
- ' action="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce())), self_admin_url('/admin.php'))).'">'."\n";
24
 
25
  /* ----------------------------------------------------------------------------------------- */
26
 
@@ -28,16 +28,16 @@ class MenuPageOptions extends MenuPage
28
 
29
  if (is_multisite()) {
30
  echo '<button type="button" class="plugin-menu-page-wipe-cache" style="float:right; margin-left:15px;" title="'.esc_attr(__('Wipe Cache (Start Fresh); clears the cache for all sites in this network at once!', 'comet-cache')).'"'.
31
- ' data-action="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => array('wipeCache' => '1'))), self_admin_url('/admin.php'))).'">'.
32
  ' '.__('Wipe', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/wipe.png')).'" style="width:16px; height:16px;" /></button>'."\n";
33
  }
34
  echo ' <button type="button" class="plugin-menu-page-clear-cache" style="float:right;" title="'.esc_attr(__('Clear Cache (Start Fresh)', 'comet-cache').((is_multisite()) ? __('; affects the current site only.', 'comet-cache') : '')).'"'.
35
- ' data-action="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => array('clearCache' => '1'))), self_admin_url('/admin.php'))).'">'.
36
  ' '.__('Clear', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px;" /></button>'."\n";
37
 
38
  echo ' <button type="button" class="plugin-menu-page-restore-defaults"'.// Restores default options.
39
  ' data-confirmation="'.esc_attr(__('Restore default plugin options? You will lose all of your current settings! Are you absolutely sure about this?', 'comet-cache')).'"'.
40
- ' data-action="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => array('restoreDefaultOptions' => '1'))), self_admin_url('/admin.php'))).'">'.
41
  ' '.__('Restore', 'comet-cache').' <i class="si si-ambulance"></i></button>'."\n";
42
 
43
  echo ' <div class="plugin-menu-page-panel-togglers" title="'.esc_attr(__('All Panels', 'comet-cache')).'">'."\n";
@@ -47,12 +47,12 @@ class MenuPageOptions extends MenuPage
47
 
48
  echo ' <div class="plugin-menu-page-upsells">'."\n";
49
  if (IS_PRO && current_user_can($this->plugin->update_cap)) {
50
- echo '<a href="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS.'-pro-updater')), self_admin_url('/admin.php'))).'"><i class="si si-magic"></i> '.__('Pro Updater', 'comet-cache').'</a>'."\n";
51
  echo '<a href="'.esc_attr('http://cometcache.com/r/comet-cache-subscribe/').'" target="_blank"><i class="si si-envelope"></i> '.__('Newsletter', 'comet-cache').'</a>'."\n";
52
  echo '<a href="'.esc_attr('http://cometcache.com/r/comet-cache-beta-testers-list/').'" target="_blank"><i class="si si-envelope"></i> '.__('Beta Testers', 'comet-cache').'</a>'."\n";
53
  }
54
  if (!IS_PRO) {
55
- echo ' <a href="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, GLOBAL_NS.'_pro_preview' => '1')), self_admin_url('/admin.php'))).'"><i class="si si-eye"></i> '.__('Preview Pro Features', 'comet-cache').'</a>'."\n";
56
  echo ' <a href="'.esc_attr('http://cometcache.com/prices/').'" target="_blank"><i class="si si-heart-o"></i> '.__('Pro Upgrade', 'comet-cache').'</a>'."\n";
57
  }
58
  echo ' </div>'."\n";
@@ -80,7 +80,7 @@ class MenuPageOptions extends MenuPage
80
  echo ' '.sprintf(__('%1$s&trade; Pro v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
81
 
82
  if ($this->plugin->options['latest_pro_version'] && version_compare(VERSION, $this->plugin->options['latest_pro_version'], '<')) {
83
- echo '(<a href="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS.'-pro-updater')), self_admin_url('/admin.php'))).'" style="font-weight:bold;">'.__('update available', 'comet-cache').'</a>)'."\n";
84
  } else {
85
  echo '(<a href="'.esc_attr('https://cometcache.com/changelog/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
86
  }
@@ -173,7 +173,7 @@ class MenuPageOptions extends MenuPage
173
  }
174
  if (!IS_PRO && $this->plugin->isProPreview()) {
175
  echo '<div class="plugin-menu-page-notice info">'."\n";
176
- echo '<a href="'.add_query_arg(urlencode_deep(array('page' => GLOBAL_NS)), self_admin_url('/admin.php')).'" class="pull-right" style="margin:0 0 15px 25px; float:right; font-variant:small-caps; text-decoration:none;">'.__('close', 'comet-cache').' <i class="si si-eye-slash"></i></a>'."\n";
177
  echo ' <i class="si si-eye"></i> '.sprintf(__('<strong>Pro Features (Preview)</strong> ~ New option panels below. Please explore before <a href="http://cometcache.com/prices/" target="_blank">upgrading <i class="si si-heart-o"></i></a>.<br /><small>NOTE: the free version of %1$s (this lite version) is more-than-adequate for most sites. Please upgrade only if you desire advanced features or would like to support the developer.</small>', 'comet-cache'), esc_html(NAME))."\n";
178
  echo '</div>'."\n";
179
  }
@@ -251,9 +251,9 @@ class MenuPageOptions extends MenuPage
251
  /* --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
252
 
253
  if (IS_PRO || $this->plugin->isProPreview()) {
254
- echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
255
 
256
- echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
257
  echo ' <i class="si si-broom"></i> '.__('Manual Cache Clearing', 'comet-cache')."\n";
258
  echo ' </a>'."\n";
259
 
@@ -891,7 +891,7 @@ class MenuPageOptions extends MenuPage
891
  echo ' <p>'.__('You don\'t have to use an <code>.htaccess</code> file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an <code>.htaccess</code> file to accomplish that part.', 'comet-cache').'</p>'."\n";
892
  echo ' <p>'.sprintf(__('%1$s fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your <code>php.ini</code> file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
893
  echo ' <p>'.__('If you want to enable GZIP, create an <code>.htaccess</code> file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an <code>.htaccess</code> file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: <a href="https://developers.google.com/speed/articles/gzip" target="_blank"><i class="si si-youtube-play"></i> video about GZIP Compression</a>.', 'comet-cache').'</p>'."\n";
894
- echo ' <pre class="code"><code>'.esc_html(file_get_contents(dirname(dirname(__FILE__)).'/templates/gzip-htaccess.txt')).'</code></pre>'."\n";
895
  echo ' <hr />'."\n";
896
  echo ' <p class="info" style="display:block;"><strong>Or</strong>, if your server is missing <code>mod_deflate</code>/<code>mod_filter</code>; open your <strong>php.ini</strong> file and add this line: <a href="http://php.net/manual/en/zlib.configuration.php" target="_blank" style="text-decoration:none;"><code>zlib.output_compression = on</code></a></p>'."\n";
897
  echo ' </div>'."\n";
@@ -1062,7 +1062,7 @@ class MenuPageOptions extends MenuPage
1062
  echo ' <hr />'."\n";
1063
  echo ' <h3>'.sprintf(__('Export Existing Options from this %1$s Installation?', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1064
  echo ' <button type="button" class="plugin-menu-page-export-options" style="float:right; margin: 0 0 0 25px;"'.// Exports existing options from this installation.
1065
- ' data-action="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => array('exportOptions' => '1'))), self_admin_url('/admin.php'))).'">'.
1066
  ' '.sprintf(__('%1$s-options.json', 'comet-cache'), GLOBAL_NS).' <i class="si si-arrow-circle-o-down"></i></button>'."\n";
1067
  echo ' <p>'.sprintf(__('Download your existing options and import them all into another %1$s installation; saves time on future installs.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1068
  echo ' </div>'."\n";
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Options Page.
20
  global $is_nginx; // WP global for web server checks below.
21
 
22
  echo '<form id="plugin-menu-page" class="plugin-menu-page" method="post" enctype="multipart/form-data"'.
23
+ ' action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n";
24
 
25
  /* ----------------------------------------------------------------------------------------- */
26
 
28
 
29
  if (is_multisite()) {
30
  echo '<button type="button" class="plugin-menu-page-wipe-cache" style="float:right; margin-left:15px;" title="'.esc_attr(__('Wipe Cache (Start Fresh); clears the cache for all sites in this network at once!', 'comet-cache')).'"'.
31
+ ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['wipeCache' => '1']]), self_admin_url('/admin.php'))).'">'.
32
  ' '.__('Wipe', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/wipe.png')).'" style="width:16px; height:16px;" /></button>'."\n";
33
  }
34
  echo ' <button type="button" class="plugin-menu-page-clear-cache" style="float:right;" title="'.esc_attr(__('Clear Cache (Start Fresh)', 'comet-cache').((is_multisite()) ? __('; affects the current site only.', 'comet-cache') : '')).'"'.
35
+ ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['clearCache' => '1']]), self_admin_url('/admin.php'))).'">'.
36
  ' '.__('Clear', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px;" /></button>'."\n";
37
 
38
  echo ' <button type="button" class="plugin-menu-page-restore-defaults"'.// Restores default options.
39
  ' data-confirmation="'.esc_attr(__('Restore default plugin options? You will lose all of your current settings! Are you absolutely sure about this?', 'comet-cache')).'"'.
40
+ ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['restoreDefaultOptions' => '1']]), self_admin_url('/admin.php'))).'">'.
41
  ' '.__('Restore', 'comet-cache').' <i class="si si-ambulance"></i></button>'."\n";
42
 
43
  echo ' <div class="plugin-menu-page-panel-togglers" title="'.esc_attr(__('All Panels', 'comet-cache')).'">'."\n";
47
 
48
  echo ' <div class="plugin-menu-page-upsells">'."\n";
49
  if (IS_PRO && current_user_can($this->plugin->update_cap)) {
50
+ echo '<a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS.'-pro-updater']), self_admin_url('/admin.php'))).'"><i class="si si-magic"></i> '.__('Pro Updater', 'comet-cache').'</a>'."\n";
51
  echo '<a href="'.esc_attr('http://cometcache.com/r/comet-cache-subscribe/').'" target="_blank"><i class="si si-envelope"></i> '.__('Newsletter', 'comet-cache').'</a>'."\n";
52
  echo '<a href="'.esc_attr('http://cometcache.com/r/comet-cache-beta-testers-list/').'" target="_blank"><i class="si si-envelope"></i> '.__('Beta Testers', 'comet-cache').'</a>'."\n";
53
  }
54
  if (!IS_PRO) {
55
+ echo ' <a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, GLOBAL_NS.'_pro_preview' => '1']), self_admin_url('/admin.php'))).'"><i class="si si-eye"></i> '.__('Preview Pro Features', 'comet-cache').'</a>'."\n";
56
  echo ' <a href="'.esc_attr('http://cometcache.com/prices/').'" target="_blank"><i class="si si-heart-o"></i> '.__('Pro Upgrade', 'comet-cache').'</a>'."\n";
57
  }
58
  echo ' </div>'."\n";
80
  echo ' '.sprintf(__('%1$s&trade; Pro v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
81
 
82
  if ($this->plugin->options['latest_pro_version'] && version_compare(VERSION, $this->plugin->options['latest_pro_version'], '<')) {
83
+ echo '(<a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS.'-pro-updater']), self_admin_url('/admin.php'))).'" style="font-weight:bold;">'.__('update available', 'comet-cache').'</a>)'."\n";
84
  } else {
85
  echo '(<a href="'.esc_attr('https://cometcache.com/changelog/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
86
  }
173
  }
174
  if (!IS_PRO && $this->plugin->isProPreview()) {
175
  echo '<div class="plugin-menu-page-notice info">'."\n";
176
+ echo '<a href="'.add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), self_admin_url('/admin.php')).'" class="pull-right" style="margin:0 0 15px 25px; float:right; font-variant:small-caps; text-decoration:none;">'.__('close', 'comet-cache').' <i class="si si-eye-slash"></i></a>'."\n";
177
  echo ' <i class="si si-eye"></i> '.sprintf(__('<strong>Pro Features (Preview)</strong> ~ New option panels below. Please explore before <a href="http://cometcache.com/prices/" target="_blank">upgrading <i class="si si-heart-o"></i></a>.<br /><small>NOTE: the free version of %1$s (this lite version) is more-than-adequate for most sites. Please upgrade only if you desire advanced features or would like to support the developer.</small>', 'comet-cache'), esc_html(NAME))."\n";
178
  echo '</div>'."\n";
179
  }
251
  /* --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
252
 
253
  if (IS_PRO || $this->plugin->isProPreview()) {
254
+ echo '<div class="plugin-menu-page-panel">'."\n";
255
 
256
+ echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
257
  echo ' <i class="si si-broom"></i> '.__('Manual Cache Clearing', 'comet-cache')."\n";
258
  echo ' </a>'."\n";
259
 
891
  echo ' <p>'.__('You don\'t have to use an <code>.htaccess</code> file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an <code>.htaccess</code> file to accomplish that part.', 'comet-cache').'</p>'."\n";
892
  echo ' <p>'.sprintf(__('%1$s fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your <code>php.ini</code> file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
893
  echo ' <p>'.__('If you want to enable GZIP, create an <code>.htaccess</code> file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an <code>.htaccess</code> file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: <a href="https://developers.google.com/speed/articles/gzip" target="_blank"><i class="si si-youtube-play"></i> video about GZIP Compression</a>.', 'comet-cache').'</p>'."\n";
894
+ echo ' <pre class="code"><code>'.esc_html(file_get_contents(dirname(__DIR__).'/templates/gzip-htaccess.txt')).'</code></pre>'."\n";
895
  echo ' <hr />'."\n";
896
  echo ' <p class="info" style="display:block;"><strong>Or</strong>, if your server is missing <code>mod_deflate</code>/<code>mod_filter</code>; open your <strong>php.ini</strong> file and add this line: <a href="http://php.net/manual/en/zlib.configuration.php" target="_blank" style="text-decoration:none;"><code>zlib.output_compression = on</code></a></p>'."\n";
897
  echo ' </div>'."\n";
1062
  echo ' <hr />'."\n";
1063
  echo ' <h3>'.sprintf(__('Export Existing Options from this %1$s Installation?', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1064
  echo ' <button type="button" class="plugin-menu-page-export-options" style="float:right; margin: 0 0 0 25px;"'.// Exports existing options from this installation.
1065
+ ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['exportOptions' => '1']]), self_admin_url('/admin.php'))).'">'.
1066
  ' '.sprintf(__('%1$s-options.json', 'comet-cache'), GLOBAL_NS).' <i class="si si-arrow-circle-o-down"></i></button>'."\n";
1067
  echo ' <p>'.sprintf(__('Download your existing options and import them all into another %1$s installation; saves time on future installs.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1068
  echo ' </div>'."\n";
src/includes/classes/Plugin.php CHANGED
@@ -1,5 +1,8 @@
1
  <?php
2
- namespace WebSharks\CometCache;
 
 
 
3
 
4
  /**
5
  * Comet Cache Plugin.
@@ -8,6 +11,40 @@ namespace WebSharks\CometCache;
8
  */
9
  class Plugin extends AbsBaseAp
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * Enable plugin hooks?
13
  *
@@ -24,7 +61,7 @@ class Plugin extends AbsBaseAp
24
  *
25
  * @type array Pro-only option keys.
26
  */
27
- public $pro_only_option_keys = array();
28
 
29
  /**
30
  * Default options.
@@ -33,7 +70,7 @@ class Plugin extends AbsBaseAp
33
  *
34
  * @type array Default options.
35
  */
36
- public $default_options = array();
37
 
38
  /**
39
  * Configured options.
@@ -42,7 +79,7 @@ class Plugin extends AbsBaseAp
42
  *
43
  * @type array Configured options.
44
  */
45
- public $options = array();
46
 
47
  /**
48
  * WordPress capability.
@@ -108,25 +145,15 @@ class Plugin extends AbsBaseAp
108
  {
109
  parent::__construct();
110
 
111
- $closures_dir = dirname(dirname(__FILE__)).'/closures/Plugin';
112
- $self = $this; // Reference for closures.
113
-
114
- foreach (scandir($closures_dir) as $_closure) {
115
- if (substr($_closure, -4) === '.php') {
116
- require $closures_dir.'/'.$_closure;
117
- }
118
- }
119
- unset($_closure); // Housekeeping.
120
  /* -------------------------------------------------------------- */
121
-
122
  if (!($this->enable_hooks = (boolean) $enable_hooks)) {
123
  return; // Stop here; construct without hooks.
124
  }
125
  /* -------------------------------------------------------------- */
126
 
127
- add_action('after_setup_theme', array($this, 'setup'));
128
- register_activation_hook(PLUGIN_FILE, array($this, 'activate'));
129
- register_deactivation_hook(PLUGIN_FILE, array($this, 'deactivate'));
130
  }
131
 
132
  /**
@@ -148,7 +175,7 @@ class Plugin extends AbsBaseAp
148
 
149
  load_plugin_textdomain(SLUG_TD); // Text domain.
150
 
151
- $this->pro_only_option_keys = array(
152
  'cache_max_age_disable_if_load_average_is_gte',
153
 
154
  'change_notifications_enable',
@@ -216,13 +243,12 @@ class Plugin extends AbsBaseAp
216
  'pro_update_username',
217
  'pro_update_password',
218
  'last_pro_stats_log',
219
- );
220
- $this->default_options = array(
221
  /* Core/systematic plugin options. */
222
 
223
- 'version' => VERSION,
224
- 'welcomed' => '0', // `0|1` welcomed yet?
225
- 'comet_cache_notice1_enqueued' => '0', // `0|1` announced Comet Cache yet?
226
 
227
  'crons_setup' => '0', // A timestamp when last set up.
228
  'crons_setup_on_namespace' => '', // The namespace on which they were set up.
@@ -382,7 +408,7 @@ class Plugin extends AbsBaseAp
382
  /* Related to uninstallation routines. */
383
 
384
  'uninstall_on_deletion' => '0', // `0|1`.
385
- );
386
  $this->default_options = $this->applyWpFilters(GLOBAL_NS.'_default_options', $this->default_options);
387
  $this->options = $this->getOptions(); // Filters, validates, and returns plugin options.
388
 
@@ -398,13 +424,13 @@ class Plugin extends AbsBaseAp
398
  }
399
  /* -------------------------------------------------------------- */
400
 
401
- add_action('init', array($this, 'checkAdvancedCache'));
402
- add_action('init', array($this, 'checkBlogPaths'));
403
- add_action('init', array($this, 'checkCronSetup'), PHP_INT_MAX);
404
- add_action('wp_loaded', array($this, 'actions'));
405
 
406
- add_action('admin_init', array($this, 'checkVersion'));
407
- add_action('admin_init', array($this, 'maybeCheckLatestLiteVersion'));
408
 
409
 
410
 
@@ -414,56 +440,56 @@ class Plugin extends AbsBaseAp
414
 
415
 
416
 
417
- add_action('admin_enqueue_scripts', array($this, 'enqueueAdminStyles'));
418
- add_action('admin_enqueue_scripts', array($this, 'enqueueAdminScripts'));
419
 
420
- add_action('admin_menu', array($this, 'addMenuPages'));
421
- add_action('network_admin_menu', array($this, 'addNetworkMenuPages'));
422
 
423
- add_action('all_admin_notices', array($this, 'allAdminNotices'));
424
 
425
- add_filter('plugin_action_links_'.plugin_basename(PLUGIN_FILE), array($this, 'addSettingsLink'));
426
 
427
- add_filter('enable_live_network_counts', array($this, 'updateBlogPaths'));
428
 
429
- add_action('activated_plugin', array($this, 'autoClearOnPluginActivationDeactivation'), 10, 2);
430
- add_action('deactivated_plugin', array($this, 'autoClearOnPluginActivationDeactivation'), 10, 2);
431
- add_action('admin_init', array($this, 'autoClearCacheOnSettingChanges'));
432
- add_action('safecss_save_pre', array($this, 'autoClearCacheOnJetpackCustomCss'), 10, 1);
433
- add_action('upgrader_process_complete', array($this, 'autoClearOnUpgraderProcessComplete'), 10, 2);
434
 
435
- add_action('switch_theme', array($this, 'autoClearCache'));
436
- add_action('wp_create_nav_menu', array($this, 'autoClearCache'));
437
- add_action('wp_update_nav_menu', array($this, 'autoClearCache'));
438
- add_action('wp_delete_nav_menu', array($this, 'autoClearCache'));
439
 
440
- add_action('save_post', array($this, 'autoClearPostCache'));
441
- add_action('delete_post', array($this, 'autoClearPostCache'));
442
- add_action('clean_post_cache', array($this, 'autoClearPostCache'));
443
- add_action('post_updated', array($this, 'autoClearAuthorPageCache'), 10, 3);
444
- add_action('pre_post_update', array($this, 'autoClearPostCacheTransition'), 10, 2);
445
- add_action('woocommerce_product_set_stock', array($this, 'autoClearPostCacheOnWooCommerceSetStock'), 10, 1);
446
 
447
- add_action('added_term_relationship', array($this, 'autoClearPostTermsCache'), 10, 1);
448
- add_action('delete_term_relationships', array($this, 'autoClearPostTermsCache'), 10, 1);
449
 
450
- add_action('trackback_post', array($this, 'autoClearCommentPostCache'));
451
- add_action('pingback_post', array($this, 'autoClearCommentPostCache'));
452
- add_action('comment_post', array($this, 'autoClearCommentPostCache'));
453
- add_action('transition_comment_status', array($this, 'autoClearCommentPostCacheTransition'), 10, 3);
454
 
455
- add_action('create_term', array($this, 'autoClearCache'));
456
- add_action('edit_terms', array($this, 'autoClearCache'));
457
- add_action('delete_term', array($this, 'autoClearCache'));
458
 
459
- add_action('add_link', array($this, 'autoClearCache'));
460
- add_action('edit_link', array($this, 'autoClearCache'));
461
- add_action('delete_link', array($this, 'autoClearCache'));
462
 
463
 
464
 
465
  if ($this->options['enable'] && $this->applyWpFilters(GLOBAL_NS.'_disable_akismet_comment_nonce', true)) {
466
- add_filter('akismet_comment_nonce', function() {
467
  return 'disabled-by-'.SLUG_TD; // MUST return a string literal that is not 'true' or '' (an empty string). See <http://bit.ly/1YItpdE>
468
  }); // See also why the Akismet nonce should be disabled: <http://jas.xyz/1R23f5c>
469
  }
@@ -476,8 +502,8 @@ class Plugin extends AbsBaseAp
476
  /* -------------------------------------------------------------- */
477
 
478
  if (!is_multisite() || is_main_site()) { // Main site only.
479
- add_filter('cron_schedules', array($this, 'extendCronSchedules'));
480
- add_action('_cron_'.GLOBAL_NS.'_cleanup', array($this, 'cleanupCache'));
481
 
482
 
483
  }
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+ use WebSharks\CometCache\Traits;
6
 
7
  /**
8
  * Comet Cache Plugin.
11
  */
12
  class Plugin extends AbsBaseAp
13
  {
14
+ /*[.build.php-auto-generate-use-Traits]*/
15
+ use Traits\Plugin\ActionUtils;
16
+ use Traits\Plugin\BbPressUtils;
17
+ use Traits\Plugin\CleanupUtils;
18
+ use Traits\Plugin\CondUtils;
19
+ use Traits\Plugin\CronUtils;
20
+ use Traits\Plugin\DbUtils;
21
+ use Traits\Plugin\DirUtils;
22
+ use Traits\Plugin\HtaccessUtils;
23
+ use Traits\Plugin\InstallUtils;
24
+ use Traits\Plugin\MenuPageUtils;
25
+ use Traits\Plugin\NoticeUtils;
26
+ use Traits\Plugin\OptionUtils;
27
+ use Traits\Plugin\PostUtils;
28
+ use Traits\Plugin\UpdateUtils;
29
+ use Traits\Plugin\UrlUtils;
30
+ use Traits\Plugin\UserUtils;
31
+ use Traits\Plugin\WcpAuthorUtils;
32
+ use Traits\Plugin\WcpCommentUtils;
33
+ use Traits\Plugin\WcpFeedUtils;
34
+ use Traits\Plugin\WcpHomeBlogUtils;
35
+ use Traits\Plugin\WcpJetpackUtils;
36
+ use Traits\Plugin\WcpOpcacheUtils;
37
+ use Traits\Plugin\WcpPluginUtils;
38
+ use Traits\Plugin\WcpPostTypeUtils;
39
+ use Traits\Plugin\WcpPostUtils;
40
+ use Traits\Plugin\WcpSettingUtils;
41
+ use Traits\Plugin\WcpSitemapUtils;
42
+ use Traits\Plugin\WcpTermUtils;
43
+ use Traits\Plugin\WcpUpdaterUtils;
44
+ use Traits\Plugin\WcpUtils;
45
+ use Traits\Plugin\WcpWooCommerceUtils;
46
+ /*[/.build.php-auto-generate-use-Traits]*/
47
+
48
  /**
49
  * Enable plugin hooks?
50
  *
61
  *
62
  * @type array Pro-only option keys.
63
  */
64
+ public $pro_only_option_keys = [];
65
 
66
  /**
67
  * Default options.
70
  *
71
  * @type array Default options.
72
  */
73
+ public $default_options = [];
74
 
75
  /**
76
  * Configured options.
79
  *
80
  * @type array Configured options.
81
  */
82
+ public $options = [];
83
 
84
  /**
85
  * WordPress capability.
145
  {
146
  parent::__construct();
147
 
 
 
 
 
 
 
 
 
 
148
  /* -------------------------------------------------------------- */
 
149
  if (!($this->enable_hooks = (boolean) $enable_hooks)) {
150
  return; // Stop here; construct without hooks.
151
  }
152
  /* -------------------------------------------------------------- */
153
 
154
+ add_action('plugins_loaded', [$this, 'setup']);
155
+ register_activation_hook(PLUGIN_FILE, [$this, 'activate']);
156
+ register_deactivation_hook(PLUGIN_FILE, [$this, 'deactivate']);
157
  }
158
 
159
  /**
175
 
176
  load_plugin_textdomain(SLUG_TD); // Text domain.
177
 
178
+ $this->pro_only_option_keys = [
179
  'cache_max_age_disable_if_load_average_is_gte',
180
 
181
  'change_notifications_enable',
243
  'pro_update_username',
244
  'pro_update_password',
245
  'last_pro_stats_log',
246
+ ];
247
+ $this->default_options = [
248
  /* Core/systematic plugin options. */
249
 
250
+ 'version' => VERSION,
251
+ 'welcomed' => '0', // `0|1` welcomed yet?
 
252
 
253
  'crons_setup' => '0', // A timestamp when last set up.
254
  'crons_setup_on_namespace' => '', // The namespace on which they were set up.
408
  /* Related to uninstallation routines. */
409
 
410
  'uninstall_on_deletion' => '0', // `0|1`.
411
+ ];
412
  $this->default_options = $this->applyWpFilters(GLOBAL_NS.'_default_options', $this->default_options);
413
  $this->options = $this->getOptions(); // Filters, validates, and returns plugin options.
414
 
424
  }
425
  /* -------------------------------------------------------------- */
426
 
427
+ add_action('init', [$this, 'checkAdvancedCache']);
428
+ add_action('init', [$this, 'checkBlogPaths']);
429
+ add_action('init', [$this, 'checkCronSetup'], PHP_INT_MAX);
430
+ add_action('wp_loaded', [$this, 'actions']);
431
 
432
+ add_action('admin_init', [$this, 'checkVersion']);
433
+ add_action('admin_init', [$this, 'maybeCheckLatestLiteVersion']);
434
 
435
 
436
 
440
 
441
 
442
 
443
+ add_action('admin_enqueue_scripts', [$this, 'enqueueAdminStyles']);
444
+ add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']);
445
 
446
+ add_action('admin_menu', [$this, 'addMenuPages']);
447
+ add_action('network_admin_menu', [$this, 'addNetworkMenuPages']);
448
 
449
+ add_action('all_admin_notices', [$this, 'allAdminNotices']);
450
 
451
+ add_filter('plugin_action_links_'.plugin_basename(PLUGIN_FILE), [$this, 'addSettingsLink']);
452
 
453
+ add_filter('enable_live_network_counts', [$this, 'updateBlogPaths']);
454
 
455
+ add_action('activated_plugin', [$this, 'autoClearOnPluginActivationDeactivation'], 10, 2);
456
+ add_action('deactivated_plugin', [$this, 'autoClearOnPluginActivationDeactivation'], 10, 2);
457
+ add_action('admin_init', [$this, 'autoClearCacheOnSettingChanges']);
458
+ add_action('safecss_save_pre', [$this, 'autoClearCacheOnJetpackCustomCss'], 10, 1);
459
+ add_action('upgrader_process_complete', [$this, 'autoClearOnUpgraderProcessComplete'], 10, 2);
460
 
461
+ add_action('switch_theme', [$this, 'autoClearCache']);
462
+ add_action('wp_create_nav_menu', [$this, 'autoClearCache']);
463
+ add_action('wp_update_nav_menu', [$this, 'autoClearCache']);
464
+ add_action('wp_delete_nav_menu', [$this, 'autoClearCache']);
465
 
466
+ add_action('save_post', [$this, 'autoClearPostCache']);
467
+ add_action('delete_post', [$this, 'autoClearPostCache']);
468
+ add_action('clean_post_cache', [$this, 'autoClearPostCache']);
469
+ add_action('post_updated', [$this, 'autoClearAuthorPageCache'], 10, 3);
470
+ add_action('pre_post_update', [$this, 'autoClearPostCacheTransition'], 10, 2);
471
+ add_action('woocommerce_product_set_stock', [$this, 'autoClearPostCacheOnWooCommerceSetStock'], 10, 1);
472
 
473
+ add_action('added_term_relationship', [$this, 'autoClearPostTermsCache'], 10, 1);
474
+ add_action('delete_term_relationships', [$this, 'autoClearPostTermsCache'], 10, 1);
475
 
476
+ add_action('trackback_post', [$this, 'autoClearCommentPostCache']);
477
+ add_action('pingback_post', [$this, 'autoClearCommentPostCache']);
478
+ add_action('comment_post', [$this, 'autoClearCommentPostCache']);
479
+ add_action('transition_comment_status', [$this, 'autoClearCommentPostCacheTransition'], 10, 3);
480
 
481
+ add_action('create_term', [$this, 'autoClearCache']);
482
+ add_action('edit_terms', [$this, 'autoClearCache']);
483
+ add_action('delete_term', [$this, 'autoClearCache']);
484
 
485
+ add_action('add_link', [$this, 'autoClearCache']);
486
+ add_action('edit_link', [$this, 'autoClearCache']);
487
+ add_action('delete_link', [$this, 'autoClearCache']);
488
 
489
 
490
 
491
  if ($this->options['enable'] && $this->applyWpFilters(GLOBAL_NS.'_disable_akismet_comment_nonce', true)) {
492
+ add_filter('akismet_comment_nonce', function () {
493
  return 'disabled-by-'.SLUG_TD; // MUST return a string literal that is not 'true' or '' (an empty string). See <http://bit.ly/1YItpdE>
494
  }); // See also why the Akismet nonce should be disabled: <http://jas.xyz/1R23f5c>
495
  }
502
  /* -------------------------------------------------------------- */
503
 
504
  if (!is_multisite() || is_main_site()) { // Main site only.
505
+ add_filter('cron_schedules', [$this, 'extendCronSchedules']);
506
+ add_action('_cron_'.GLOBAL_NS.'_cleanup', [$this, 'cleanupCache']);
507
 
508
 
509
  }
src/includes/classes/VsUpgrades.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
  /**
5
  * Version-Specific Upgrades.
@@ -140,7 +140,7 @@ class VsUpgrades extends AbsBase
140
  return; // Template blocks are already gone.
141
  }
142
  if ($htaccess = $this->plugin->readHtaccessFile($htaccess_file)) {
143
- if (is_dir($templates_dir = dirname(dirname(__FILE__)).'/templates/htaccess/back-compat')) {
144
  $htaccess['file_contents'] = str_replace(file_get_contents($templates_dir.'/v151114.txt'), '', $htaccess['file_contents']);
145
  $htaccess['file_contents'] = str_replace(file_get_contents($templates_dir.'/v151114-2.txt'), '', $htaccess['file_contents']);
146
  $htaccess['file_contents'] = trim($htaccess['file_contents']);
@@ -176,7 +176,7 @@ class VsUpgrades extends AbsBase
176
  wp_clear_scheduled_hook('_cron_zencache_auto_cache');
177
  wp_clear_scheduled_hook('_cron_zencache_cleanup');
178
  }
179
- deactivate_plugins(array('zencache/zencache.php', 'zencache-pro/zencache-pro.php'), true);
180
 
181
  if (!empty($zencache_options['base_dir'])) {
182
  $this->plugin->deleteAllFilesDirsIn(WP_CONTENT_DIR.'/'.trim($zencache_options['base_dir'], '/'), true);
@@ -198,11 +198,10 @@ class VsUpgrades extends AbsBase
198
  $this->plugin->activate(); // Reactivate plugin w/ new options.
199
 
200
  $this->plugin->enqueueMainNotice(
201
- '<p>'.sprintf(__('<strong>Woohoo! %1$s activated.</strong> :-)', 'comet-cache'), esc_html(NAME)).'</p>'.
202
- '<p>'.sprintf(__('NOTE: Your ZenCache options were preserved by %1$s (for more details, visit the <a href="%2$s" target="_blank">Migration FAQ</a>).'.'', 'comet-cache'), esc_html(NAME), esc_attr(IS_PRO ? 'http://cometcache.com/r/zencache-pro-migration-faq/' : 'https://cometcache.com/r/zencache-migration-faq/')).'</p>'.
203
- '<p>'.sprintf(__('To review your configuration, please see: <a href="%2$s">%1$s → Plugin Options</a>.'.'', 'comet-cache'), esc_html(NAME), esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS)), self_admin_url('/admin.php')))).'</p>'
204
  );
205
  }
206
  }
207
-
208
  }
1
  <?php
2
+ namespace WebSharks\CometCache\Classes;
3
 
4
  /**
5
  * Version-Specific Upgrades.
140
  return; // Template blocks are already gone.
141
  }
142
  if ($htaccess = $this->plugin->readHtaccessFile($htaccess_file)) {
143
+ if (is_dir($templates_dir = dirname(__DIR__).'/templates/htaccess/back-compat')) {
144
  $htaccess['file_contents'] = str_replace(file_get_contents($templates_dir.'/v151114.txt'), '', $htaccess['file_contents']);
145
  $htaccess['file_contents'] = str_replace(file_get_contents($templates_dir.'/v151114-2.txt'), '', $htaccess['file_contents']);
146
  $htaccess['file_contents'] = trim($htaccess['file_contents']);
176
  wp_clear_scheduled_hook('_cron_zencache_auto_cache');
177
  wp_clear_scheduled_hook('_cron_zencache_cleanup');
178
  }
179
+ deactivate_plugins(['zencache/zencache.php', 'zencache-pro/zencache-pro.php'], true);
180
 
181
  if (!empty($zencache_options['base_dir'])) {
182
  $this->plugin->deleteAllFilesDirsIn(WP_CONTENT_DIR.'/'.trim($zencache_options['base_dir'], '/'), true);
198
  $this->plugin->activate(); // Reactivate plugin w/ new options.
199
 
200
  $this->plugin->enqueueMainNotice(
201
+ '<p>'.sprintf(__('<strong>Woohoo! %1$s activated.</strong> :-)', 'comet-cache'), esc_html(NAME)).'</p>'.
202
+ '<p>'.sprintf(__('NOTE: Your ZenCache options were preserved by %1$s (for more details, visit the <a href="%2$s" target="_blank">Migration FAQ</a>).'.'', 'comet-cache'), esc_html(NAME), esc_attr(IS_PRO ? 'http://cometcache.com/r/zencache-pro-migration-faq/' : 'https://cometcache.com/r/zencache-migration-faq/')).'</p>'.
203
+ '<p>'.sprintf(__('To review your configuration, please see: <a href="%2$s">%1$s → Plugin Options</a>.'.'', 'comet-cache'), esc_html(NAME), esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), self_admin_url('/admin.php')))).'</p>'
204
  );
205
  }
206
  }
 
207
  }
src/includes/closures/Ac/AbortUtils.php DELETED
@@ -1,11 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Ignores user aborts; when/if the Auto-Cache Engine is running.
6
- *
7
- * @since 150422 Rewrite.
8
- */
9
- $self->maybeIgnoreUserAbort = function () use ($self) {
10
-
11
- };
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/AcPluginUtils.php DELETED
@@ -1,25 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Loads any advanced cache plugin files found inside `/wp-content/ac-plugins`.
6
- *
7
- * @since 150422 Rewrite.
8
- */
9
- $self->loadAcPlugins = function () use ($self) {
10
- if (!is_dir(WP_CONTENT_DIR.'/ac-plugins')) {
11
- return; // Nothing to do here.
12
- }
13
- $GLOBALS[GLOBAL_NS.'_advanced_cache'] = $self; // Self reference.
14
- $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
15
- if (!isset($GLOBALS['zencache__advanced_cache'])) {
16
- $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
17
- $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
18
- }
19
- foreach ((array) glob(WP_CONTENT_DIR.'/ac-plugins/*.php') as $_ac_plugin) {
20
- if (is_file($_ac_plugin)) {
21
- include_once $_ac_plugin;
22
- }
23
- }
24
- unset($_ac_plugin); // Houskeeping.
25
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/BrowserUtils.php DELETED
@@ -1,34 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Sends no-cache headers (if applicable).
6
- *
7
- * @since 150422 Rewrite. Enhanced/altered 151220.
8
- */
9
- $self->maybeStopBrowserCaching = function () use ($self) {
10
- switch ((bool) COMET_CACHE_ALLOW_BROWSER_CACHE) {
11
-
12
- case true: // If global config allows, check exclusions.
13
-
14
- if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
15
- if (!filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
16
- return $self->sendNoCacheHeaders(); // Disallow.
17
- } // Else, allow client-side caching; because `ABC` is a true-ish value.
18
- // ↑ Note that exclusion patterns are ignored in this case, in favor of `ABC`.
19
- } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI'])) {
20
- return $self->sendNoCacheHeaders(); // Disallow.
21
- }
22
- return; // Allow browser caching; default behavior in this mode.
23
-
24
- case false: // Global config disallows; check inclusions.
25
-
26
- if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
27
- if (filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
28
- return; // Allow, because `ABC` is a false-ish value.
29
- } // Else, disallow client-side caching; because `ABC` is a true-ish value.
30
- // ↑ Note that inclusion patterns are ignored in this case, in favor of `ABC`.
31
- }
32
- return $self->sendNoCacheHeaders(); // Disallow; default behavior in this mode.
33
- }
34
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/NcDebugConsts.php DELETED
@@ -1,293 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- if (defined(__NAMESPACE__.'\\NC_DEBUG_PHP_SAPI_CLI')) {
5
- return; // Already defined these.
6
- }
7
- /**
8
- * No-cache because of the current {@link \PHP_SAPI}.
9
- *
10
- * @since 140422 First documented version.
11
- *
12
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
13
- */
14
- const NC_DEBUG_PHP_SAPI_CLI = 'nc_debug_php_sapi_cli';
15
-
16
- /**
17
- * No-cache because of a missing http host.
18
- *
19
- * @since 140422 First documented version.
20
- *
21
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
22
- */
23
- const NC_DEBUG_NO_SERVER_HTTP_HOST = 'nc_debug_no_server_http_host';
24
-
25
- /**
26
- * No-cache because of a missing `$_SERVER['REQUEST_URI']`.
27
- *
28
- * @since 140422 First documented version.
29
- *
30
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
31
- */
32
- const NC_DEBUG_NO_SERVER_REQUEST_URI = 'nc_debug_no_server_request_uri';
33
-
34
- /**
35
- * No-cache because the {@link \COMET_CACHE_ALLOWED} constant says not to.
36
- *
37
- * @since 140422 First documented version.
38
- *
39
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
40
- */
41
- const NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT = 'nc_debug_comet_cache_allowed_constant';
42
-
43
- /**
44
- * No-cache because the `$_SERVER['COMET_CACHE_ALLOWED']` environment variable says not to.
45
- *
46
- * @since 140422 First documented version.
47
- *
48
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
49
- */
50
- const NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR = 'nc_debug_comet_cache_allowed_server_var';
51
-
52
- /**
53
- * No-cache because the {@link \DONOTCACHEPAGE} constant says not to.
54
- *
55
- * @since 140422 First documented version.
56
- *
57
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
58
- */
59
- const NC_DEBUG_DONOTCACHEPAGE_CONSTANT = 'nc_debug_donotcachepage_constant';
60
-
61
- /**
62
- * No-cache because the `$_SERVER['DONOTCACHEPAGE']` environment variable says not to.
63
- *
64
- * @since 140422 First documented version.
65
- *
66
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
67
- */
68
- const NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR = 'nc_debug_donotcachepage_server_var';
69
-
70
- /**
71
- * No-cache because the current request includes the `?[SHORT_NAME]AC=0` parameter.
72
- *
73
- * @since 140422 First documented version.
74
- *
75
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
76
- */
77
- const NC_DEBUG_AC_GET_VAR = 'nc_debug_ac_get_var';
78
-
79
- /**
80
- * No-cache because the current request method is `POST|PUT|DELETE`.
81
- *
82
- * @since 140422 First documented version.
83
- *
84
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
85
- */
86
- const NC_DEBUG_UNCACHEABLE_REQUEST = 'nc_debug_post_put_del_request';
87
-
88
- /**
89
- * No-cache because the current request originated from the server itself.
90
- *
91
- * @since 140422 First documented version.
92
- *
93
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
94
- */
95
- const NC_DEBUG_SELF_SERVE_REQUEST = 'nc_debug_self_serve_request';
96
-
97
- /**
98
- * No-cache because the current request is for a feed.
99
- *
100
- * @since 140422 First documented version.
101
- *
102
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
103
- */
104
- const NC_DEBUG_FEED_REQUEST = 'nc_debug_feed_request';
105
-
106
- /**
107
- * No-cache because the current request is systematic.
108
- *
109
- * @since 140422 First documented version.
110
- *
111
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
112
- */
113
- const NC_DEBUG_WP_SYSTEMATICS = 'nc_debug_wp_systematics';
114
-
115
- /**
116
- * No-cache because the current request is for an administrative area.
117
- *
118
- * @since 140422 First documented version.
119
- *
120
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
121
- */
122
- const NC_DEBUG_WP_ADMIN = 'nc_debug_wp_admin';
123
-
124
- /**
125
- * No-cache because the current request is multisite `/files/`.
126
- *
127
- * @since 140422 First documented version.
128
- *
129
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
130
- */
131
- const NC_DEBUG_MS_FILES = 'nc_debug_ms_files';
132
-
133
- /**
134
- * No-cache because the current user is like a logged-in user.
135
- *
136
- * @since 140422 First documented version.
137
- *
138
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
139
- */
140
- const NC_DEBUG_IS_LIKE_LOGGED_IN_USER = 'nc_debug_is_like_logged_in_user';
141
-
142
- /**
143
- * No-cache because the current user is logged into the site.
144
- *
145
- * @since 140422 First documented version.
146
- *
147
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
148
- */
149
- const NC_DEBUG_IS_LOGGED_IN_USER = 'nc_debug_is_logged_in_user';
150
-
151
- /**
152
- * No-cache because the current user is logged into the site and the current page contains an `nonce`.
153
- *
154
- * @since 151220 Enhancing logged-in user caching support.
155
- *
156
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
157
- */
158
- const NC_DEBUG_IS_LOGGED_IN_USER_NONCE = 'nc_debug_is_logged_in_user_nonce';
159
-
160
- /**
161
- * No-cache because the current page contains an `nonce`.
162
- *
163
- * @since 151220 Enhancing `nonce` detection.
164
- *
165
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
166
- */
167
- const NC_DEBUG_PAGE_CONTAINS_NONCE = 'nc_debug_page_contains_nonce';
168
-
169
- /**
170
- * No-cache because it was not possible to acquire a user token.
171
- *
172
- * @since 140422 First documented version.
173
- *
174
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
175
- */
176
- const NC_DEBUG_NO_USER_TOKEN = 'nc_debug_no_user_token';
177
-
178
- /**
179
- * No-cache because the current request contains a query string.
180
- *
181
- * @since 140422 First documented version.
182
- *
183
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
184
- */
185
- const NC_DEBUG_GET_REQUEST_QUERIES = 'nc_debug_get_request_queries';
186
-
187
- /**
188
- * No-cache because it's a preview.
189
- *
190
- * @since 151114 Adding support for preview detection.
191
- *
192
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
193
- */
194
- const NC_DEBUG_PREVIEW = 'nc_debug_preview';
195
-
196
- /**
197
- * No-cache because the current request excluded by its URI.
198
- *
199
- * @since 140422 First documented version.
200
- *
201
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
202
- */
203
- const NC_DEBUG_EXCLUDED_URIS = 'nc_debug_excluded_uris';
204
-
205
- /**
206
- * No-cache because the current user-agent is excluded.
207
- *
208
- * @since 140422 First documented version.
209
- *
210
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
211
- */
212
- const NC_DEBUG_EXCLUDED_AGENTS = 'nc_debug_excluded_agents';
213
-
214
- /**
215
- * No-cache because the current HTTP referrer is excluded.
216
- *
217
- * @since 140422 First documented version.
218
- *
219
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
220
- */
221
- const NC_DEBUG_EXCLUDED_REFS = 'nc_debug_excluded_refs';
222
-
223
- /**
224
- * No-cache because the current request is a 404 error.
225
- *
226
- * @since 140422 First documented version.
227
- *
228
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
229
- */
230
- const NC_DEBUG_404_REQUEST = 'nc_debug_404_request';
231
-
232
- /**
233
- * No-cache because the requested page is currently in maintenance mode.
234
- *
235
- * @since 140422 First documented version.
236
- *
237
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
238
- */
239
- const NC_DEBUG_MAINTENANCE_PLUGIN = 'nc_debug_maintenance_plugin';
240
-
241
- /**
242
- * No-cache because the current request is being compressed by an incompatible ZLIB coding type.
243
- *
244
- * @since 140422 First documented version.
245
- *
246
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
247
- */
248
- const NC_DEBUG_OB_ZLIB_CODING_TYPE = 'nc_debug_ob_zlib_coding_type';
249
-
250
- /**
251
- * No-cache because the current request resulted in a WP error message.
252
- *
253
- * @since 140422 First documented version.
254
- *
255
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
256
- */
257
- const NC_DEBUG_WP_ERROR_PAGE = 'nc_debug_wp_error_page';
258
-
259
- /**
260
- * No-cache because the current request is serving an uncacheable content type.
261
- *
262
- * @since 140422 First documented version.
263
- *
264
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
265
- */
266
- const NC_DEBUG_UNCACHEABLE_CONTENT_TYPE = 'nc_debug_uncacheable_content_type';
267
-
268
- /**
269
- * No-cache because the current request sent a non-2xx & non-404 status code.
270
- *
271
- * @since 140422 First documented version.
272
- *
273
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
274
- */
275
- const NC_DEBUG_UNCACHEABLE_STATUS = 'nc_debug_uncacheable_status';
276
-
277
- /**
278
- * No-cache because this is a new 404 error that we are symlinking.
279
- *
280
- * @since 140422 First documented version.
281
- *
282
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
283
- */
284
- const NC_DEBUG_1ST_TIME_404_SYMLINK = 'nc_debug_1st_time_404_symlink';
285
-
286
- /**
287
- * No-cache because we detected an early buffer termination.
288
- *
289
- * @since 140605 Improving output buffer.
290
- *
291
- * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
292
- */
293
- const NC_DEBUG_EARLY_BUFFER_TERMINATION = 'nc_debug_early_buffer_termination';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/NcDebugUtils.php DELETED
@@ -1,209 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * An array of debug info.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @type array An array of debug info; i.e. `reason_code` and `reason` (optional).
10
- */
11
- $self->debug_info = array('reason_code' => '', 'reason' => '');
12
-
13
- /*
14
- * Used to setup debug info (if enabled).
15
- *
16
- * @since 150422 Rewrite.
17
- *
18
- * @param string $reason_code One of the `NC_DEBUG_` constants.
19
- * @param string $reason Optionally override the built-in description with a custom message.
20
- */
21
- $self->maybeSetDebugInfo = function ($reason_code, $reason = '') use ($self) {
22
- if (!COMET_CACHE_DEBUGGING_ENABLE) {
23
- return; // Nothing to do.
24
- }
25
- $reason = (string) $reason;
26
- if (!($reason_code = (string) $reason_code)) {
27
- return; // Not applicable.
28
- }
29
- $self->debug_info = array('reason_code' => $reason_code, 'reason' => $reason);
30
- };
31
-
32
- /*
33
- * Echoes `NC_DEBUG_` info in the WordPress `shutdown` phase (if applicable).
34
- *
35
- * @since 150422 Rewrite.
36
- *
37
- * @attaches-to `shutdown` hook in WordPress w/ a late priority.
38
- */
39
- $self->maybeEchoNcDebugInfo = function () use ($self) {
40
- if (!COMET_CACHE_DEBUGGING_ENABLE) {
41
- return; // Nothing to do.
42
- }
43
- if (is_admin()) {
44
- return; // Not applicable.
45
- }
46
- if (strcasecmp(PHP_SAPI, 'cli') === 0) {
47
- return; // Let's not run the risk here.
48
- }
49
- if ($self->debug_info && $self->hasACacheableContentType() && $self->is_a_wp_content_type) {
50
- echo (string) $self->maybeGetNcDebugInfo($self->debug_info['reason_code'], $self->debug_info['reason']);
51
- }
52
- };
53
-
54
- /*
55
- * Gets `NC_DEBUG_` info (if applicable).
56
- *
57
- * @since 150422 Rewrite.
58
- *
59
- * @param string $reason_code One of the `NC_DEBUG_` constants.
60
- * @param string $reason Optional; to override the default description with a custom message.
61
- *
62
- * @return string The debug info; i.e. full description (if applicable).
63
- */
64
- $self->maybeGetNcDebugInfo = function ($reason_code = '', $reason = '') use ($self) {
65
- if (!COMET_CACHE_DEBUGGING_ENABLE) {
66
- return ''; // Not applicable.
67
- }
68
- $reason = (string) $reason;
69
- if (!($reason_code = (string) $reason_code)) {
70
- return ''; // Not applicable.
71
- }
72
- if (!$reason) {
73
- switch ($reason_code) {
74
- case NC_DEBUG_PHP_SAPI_CLI:
75
- $reason = __('because `PHP_SAPI` reports that you are currently running from the command line.', 'comet-cache');
76
- break; // Break switch handler.
77
-
78
- case NC_DEBUG_NO_SERVER_HTTP_HOST:
79
- $reason = __('because `$_SERVER[\'HTTP_HOST\']` is missing from your server configuration.', 'comet-cache');
80
- break; // Break switch handler.
81
-
82
- case NC_DEBUG_NO_SERVER_REQUEST_URI:
83
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` is missing from your server configuration.', 'comet-cache');
84
- break; // Break switch handler.
85
-
86
- case NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT:
87
- if ($self->functionIsPossible('did_action') && did_action('ws_plugin__s2member_during_no_cache_constants')) {
88
- $reason = __('because the s2Member plugin set the PHP constant `COMET_CACHE_ALLOWED` to a boolean-ish `FALSE` value at runtime. The s2Member plugin is serving content that must remain dynamic on this particular page, and therefore this page was intentionally not cached for a very good reason.', 'comet-cache');
89
- } else {
90
- $reason = __('because the PHP constant `COMET_CACHE_ALLOWED` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
91
- }
92
- break; // Break switch handler.
93
-
94
- case NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR:
95
- $reason = __('because the environment variable `$_SERVER[\'COMET_CACHE_ALLOWED\']` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
96
- break; // Break switch handler.
97
-
98
- case NC_DEBUG_DONOTCACHEPAGE_CONSTANT:
99
- $reason = __('because the PHP constant `DONOTCACHEPAGE` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
100
- break; // Break switch handler.
101
-
102
- case NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR:
103
- $reason = __('because the environment variable `$_SERVER[\'DONOTCACHEPAGE\']` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
104
- break; // Break switch handler.
105
-
106
- case NC_DEBUG_AC_GET_VAR:
107
- $reason = sprintf(__('because `$_GET[\'%1$sAC\']` is set to a boolean-ish FALSE value.', 'comet-cache'), strtolower(SHORT_NAME));
108
- break; // Break switch handler.
109
-
110
- case NC_DEBUG_UNCACHEABLE_REQUEST:
111
- $reason = __('because `$_SERVER[\'REQUEST_METHOD\']` is `POST`, `PUT`, `DELETE`, `HEAD`, `OPTIONS`, `TRACE` or `CONNECT`. These request methods should never (ever) be cached in any way.', 'comet-cache');
112
- break; // Break switch handler.
113
-
114
- case NC_DEBUG_SELF_SERVE_REQUEST:
115
- $reason = __('because `[current IP address]` === `$_SERVER[\'SERVER_ADDR\']`; i.e. a self-serve request. DEVELOPER TIP: if you are testing on a localhost installation, please add `define(\'LOCALHOST\', TRUE);` to your `/wp-config.php` file while you run tests :-) Remove it (or set it to a `FALSE` value) once you go live on the web.', 'comet-cache');
116
- break; // Break switch handler.
117
-
118
- case NC_DEBUG_FEED_REQUEST:
119
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a `/feed`; and the configuration of this site says not to cache XML-based feeds.', 'comet-cache');
120
- break; // Break switch handler.
121
-
122
- case NC_DEBUG_WP_SYSTEMATICS:
123
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a `wp-` or `xmlrpc` file; i.e. a WordPress systematic file. WordPress systematics are never (ever) cached in any way.', 'comet-cache');
124
- break; // Break switch handler.
125
-
126
- case NC_DEBUG_WP_ADMIN:
127
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` or the `is_admin()` function indicates this is an administrative area of the site.', 'comet-cache');
128
- break; // Break switch handler.
129
-
130
- case NC_DEBUG_MS_FILES:
131
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a Multisite Network; and this was a request for `/files/*`, not a page.', 'comet-cache');
132
- break; // Break switch handler.
133
-
134
- case NC_DEBUG_IS_LOGGED_IN_USER:
135
- case NC_DEBUG_IS_LIKE_LOGGED_IN_USER:
136
- $reason = __('because the current user visiting this page (usually YOU), appears to be logged-in. The current configuration says NOT to cache pages for logged-in visitors. This message may also appear if you have an active PHP session on this site, or if you\'ve left (or replied to) a comment recently. If this message continues, please clear your cookies and try again.', 'comet-cache');
137
- break; // Break switch handler.
138
-
139
- case NC_DEBUG_IS_LOGGED_IN_USER_NONCE:
140
- $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. While your current configuration states that pages SHOULD be cache for logged-in visitors, `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
141
- break; // Break switch handler.
142
-
143
- case NC_DEBUG_PAGE_CONTAINS_NONCE:
144
- $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. Note that `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
145
- break; // Break switch handler.
146
-
147
- case NC_DEBUG_NO_USER_TOKEN:
148
- $reason = sprintf(__('because the current user appeared to be logged into the site (in one way or another); but %1$s was unable to formulate a User Token for them. Please report this as a possible bug.', 'comet-cache'), NAME);
149
- break; // Break switch handler.
150
-
151
- case NC_DEBUG_GET_REQUEST_QUERIES:
152
- $reason = __('because `$_GET` contains query string data. The current configuration says NOT to cache GET requests with a query string.', 'comet-cache');
153
- break; // Break switch handler.
154
-
155
- case NC_DEBUG_PREVIEW:
156
- $reason = __('because `$_REQUEST` indicates this is simply a preview of something to come.', 'comet-cache');
157
- break; // Break switch handler.
158
-
159
- case NC_DEBUG_EXCLUDED_URIS:
160
- $reason = __('because `$_SERVER[\'REQUEST_URI\']` matches a configured URI Exclusion Pattern on this installation.', 'comet-cache');
161
- break; // Break switch handler.
162
-
163
- case NC_DEBUG_EXCLUDED_AGENTS:
164
- $reason = __('because `$_SERVER[\'HTTP_USER_AGENT\']` matches a configured User-Agent Exclusion Pattern on this installation.', 'comet-cache');
165
- break; // Break switch handler.
166
-
167
- case NC_DEBUG_EXCLUDED_REFS:
168
- $reason = __('because `$_SERVER[\'HTTP_REFERER\']` and/or `$_GET[\'_wp_http_referer\']` matches a configured HTTP Referrer Exclusion Pattern on this installation.', 'comet-cache');
169
- break; // Break switch handler.
170
-
171
- case NC_DEBUG_404_REQUEST:
172
- $reason = __('because the WordPress `is_404()` Conditional Tag says the current page is a 404 error. The current configuration says NOT to cache 404 errors.', 'comet-cache');
173
- break; // Break switch handler.
174
-
175
- case NC_DEBUG_MAINTENANCE_PLUGIN:
176
- $reason = __('because a plugin running on this installation says this page is in Maintenance Mode; i.e. is not available publicly at this time.', 'comet-cache');
177
- break; // Break switch handler.
178
-
179
- case NC_DEBUG_OB_ZLIB_CODING_TYPE:
180
- $reason = sprintf(__('because %1$s is unable to cache already-compressed output. Please use `mod_deflate` w/ Apache; or use `zlib.output_compression` in your `php.ini` file. %1$s is NOT compatible with `ob_gzhandler()` and others like this.', 'comet-cache'), NAME);
181
- break; // Break switch handler.
182
-
183
- case NC_DEBUG_WP_ERROR_PAGE:
184
- $reason = __('because the contents of this document contain `<body id="error-page">`, which indicates this is an auto-generated WordPress error message.', 'comet-cache');
185
- break; // Break switch handler.
186
-
187
- case NC_DEBUG_UNCACHEABLE_CONTENT_TYPE:
188
- $reason = __('because a `Content-Type:` header was set via PHP at runtime. The header contains a MIME type which is NOT a variation of HTML or XML. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins.', 'comet-cache');
189
- break; // Break switch handler.
190
-
191
- case NC_DEBUG_UNCACHEABLE_STATUS:
192
- $reason = __('because a `Status:` header (or an `HTTP/` header) was set via PHP at runtime. The header contains a non-`2xx` status code. This indicates the current page was not loaded successfully. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins.', 'comet-cache');
193
- break; // Break switch handler.
194
-
195
- case NC_DEBUG_1ST_TIME_404_SYMLINK:
196
- $reason = sprintf(__('because the WordPress `is_404()` Conditional Tag says the current page is a 404 error; and this is the first time it\'s happened on this page. Your current configuration says that 404 errors SHOULD be cached, so %1$s built a cached symlink which points future requests for this location to your already-cached 404 error document. If you reload this page (assuming you don\'t clear the cache before you do so); you should get a cached version of your 404 error document. This message occurs ONCE for each new/unique 404 error request.', 'comet-cache'), NAME);
197
- break; // Break switch handler.
198
-
199
- case NC_DEBUG_EARLY_BUFFER_TERMINATION:
200
- $reason = sprintf(__('because %1$s detected an early output buffer termination. This may happen when a theme/plugin ends, cleans, or flushes all output buffers before reaching the PHP shutdown phase. It\'s not always a bad thing. Sometimes it is necessary for a theme/plugin to do this. However, in this scenario it is NOT possible to cache the output; since %1$s is effectively disabled at runtime when this occurs.', 'comet-cache'), NAME);
201
- break; // Break switch handler.
202
-
203
- default: // Default case handler.
204
- $reason = __('due to an unexpected behavior in the application. Please report this as a bug!', 'comet-cache');
205
- break; // Break switch handler.
206
- }
207
- }
208
- return "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s is NOT caching this page, %2$s', 'comet-cache'), NAME, $reason)).' -->';
209
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/ObUtils.php DELETED
@@ -1,353 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Calculated protocol; one of `http://` or `https://`.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @type float One of `http://` or `https://`.
10
- */
11
- $self->protocol = '';
12
-
13
- /*
14
- * Host token for this request.
15
- *
16
- * @since 150821 Improving multisite compat.
17
- *
18
- * @type string Host token for this request.
19
- */
20
- $self->host_token = '';
21
-
22
- /*
23
- * Host base/dir tokens for this request.
24
- *
25
- * @since 150821 Improving multisite compat.
26
- *
27
- * @type string Host base/dir tokens for this request.
28
- */
29
- $self->host_base_dir_tokens = '';
30
-
31
- /*
32
- * Calculated version salt; set by site configuration data.
33
- *
34
- * @since 150422 Rewrite.
35
- *
36
- * @type string|mixed Any scalar value does fine.
37
- */
38
- $self->version_salt = '';
39
-
40
- /*
41
- * Relative cache path for the current request.
42
- *
43
- * @since 150422 Rewrite.
44
- *
45
- * @type string Cache path for the current request.
46
- */
47
- $self->cache_path = '';
48
-
49
- /*
50
- * Absolute cache file path for the current request.
51
- *
52
- * @since 150422 Rewrite.
53
- *
54
- * @type string Absolute cache file path for the current request.
55
- */
56
- $self->cache_file = '';
57
-
58
- /*
59
- * Relative 404 cache path for the current request.
60
- *
61
- * @since 150422 Rewrite.
62
- *
63
- * @type string 404 cache path for the current request.
64
- */
65
- $self->cache_path_404 = '';
66
-
67
- /*
68
- * Absolute 404 cache file path for the current request.
69
- *
70
- * @since 150422 Rewrite.
71
- *
72
- * @type string Absolute 404 cache file path for the current request.
73
- */
74
- $self->cache_file_404 = '';
75
-
76
- /*
77
- * Version salt followed by the current request location.
78
- *
79
- * @since 150422 Rewrite.
80
- *
81
- * @type string Version salt followed by the current request location.
82
- */
83
- $self->salt_location = '';
84
-
85
- /*
86
- * Calculated max age; i.e., before expiration.
87
- *
88
- * @since 151002 Load average checks in pro version.
89
- *
90
- * @type integer Calculated max age; i.e., before expiration.
91
- */
92
- $self->cache_max_age = 0;
93
-
94
- /*
95
- * Start output buffering (if applicable); or serve a cache file (if possible).
96
- *
97
- * @since 150422 Rewrite.
98
- *
99
- * @note This is a vital part of Comet Cache. This method serves existing (fresh) cache files.
100
- * It is also responsible for beginning the process of collecting the output buffer.
101
- */
102
- $self->maybeStartOutputBuffering = function () use ($self) {
103
- if (strcasecmp(PHP_SAPI, 'cli') === 0) {
104
- return $self->maybeSetDebugInfo(NC_DEBUG_PHP_SAPI_CLI);
105
- }
106
- if (empty($_SERVER['HTTP_HOST']) || !$self->hostToken()) {
107
- return $self->maybeSetDebugInfo(NC_DEBUG_NO_SERVER_HTTP_HOST);
108
- }
109
- if (empty($_SERVER['REQUEST_URI'])) {
110
- return $self->maybeSetDebugInfo(NC_DEBUG_NO_SERVER_REQUEST_URI);
111
- }
112
- if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
113
- return $self->maybeSetDebugInfo(NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
114
- }
115
- if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
116
- return $self->maybeSetDebugInfo(NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
117
- }
118
- if (defined('DONOTCACHEPAGE')) {
119
- return $self->maybeSetDebugInfo(NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
120
- }
121
- if (isset($_SERVER['DONOTCACHEPAGE'])) {
122
- return $self->maybeSetDebugInfo(NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
123
- }
124
- if (isset($_GET[strtolower(SHORT_NAME).'AC']) && !filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN)) {
125
- return $self->maybeSetDebugInfo(NC_DEBUG_AC_GET_VAR);
126
- }
127
- if ($self->isUncacheableRequestMethod()) {
128
- return $self->maybeSetDebugInfo(NC_DEBUG_UNCACHEABLE_REQUEST);
129
- }
130
- if (isset($_SERVER['SERVER_ADDR']) && $self->currentIp() === $_SERVER['SERVER_ADDR']) {
131
- if ((!IS_PRO || !$self->isAutoCacheEngine()) && !$self->isLocalhost()) {
132
- return $self->maybeSetDebugInfo(NC_DEBUG_SELF_SERVE_REQUEST);
133
- }
134
- }
135
- if (!COMET_CACHE_FEEDS_ENABLE && $self->isFeed()) {
136
- return $self->maybeSetDebugInfo(NC_DEBUG_FEED_REQUEST);
137
- }
138
- if (preg_match('/\/(?:wp\-[^\/]+|xmlrpc)\.php(?:[?]|$)/i', $_SERVER['REQUEST_URI'])) {
139
- return $self->maybeSetDebugInfo(NC_DEBUG_WP_SYSTEMATICS);
140
- }
141
- if (is_admin() || preg_match('/\/wp-admin(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
142
- return $self->maybeSetDebugInfo(NC_DEBUG_WP_ADMIN);
143
- }
144
- if (is_multisite() && preg_match('/\/files(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
145
- return $self->maybeSetDebugInfo(NC_DEBUG_MS_FILES);
146
- }
147
- if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $self->isLikeUserLoggedIn()) {
148
- return $self->maybeSetDebugInfo(NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
149
- }
150
- if (!COMET_CACHE_GET_REQUESTS && $self->requestContainsUncacheableQueryVars()) {
151
- return $self->maybeSetDebugInfo(NC_DEBUG_GET_REQUEST_QUERIES);
152
- }
153
- if (!empty($_REQUEST['preview'])) {
154
- return $self->maybeSetDebugInfo(NC_DEBUG_PREVIEW);
155
- }
156
- if (COMET_CACHE_EXCLUDE_URIS && preg_match(COMET_CACHE_EXCLUDE_URIS, $_SERVER['REQUEST_URI'])) {
157
- return $self->maybeSetDebugInfo(NC_DEBUG_EXCLUDED_URIS);
158
- }
159
- if (COMET_CACHE_EXCLUDE_AGENTS && !empty($_SERVER['HTTP_USER_AGENT']) && (!IS_PRO || !$self->isAutoCacheEngine())) {
160
- if (preg_match(COMET_CACHE_EXCLUDE_AGENTS, $_SERVER['HTTP_USER_AGENT'])) {
161
- return $self->maybeSetDebugInfo(NC_DEBUG_EXCLUDED_AGENTS);
162
- }
163
- }
164
- if (COMET_CACHE_EXCLUDE_REFS && !empty($_REQUEST['_wp_http_referer'])) {
165
- if (preg_match(COMET_CACHE_EXCLUDE_REFS, stripslashes($_REQUEST['_wp_http_referer']))) {
166
- return $self->maybeSetDebugInfo(NC_DEBUG_EXCLUDED_REFS);
167
- }
168
- }
169
- if (COMET_CACHE_EXCLUDE_REFS && !empty($_SERVER['HTTP_REFERER'])) {
170
- if (preg_match(COMET_CACHE_EXCLUDE_REFS, $_SERVER['HTTP_REFERER'])) {
171
- return $self->maybeSetDebugInfo(NC_DEBUG_EXCLUDED_REFS);
172
- }
173
- }
174
- $self->protocol = $self->isSsl() ? 'https://' : 'http://';
175
- $self->host_token = $self->hostToken();
176
- $self->host_base_dir_tokens = $self->hostBaseDirTokens();
177
-
178
- $self->version_salt = ''; // Initialize the version salt.
179
-
180
- $self->version_salt = $self->applyFilters(get_class($self).'__version_salt', $self->version_salt);
181
- $self->version_salt = $self->applyFilters(GLOBAL_NS.'_version_salt', $self->version_salt);
182
-
183
- $self->cache_path = $self->buildCachePath($self->protocol.$self->host_token.$_SERVER['REQUEST_URI'], '', $self->version_salt);
184
- $self->cache_file = COMET_CACHE_DIR.'/'.$self->cache_path; // Not considering a user cache. That's done in the postload phase.
185
-
186
- $self->cache_path_404 = $self->buildCachePath($self->protocol.$self->host_token.rtrim($self->host_base_dir_tokens, '/').'/'.COMET_CACHE_404_CACHE_FILENAME);
187
- $self->cache_file_404 = COMET_CACHE_DIR.'/'.$self->cache_path_404; // Not considering a user cache at all here--ever.
188
-
189
- $self->salt_location = ltrim($self->version_salt.' '.$self->protocol.$self->host_token.$_SERVER['REQUEST_URI']);
190
-
191
- $self->cache_max_age = strtotime('-'.COMET_CACHE_MAX_AGE);
192
-
193
- if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN === 'postload' && $self->isLikeUserLoggedIn()) {
194
- $self->postload['when_logged_in'] = true; // Enable postload check.
195
- } elseif (is_file($self->cache_file) && (!$self->cache_max_age || filemtime($self->cache_file) >= $self->cache_max_age)) {
196
- list($headers, $cache) = explode('<!--headers-->', file_get_contents($self->cache_file), 2);
197
-
198
- $headers_list = $self->headersList();
199
- foreach (unserialize($headers) as $_header) {
200
- if (!in_array($_header, $headers_list, true) && stripos($_header, 'Last-Modified:') !== 0) {
201
- header($_header); // Only cacheable/safe headers are stored in the cache.
202
- }
203
- }
204
- unset($_header); // Just a little housekeeping.
205
-
206
- if (COMET_CACHE_DEBUGGING_ENABLE && $self->isHtmlXmlDoc($cache)) {
207
- $total_time = number_format(microtime(true) - $self->timer, 5, '.', '');
208
- $cache .= "\n".'<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->';
209
- // translators: This string is actually NOT translatable because the `__()` function is not available at this point in the processing.
210
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s fully functional :-) Cache file served for (%2$s) in %3$s seconds, on: %4$s.', 'comet-cache'), NAME, $self->salt_location, $total_time, date('M jS, Y @ g:i a T'))).' -->';
211
- }
212
- exit($cache); // Exit with cache contents.
213
- } else {
214
- ob_start(array($self, 'outputBufferCallbackHandler'));
215
- }
216
- return; // Return value not applicable.
217
- };
218
-
219
- /*
220
- * Output buffer handler; i.e. the cache file generator.
221
- *
222
- * @note We CANNOT depend on any WP functionality here; it will cause problems.
223
- * Anything we need from WP should be saved in the postload phase as a scalar value.
224
- *
225
- * @since 150422 Rewrite.
226
- *
227
- * @param string $buffer The buffer from {@link \ob_start()}.
228
- * @param int $phase A set of bitmask flags.
229
- *
230
- * @throws \Exception If unable to handle output buffering for any reason.
231
- *
232
- * @return string|bool The output buffer, or `FALSE` to indicate no change.
233
- *
234
- * @attaches-to {@link \ob_start()}
235
- */
236
- $self->outputBufferCallbackHandler = function ($buffer, $phase) use ($self) {
237
- if (!($phase & PHP_OUTPUT_HANDLER_END)) {
238
- throw new \Exception(sprintf(__('Unexpected OB phase: `%1$s`.', 'comet-cache'), $phase));
239
- }
240
- AdvCacheBackCompat::zenCacheConstants();
241
-
242
- $cache = trim((string) $buffer);
243
-
244
- if (!isset($cache[0])) {
245
- return false; // Don't cache an empty buffer.
246
- }
247
- if (!isset($GLOBALS[GLOBAL_NS.'_shutdown_flag'])) {
248
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_EARLY_BUFFER_TERMINATION);
249
- }
250
- if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
251
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
252
- }
253
- if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
254
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
255
- }
256
- if (defined('DONOTCACHEPAGE')) {
257
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
258
- }
259
- if (isset($_SERVER['DONOTCACHEPAGE'])) {
260
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
261
- }
262
- if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $self->is_user_logged_in) {
263
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_IS_LOGGED_IN_USER);
264
- }
265
- if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $self->isLikeUserLoggedIn()) {
266
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
267
- }
268
- if (!COMET_CACHE_CACHE_NONCE_VALUES && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/', $cache)) {
269
- if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $self->isLikeUserLoggedIn()) {
270
- if (!COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN) {
271
- return (boolean)$self->maybeSetDebugInfo(NC_DEBUG_IS_LOGGED_IN_USER_NONCE);
272
- }
273
- } else { // Use the default debug notice for nonce conflicts.
274
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_PAGE_CONTAINS_NONCE);
275
- } // An nonce makes the page dynamic; i.e., NOT cache compatible.
276
- }
277
- if ($self->is_404 && !COMET_CACHE_CACHE_404_REQUESTS) {
278
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_404_REQUEST);
279
- }
280
- if (stripos($cache, '<body id="error-page">') !== false) {
281
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_WP_ERROR_PAGE);
282
- }
283
- if (!$self->functionIsPossible('http_response_code')) {
284
- if (stripos($cache, '<title>database error</title>') !== false) {
285
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_WP_ERROR_PAGE);
286
- }
287
- }
288
- if (!$self->hasACacheableContentType()) {
289
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_UNCACHEABLE_CONTENT_TYPE);
290
- }
291
- if (!$self->hasACacheableStatus()) {
292
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_UNCACHEABLE_STATUS);
293
- }
294
- if ($self->is_maintenance) {
295
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_MAINTENANCE_PLUGIN);
296
- }
297
- if ($self->functionIsPossible('zlib_get_coding_type') && zlib_get_coding_type()
298
- && (!($zlib_oc = ini_get('zlib.output_compression')) || !filter_var($zlib_oc, FILTER_VALIDATE_BOOLEAN))) {
299
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_OB_ZLIB_CODING_TYPE);
300
- }
301
- # Lock the cache directory while writes take place here.
302
-
303
- $cache_lock = $self->cacheLock(); // Lock cache directory.
304
-
305
- # Construct a temp file for atomic cache writes.
306
-
307
- $cache_file_tmp = $self->addTmpSuffix($self->cache_file);
308
-
309
- # Cache directory checks. The cache file directory is created here if necessary.
310
-
311
- if (!is_dir(COMET_CACHE_DIR) && mkdir(COMET_CACHE_DIR, 0775, true) && !is_file(COMET_CACHE_DIR.'/.htaccess')) {
312
- file_put_contents(COMET_CACHE_DIR.'/.htaccess', $self->htaccess_deny);
313
- }
314
- if (!is_dir($cache_file_dir = dirname($self->cache_file))) {
315
- $cache_file_dir_writable = mkdir($cache_file_dir, 0775, true);
316
- }
317
- if (empty($cache_file_dir_writable) && !is_writable($cache_file_dir)) {
318
- throw new \Exception(sprintf(__('Cache directory not writable. %1$s needs this directory please: `%2$s`. Set permissions to `755` or higher; `777` might be needed in some cases.', 'comet-cache'), NAME, $cache_file_dir));
319
- }
320
- # This is where a new 404 request might be detected for the first time.
321
-
322
- if ($self->is_404 && is_file($self->cache_file_404)) {
323
- if (!(symlink($self->cache_file_404, $cache_file_tmp) && rename($cache_file_tmp, $self->cache_file))) {
324
- throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $self->cache_file, $self->cache_file_404, COMET_CACHE_DIR));
325
- }
326
- $self->cacheUnlock($cache_lock); // Release.
327
- return (boolean) $self->maybeSetDebugInfo(NC_DEBUG_1ST_TIME_404_SYMLINK);
328
- }
329
- /* ------- Otherwise, we need to construct & store a new cache file. ----------------------------------------------- */
330
-
331
-
332
-
333
- if (COMET_CACHE_DEBUGGING_ENABLE && $self->isHtmlXmlDoc($cache)) {
334
- $total_time = number_format(microtime(true) - $self->timer, 5, '.', ''); // Based on the original timer.
335
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file path: %2$s', 'comet-cache'), NAME, str_replace(WP_CONTENT_DIR, '', $self->is_404 ? $self->cache_file_404 : $self->cache_file))).' -->';
336
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file built for (%2$s%3$s) in %4$s seconds, on: %5$s.', 'comet-cache'), NAME, $self->is_404 ? '404 [error document]' : $self->salt_location, (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $self->user_token ? '; '.sprintf(__('user token: %1$s', 'comet-cache'), $self->user_token) : ''), $total_time, date('M jS, Y @ g:i a T'))).' -->';
337
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('This %1$s file will auto-expire (and be rebuilt) on: %2$s (based on your configured expiration time).', 'comet-cache'), NAME, date('M jS, Y @ g:i a T', strtotime('+'.COMET_CACHE_MAX_AGE)))).' -->';
338
- }
339
- if ($self->is_404) {
340
- if (file_put_contents($cache_file_tmp, serialize($self->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $self->cache_file_404)) {
341
- if (!(symlink($self->cache_file_404, $cache_file_tmp) && rename($cache_file_tmp, $self->cache_file))) {
342
- throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $self->cache_file, $self->cache_file_404, COMET_CACHE_DIR));
343
- }
344
- $self->cacheUnlock($cache_lock); // Release.
345
- return $cache; // Return the newly built cache; with possible debug information also.
346
- }
347
- } elseif (file_put_contents($cache_file_tmp, serialize($self->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $self->cache_file)) {
348
- $self->cacheUnlock($cache_lock); // Release.
349
- return $cache; // Return the newly built cache; with possible debug information also.
350
- }
351
- @unlink($cache_file_tmp); // Clean this up (if it exists); and throw an exception with information for the site owner.
352
- throw new \Exception(sprintf(__('%1$s: failed to write cache file for: `%2$s`; possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), NAME, $_SERVER['REQUEST_URI'], COMET_CACHE_DIR));
353
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/PostloadUtils.php DELETED
@@ -1,187 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Have we caught the main WP loaded being loaded yet?
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @type bool `TRUE` if main query has been loaded; else `FALSE`.
10
- *
11
- * @see wpMainQueryPostload()
12
- */
13
- $self->is_wp_loaded_query = false;
14
-
15
- /*
16
- * Is the current request a WordPress 404 error?
17
- *
18
- * @since 150422 Rewrite.
19
- *
20
- * @type bool `TRUE` if is a 404 error; else `FALSE`.
21
- *
22
- * @see wpMainQueryPostload()
23
- */
24
- $self->is_404 = false;
25
-
26
- /*
27
- * Last HTTP status code passed through {@link \status_header}.
28
- *
29
- * @since 150422 Rewrite.
30
- *
31
- * @type int Last HTTP status code (if applicable).
32
- *
33
- * @see maybeFilterStatusHeaderPostload()
34
- */
35
- $self->http_status = 0;
36
-
37
- /*
38
- * Is the current request a WordPress content type?
39
- *
40
- * @since 150422 Rewrite.
41
- *
42
- * @type bool `TRUE` if is a WP content type.
43
- *
44
- * @see wpMainQueryPostload()
45
- */
46
- $self->is_a_wp_content_type = false;
47
-
48
- /*
49
- * Current WordPress {@link \content_url()}.
50
- *
51
- * @since 150422 Rewrite.
52
- *
53
- * @type string Current WordPress {@link \content_url()}.
54
- *
55
- * @see wpMainQueryPostload()
56
- */
57
- $self->content_url = '';
58
-
59
- /*
60
- * Flag for {@link \is_user_loged_in()}.
61
- *
62
- * @since 150422 Rewrite.
63
- *
64
- * @type bool `TRUE` if {@link \is_user_loged_in()}; else `FALSE`.
65
- *
66
- * @see wpMainQueryPostload()
67
- */
68
- $self->is_user_logged_in = false;
69
-
70
- /*
71
- * Flag for {@link \is_maintenance()}.
72
- *
73
- * @since 150422 Rewrite.
74
- *
75
- * @type bool `TRUE` if {@link \is_maintenance()}; else `FALSE`.
76
- *
77
- * @see wpMainQueryPostload()
78
- */
79
- $self->is_maintenance = false;
80
-
81
- /*
82
- * Array of data targeted at the postload phase.
83
- *
84
- * @since 150422 Rewrite.
85
- *
86
- * @type array Data and/or flags that work with various postload handlers.
87
- */
88
- $self->postload = array(
89
-
90
- 'filter_status_header' => true,
91
- 'wp_main_query' => true,
92
- 'set_debug_info' => COMET_CACHE_DEBUGGING_ENABLE,
93
- );
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
- /*
104
- * Filters WP {@link \status_header()} (if applicable).
105
- *
106
- * @since 150422 Rewrite.
107
- */
108
- $self->maybeFilterStatusHeaderPostload = function () use ($self) {
109
- if (empty($self->postload['filter_status_header'])) {
110
- return; // Nothing to do in this case.
111
- }
112
- $_self = $self; // Reference needed below.
113
-
114
- add_filter(
115
- 'status_header',
116
- function ($status_header, $status_code) use ($_self) {
117
- if ($status_code > 0) {
118
- $_self->http_status = (integer) $status_code;
119
- }
120
- return $status_header;
121
- },
122
- PHP_INT_MAX,
123
- 2
124
- );
125
- };
126
-
127
- /*
128
- * Hooks `NC_DEBUG_` info into the WordPress `shutdown` phase (if applicable).
129
- *
130
- * @since 150422 Rewrite.
131
- */
132
- $self->maybeSetDebugInfoPostload = function () use ($self) {
133
- if (!COMET_CACHE_DEBUGGING_ENABLE) {
134
- return; // Nothing to do.
135
- }
136
- if (empty($self->postload['set_debug_info'])) {
137
- return; // Nothing to do in this case.
138
- }
139
- if (is_admin()) {
140
- return; // Not applicable.
141
- }
142
- if (strcasecmp(PHP_SAPI, 'cli') === 0) {
143
- return; // Let's not run the risk here.
144
- }
145
- add_action('shutdown', array($self, 'maybeEchoNcDebugInfo'), PHP_INT_MAX - 10);
146
- };
147
-
148
- /*
149
- * Grab details from WP and the Comet Cache plugin itself,
150
- * after the main query is loaded (if at all possible).
151
- *
152
- * This is where we have a chance to grab any values we need from WordPress; or from the CC plugin.
153
- * It is EXTREMEMLY important that we NOT attempt to grab any object references here.
154
- * Anything acquired in this phase should be stored as a scalar value.
155
- * See {@link outputBufferCallbackHandler()} for further details.
156
- *
157
- * @since 150422 Rewrite.
158
- *
159
- * @attaches-to `wp` hook.
160
- */
161
- $self->wpMainQueryPostload = function () use ($self) {
162
- if (empty($self->postload['wp_main_query'])) {
163
- return; // Nothing to do in this case.
164
- }
165
- if ($self->is_wp_loaded_query || is_admin()) {
166
- return; // Nothing to do.
167
- }
168
- if (!is_main_query()) {
169
- return; // Not main query.
170
- }
171
- $self->is_wp_loaded_query = true;
172
- $self->is_404 = is_404();
173
- $self->is_user_logged_in = is_user_logged_in();
174
- $self->content_url = rtrim(content_url(), '/');
175
- $self->is_maintenance = $self->functionIsPossible('is_maintenance') && is_maintenance();
176
- $_self = $self; // Reference for the closure below.
177
-
178
- add_action(
179
- 'template_redirect',
180
- function () use ($_self) {
181
- $_self->is_a_wp_content_type = $_self->is_404 || $_self->is_maintenance
182
- || is_front_page() // See <https://core.trac.wordpress.org/ticket/21602#comment:7>
183
- || is_home() || is_singular() || is_archive() || is_post_type_archive() || is_tax() || is_search() || is_feed();
184
- },
185
- 11
186
- );
187
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Ac/ShutdownUtils.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Registers a shutdown flag.
6
- *
7
- * @since 140605 Improving output buffer.
8
- *
9
- * @note In `/wp-settings.php`, Comet Cache is loaded before WP registers its own shutdown function.
10
- * Therefore, this flag is set before {@link shutdown_action_hook()} fires, and thus before {@link wp_ob_end_flush_all()}.
11
- *
12
- * @see http://www.php.net/manual/en/function.register-shutdown-function.php
13
- */
14
- $self->registerShutdownFlag = function () use ($self) {
15
- register_shutdown_function(function () {
16
- $GLOBALS[GLOBAL_NS.'_shutdown_flag'] = -1;
17
- });
18
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/ActionUtils.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Plugin action handler.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `wp_loaded` hook.
10
- */
11
- $self->actions = function () use ($self) {
12
- if (!empty($_REQUEST[GLOBAL_NS])) {
13
- new Actions();
14
- }
15
-
16
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/BbPressUtils.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Is bbPress active?
6
- *
7
- * @since 150821 Improving bbPress support.
8
- *
9
- * @return bool `TRUE` if bbPress is active.
10
- */
11
- $self->isBbPressActive = function () use ($self) {
12
- return class_exists('bbPress');
13
- };
14
-
15
- /*
16
- * bbPress post types.
17
- *
18
- * @since 150821 Improving bbPress support.
19
- *
20
- * @return array All bbPress post types.
21
- */
22
- $self->bbPressPostTypes = function () use ($self) {
23
- if (!$self->isBbPressActive()) {
24
- return array();
25
- }
26
- if (!is_null($types = &$self->cacheKey('bbPressPostTypes'))) {
27
- return $types; // Already did this.
28
- }
29
- $types = array(); // Initialize.
30
- $types[] = bbp_get_forum_post_type();
31
- $types[] = bbp_get_topic_post_type();
32
- $types[] = bbp_get_reply_post_type();
33
-
34
- return $types;
35
- };
36
-
37
- /*
38
- * bbPress post statuses.
39
- *
40
- * @since 150821 Improving bbPress support.
41
- *
42
- * @return array All bbPress post statuses.
43
- */
44
- $self->bbPressStatuses = function () use ($self) {
45
- if (!$self->isBbPressActive()) {
46
- return array();
47
- }
48
- if (!is_null($statuses = &$self->cacheKey('bbPressStatuses'))) {
49
- return $statuses; // Already did this.
50
- }
51
- $statuses = array(); // Initialize.
52
-
53
- foreach (get_post_stati(array(), 'objects') as $_key => $_status) {
54
- if (isset($_status->label_count['domain']) && $_status->label_count['domain'] === 'bbpress') {
55
- $statuses[] = $_status->name;
56
- }
57
- }
58
- unset($_key, $_status); // Housekeeping.
59
-
60
- return $statuses;
61
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/CleanupUtils.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Runs cleanup routine via CRON job.
6
- *
7
- * @since 151002 While working on directory stats.
8
- *
9
- * @attaches-to `'_cron_'.__GLOBAL_NS__.'_cleanup'`
10
- */
11
- $self->cleanupCache = function () use ($self) {
12
- if (!$self->options['enable']) {
13
- return; // Nothing to do.
14
- }
15
-
16
-
17
-
18
- $self->wurgeCache(); // Purge now.
19
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/CondUtils.php DELETED
@@ -1,13 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Is pro preview?
6
- *
7
- * @since 150511 Rewrite.
8
- *
9
- * @return bool `TRUE` if it's a pro preview.
10
- */
11
- $self->isProPreview = function () use ($self) {
12
- return !empty($_REQUEST[GLOBAL_NS.'_pro_preview']);
13
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/CronUtils.php DELETED
@@ -1,80 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Extends WP-Cron schedules.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `cron_schedules` filter.
10
- *
11
- * @param array $schedules An array of the current schedules.
12
- *
13
- * @return array Revised array of WP-Cron schedules.
14
- */
15
- $self->extendCronSchedules = function ($schedules) use ($self) {
16
- $schedules['every15m'] = array(
17
- 'interval' => 900,
18
- 'display' => __('Every 15 Minutes', 'comet-cache'),
19
- );
20
- return $schedules;
21
- };
22
-
23
- /*
24
- * Checks Cron setup, validates schedules, and reschedules events if necessary.
25
- *
26
- * @attaches-to `init` hook.
27
- *
28
- * @since 151220 Improving WP Cron setup and validation of schedules
29
- */
30
- $self->checkCronSetup = function () use ($self) {
31
- if ($self->options['crons_setup'] < 1439005906
32
- || $self->options['crons_setup_on_namespace'] !== __NAMESPACE__
33
- || $self->options['crons_setup_with_cache_cleanup_schedule'] !== $self->options['cache_cleanup_schedule']
34
- || $self->options['crons_setup_on_wp_with_schedules'] !== sha1(serialize(wp_get_schedules()))
35
- || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_cleanup')
36
-
37
- ) {
38
-
39
- wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
40
- wp_schedule_event(time() + 60, $self->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup');
41
-
42
-
43
-
44
- $self->updateOptions(
45
- array(
46
- 'crons_setup' => time(),
47
- 'crons_setup_on_namespace' => __NAMESPACE__,
48
- 'crons_setup_with_cache_cleanup_schedule' => $self->options['cache_cleanup_schedule'],
49
- 'crons_setup_on_wp_with_schedules' => sha1(serialize(wp_get_schedules()))
50
- )
51
- );
52
- }
53
- };
54
-
55
- /*
56
- * Resets `crons_setup` and clears WP-Cron schedules.
57
- *
58
- * @since 151220 Fixing bug with Auto-Cache Engine cron disappearing in some scenarios
59
- *
60
- * @note This MUST happen upon uninstall and deactivation due to buggy WP_Cron behavior. Events with a custom schedule will disappear when plugin is not active (see http://bit.ly/1lGdr78).
61
- */
62
- $self->resetCronSetup = function ( ) use ($self) {
63
- if (is_multisite()) { // Main site CRON jobs.
64
- switch_to_blog(get_current_site()->blog_id);
65
-
66
- wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
67
- restore_current_blog(); // Restore current blog.
68
- } else { // Standard WP installation.
69
-
70
- wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
71
- }
72
- $self->updateOptions(
73
- array( // Reset so that crons are rescheduled upon next activation
74
- 'crons_setup' => $self->default_options['crons_setup'],
75
- 'crons_setup_on_namespace' => $self->default_options['crons_setup_on_namespace'],
76
- 'crons_setup_with_cache_cleanup_schedule' => $self->default_options['crons_setup_with_cache_cleanup_schedule'],
77
- 'crons_setup_on_wp_with_schedules' => $self->default_options['crons_setup_on_wp_with_schedules']
78
- )
79
- );
80
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/DbUtils.php DELETED
@@ -1,13 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * WordPress database instance.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @return \wpdb Reference for IDEs.
10
- */
11
- $self->wpdb = function () use ($self) {
12
- return $GLOBALS['wpdb'];
13
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/DirUtils.php DELETED
@@ -1,79 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * This constructs an absolute server directory path (no trailing slashes);
6
- * which is always nested into {@link \WP_CONTENT_DIR} and the configured `base_dir` option value.
7
- *
8
- * @since 150422 Rewrite.
9
- *
10
- * @param string $rel_dir_file A sub-directory or file; relative location please.
11
- *
12
- * @throws \Exception If `base_dir` is empty when this method is called upon;
13
- * i.e. if you attempt to call upon this method before {@link setup()} runs.
14
- *
15
- * @return string The full absolute server path to `$rel_dir_file`.
16
- */
17
- $self->wpContentBaseDirTo = function ($rel_dir_file) use ($self) {
18
- $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B");
19
-
20
- if (empty($self->options['base_dir'])) {
21
- throw new \Exception(__('Missing `base_dir` option value.', 'comet-cache'));
22
- }
23
- $wp_content_base_dir_to = WP_CONTENT_DIR.'/'.$self->options['base_dir'];
24
-
25
- if (isset($rel_dir_file[0])) {
26
- $wp_content_base_dir_to .= '/'.$rel_dir_file;
27
- }
28
- return $wp_content_base_dir_to;
29
- };
30
-
31
- /*
32
- * This constructs a relative/base directory path (no leading/trailing slashes).
33
- * Always relative to {@link \WP_CONTENT_DIR}. Depends on the configured `base_dir` option value.
34
- *
35
- * @since 150422 Rewrite.
36
- *
37
- * @param string $rel_dir_file A sub-directory or file; relative location please.
38
- *
39
- * @throws \Exception If `base_dir` is empty when this method is called upon;
40
- * i.e. if you attempt to call upon this method before {@link setup()} runs.
41
- *
42
- * @return string The relative/base directory path to `$rel_dir_file`.
43
- */
44
- $self->basePathTo = function ($rel_dir_file) use ($self) {
45
- $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B");
46
-
47
- if (empty($self->options['base_dir'])) {
48
- throw new \Exception(__('Missing `base_dir` option value.', 'comet-cache'));
49
- }
50
- $base_path_to = $self->options['base_dir'];
51
-
52
- if (isset($rel_dir_file[0])) {
53
- $base_path_to .= '/'.$rel_dir_file;
54
- }
55
- return $base_path_to;
56
- };
57
-
58
- /**
59
- * Get the absolute filesystem path to the root of the WordPress installation
60
- *
61
- * Copied verbatim from get_home_path() in wp-admin/includes/file.php
62
- *
63
- * @since 151114 Adding `.htaccess` tweaks.
64
- *
65
- * @return string Full filesystem path to the root of the WordPress installation
66
- */
67
- $self->wpHomePath = function () use ($self) {
68
- $home = set_url_scheme( get_option( 'home' ), 'http' );
69
- $siteurl = set_url_scheme( get_option( 'siteurl' ), 'http' );
70
- if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) {
71
- $wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /* $siteurl - $home */
72
- $pos = strripos( str_replace( '\\', '/', $_SERVER['SCRIPT_FILENAME'] ), trailingslashit( $wp_path_rel_to_home ) );
73
- $home_path = substr( $_SERVER['SCRIPT_FILENAME'], 0, $pos );
74
- $home_path = trailingslashit( $home_path );
75
- } else {
76
- $home_path = ABSPATH;
77
- }
78
- return str_replace( '\\', '/', $home_path );
79
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/HtaccessUtils.php DELETED
@@ -1,273 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Unique comment marker.
6
- *
7
- * @since 151220 Enhancing `.htaccess` tweaks.
8
- *
9
- * @return string Used in `.htaccess` parsing.
10
- */
11
- $self->htaccess_marker = 'WmVuQ2FjaGU';
12
-
13
- /*
14
- * Plugin options that have associated htaccess rules.
15
- *
16
- * @since 160103 Improving `.htaccess` tweaks.
17
- *
18
- * @return array Plugin options that have associated htaccess rules
19
- *
20
- * @note We keep track of this to avoid the issue described here: http://git.io/vEFIH
21
- */
22
- $self->options_with_htaccess_rules = array('cdn_enable');
23
-
24
- /*
25
- * Add template blocks to `/.htaccess` file.
26
- *
27
- * @since 151114 Adding `.htaccess` tweaks.
28
- *
29
- * @return boolean True if added successfully.
30
- *
31
- * @TODO Improve error reporting detail to better catch unexpected failures; see http://git.io/vEFLT
32
- */
33
- $self->addWpHtaccess = function () use ($self) {
34
- global $is_apache;
35
-
36
- if (!$is_apache) {
37
- return false; // Not running the Apache web server.
38
- }
39
- if (!$self->options['enable']) {
40
- return true; // Nothing to do.
41
- }
42
- if (!$self->needHtaccessRules()) {
43
- if($self->findHtaccessMarker()) { // Do we need to clean up previously added rules?
44
- $self->removeWpHtaccess(); // Fail silently since we don't need rules in place.
45
- }
46
- return true; // Nothing to do; no options enabled that require htaccess rules.
47
- }
48
- if (!$self->removeWpHtaccess()) {
49
- return false; // Unable to remove.
50
- }
51
- if (!($htaccess = $self->readHtaccessFile())) {
52
- return false; // Failure; could not read file or invalid UTF8 encountered, file may be corrupt.
53
- }
54
-
55
- $template_blocks = ''; // Initialize.
56
- if (is_dir($templates_dir = dirname(dirname(dirname(__FILE__))).'/templates/htaccess')) {
57
- foreach (scandir($templates_dir) as $_template_file) {
58
- switch ($_template_file) {
59
-
60
- }
61
- }
62
- unset($_template_file); // Housekeeping.
63
- }
64
-
65
- if(empty($template_blocks)) { // Do we need to add anything to htaccess?
66
- $self->closeHtaccessFile($htaccess); // No need to write to htaccess file in this case.
67
- return true; // Nothing to do, but no failures either.
68
- }
69
-
70
- $template_header = '# BEGIN '.NAME.' '.$self->htaccess_marker.' (the '.$self->htaccess_marker.' marker is required for '.NAME.'; do not remove)'."\n";
71
- $template_footer = '# END '.NAME.' '.$self->htaccess_marker;
72
- $htaccess['file_contents'] = $template_header.trim($template_blocks)."\n".$template_footer."\n\n".$htaccess['file_contents'];
73
-
74
- if (!$self->writeHtaccessFile($htaccess, true)) {
75
- return false; // Failure; could not write changes.
76
- }
77
-
78
- return true; // Added successfully.
79
- };
80
-
81
- /*
82
- * Remove template blocks from `/.htaccess` file.
83
- *
84
- * @since 151114 Adding `.htaccess` tweaks.
85
- *
86
- * @return boolean True if removed successfully.
87
- *
88
- * @TODO Improve error reporting detail to better catch unexpected failures; see http://git.io/vEFLT
89
- */
90
- $self->removeWpHtaccess = function () use ($self) {
91
- global $is_apache;
92
-
93
- if (!$is_apache) {
94
- return false; // Not running the Apache web server.
95
- }
96
- if (!($htaccess_file = $self->findHtaccessFile())) {
97
- return true; // File does not exist.
98
- }
99
- if (!$self->findHtaccessMarker()) {
100
- return true; // Template blocks are already gone.
101
- }
102
- if (!($htaccess = $self->readHtaccessFile())) {
103
- return false; // Failure; could not read file, create file, or invalid UTF8 encountered, file may be corrupt.
104
- }
105
-
106
- $regex = '/#\s*BEGIN\s+'.preg_quote(NAME, '/').'\s+'.$self->htaccess_marker.'.*?#\s*END\s+'.preg_quote(NAME, '/').'\s+'.$self->htaccess_marker.'\s*/is';
107
- $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
108
-
109
- if (!$self->writeHtaccessFile($htaccess, false)) {
110
- return false; // Failure; could not write changes.
111
- }
112
-
113
- return true; // Removed successfully.
114
- };
115
-
116
- /*
117
- * Finds absolute server path to `/.htaccess` file.
118
- *
119
- * @since 151114 Adding `.htaccess` tweaks.
120
- *
121
- * @return string Absolute server path to `/.htaccess` file;
122
- * else an empty string if unable to locate the file.
123
- */
124
- $self->findHtaccessFile = function () use ($self) {
125
- $file = ''; // Initialize.
126
- $home_path = $self->wpHomePath();
127
-
128
- if (is_file($htaccess_file = $home_path.'.htaccess')) {
129
- $file = $htaccess_file;
130
- }
131
- return $file;
132
- };
133
-
134
- /*
135
- * Determines if there are any plugin options enabled that require htaccess rules to be added.
136
- *
137
- * @since 160103 Improving `.htaccess` tweaks.
138
- *
139
- * @return bool True when an option is enabled that requires htaccess rules, false otherwise.
140
- */
141
- $self->needHtaccessRules = function () use ($self) {
142
- if(!is_array($self->options_with_htaccess_rules)) {
143
- return false; // Nothing to do.
144
- }
145
- foreach ($self->options_with_htaccess_rules as $option) {
146
- if ($self->options[$option]) {
147
- return true; // Yes, there are options enabled that require htaccess rules.
148
- }
149
- }
150
- return false; // No, there are no options enabled that require htaccess rules.
151
- };
152
-
153
- /*
154
- * Utility method used to check if htaccess file contains $htaccess_marker
155
- *
156
- * @since 151114 Adding `.htaccess` tweaks.
157
- *
158
- * @param string $htaccess_marker Unique comment marker used to identify rules added by this plugin.
159
- *
160
- * @return bool False on failure or when marker does not exist in htaccess, true otherwise.
161
- */
162
- $self->findHtaccessMarker = function ($htaccess_marker = '') use ($self) {
163
- if (!($htaccess_file = $self->findHtaccessFile())) {
164
- return false; // File does not exist.
165
- }
166
- if (!is_readable($htaccess_file)) {
167
- return false; // Not possible.
168
- }
169
- if (($htaccess_file_contents = file_get_contents($htaccess_file)) === false) {
170
- return false; // Failure; could not read file.
171
- }
172
- if (empty($htaccess_marker)) {
173
- $htaccess_marker = $self->htaccess_marker;
174
- }
175
- if (stripos($htaccess_file_contents, $htaccess_marker) === false) {
176
- return false; // Htaccess marker is missing
177
- }
178
-
179
- return true; // Htaccess has the marker
180
- };
181
-
182
- /*
183
- * Gets contents of `/.htaccess` file with exclusive lock to read+write. If file doesn't exist, we attempt to create it.
184
- *
185
- * @since 151220 Improving `.htaccess` utils.
186
- *
187
- * @param string $htaccess_file Absolute path to the htaccess file. Optional.
188
- * If not provided, we attempt to find it or create it if it doesn't exist.
189
- *
190
- * @return array|bool Returns an array with data necessary to call $self->writeHtaccessFile():
191
- * `fp` a file pointer resource, `file_contents` a string. Returns `false` on failure.
192
- *
193
- * @note If a call to this method is not followed by a call to $self->writeHtaccessFile(),
194
- * you must make sure that you unlock and close the `fp` resource yourself.
195
- */
196
- $self->readHtaccessFile = function ($htaccess_file = '') use ($self) {
197
-
198
- if (empty($htaccess_file) && !($htaccess_file = $self->findHtaccessFile())) {
199
- if (!is_writable($self->wpHomePath()) || file_put_contents($htaccess_file = $self->wpHomePath().'.htaccess', '') === false) {
200
- return false; // Unable to find and/or create `.htaccess`.
201
- } // If it doesn't exist, we create the `.htaccess` file here.
202
- }
203
- if (!is_readable($htaccess_file) || !is_writable($htaccess_file) || (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)) {
204
- return false; // Not possible.
205
- }
206
- if (!($fp = fopen($htaccess_file, 'rb+')) || !flock($fp, LOCK_EX)) {
207
- fclose($fp); // Just in case we opened it before failing to obtain a lock.
208
- return false; // Failure; could not open file and obtain an exclusive lock.
209
- }
210
- if (($file_contents = fread($fp, filesize($htaccess_file))) && ($file_contents === wp_check_invalid_utf8($file_contents))) {
211
- rewind($fp); // Rewind pointer to beginning of file.
212
- return compact('fp', 'file_contents');
213
- } else { // Failure; could not read file or invalid UTF8 encountered, file may be corrupt.
214
- flock($fp, LOCK_UN);
215
- fclose($fp);
216
- return false;
217
- }
218
- };
219
-
220
- /*
221
- * Writes to `/.htaccess` file using provided file pointer.
222
- *
223
- * @since 151220 Improving `.htaccess` utils.
224
- *
225
- * @param array $htaccess Array containing `fp` file resource pointing to htaccess file and `file_contents` to write to file.
226
- * @param bool $require_marker Whether or not to require the marker be present in contents before writing.
227
- * @param string $htaccess_marker Unique comment marker used to identify rules added by this plugin.
228
- *
229
- * @return bool True on success, false on failure.
230
- */
231
- $self->writeHtaccessFile = function (array $htaccess, $require_marker = true, $htaccess_marker = '') use ($self) {
232
-
233
- if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
234
- return false; // Not possible.
235
- }
236
- if (!is_resource($htaccess['fp'])) {
237
- return false;
238
- }
239
- $htaccess_marker = $htaccess_marker ?: $self->htaccess_marker;
240
-
241
- $_have_marker = stripos($htaccess['file_contents'], $htaccess_marker);
242
-
243
- // Note: rewind() necessary here because we fread() above.
244
- if (($require_marker && $_have_marker === false) || !rewind($htaccess['fp']) || !ftruncate($htaccess['fp'], 0) || !fwrite($htaccess['fp'], $htaccess['file_contents'])) {
245
- flock($htaccess['fp'], LOCK_UN);
246
- fclose($htaccess['fp']);
247
- return false; // Failure; could not write changes.
248
- }
249
- fflush($htaccess['fp']);
250
- flock($htaccess['fp'], LOCK_UN);
251
- fclose($htaccess['fp']);
252
-
253
- return true;
254
- };
255
-
256
- /*
257
- * Utility method used to unlock and close htaccess file resource.
258
- *
259
- * @since 151114 Adding `.htaccess` tweaks.
260
- *
261
- * @param array $htaccess Array containing at least an `fp` file resource pointing to htaccess file.
262
- *
263
- * @return bool False on failure, true otherwise.
264
- */
265
- $self->closeHtaccessFile = function (array $htaccess) use ($self) {
266
- if (!is_resource($htaccess['fp'])) {
267
- return false; // Failure; requires a valid file resource.
268
- }
269
- flock($htaccess['fp'], LOCK_UN);
270
- fclose($htaccess['fp']);
271
-
272
- return true;
273
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/InstallUtils.php DELETED
@@ -1,535 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Plugin activation hook.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to {@link \register_activation_hook()}
10
- */
11
- $self->activate = function () use ($self) {
12
- $self->setup(); // Ensure setup is complete.
13
-
14
- if (!$self->options['welcomed'] && !$self->options['enable']) {
15
- $settings_url = add_query_arg(urlencode_deep(array('page' => GLOBAL_NS)), network_admin_url('/admin.php'));
16
- $self->enqueueMainNotice(sprintf(__('<strong>%1$s</strong> successfully installed! :-) <strong>Please <a href="%2$s">enable caching and review options</a>.</strong>', 'comet-cache'), esc_html(NAME), esc_attr($settings_url)), array('push_to_top' => true));
17
- $self->updateOptions(array('welcomed' => '1'));
18
- }
19
-
20
- if (!$self->options['enable']) {
21
- return; // Nothing to do.
22
- }
23
-
24
- $self->addWpCacheToWpConfig();
25
- $self->addWpHtaccess();
26
- $self->addAdvancedCache();
27
- $self->updateBlogPaths();
28
- $self->autoClearCache();
29
- };
30
-
31
- /*
32
- * Check current plugin version that is installed in WP.
33
- *
34
- * @since 150422 Rewrite.
35
- *
36
- * @attaches-to `admin_init` hook.
37
- */
38
- $self->checkVersion = function () use ($self) {
39
- $prev_version = $self->options['version'];
40
- if (version_compare($prev_version, VERSION, '>=')) {
41
- return; // Nothing to do; up-to-date.
42
- }
43
- $self->updateOptions(array('version' => VERSION));
44
-
45
- new VsUpgrades($prev_version);
46
-
47
- if ($self->options['enable']) {
48
- $self->addWpCacheToWpConfig();
49
- $self->addWpHtaccess();
50
- $self->addAdvancedCache();
51
- $self->updateBlogPaths();
52
- }
53
- $self->wipeCache(); // Fresh start now.
54
-
55
- $self->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)', 'comet-cache'), esc_html(NAME)), array('push_to_top' => true));
56
- };
57
-
58
- /*
59
- * Plugin deactivation hook.
60
- *
61
- * @since 150422 Rewrite.
62
- *
63
- * @attaches-to {@link \register_deactivation_hook()}
64
- */
65
- $self->deactivate = function () use ($self) {
66
- $self->setup(); // Ensure setup is complete.
67
-
68
- $self->removeWpCacheFromWpConfig();
69
- $self->removeWpHtaccess();
70
- $self->removeAdvancedCache();
71
- $self->clearCache();
72
- $self->resetCronSetup();
73
- };
74
-
75
- /*
76
- * Plugin uninstall hook.
77
- *
78
- * @since 150422 Rewrite.
79
- */
80
- $self->uninstall = function () use ($self) {
81
- $self->setup(); // Ensure setup is complete.
82
-
83
- if (!defined('WP_UNINSTALL_PLUGIN')) {
84
- return; // Disallow.
85
- }
86
- if (empty($GLOBALS[GLOBAL_NS.'_uninstalling'])) {
87
- return; // Not uninstalling.
88
- }
89
- if (!current_user_can($self->uninstall_cap)) {
90
- return; // Extra layer of security.
91
- }
92
- $self->removeWpCacheFromWpConfig();
93
- $self->removeWpHtaccess();
94
- $self->removeAdvancedCache();
95
- $self->wipeCache();
96
- $self->resetCronSetup();
97
-
98
- if (!$self->options['uninstall_on_deletion']) {
99
- return; // Nothing to do here.
100
- }
101
- $self->deleteAdvancedCache();
102
- $self->deleteBaseDir();
103
-
104
- $wpdb = $self->wpdb(); // WordPress DB.
105
- $like = '%'.$wpdb->esc_like(GLOBAL_NS).'%';
106
-
107
- if (is_multisite()) { // Site options for a network installation.
108
- $wpdb->query('DELETE FROM `'.esc_sql($wpdb->sitemeta).'` WHERE `meta_key` LIKE \''.esc_sql($like).'\'');
109
-
110
- switch_to_blog(get_current_site()->blog_id); // In case it started as a standard WP installation.
111
- $wpdb->query('DELETE FROM `'.esc_sql($wpdb->options).'` WHERE `option_name` LIKE \''.esc_sql($like).'\'');
112
- restore_current_blog(); // Restore current blog.
113
- //
114
- } else { // Standard WP installation.
115
- $wpdb->query('DELETE FROM `'.esc_sql($wpdb->options).'` WHERE `option_name` LIKE \''.esc_sql($like).'\'');
116
- }
117
- };
118
-
119
- /*
120
- * Adds `define('WP_CACHE', TRUE);` to the `/wp-config.php` file.
121
- *
122
- * @since 150422 Rewrite.
123
- *
124
- * @return string The new contents of the updated `/wp-config.php` file;
125
- * else an empty string if unable to add the `WP_CACHE` constant.
126
- */
127
- $self->addWpCacheToWpConfig = function () use ($self) {
128
- if (!$self->options['enable']) {
129
- return ''; // Nothing to do.
130
- }
131
- if (!($wp_config_file = $self->findWpConfigFile())) {
132
- return ''; // Unable to find `/wp-config.php`.
133
- }
134
- if (!is_readable($wp_config_file)) {
135
- return ''; // Not possible.
136
- }
137
- if (!($wp_config_file_contents = file_get_contents($wp_config_file))) {
138
- return ''; // Failure; could not read file.
139
- }
140
- if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
141
- return ''; // Failure; file empty
142
- }
143
- if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[1-9][0-9\.]*|TRUE|([\'"])(?:[^0\'"]|[^\'"]{2,})\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace)) {
144
- return $wp_config_file_contents; // It's already in there; no need to modify this file.
145
- }
146
- if (!($wp_config_file_contents = $self->removeWpCacheFromWpConfig())) {
147
- return ''; // Unable to remove previous value.
148
- }
149
- if (!($wp_config_file_contents = preg_replace('/^\s*(\<\?php|\<\?)\s+/i', '${1}'."\n"."define('WP_CACHE', TRUE);"."\n", $wp_config_file_contents, 1))) {
150
- return ''; // Failure; something went terribly wrong here.
151
- }
152
- if (strpos($wp_config_file_contents, "define('WP_CACHE', TRUE);") === false) {
153
- return ''; // Failure; unable to add; unexpected PHP code.
154
- }
155
- if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
156
- return ''; // We may NOT edit any files.
157
- }
158
- if (!is_writable($wp_config_file)) {
159
- return ''; // Not possible.
160
- }
161
- if (!file_put_contents($wp_config_file, $wp_config_file_contents)) {
162
- return ''; // Failure; could not write changes.
163
- }
164
- return $wp_config_file_contents;
165
- };
166
-
167
- /*
168
- * Removes `define('WP_CACHE', TRUE);` from the `/wp-config.php` file.
169
- *
170
- * @since 150422 Rewrite.
171
- *
172
- * @return string The new contents of the updated `/wp-config.php` file;
173
- * else an empty string if unable to remove the `WP_CACHE` constant.
174
- */
175
- $self->removeWpCacheFromWpConfig = function () use ($self) {
176
- if (!($wp_config_file = $self->findWpConfigFile())) {
177
- return ''; // Unable to find `/wp-config.php`.
178
- }
179
- if (!is_readable($wp_config_file)) {
180
- return ''; // Not possible.
181
- }
182
- if (!($wp_config_file_contents = file_get_contents($wp_config_file))) {
183
- return ''; // Failure; could not read file.
184
- }
185
- if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
186
- return ''; // Failure; file empty
187
- }
188
- if (!preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents_no_whitespace)) {
189
- return $wp_config_file_contents; // Already gone.
190
- }
191
- if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:0|FALSE|NULL|([\'"])0?\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace) && !is_writable($wp_config_file)) {
192
- return $wp_config_file_contents; // It's already disabled, and since we can't write to this file let's let this slide.
193
- }
194
- if (!($wp_config_file_contents = preg_replace('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[0-9\.]+|TRUE|FALSE|NULL|([\'"])[^\'"]*\\2)\s*\)\s*;/i', '', $wp_config_file_contents))) {
195
- return ''; // Failure; something went terribly wrong here.
196
- }
197
- if (preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents)) {
198
- return ''; // Failure; perhaps the `/wp-config.php` file contains syntax we cannot remove safely.
199
- }
200
- if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
201
- return ''; // We may NOT edit any files.
202
- }
203
- if (!is_writable($wp_config_file)) {
204
- return ''; // Not possible.
205
- }
206
- if (!file_put_contents($wp_config_file, $wp_config_file_contents)) {
207
- return ''; // Failure; could not write changes.
208
- }
209
- return $wp_config_file_contents;
210
- };
211
-
212
- /*
213
- * Checks to make sure the `advanced-cache.php` file still exists;
214
- * and if it doesn't, the `advanced-cache.php` is regenerated automatically.
215
- *
216
- * @since 150422 Rewrite.
217
- *
218
- * @attaches-to `init` hook.
219
- *
220
- * @note This runs so that remote deployments which completely wipe out an
221
- * existing set of website files (like the AWS Elastic Beanstalk does) will NOT cause Comet Cache
222
- * to stop functioning due to the lack of an `advanced-cache.php` file, which is generated by Comet Cache.
223
- *
224
- * For instance, if you have a Git repo with all of your site files; when you push those files
225
- * to your website to deploy them, you most likely do NOT have the `advanced-cache.php` file.
226
- * Comet Cache creates this file on its own. Thus, if it's missing (and CC is active)
227
- * we simply regenerate the file automatically to keep Comet Cache running.
228
- */
229
- $self->checkAdvancedCache = function () use ($self) {
230
- if (!$self->options['enable']) {
231
- return; // Nothing to do.
232
- }
233
- if (!empty($_REQUEST[GLOBAL_NS])) {
234
- return; // Skip on plugin actions.
235
- }
236
- $cache_dir = $self->cacheDir();
237
- $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
238
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
239
-
240
- // Fixes zero-byte advanced-cache.php bug related to migrating from ZenCache
241
- // See: <https://github.com/websharks/zencache/issues/432>
242
-
243
- // Also fixes a missing `define('WP_CACHE', TRUE)` bug related to migrating from ZenCache
244
- // See <https://github.com/websharks/zencache/issues/450>
245
-
246
- if (!is_file($advanced_cache_check_file) || !is_file($advanced_cache_file) || filesize($advanced_cache_file) === 0) {
247
- $self->addAdvancedCache();
248
- $self->addWpCacheToWpConfig();
249
- }
250
- };
251
-
252
- /*
253
- * Creates and adds the `advanced-cache.php` file.
254
- *
255
- * @since 150422 Rewrite.
256
- *
257
- * @return bool|null `TRUE` on success. `FALSE` or `NULL` on failure.
258
- * A special `NULL` return value indicates success with a single failure
259
- * that is specifically related to the `[SHORT_NAME]-advanced-cache` file.
260
- */
261
- $self->addAdvancedCache = function () use ($self) {
262
- if (!$self->removeAdvancedCache()) {
263
- return false; // Still exists.
264
- }
265
- $cache_dir = $self->cacheDir();
266
- $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
267
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
268
- $advanced_cache_template = dirname(dirname(dirname(__FILE__))).'/templates/advanced-cache.txt';
269
-
270
- if (is_file($advanced_cache_file) && !is_writable($advanced_cache_file)) {
271
- return false; // Not possible to create.
272
- }
273
- if (!is_file($advanced_cache_file) && !is_writable(dirname($advanced_cache_file))) {
274
- return false; // Not possible to create.
275
- }
276
- if (!is_file($advanced_cache_template) || !is_readable($advanced_cache_template)) {
277
- return false; // Template file is missing; or not readable.
278
- }
279
- if (!($advanced_cache_contents = file_get_contents($advanced_cache_template))) {
280
- return false; // Template file is missing; or is not readable.
281
- }
282
- $possible_advanced_cache_constant_key_values = array_merge(
283
- $self->options, // The following additional keys are dynamic.
284
- array('cache_dir' => $self->basePathTo($self->cache_sub_dir),
285
-
286
- )
287
- );
288
- if ($self->applyWpFilters(GLOBAL_NS.'_exclude_uris_client_side_too', true)) {
289
- $possible_advanced_cache_constant_key_values['exclude_client_side_uris'] .= "\n".$self->options['exclude_uris'];
290
- }
291
- foreach ($possible_advanced_cache_constant_key_values as $_option => $_value) {
292
- $_value = (string) $_value; // Force string.
293
-
294
- switch ($_option) {
295
- case 'exclude_uris': // Converts to regex (caSe insensitive).
296
- case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
297
- case 'exclude_refs': // Converts to regex (caSe insensitive).
298
- case 'exclude_agents': // Converts to regex (caSe insensitive).
299
-
300
-
301
-
302
- $_value = "'".$self->escSq($self->lineDelimitedPatternsToRegex($_value))."'";
303
-
304
- break; // Break switch handler.
305
-
306
-
307
-
308
- default: // Default case handler.
309
-
310
- $_value = "'".$self->escSq($_value)."'";
311
-
312
- break; // Break switch handler.
313
- }
314
- $advanced_cache_contents = // Fill replacement codes.
315
- str_ireplace(
316
- array(
317
- "'%%".GLOBAL_NS.'_'.$_option."%%'",
318
- "'%%".GLOBAL_NS.'_'.preg_replace('/^cache_/i', '', $_option)."%%'",
319
- ),
320
- $_value,
321
- $advanced_cache_contents
322
- );
323
- }
324
- unset($_option, $_value, $_values, $_response); // Housekeeping.
325
-
326
- if (strpos(PLUGIN_FILE, WP_CONTENT_DIR) === 0) {
327
- $plugin_file = "WP_CONTENT_DIR.'".$self->escSq(str_replace(WP_CONTENT_DIR, '', PLUGIN_FILE))."'";
328
- } else {
329
- $plugin_file = "'".$self->escSq(PLUGIN_FILE)."'"; // Full absolute path.
330
- }
331
- // Make it possible for the `advanced-cache.php` handler to find the plugin directory reliably.
332
- $advanced_cache_contents = str_ireplace("'%%".GLOBAL_NS."_PLUGIN_FILE%%'", $plugin_file, $advanced_cache_contents);
333
-
334
- // Ignore; this is created by Comet Cache; and we don't need to obey in this case.
335
- #if(defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)
336
- # return FALSE; // We may NOT edit any files.
337
-
338
- if (!file_put_contents($advanced_cache_file, $advanced_cache_contents)) {
339
- return false; // Failure; could not write file.
340
- }
341
- $cache_lock = $self->cacheLock(); // Lock cache.
342
-
343
- if (!is_dir($cache_dir)) {
344
- mkdir($cache_dir, 0775, true);
345
- }
346
- if (is_writable($cache_dir) && !is_file($cache_dir.'/.htaccess')) {
347
- file_put_contents($cache_dir.'/.htaccess', $self->htaccess_deny);
348
- }
349
- if (!is_dir($cache_dir) || !is_writable($cache_dir) || !is_file($cache_dir.'/.htaccess') || !file_put_contents($advanced_cache_check_file, time())) {
350
- $self->cacheUnlock($cache_lock); // Release.
351
- return; // Special return value (NULL).
352
- }
353
- $self->cacheUnlock($cache_lock); // Release.
354
-
355
- $self->clearAcDropinFromOpcacheByForce();
356
-
357
- return true;
358
- };
359
-
360
- /*
361
- * Removes the `advanced-cache.php` file.
362
- *
363
- * @since 150422 Rewrite.
364
- *
365
- * @return bool `TRUE` on success. `FALSE` on failure.
366
- *
367
- * @note The `advanced-cache.php` file is NOT actually deleted by this routine.
368
- * Instead of deleting the file, we simply empty it out so that it's `0` bytes in size.
369
- *
370
- * The reason for this is to preserve any file permissions set by the site owner.
371
- * If the site owner previously allowed this specific file to become writable, we don't want to
372
- * lose that permission by deleting the file; forcing the site owner to do it all over again later.
373
- *
374
- * An example of where this is useful is when a site owner deactivates the CC plugin,
375
- * but later they decide that CC really is the most awesome plugin in the world and they turn it back on.
376
- */
377
- $self->removeAdvancedCache = function () use ($self) {
378
- $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
379
-
380
- if (!is_file($advanced_cache_file)) {
381
- return true; // Already gone.
382
- }
383
- if (is_readable($advanced_cache_file) && filesize($advanced_cache_file) === 0) {
384
- return true; // Already gone; i.e. it's empty already.
385
- }
386
- if (!is_writable($advanced_cache_file)) {
387
- return false; // Not possible.
388
- }
389
- /* Empty the file only. This way permissions are NOT lost in cases where
390
- a site owner makes this specific file writable for Comet Cache. */
391
- if (file_put_contents($advanced_cache_file, '') !== 0) {
392
- return false; // Failure.
393
- }
394
- $self->clearAcDropinFromOpcacheByForce();
395
-
396
- return true;
397
- };
398
-
399
- /*
400
- * Deletes the `advanced-cache.php` file.
401
- *
402
- * @since 150422 Rewrite.
403
- *
404
- * @return bool `TRUE` on success. `FALSE` on failure.
405
- *
406
- * @note The `advanced-cache.php` file is deleted by this routine.
407
- */
408
- $self->deleteAdvancedCache = function () use ($self) {
409
- $cache_dir = $self->cacheDir();
410
- $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
411
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
412
-
413
- if (is_file($advanced_cache_file)) {
414
- if (!is_writable($advanced_cache_file) || !unlink($advanced_cache_file)) {
415
- return false; // Not possible; or outright failure.
416
- }
417
- }
418
- if (is_file($advanced_cache_check_file)) {
419
- if (!is_writable($advanced_cache_check_file) || !unlink($advanced_cache_check_file)) {
420
- return false; // Not possible; or outright failure.
421
- }
422
- }
423
- $self->clearAcDropinFromOpcacheByForce();
424
-
425
- return true; // Deletion success.
426
- };
427
-
428
- /*
429
- * Checks to make sure the `[SHORT_NAME]-blog-paths` file still exists;
430
- * and if it doesn't, the `[SHORT_NAME]-blog-paths` file is regenerated automatically.
431
- *
432
- * @since 150422 Rewrite.
433
- *
434
- * @attaches-to `init` hook.
435
- *
436
- * @note This runs so that remote deployments which completely wipe out an
437
- * existing set of website files (like the AWS Elastic Beanstalk does) will NOT cause Comet Cache
438
- * to stop functioning due to the lack of a `[SHORT_NAME]-blog-paths` file, which is generated by Comet Cache.
439
- *
440
- * For instance, if you have a Git repo with all of your site files; when you push those files
441
- * to your website to deploy them, you most likely do NOT have the `[SHORT_NAME]-blog-paths` file.
442
- * Comet Cache creates this file on its own. Thus, if it's missing (and CC is active)
443
- * we simply regenerate the file automatically to keep Comet Cache running.
444
- */
445
- $self->checkBlogPaths = function () use ($self) {
446
- if (!$self->options['enable']) {
447
- return; // Nothing to do.
448
- }
449
- if (!is_multisite()) {
450
- return; // N/A.
451
- }
452
- if (!empty($_REQUEST[GLOBAL_NS])) {
453
- return; // Skip on plugin actions.
454
- }
455
- $cache_dir = $self->cacheDir();
456
- $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
457
-
458
- if (!is_file($blog_paths_file)) {
459
- $self->updateBlogPaths();
460
- }
461
- };
462
-
463
- /*
464
- * Creates and/or updates the `[SHORT_NAME]-blog-paths` file.
465
- *
466
- * @since 150422 Rewrite.
467
- *
468
- * @attaches-to `enable_live_network_counts` filter.
469
- *
470
- * @param mixed $enable_live_network_counts Optional, defaults to a `NULL` value.
471
- *
472
- * @return mixed The value of `$enable_live_network_counts` (passes through).
473
- *
474
- * @note While this routine is attached to a WP filter, we also call upon it directly at times.
475
- */
476
- $self->updateBlogPaths = function ($enable_live_network_counts = null) use ($self) {
477
- $value = $enable_live_network_counts; // This hook actually rides on a filter.
478
-
479
- if (!$self->options['enable']) {
480
- return $value; // Nothing to do.
481
- }
482
- if (!is_multisite()) {
483
- return $value; // N/A.
484
- }
485
- $cache_dir = $self->cacheDir();
486
- $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
487
-
488
- $cache_lock = $self->cacheLock();
489
-
490
- if (!is_dir($cache_dir)) {
491
- mkdir($cache_dir, 0775, true);
492
- }
493
- if (is_writable($cache_dir) && !is_file($cache_dir.'/.htaccess')) {
494
- file_put_contents($cache_dir.'/.htaccess', $self->htaccess_deny);
495
- }
496
- if (is_dir($cache_dir) && is_writable($cache_dir)) {
497
- $paths = // Collect child `[/base]/path/`s from the WordPress database.
498
- $self->wpdb()->get_col('SELECT `path` FROM `'.esc_sql($self->wpdb()->blogs)."` WHERE `deleted` <= '0'");
499
-
500
- $host_base_token = $self->hostBaseToken(); // Pull this once only.
501
-
502
- foreach ($paths as $_key => &$_path) {
503
- if ($_path && $_path !== '/' && $host_base_token && $host_base_token !== '/') {
504
- // Note that each `path` in the DB looks like: `[/base]/path/` (i.e., it includes base).
505
- $_path = '/'.ltrim(preg_replace('/^'.preg_quote($host_base_token, '/').'/', '', $_path), '/');
506
- }
507
- if (!$_path || $_path === '/') {
508
- unset($paths[$_key]); // Exclude main site.
509
- }
510
- }
511
- unset($_key, $_path); // Housekeeping.
512
-
513
- file_put_contents($blog_paths_file, serialize($paths));
514
- }
515
- $self->cacheUnlock($cache_lock); // Release.
516
-
517
- return $value; // Pass through untouched (always).
518
- };
519
-
520
- /*
521
- * Deletes base directory.
522
- *
523
- * @since 151002 Improving multisite compat.
524
- *
525
- * @return int Total files removed by this routine (if any).
526
- */
527
- $self->deleteBaseDir = function () use ($self) {
528
- $counter = 0; // Initialize.
529
-
530
- @set_time_limit(1800); // @TODO Display a warning.
531
-
532
- $counter += $self->deleteAllFilesDirsIn($self->wpContentBaseDirTo(''), true);
533
-
534
- return $counter;
535
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/MenuPageUtils.php DELETED
@@ -1,219 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Adds CSS for administrative menu pages.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `admin_enqueue_scripts` hook.
10
- */
11
- $self->enqueueAdminStyles = function () use ($self) {
12
- if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
13
- return; // NOT a plugin page in the administrative area.
14
- }
15
- $deps = array(); // Plugin dependencies.
16
-
17
- wp_enqueue_style(GLOBAL_NS, $self->url('/src/client-s/css/menu-pages.min.css'), $deps, VERSION, 'all');
18
- };
19
-
20
- /*
21
- * Adds JS for administrative menu pages.
22
- *
23
- * @since 150422 Rewrite.
24
- *
25
- * @attaches-to `admin_enqueue_scripts` hook.
26
- */
27
- $self->enqueueAdminScripts = function () use ($self) {
28
- if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
29
- return; // NOT a plugin page in the administrative area.
30
- }
31
- $deps = array('jquery', 'chartjs'); // Plugin dependencies.
32
-
33
- wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), array(), null, true);
34
- wp_enqueue_script(GLOBAL_NS, $self->url('/src/client-s/js/menu-pages.min.js'), $deps, VERSION, true);
35
- wp_localize_script(GLOBAL_NS, GLOBAL_NS.'_menu_page_vars', array(
36
- '_wpnonce' => wp_create_nonce(),
37
- 'isMultisite' => is_multisite(), // Network?
38
- 'currentUserHasCap' => current_user_can($self->cap),
39
- 'currentUserHasNetworkCap' => current_user_can($self->network_cap),
40
- 'htmlCompressorEnabled' => (boolean) $self->options['htmlc_enable'],
41
- 'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
42
- 'emptyStatsCountsImageUrl' => $self->url('/src/client-s/images/stats-fc-empty.png'),
43
- 'emptyStatsFilesImageUrl' => $self->url('/src/client-s/images/stats-fs-empty.png'),
44
- 'i18n' => array(
45
- 'name' => NAME,
46
- 'perSymbol' => __('%', 'comet-cache'),
47
- 'file' => __('file', 'comet-cache'),
48
- 'files' => __('files', 'comet-cache'),
49
- 'pageCache' => __('Page Cache', 'comet-cache'),
50
- 'htmlCompressor' => __('HTML Compressor', 'comet-cache'),
51
- 'currentTotal' => __('Current Total', 'comet-cache'),
52
- 'currentSite' => __('Current Site', 'comet-cache'),
53
- 'xDayHigh' => __('%s Day High', 'comet-cache'),
54
- ),
55
- ));
56
- };
57
-
58
- /*
59
- * Creates network admin menu pages.
60
- *
61
- * @since 150422 Rewrite.
62
- *
63
- * @attaches-to `network_admin_menu` hook.
64
- */
65
- $self->addNetworkMenuPages = function () use ($self) {
66
- if (!is_multisite()) {
67
- return; // Not applicable.
68
- }
69
- $icon = file_get_contents(dirname(dirname(dirname(dirname(__FILE__)))).'/client-s/images/inline-icon.svg');
70
- $icon = 'data:image/svg+xml;base64,'.base64_encode($self->colorSvgMenuIcon($icon));
71
-
72
- add_menu_page(NAME . (IS_PRO ? ' Pro' : ''), NAME . (IS_PRO ? ' Pro' : ''), $self->network_cap, GLOBAL_NS, array($self, 'menuPageOptions'), $icon);
73
- add_submenu_page(GLOBAL_NS, __('Plugin Options', 'comet-cache'), __('Plugin Options', 'comet-cache'), $self->network_cap, GLOBAL_NS, array($self, 'menuPageOptions'));
74
-
75
-
76
-
77
-
78
- };
79
-
80
- /*
81
- * Creates admin menu pages.
82
- *
83
- * @since 150422 Rewrite.
84
- *
85
- * @attaches-to `admin_menu` hook.
86
- */
87
- $self->addMenuPages = function () use ($self) {
88
- if (is_multisite()) {
89
- return; // Multisite networks MUST use network admin area.
90
- }
91
- $icon = file_get_contents(dirname(dirname(dirname(dirname(__FILE__)))).'/client-s/images/inline-icon.svg');
92
- $icon = 'data:image/svg+xml;base64,'.base64_encode($self->colorSvgMenuIcon($icon));
93
-
94
- add_menu_page(NAME . (IS_PRO ? ' Pro' : ''), NAME . (IS_PRO ? ' Pro' : ''), $self->cap, GLOBAL_NS, array($self, 'menuPageOptions'), $icon);
95
- add_submenu_page(GLOBAL_NS, __('Plugin Options', 'comet-cache'), __('Plugin Options', 'comet-cache'), $self->cap, GLOBAL_NS, array($self, 'menuPageOptions'));
96
-
97
-
98
-
99
-
100
- };
101
-
102
- /*
103
- * Adds link(s) to Comet Cache row on the WP plugins page.
104
- *
105
- * @since 150422 Rewrite.
106
- *
107
- * @attaches-to `plugin_action_links_'.plugin_basename(PLUGIN_FILE)` filter.
108
- *
109
- * @param array $links An array of the existing links provided by WordPress.
110
- *
111
- * @return array Revised array of links.
112
- */
113
- $self->addSettingsLink = function ($links) use ($self) {
114
- if (is_multisite() && !is_network_admin()) {
115
- return $links;
116
- }
117
-
118
- $links[] = '<a href="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS)), self_admin_url('/admin.php'))).'">'.__('Settings', 'comet-cache').'</a>';
119
- if (!IS_PRO) {
120
- $links[] = '<br/><a href="'.esc_attr(add_query_arg(urlencode_deep(array('page' => GLOBAL_NS, GLOBAL_NS.'_pro_preview' => '1')), self_admin_url('/admin.php'))).'">'.__('Preview Pro Features', 'comet-cache').'</a>';
121
- $links[] = '<a href="'.esc_attr('http://cometcache.com/prices/').'" target="_blank">'.__('Upgrade', 'comet-cache').'</a>';
122
- }
123
- return $links;
124
- };
125
-
126
- /*
127
- * Fills menu page inline SVG icon color.
128
- *
129
- * @since 150422 Rewrite.
130
- *
131
- * @param string $svg Inline SVG icon markup.
132
- *
133
- * @return string Inline SVG icon markup.
134
- */
135
- $self->colorSvgMenuIcon = function ($svg) use ($self) {
136
- if (!($color = get_user_option('admin_color'))) {
137
- $color = 'fresh'; // Default color scheme.
138
- }
139
- if (empty($self->wp_admin_icon_colors[$color])) {
140
- return $svg; // Not possible.
141
- }
142
- $icon_colors = $self->wp_admin_icon_colors[$color];
143
- $use_icon_fill_color = $icon_colors['base']; // Default base.
144
-
145
- $current_pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
146
- $current_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
147
-
148
- if (strpos($current_pagenow, GLOBAL_NS) === 0 || strpos($current_page, GLOBAL_NS) === 0) {
149
- $use_icon_fill_color = $icon_colors['current'];
150
- }
151
- return str_replace(' fill="currentColor"', ' fill="'.esc_attr($use_icon_fill_color).'"', $svg);
152
- };
153
-
154
- /*
155
- * Loads the admin menu page options.
156
- *
157
- * @since 150422 Rewrite.
158
- */
159
- $self->menuPageOptions = function () use ($self) {
160
- new MenuPage('options');
161
- };
162
-
163
-
164
-
165
-
166
-
167
- /*
168
- * WordPress admin icon color schemes.
169
- *
170
- * @since 150422 Rewrite.
171
- *
172
- * @type array WP admin icon colors.
173
- *
174
- * @note These must be hard-coded, because they don't become available
175
- * in core until `admin_init`; i.e., too late for `admin_menu`.
176
- */
177
- $self->wp_admin_icon_colors = array(
178
- 'fresh' => array('base' => '#999999', 'focus' => '#2EA2CC', 'current' => '#FFFFFF'),
179
- 'light' => array('base' => '#999999', 'focus' => '#CCCCCC', 'current' => '#CCCCCC'),
180
- 'blue' => array('base' => '#E5F8FF', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
181
- 'midnight' => array('base' => '#F1F2F3', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
182
- 'sunrise' => array('base' => '#F3F1F1', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
183
- 'ectoplasm' => array('base' => '#ECE6F6', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
184
- 'ocean' => array('base' => '#F2FCFF', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
185
- 'coffee' => array('base' => '#F3F2F1', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'),
186
- );
187
-
188
- /*
189
- * On a specific menu page?
190
- *
191
- * @since 151002 Improving multisite compat.
192
- *
193
- * @param string $which Which page to check; may contain wildcards.
194
- *
195
- * @return boolean True if is the menu page.
196
- */
197
- $self->isMenuPage = function ($which) use ($self) {
198
- if (!($which = trim((string) $which))) {
199
- return false; // Empty.
200
- }
201
- if (!is_admin()) {
202
- return false;
203
- }
204
- $page = $pagenow = ''; // Initialize.
205
-
206
- if (!empty($_REQUEST['page'])) {
207
- $page = (string) $_REQUEST['page'];
208
- }
209
- if (!empty($GLOBALS['pagenow'])) {
210
- $pagenow = (string) $GLOBALS['pagenow'];
211
- }
212
- if ($page && fnmatch($which, $page, FNM_CASEFOLD)) {
213
- return true; // Wildcard match.
214
- }
215
- if ($pagenow && fnmatch($which, $pagenow, FNM_CASEFOLD)) {
216
- return true; // Wildcard match.
217
- }
218
- return false; // Nope.
219
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/NoticeUtils.php DELETED
@@ -1,296 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Notice queue handlers.
6
- */
7
-
8
- /*
9
- * Enqueue an administrative notice.
10
- *
11
- * @since 150422 Rewrite. Improved 151002.
12
- *
13
- * @param string $notice HTML markup containing the notice itself.
14
- * @param string $args Any additional arguments supported by the notice API in this plugin.
15
- * @param integer $blog_id Optional. Defaults to the current blog ID. Use any value `< 0` to indicate the main site.
16
- *
17
- * @return string A unique key generated for this notice.
18
- */
19
- $self->enqueueNotice = function ($notice, array $args = array(), $blog_id = 0) use ($self) {
20
- $notice = trim((string) $notice);
21
- $blog_id = (integer) $blog_id;
22
-
23
- if (!$notice) {
24
- return; // Nothing to do.
25
- }
26
- $notice = array('notice' => $notice);
27
- $notice = $self->normalizeNotice($notice, $args);
28
- $key = sha1(serialize($notice)); // Prevent dupes.
29
-
30
- $notices = $self->getNotices($blog_id);
31
-
32
- if ($notice['push_to_top']) {
33
- $notices = array($key => $notice) + $notices;
34
- } else {
35
- $notices[$key] = $notice; // Default behavior.
36
- }
37
- $self->updateNotices($notices, $blog_id);
38
-
39
- return $key; // For dismissals.
40
- };
41
-
42
- /*
43
- * Dismiss an administrative notice.
44
- *
45
- * @since 151002 Improving multisite compat.
46
- *
47
- * @param string $key_to_dismiss A unique key which identifies a particular notice.
48
- * Or, a persistent key which identifies one or more persistent notices.
49
- *
50
- * @param integer $blog_id The blog ID from which to dismiss the notice.
51
- *
52
- * @return array All remaining notices.
53
- */
54
- $self->dismissNotice = function ($key_to_dismiss, $blog_id = 0) use ($self) {
55
- $key_to_dismiss = trim((string) $key_to_dismiss);
56
- $blog_id = (integer) $blog_id; // For multisite compat.
57
- $notices = $enqueued_notices = $self->getNotices($blog_id);
58
-
59
- if (!$key_to_dismiss) {
60
- return $notices; // Nothing to do.
61
- }
62
- foreach ($notices as $_key => $_notice) {
63
- if ($_key === $key_to_dismiss) {
64
- unset($notices[$_key]); // A specific key.
65
- } elseif ($_notice['persistent_key'] === $key_to_dismiss) {
66
- unset($notices[$_key]); // All matching keys.
67
- }
68
- } // ↑ Dismisses all matching keys.
69
- unset($_key, $_notice); // Housekeeping.
70
-
71
- if ($notices !== $enqueued_notices) { // Something changed?
72
- $self->updateNotices($notices, $blog_id); // Update.
73
- }
74
- return $notices; // All remaining notices.
75
- };
76
-
77
- /*
78
- * Enqueue an administrative error notice.
79
- *
80
- * @since 150422 Rewrite. Improved 151002.
81
- */
82
- $self->enqueueError = function ($notice, array $args = array(), $blog_id = 0) use ($self) {
83
- return $self->enqueueNotice($notice, array_merge($args, array('class' => 'error')), $blog_id);
84
- };
85
-
86
- /*
87
- * Enqueue an administrative notice (main site).
88
- *
89
- * @since 151002. Improving multisite compat.
90
- */
91
- $self->enqueueMainNotice = function ($notice, array $args = array()) use ($self) {
92
- return $self->enqueueNotice($notice, $args, -1);
93
- };
94
-
95
- /*
96
- * Enqueue an administrative error notice (main site).
97
- *
98
- * @since 151002. Improving multisite compat.
99
- */
100
- $self->enqueueMainError = function ($notice, array $args = array()) use ($self) {
101
- return $self->enqueueNotice($notice, array_merge($args, array('class' => 'error')), -1);
102
- };
103
-
104
- /*
105
- * Dismiss an administrative notice (main site).
106
- *
107
- * @since 151002 Improving multisite compat.
108
- */
109
- $self->dismissMainNotice = function ($key_to_dismiss) use ($self) {
110
- return $self->dismissNotice($key_to_dismiss, -1);
111
- };
112
-
113
- /*
114
- * Notice display handler.
115
- */
116
-
117
- /*
118
- * Render admin notices.
119
- *
120
- * @since 150422 Rewrite. Improved 151002.
121
- *
122
- * @attaches-to `all_admin_notices` hook.
123
- */
124
- $self->allAdminNotices = function () use ($self) {
125
- $notices = $enqueued_notices = $self->getNotices();
126
-
127
- foreach ($notices as $_key => $_notice) {
128
- # Always dismiss all non-persistent transients.
129
-
130
- if ($_notice['is_transient'] && !$_notice['persistent_key']) {
131
- unset($notices[$_key]); // Dismiss.
132
- }
133
- # Current user can see this notice?
134
-
135
- if (!current_user_can($self->cap)) {
136
- continue; // Current user unable to see.
137
- }
138
- if ($_notice['cap_required'] && !current_user_can($_notice['cap_required'])) {
139
- continue; // Current user unable to see this notice.
140
- }
141
- # Current URI matches a limited scope/context for this notice?
142
-
143
- if ($_notice['only_on_uris'] && !@preg_match($_notice['only_on_uris'], $_SERVER['REQUEST_URI'])) {
144
- continue; // Not in the right context at the moment; i.e., does not regex.
145
- }
146
- # If persistent, allow a site owner to dismiss.
147
-
148
- $_dismiss = ''; // Reset this to its default state.
149
- if ($_notice['persistent_key'] && $_notice['dismissable']) { // See above. The `dismissNotice()` action requires `$self->cap` always.
150
- $_dismiss = add_query_arg(urlencode_deep(array(GLOBAL_NS => array('dismissNotice' => array('key' => $_key)), '_wpnonce' => wp_create_nonce())));
151
- $_dismiss = '<a style="display:inline-block; float:right; margin:0 0 0 15px; text-decoration:none; font-weight:bold;" href="'.esc_attr($_dismiss).'">'.__('dismiss &times;', 'comet-cache').'</a>';
152
- }
153
- # Display this notice. If not persistent, we can dismiss it too.
154
-
155
- echo '<div class="'.esc_attr($_notice['class']).'"><p>'.$_notice['notice'].$_dismiss.'</p></div>';
156
-
157
- if (!$_notice['persistent_key']) { // If not persistent, dismiss.
158
- unset($notices[$_key]); // Dismiss; this notice has been displayed now.
159
- }
160
- }
161
- unset($_key, $_notice, $_dismiss); // Housekeeping.
162
-
163
- # Update notices if something changed above.
164
-
165
- if ($notices !== $enqueued_notices) { // Something changed?
166
- $self->updateNotices($notices); // Update.
167
- }
168
- };
169
-
170
- /*
171
- * Notice getter/setter.
172
- */
173
-
174
- /*
175
- * Get admin notices.
176
- *
177
- * @since 151002 Improving multisite compat.
178
- *
179
- * @param integer $blog_id Optional. Defaults to the current blog ID.
180
- * Use any value `< 0` to indicate the main site.
181
- *
182
- * @return array All notices.
183
- */
184
- $self->getNotices = function ($blog_id = 0) use ($self) {
185
- if (is_multisite()) {
186
- if (!($blog_id = (integer) $blog_id)) {
187
- $blog_id = (integer) get_current_blog_id();
188
- }
189
- if ($blog_id < 0) { // Blog for main site.
190
- $blog_id = (integer) get_current_site()->blog_id;
191
- }
192
- $blog_suffix = '_'.$blog_id; // Site option suffix.
193
- $notices = get_site_option(GLOBAL_NS.$blog_suffix.'_notices');
194
- } else {
195
- $notices = get_site_option(GLOBAL_NS.'_notices');
196
- }
197
- if (!is_array($notices)) {
198
- $notices = array(); // Force array.
199
- // Prevent multiple DB queries by adding this key.
200
- $self->updateNotices($notices, $blog_id);
201
- }
202
- foreach ($notices as $_key => &$_notice) {
203
- if (!is_string($_key) || !is_array($_notice) || empty($_notice['notice'])) {
204
- unset($notices[$_key]); // Old notice.
205
- continue; // Bypass; i.e., do not normalize.
206
- }
207
- $_notice = $self->normalizeNotice($_notice);
208
- } // ↑ Typecast/normalized each of the array elements.
209
- unset($_key, $_notice); // Housekeeping.
210
-
211
- return $notices;
212
- };
213
-
214
- /*
215
- * Update admin notices.
216
- *
217
- * @since 151002 Improving multisite compat.
218
- *
219
- * @param array $notices New array of notices.
220
- *
221
- * @param integer $blog_id Optional. Defaults to the current blog ID.
222
- * Use any value `< 0` to indicate the main site.
223
- *
224
- * @return array All notices.
225
- */
226
- $self->updateNotices = function (array $notices, $blog_id = 0) use ($self) {
227
- if (is_multisite()) {
228
- if (!($blog_id = (integer) $blog_id)) {
229
- $blog_id = (integer) get_current_blog_id();
230
- }
231
- if ($blog_id < 0) { // Blog for main site.
232
- $blog_id = (integer) get_current_site()->blog_id;
233
- }
234
- $blog_suffix = '_'.$blog_id; // Site option suffix.
235
- update_site_option(GLOBAL_NS.$blog_suffix.'_notices', $notices);
236
- } else {
237
- update_site_option(GLOBAL_NS.'_notices', $notices);
238
- }
239
- return $notices;
240
- };
241
-
242
- /*
243
- * Notice property utilities.
244
- */
245
-
246
- /*
247
- * Normalize notice elements.
248
- *
249
- * @since 151002 Improving multisite compat.
250
- *
251
- * @param array $notice Notice array elements.
252
- * @param array $args Any additional array elements.
253
- *
254
- * @return array Normalized notice array elements.
255
- */
256
- $self->normalizeNotice = function (array $notice, array $args = array()) use ($self) {
257
- $notice_defaults = array(
258
- 'notice' => '',
259
- 'only_on_uris' => '',
260
- 'persistent_key' => '',
261
- 'dismissable' => true,
262
- 'is_transient' => true,
263
- 'push_to_top' => false,
264
- 'class' => 'updated',
265
- 'cap_required' => '', // `$self->cap` always.
266
- // i.e., this cap is in addition to `$self->cap`.
267
- );
268
- $notice = array_merge($notice_defaults, $notice, $args);
269
- $notice = array_intersect_key($notice, $notice_defaults);
270
-
271
- foreach ($notice as $_key => &$_value) {
272
- switch ($_key) {
273
- case 'notice':
274
- case 'only_on_uris':
275
- case 'persistent_key':
276
- $_value = trim((string) $_value);
277
- break; // Stop here.
278
-
279
- case 'is_transient':
280
- case 'push_to_top':
281
- case 'dismissable':
282
- $_value = (boolean) $_value;
283
- break; // Stop here.
284
-
285
- case 'class':
286
- case 'cap_required':
287
- $_value = trim((string) $_value);
288
- break; // Stop here.
289
- }
290
- } // ↑ Typecast each of the array elements.
291
- unset($_key, $_value); // A little housekeeping.
292
-
293
- ksort($notice); // For more accurate comparison in other routines.
294
-
295
- return $notice; // Normalized.
296
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/OptionUtils.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Get plugin options.
6
- *
7
- * @since 151002 Improving multisite compat.
8
- *
9
- * @return array Plugin options.
10
- */
11
- $self->getOptions = function () use ($self) {
12
- if (!($options = $self->options)) { // Not defined yet?
13
- if (!is_array($options = get_site_option(GLOBAL_NS.'_options'))) {
14
- $options = array(); // Force array.
15
- }
16
- if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) {
17
- $options = $zencache_options; // Old ZenCache options.
18
- $options['crons_setup'] = $this->default_options['crons_setup'];
19
- }
20
- }
21
- $self->options = array_merge($self->default_options, $options);
22
- $self->options = $self->applyWpFilters(GLOBAL_NS.'_options', $self->options);
23
- $self->options = array_intersect_key($self->options, $self->default_options);
24
-
25
- foreach ($self->options as $_key => &$_value) {
26
- $_value = trim((string) $_value); // Force strings.
27
- } unset($_key, $_value); // Housekeeping.
28
-
29
- $self->options['base_dir'] = trim($self->options['base_dir'], '\\/'." \t\n\r\0\x0B");
30
- if (!$self->options['base_dir'] || strpos(basename($self->options['base_dir']), 'wp-') === 0) {
31
- $self->options['base_dir'] = $self->default_options['base_dir'];
32
- }
33
- return $self->options; // Plugin options.
34
- };
35
-
36
- /*
37
- * Update plugin options.
38
- *
39
- * @since 151002 Improving multisite compat.
40
- *
41
- * @param array $options One or more new options.
42
- *
43
- * @return array Plugin options after update.
44
- */
45
- $self->updateOptions = function (array $options) use ($self) {
46
- if (!IS_PRO) { // Do not save Pro option keys.
47
- $options = array_diff_key($options, $self->pro_only_option_keys);
48
- }
49
- if (!empty($options['base_dir']) && $options['base_dir'] !== $self->options['base_dir']) {
50
- $self->tryErasingAllFilesDirsIn($self->wpContentBaseDirTo(''));
51
- }
52
- $self->options = array_merge($self->default_options, $self->options, $options);
53
- $self->options = array_intersect_key($self->options, $self->default_options);
54
- update_site_option(GLOBAL_NS.'_options', $self->options);
55
-
56
- return $self->getOptions();
57
- };
58
-
59
- /*
60
- * Restore default plugin options.
61
- *
62
- * @since 151002 Improving multisite compat.
63
- *
64
- * @return array Plugin options after update.
65
- */
66
- $self->restoreDefaultOptions = function () use ($self) {
67
- delete_site_option(GLOBAL_NS.'_options'); // Force restore.
68
- $self->options = $self->default_options; // In real-time.
69
- return $self->getOptions();
70
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/PostUtils.php DELETED
@@ -1,42 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * All post statuses.
6
- *
7
- * @since 150821 Improving bbPress support.
8
- *
9
- * @return array All post statuses.
10
- */
11
- $self->postStatuses = function () use ($self) {
12
- if (!is_null($statuses = &$self->cacheKey('postStatuses'))) {
13
- return $statuses; // Already did this.
14
- }
15
- $statuses = get_post_stati();
16
- $statuses = array_keys($statuses);
17
-
18
- return $statuses;
19
- };
20
-
21
- /*
22
- * All built-in post statuses.
23
- *
24
- * @since 150821 Improving bbPress support.
25
- *
26
- * @return array All built-in post statuses.
27
- */
28
- $self->builtInPostStatuses = function () use ($self) {
29
- if (!is_null($statuses = &$self->cacheKey('builtInPostStatuses'))) {
30
- return $statuses; // Already did this.
31
- }
32
- $statuses = array(); // Initialize.
33
-
34
- foreach (get_post_stati(array(), 'objects') as $_key => $_status) {
35
- if (!empty($_status->_builtin)) {
36
- $statuses[] = $_status->name;
37
- }
38
- }
39
- unset($_key, $_status); // Housekeeping.
40
-
41
- return $statuses;
42
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/UpdateUtils.php DELETED
@@ -1,46 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Checks for a new lite release.
6
- *
7
- * @since 151220 Show version number in plugin options.
8
- *
9
- * @attaches-to `admin_init` hook.
10
- */
11
- $self->maybeCheckLatestLiteVersion = function () use ($self) {
12
- if (IS_PRO) {
13
- return; // Not applicable.
14
- }
15
- if (!$self->options['lite_update_check']) {
16
- return; // Nothing to do.
17
- }
18
- if (!current_user_can($self->update_cap)) {
19
- return; // Nothing to do.
20
- }
21
- if (is_multisite() && !current_user_can($self->network_cap)) {
22
- return; // Nothing to do.
23
- }
24
- if ($self->options['last_lite_update_check'] >= strtotime('-1 hour')) {
25
- return; // No reason to keep checking on this.
26
- }
27
- $self->updateOptions(array('last_lite_update_check' => time()));
28
-
29
- $product_api_url = 'https://'.urlencode(DOMAIN).'/';
30
- $product_api_input_vars = array('product_api' => array('action' => 'latest_lite_version'));
31
-
32
- $product_api_response = wp_remote_post($product_api_url, array('body' => $product_api_input_vars));
33
- $product_api_response = json_decode(wp_remote_retrieve_body($product_api_response));
34
-
35
- if (is_object($product_api_response) && !empty($product_api_response->lite_version)) {
36
- $self->updateOptions(array('latest_lite_version' => $product_api_response->lite_version));
37
- }
38
- // Disabling the notice for now. We only run this check to collect the latest version number.
39
- #if ($self->options['latest_lite_version'] && version_compare(VERSION, $self->options['latest_lite_version'], '<')) {
40
- # $self->dismissMainNotice('new-lite-version-available'); // Dismiss any existing notices like this.
41
- # $lite_updater_page = network_admin_url('/plugins.php'); // In a network this points to the master plugins list.
42
- # $self->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> a new version is now available. Please <a href="%2$s">upgrade to v%3$s</a>.', 'comet-cache'), esc_html(NAME), esc_attr($lite_updater_page), esc_html($self->options['latest_lite_version'])), array('persistent_key' => 'new-lite-version-available'));
43
- #}
44
- };
45
-
46
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/UrlUtils.php DELETED
@@ -1,22 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * URL to a Comet Cache plugin file.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $file Optional file path; relative to plugin directory.
10
- * @param string $scheme Optional URL scheme; defaults to the current scheme.
11
- *
12
- * @return string URL to plugin directory; or to the specified `$file` if applicable.
13
- */
14
- $self->url = function ($file = '', $scheme = '') use ($self) {
15
- $url = rtrim(plugin_dir_url(PLUGIN_FILE), '/');
16
- $url .= (string) $file;
17
-
18
- if ($scheme) {
19
- $url = set_url_scheme($url, (string) $scheme);
20
- }
21
- return $url;
22
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/UserUtils.php DELETED
@@ -1,118 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Current user can clear the cache?
6
- *
7
- * @since 151002 Enhancing user permissions.
8
- *
9
- * @return boolean Current user can clear the cache?
10
- */
11
- $self->currentUserCanClearCache = function () use ($self) {
12
- if (!is_null($can = &$self->cacheKey('currentUserCanClearCache'))) {
13
- return $can; // Already cached this.
14
- }
15
- $is_multisite = is_multisite();
16
-
17
- if (!$is_multisite && current_user_can($self->cap)) {
18
- return ($can = true); // Plugin admin.
19
- }
20
- if ($is_multisite && current_user_can($self->network_cap)) {
21
- return ($can = true); // Plugin admin.
22
- }
23
-
24
- return ($can = false);
25
- };
26
- $self->currentUserCanWipeCache = $self->currentUserCanClearCache;
27
-
28
- /*
29
- * Current user can clear the opcache?
30
- *
31
- * @since 151114 Enhancing user permissions.
32
- *
33
- * @return boolean Current user can clear the opcache?
34
- */
35
- $self->currentUserCanClearOpCache = function () use ($self) {
36
- if (!is_null($can = &$self->cacheKey('currentUserCanClearOpCache'))) {
37
- return $can; // Already cached this.
38
- }
39
- $is_multisite = is_multisite();
40
-
41
- if (!$is_multisite && current_user_can($self->cap)) {
42
- return ($can = true); // Plugin admin.
43
- }
44
- if ($is_multisite && current_user_can($self->network_cap)) {
45
- return ($can = true); // Plugin admin.
46
- }
47
- return ($can = false);
48
- };
49
- $self->currentUserCanWipeOpCache = $self->currentUserCanClearOpCache;
50
-
51
- /*
52
- * Current user can clear the CDN cache?
53
- *
54
- * @since 151114 Enhancing user permissions.
55
- *
56
- * @return boolean Current user can clear the CDN cache?
57
- */
58
- $self->currentUserCanClearCdnCache = function () use ($self) {
59
- if (!is_null($can = &$self->cacheKey('currentUserCanClearCdnCache'))) {
60
- return $can; // Already cached this.
61
- }
62
- $is_multisite = is_multisite();
63
-
64
- if (!$is_multisite && current_user_can($self->cap)) {
65
- return ($can = true); // Plugin admin.
66
- }
67
- if ($is_multisite && current_user_can($self->network_cap)) {
68
- return ($can = true); // Plugin admin.
69
- }
70
- return ($can = false);
71
- };
72
- $self->currentUserCanWipeCdnCache = $self->currentUserCanClearCdnCache;
73
-
74
- /*
75
- * Current user can clear expired transients?
76
- *
77
- * @since 151220 Enhancing user permissions.
78
- *
79
- * @return boolean Current user can clear expired transients?
80
- */
81
- $self->currentUserCanClearExpiredTransients = function () use ($self) {
82
- if (!is_null($can = &$self->cacheKey('currentUserCanClearExpiredTransients'))) {
83
- return $can; // Already cached this.
84
- }
85
- $is_multisite = is_multisite();
86
-
87
- if (!$is_multisite && current_user_can($self->cap)) {
88
- return ($can = true); // Plugin admin.
89
- }
90
- if ($is_multisite && current_user_can($self->network_cap)) {
91
- return ($can = true); // Plugin admin.
92
- }
93
- return ($can = false);
94
- };
95
- $self->currentUserCanWipeExpiredTransients = $self->currentUserCanClearExpiredTransients;
96
-
97
- /*
98
- * Current user can see stats?
99
- *
100
- * @since 151002 Enhancing user permissions.
101
- *
102
- * @return boolean Current user can see stats?
103
- */
104
- $self->currentUserCanSeeStats = function () use ($self) {
105
- if (!is_null($can = &$self->cacheKey('currentUserCanSeeStats'))) {
106
- return $can; // Already cached this.
107
- }
108
- $is_multisite = is_multisite();
109
-
110
- if (!$is_multisite && current_user_can($self->cap)) {
111
- return ($can = true); // Plugin admin.
112
- }
113
- if ($is_multisite && current_user_can($self->network_cap)) {
114
- return ($can = true); // Plugin admin.
115
- }
116
-
117
- return ($can = false);
118
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpAuthorUtils.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for the author page(s).
6
- *
7
- * @attaches-to `post_updated` hook.
8
- *
9
- * @since 150422 Rewrite.
10
- *
11
- * @param int $post_id A WordPress post ID.
12
- * @param \WP_Post $post_after WP_Post object following the update.
13
- * @param \WP_Post $post_before WP_Post object before the update.
14
- *
15
- * @throws \Exception If a clear failure occurs.
16
- *
17
- * @return int Total files cleared by this routine (if any).
18
- *
19
- * @note If the author for the post is being changed, both the previous author
20
- * and current author pages are cleared, if the post status is applicable.
21
- */
22
- $self->autoClearAuthorPageCache = function ($post_id, \WP_Post $post_after, \WP_Post $post_before) use ($self) {
23
- $counter = 0; // Initialize.
24
- $enqueued_notices = 0; // Initialize.
25
- $authors = array(); // Initialize.
26
- $authors_to_clear = array(); // Initialize.
27
-
28
- if (!($post_id = (integer) $post_id)) {
29
- return $counter; // Nothing to do.
30
- }
31
- if (!is_null($done = &$self->cacheKey('autoClearAuthorPageCache', array($post_id, $post_after->ID, $post_before->ID)))) {
32
- return $counter; // Already did this.
33
- }
34
- $done = true; // Flag as having been done.
35
-
36
- if (!$self->options['enable']) {
37
- return $counter; // Nothing to do.
38
- }
39
- if (!$self->options['cache_clear_author_page_enable']) {
40
- return $counter; // Nothing to do.
41
- }
42
- if (!is_dir($cache_dir = $self->cacheDir())) {
43
- return $counter; // Nothing to do.
44
- }
45
- /*
46
- * If we're changing the post author AND
47
- * the previous post status was either 'published' or 'private'
48
- * then clear the author page for both authors.
49
- *
50
- * Else if the old post status was 'published' or 'private' OR
51
- * the new post status is 'published' or 'private'
52
- * then clear the author page for the current author.
53
- *
54
- * Else return the counter; post status does not warrant clearing author page cache.
55
- */
56
- if ($post_after->post_author !== $post_before->post_author &&
57
- ($post_before->post_status === 'publish' || $post_before->post_status === 'private')
58
- ) {
59
- $authors[] = (integer) $post_before->post_author;
60
- $authors[] = (integer) $post_after->post_author;
61
- } elseif (($post_before->post_status === 'publish' || $post_before->post_status === 'private') ||
62
- ($post_after->post_status === 'publish' || $post_after->post_status === 'private')
63
- ) {
64
- $authors[] = (integer) $post_after->post_author;
65
- }
66
- if (!$authors) {
67
- return $counter; // Nothing to do.
68
- }
69
- foreach ($authors as $_author_id) {
70
- $authors_to_clear[$_author_id]['posts_url'] = get_author_posts_url($_author_id);
71
- $authors_to_clear[$_author_id]['display_name'] = get_the_author_meta('display_name', $_author_id);
72
- }
73
- unset($_author_id); // Housekeeping.
74
-
75
- foreach ($authors_to_clear as $_author) {
76
- $_author_regex = $self->buildHostCachePathRegex($_author['posts_url']);
77
- $_author_counter = $self->clearFilesFromHostCacheDir($_author_regex);
78
- $counter += $_author_counter; // Add to overall counter.
79
-
80
- if ($_author_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
81
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
82
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for Author Page: <code>%3$s</code>; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($_author_counter)), esc_html($_author['display_name'])));
83
- $enqueued_notices++; // Increment enqueued notices counter.
84
- }
85
- }
86
- unset($_author, $_author_regex, $_author_counter); // Housekeeping.
87
-
88
- $counter += $self->autoClearXmlFeedsCache('blog');
89
- $counter += $self->autoClearXmlFeedsCache('post-authors', $post_id);
90
-
91
- return $counter;
92
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpCommentUtils.php DELETED
@@ -1,96 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for a post associated with a particular comment.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `trackback_post` hook.
10
- * @attaches-to `pingback_post` hook.
11
- * @attaches-to `comment_post` hook.
12
- *
13
- * @param int $comment_id A WordPress comment ID.
14
- *
15
- * @return int Total files cleared by this routine (if any).
16
- */
17
- $self->autoClearCommentPostCache = function ($comment_id) use ($self) {
18
- $counter = 0; // Initialize.
19
-
20
- if (!($comment_id = (integer) $comment_id)) {
21
- return $counter; // Nothing to do.
22
- }
23
- if (!is_null($done = &$self->cacheKey('autoClearCommentPostCache', $comment_id))) {
24
- return $counter; // Already did this.
25
- }
26
- $done = true; // Flag as having been done.
27
-
28
- if (!$self->options['enable']) {
29
- return $counter; // Nothing to do.
30
- }
31
- if (!is_object($comment = get_comment($comment_id))) {
32
- return $counter; // Nothing we can do.
33
- }
34
- if (empty($comment->comment_post_ID)) {
35
- return $counter; // Nothing we can do.
36
- }
37
- if ($comment->comment_approved === 'spam' || $comment->comment_approved === '0') {
38
- // Don't allow next `autoClearPostCache()` call to clear post cache.
39
- $allow = &$self->cacheKey('autoClearPostCache_allow');
40
- $allow = false; // Flag as false; i.e., disallow.
41
- return $counter;
42
- }
43
- $counter += $self->autoClearXmlFeedsCache('blog-comments');
44
- $counter += $self->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
45
- $counter += $self->autoClearPostCache($comment->comment_post_ID);
46
-
47
- return $counter;
48
- };
49
-
50
- /*
51
- * Automatically clears cache files for a post associated with a particular comment.
52
- *
53
- * @since 150422 Rewrite.
54
- *
55
- * @attaches-to `transition_comment_status` hook.
56
- *
57
- * @param string $new_status New comment status.
58
- * @param string $old_status Old comment status.
59
- * @param \stdClass $comment Comment object.
60
- *
61
- * @throws \Exception If a clear failure occurs.
62
- *
63
- * @return int Total files cleared by this routine (if any).
64
- *
65
- * @note This is also called upon by other routines which listen for
66
- * events that are indirectly associated with a comment ID.
67
- */
68
- $self->autoClearCommentPostCacheTransition = function ($new_status, $old_status, $comment) use ($self) {
69
- $counter = 0; // Initialize.
70
-
71
- if (!is_object($comment)) {
72
- return $counter; // Nothing we can do.
73
- }
74
- if (empty($comment->comment_post_ID)) {
75
- return $counter; // Nothing we can do.
76
- }
77
- if (!is_null($done = &$self->cacheKey('autoClearCommentPostCacheTransition', array($new_status, $old_status, $comment->comment_post_ID)))) {
78
- return $counter; // Already did this.
79
- }
80
- $done = true; // Flag as having been done.
81
-
82
- if (!$self->options['enable']) {
83
- return $counter; // Nothing to do.
84
- }
85
- if (!($old_status === 'approved' || ($old_status === 'unapproved' && $new_status === 'approved'))) {
86
- // If excluded here, don't allow next `autoClearPostCache()` call to clear post cache.
87
- $allow = &$self->cacheKey('autoClearPostCache_allow');
88
- $allow = false; // Flag as false; i.e., disallow.
89
- return $counter;
90
- }
91
- $counter += $self->autoClearXmlFeedsCache('blog-comments');
92
- $counter += $self->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
93
- $counter += $self->autoClearPostCache($comment->comment_post_ID);
94
-
95
- return $counter;
96
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpFeedUtils.php DELETED
@@ -1,116 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files related to XML feeds.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $type Type of feed(s) to auto-clear.
10
- * @param int $post_id A Post ID (when applicable).
11
- *
12
- * @throws \Exception If a clear failure occurs.
13
- *
14
- * @return int Total files cleared by this routine (if any).
15
- *
16
- * @note Unlike many of the other `auto_` methods, this one is NOT currently
17
- * attached to any hooks. However, it is called upon by other routines attached to hooks.
18
- */
19
- $self->autoClearXmlFeedsCache = function ($type, $post_id = 0) use ($self) {
20
- $counter = 0; // Initialize.
21
-
22
- if (!($type = (string) $type)) {
23
- return $counter; // Nothing we can do.
24
- }
25
- $post_id = (integer) $post_id; // Force integer.
26
-
27
- if (!is_null($done = &$self->cacheKey('autoClearXmlFeedsCache', array($type, $post_id)))) {
28
- return $counter; // Already did this.
29
- }
30
- $done = true; // Flag as having been done.
31
-
32
- if (!$self->options['enable']) {
33
- return $counter; // Nothing to do.
34
- }
35
- if (!$self->options['feeds_enable']) {
36
- return $counter; // Nothing to do.
37
- }
38
- if (!$self->options['cache_clear_xml_feeds_enable']) {
39
- return $counter; // Nothing to do.
40
- }
41
- if (!is_dir($cache_dir = $self->cacheDir())) {
42
- return $counter; // Nothing to do.
43
- }
44
- $utils = new FeedUtils(); // Feed utilities.
45
- $variations = $variation_regex_frags = array(); // Initialize.
46
-
47
- switch ($type) { // Handle clearing based on the `$type`.
48
-
49
- case 'blog': // The blog feed; i.e. `/feed/` on most WP installs.
50
- $variations = array_merge($variations, $utils->feedLinkVariations());
51
- break; // Break switch handler.
52
-
53
- case 'blog-comments': // The blog comments feed; i.e. `/comments/feed/` on most WP installs.
54
- $variations = array_merge($variations, $utils->feedLinkVariations('comments_'));
55
- break; // Break switch handler.
56
-
57
- case 'post-comments': // Feeds related to comments that a post has.
58
- if (!$post_id) {
59
- break; // Break switch handler.
60
- }
61
- if (!($post = get_post($post_id))) {
62
- break; // Break switch handler.
63
- }
64
- $variations = array_merge($variations, $utils->postCommentsFeedLinkVariations($post));
65
- break; // Break switch handler.
66
-
67
- case 'post-authors': // Feeds related to authors that a post has.
68
- if (!$post_id) {
69
- break; // Break switch handler.
70
- }
71
- if (!($post = get_post($post_id))) {
72
- break; // Break switch handler.
73
- }
74
- $variations = array_merge($variations, $utils->postAuthorFeedLinkVariations($post));
75
- break; // Break switch handler.
76
-
77
- case 'post-terms': // Feeds related to terms that a post has.
78
- if (!$post_id) {
79
- break; // Break switch handler.
80
- }
81
- if (!($post = get_post($post_id))) {
82
- break; // Break switch handler.
83
- }
84
- $variations = array_merge($variations, $utils->postTermFeedLinkVariations($post, true));
85
- break; // Break switch handler.
86
-
87
- case 'custom-post-type': // Feeds related to a custom post type archive view.
88
- if (!$post_id) {
89
- break; // Break switch handler.
90
- }
91
- if (!($post = get_post($post_id))) {
92
- break; // Break switch handler.
93
- }
94
- $variations = array_merge($variations, $utils->postTypeArchiveFeedLinkVariations($post));
95
- break; // Break switch handler.
96
-
97
- // @TODO Possibly consider search-related feeds in the future.
98
- // See: <http://codex.wordpress.org/WordPress_Feeds#Categories_and_Tags>
99
- }
100
- if (!($variation_regex_frags = $utils->convertVariationsToHostCachePathRegexFrags($variations))) {
101
- return $counter; // Nothing to do here.
102
- }
103
- $in_sets_of = $self->applyWpFilters(GLOBAL_NS.'_autoClearXmlFeedsCache_in_sets_of', 10, get_defined_vars());
104
- for ($_i = 0; $_i < count($variation_regex_frags); $_i = $_i + $in_sets_of) {
105
- $_variation_regex_frags = array_slice($variation_regex_frags, $_i, $in_sets_of);
106
- $_regex = '/^\/(?:'.implode('|', $_variation_regex_frags).')\./i';
107
- $counter += $self->clearFilesFromHostCacheDir($_regex);
108
- }
109
- unset($_i, $_variation_regex_frags, $_regex); // Housekeeping.
110
-
111
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
112
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
113
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache, for XML feeds of type: <code>%3$s</code>; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter)), esc_html($type)));
114
- }
115
- return $counter;
116
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpHomeBlogUtils.php DELETED
@@ -1,101 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for the home page.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @throws \Exception If a clear failure occurs.
10
- *
11
- * @return int Total files cleared by this routine (if any).
12
- *
13
- * @note Unlike many of the other `auto_` methods, this one is NOT currently
14
- * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
15
- */
16
- $self->autoClearHomePageCache = function () use ($self) {
17
- $counter = 0; // Initialize.
18
-
19
- if (!is_null($done = &$self->cacheKey('autoClearHomePageCache'))) {
20
- return $counter; // Already did this.
21
- }
22
- $done = true; // Flag as having been done.
23
-
24
- if (!$self->options['enable']) {
25
- return $counter; // Nothing to do.
26
- }
27
- if (!$self->options['cache_clear_home_page_enable']) {
28
- return $counter; // Nothing to do.
29
- }
30
- if (!is_dir($cache_dir = $self->cacheDir())) {
31
- return $counter; // Nothing to do.
32
- }
33
- $regex = $self->buildHostCachePathRegex(home_url('/'));
34
- $counter += $self->clearFilesFromHostCacheDir($regex);
35
-
36
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
37
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
38
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for the designated "Home Page"; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
39
- }
40
- $counter += $self->autoClearXmlFeedsCache('blog');
41
-
42
- return $counter;
43
- };
44
-
45
- /*
46
- * Automatically clears cache files for the posts page.
47
- *
48
- * @since 150422 Rewrite.
49
- *
50
- * @throws \Exception If a clear failure occurs.
51
- *
52
- * @return int Total files cleared by this routine (if any).
53
- *
54
- * @note Unlike many of the other `auto_` methods, this one is NOT currently
55
- * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
56
- */
57
- $self->autoClearPostsPageCache = function () use ($self) {
58
- $counter = 0; // Initialize.
59
-
60
- if (!is_null($done = &$self->cacheKey('autoClearPostsPageCache'))) {
61
- return $counter; // Already did this.
62
- }
63
- $done = true; // Flag as having been done.
64
-
65
- if (!$self->options['enable']) {
66
- return $counter; // Nothing to do.
67
- }
68
- if (!$self->options['cache_clear_posts_page_enable']) {
69
- return $counter; // Nothing to do.
70
- }
71
- if (!is_dir($cache_dir = $self->cacheDir())) {
72
- return $counter; // Nothing to do.
73
- }
74
- $show_on_front = get_option('show_on_front');
75
- $page_for_posts = get_option('page_for_posts');
76
-
77
- if (!in_array($show_on_front, array('posts', 'page'), true)) {
78
- return $counter; // Nothing we can do in this case.
79
- }
80
- if ($show_on_front === 'page' && !$page_for_posts) {
81
- return $counter; // Nothing we can do.
82
- }
83
- if ($show_on_front === 'posts') {
84
- $posts_page = home_url('/');
85
- } elseif ($show_on_front === 'page') {
86
- $posts_page = get_permalink($page_for_posts);
87
- }
88
- if (empty($posts_page)) {
89
- return $counter; // Nothing we can do.
90
- }
91
- $regex = $self->buildHostCachePathRegex($posts_page);
92
- $counter += $self->clearFilesFromHostCacheDir($regex);
93
-
94
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
95
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
96
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for the designated "Posts Page"; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
97
- }
98
- $counter += $self->autoClearXmlFeedsCache('blog');
99
-
100
- return $counter;
101
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpJetpackUtils.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears all cache files for current blog when JetPack Custom CSS is saved.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `safecss_save_pre` hook.
10
- *
11
- * @param array $args Args passed in by hook.
12
- */
13
- $self->autoClearCacheOnJetpackCustomCss = function ($args) use ($self) {
14
- $counter = 0; // Initialize.
15
-
16
- if (!is_null($done = &$self->cacheKey('autoClearCacheOnJetpackCustomCss', $args))) {
17
- return $counter; // Already did this.
18
- }
19
- $done = true; // Flag as having been done.
20
-
21
- if (empty($args['is_preview']) && class_exists('\\Jetpack')) {
22
- $counter += $self->autoClearCache();
23
- }
24
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpOpcacheUtils.php DELETED
@@ -1,69 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Wipe (i.e., reset) OPCache.
6
- *
7
- * @since 151002 Adding OPCache support.
8
- *
9
- * @param bool $manually True if wiping is done manually.
10
- * @param boolean $maybe Defaults to a true value.
11
- * @param array $files Optional; wipe only specific files?
12
- *
13
- * @return integer Total keys wiped.
14
- */
15
- $self->wipeOpcache = function ($manually = false, $maybe = true, $files = array()) use ($self) {
16
- $counter = 0; // Initialize counter.
17
-
18
- if ($maybe && !$self->options['cache_clear_opcache_enable']) {
19
- return $counter; // Not enabled at this time.
20
- }
21
- if (!$self->functionIsPossible('opcache_reset')) {
22
- return $counter; // Not possible.
23
- }
24
- if (!($status = $self->sysOpcacheStatus())) {
25
- return $counter; // Not possible.
26
- }
27
- if (empty($status->opcache_enabled)) {
28
- return $counter; // Not necessary.
29
- }
30
- if (empty($status->opcache_statistics->num_cached_keys)) {
31
- return $counter; // Not possible.
32
- }
33
- if ($files) { // Specific files?
34
- foreach ($files as $_file) {
35
- $counter += (int) opcache_invalidate($_file, true);
36
- } // unset($_file); // Housekeeping.
37
- } elseif (opcache_reset()) { // True if a reset occurs.
38
- $counter += $status->opcache_statistics->num_cached_keys;
39
- }
40
- return $counter;
41
- };
42
-
43
- /*
44
- * Clear (i.e., reset) OPCache.
45
- *
46
- * @since 151002 Adding OPCache support.
47
- *
48
- * @param bool $manually True if clearing is done manually.
49
- * @param boolean $maybe Defaults to a true value.
50
- *
51
- * @return integer Total keys cleared.
52
- */
53
- $self->clearOpcache = function ($manually = false, $maybe = true) use ($self) {
54
- if (!is_multisite() || is_main_site() || current_user_can($self->network_cap)) {
55
- return $self->wipeOpcache($manually, $maybe);
56
- }
57
- return 0; // Not applicable.
58
- };
59
-
60
- /*
61
- * Clear AC class file from Opcache (by force).
62
- *
63
- * @since 151215 Adding OPCache support.
64
- *
65
- * @return integer Total keys cleared.
66
- */
67
- $self->clearAcDropinFromOpcacheByForce = function () use ($self) {
68
- return $self->wipeOpcache(false, false, array(WP_CONTENT_DIR.'/advanced-cache.php'));
69
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpPluginUtils.php DELETED
@@ -1,22 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically wipes/clears on plugin activation/deactivation.
6
- *
7
- * @since 151220 Adding auto-wipe|clear on plugin activations/deactivations.
8
- *
9
- * @attaches-to `activated_plugin` hook.
10
- * @attaches-to `deactivated_plugin` hook.
11
- *
12
- * @param string $plugin Plugin basename.
13
- * @param bool True if activating|deactivating network-wide. Defaults to boolean `FALSE` in case parameter is not passed to hook.
14
- *
15
- * @return int Total files wiped|cleared by this routine (if any).
16
- */
17
- $self->autoClearOnPluginActivationDeactivation = function ($plugin, $network_wide = false) use ($self) {
18
- if (!$self->applyWpFilters(GLOBAL_NS.'_auto_clear_on_plugin_activation_deactivation', true)) {
19
- return 0; // Nothing to do here.
20
- }
21
- return $self->{($network_wide ? 'autoWipeCache' : 'autoClearCache')}();
22
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpPostTypeUtils.php DELETED
@@ -1,66 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for a custom post type archive view.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param int $post_id A WordPress post ID.
10
- *
11
- * @throws \Exception If a clear failure occurs.
12
- *
13
- * @return int Total files cleared by this routine (if any).
14
- *
15
- * @note Unlike many of the other `auto_` methods, this one is NOT currently
16
- * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
17
- */
18
- $self->autoClearCustomPostTypeArchiveCache = function ($post_id) use ($self) {
19
- $counter = 0; // Initialize.
20
-
21
- if (!($post_id = (integer) $post_id)) {
22
- return $counter; // Nothing to do.
23
- }
24
- if (!is_null($done = &$self->cacheKey('autoClearCustomPostTypeArchiveCache', $post_id))) {
25
- return $counter; // Already did this.
26
- }
27
- $done = true; // Flag as having been done.
28
-
29
- if (!$self->options['enable']) {
30
- return $counter; // Nothing to do.
31
- }
32
- if (!$self->options['cache_clear_custom_post_type_enable']) {
33
- return $counter; // Nothing to do.
34
- }
35
- if (!is_dir($cache_dir = $self->cacheDir())) {
36
- return $counter; // Nothing to do.
37
- }
38
- if (!($post_type = get_post_type($post_id))) {
39
- return $counter; // Nothing to do.
40
- }
41
- if (!($all_custom_post_types = get_post_types(array('_builtin' => false)))) {
42
- return $counter; // No custom post types.
43
- }
44
- if (!in_array($post_type, array_keys($all_custom_post_types), true)) {
45
- return $counter; // This is NOT a custom post type.
46
- }
47
- if (!($custom_post_type = get_post_type_object($post_type))) {
48
- return $counter; // Unable to retrieve post type.
49
- }
50
- if (empty($custom_post_type->labels->name) || !($custom_post_type_name = $custom_post_type->labels->name)) {
51
- $custom_post_type_name = __('Untitled', 'comet-cache');
52
- }
53
- if (!($custom_post_type_archive_link = get_post_type_archive_link($post_type))) {
54
- return $counter; // Nothing to do; no link to work from in this case.
55
- }
56
- $regex = $self->buildHostCachePathRegex($custom_post_type_archive_link);
57
- $counter += $self->clearFilesFromHostCacheDir($regex);
58
-
59
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
60
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
61
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for Custom Post Type: <code>%3$s</code>; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter)), esc_html($custom_post_type_name)));
62
- }
63
- $counter += $self->autoClearXmlFeedsCache('custom-post-type', $post_id);
64
-
65
- return $counter;
66
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpPostUtils.php DELETED
@@ -1,176 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for a particular post.
6
- *
7
- * @attaches-to `save_post` hook.
8
- * @attaches-to `delete_post` hook.
9
- * @attaches-to `clean_post_cache` hook.
10
- *
11
- * @since 150422 Rewrite.
12
- *
13
- * @param int $post_id A WordPress post ID.
14
- * @param bool $force Defaults to a `FALSE` value.
15
- * Pass as TRUE if clearing should be done for `draft`, `pending`,
16
- * `future`, or `trash` post statuses.
17
- *
18
- * @throws \Exception If a clear failure occurs.
19
- *
20
- * @return int Total files cleared by this routine (if any).
21
- *
22
- * @note This is also called upon by other routines which listen for
23
- * events that are indirectly associated with a post ID.
24
- */
25
- $self->autoClearPostCache = function ($post_id, $force = false) use ($self) {
26
- $counter = 0; // Initialize.
27
-
28
- if (!is_null($allow = &$self->cacheKey('autoClearPostCache_allow'))) {
29
- if ($allow === false) { // Disallow?
30
- $allow = true; // Reset flag.
31
- return $counter;
32
- }
33
- }
34
- if (!($post_id = (integer) $post_id)) {
35
- return $counter; // Nothing to do.
36
- }
37
- if (!is_null($done = &$self->cacheKey('autoClearPostCache', array($post_id, $force)))) {
38
- return $counter; // Already did this.
39
- }
40
- $done = true; // Flag as having been done.
41
-
42
- if (!$self->options['enable']) {
43
- return $counter; // Nothing to do.
44
- }
45
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
46
- return $counter; // Nothing to do.
47
- }
48
- if (!is_dir($cache_dir = $self->cacheDir())) {
49
- return $counter; // Nothing to do.
50
- }
51
- if (!($post_type = get_post_type($post_id))) {
52
- return $counter; // Nothing to do.
53
- }
54
- $post_statuses = $self->postStatuses();
55
- $unpublished_post_statuses = array_diff($post_statuses, array('publish'));
56
- $is_bbpress_post_type = in_array($post_type, $self->bbPressPostTypes(), true);
57
-
58
- if (!empty($self->pre_post_update_post_permalink[$post_id])) {
59
- $permalink = $self->pre_post_update_post_permalink[$post_id];
60
- $self->pre_post_update_post_permalink[$post_id] = ''; // Reset; only used for post status transitions.
61
- } elseif (!($permalink = get_permalink($post_id))) {
62
- return $counter; // Nothing we can do.
63
- }
64
- if (!($post_status = get_post_status($post_id))) {
65
- return $counter; // Nothing to do.
66
- }
67
- if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
68
- && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
69
- && strpos(wp_get_referer(), '/post-new.php') !== false
70
- ) {
71
- $post_status = 'publish'; // A new post being published now.
72
- }
73
- if (in_array($post_status, array('inherit', 'auto-draft'), true)) {
74
- return $counter; // Nothing to do. Note: `inherit` = revision.
75
- }
76
- if (in_array($post_status, array('draft', 'pending', 'future', 'trash'), true) && !$force) {
77
- return $counter; // Nothing to do; i.e., NOT forcing in this case.
78
- }
79
- if (($post_type_obj = get_post_type_object($post_type)) && !empty($post_type_obj->labels->singular_name)) {
80
- $post_type_singular_name = $post_type_obj->labels->singular_name; // Singular name for the post type.
81
- } else {
82
- $post_type_singular_name = __('Post', 'comet-cache'); // Default value.
83
- }
84
- $regex = $self->buildHostCachePathRegex($permalink);
85
- $counter += $self->clearFilesFromHostCacheDir($regex);
86
-
87
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
88
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
89
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for %3$s ID: <code>%4$s</code>; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter)), esc_html($post_type_singular_name), esc_html($post_id)));
90
- }
91
- $counter += $self->autoClearXmlFeedsCache('blog');
92
- $counter += $self->autoClearXmlFeedsCache('post-terms', $post_id);
93
- $counter += $self->autoClearXmlFeedsCache('post-authors', $post_id);
94
-
95
- $counter += $self->autoClearXmlSitemapsCache();
96
- $counter += $self->autoClearHomePageCache();
97
- $counter += $self->autoClearPostsPageCache();
98
- $counter += $self->autoClearPostTermsCache($post_id, $force);
99
- $counter += $self->autoClearCustomPostTypeArchiveCache($post_id);
100
-
101
-
102
- if ($post_type !== 'page' && ($parent_post_id = wp_get_post_parent_id($post_id))) {
103
- // Recursion: i.e., nested post types like bbPress forums/topic/replies.
104
- $counter += $self->autoClearPostCache($parent_post_id, $force);
105
- }
106
- return $counter;
107
- };
108
- $self->auto_clear_post_cache = $self->autoClearPostCache; // Back compat.
109
-
110
- /*
111
- * Handles post status transitioning.
112
- *
113
- * @attaches-to `pre_post_update` hook.
114
- *
115
- * @since 150422 Rewrite.
116
- *
117
- * @param int $post_id Post ID.
118
- * @param array $data Array of unslashed post data.
119
- *
120
- * @throws \Exception If a clear failure occurs.
121
- *
122
- * @return int Total files cleared by this routine (if any).
123
- *
124
- * @note This is also called upon by other routines which listen for
125
- * events that are indirectly associated with a post ID.
126
- */
127
- $self->autoClearPostCacheTransition = function ($post_id, $data) use ($self) {
128
- $counter = 0; // Initialize.
129
-
130
- $old_status = (string) get_post_status($post_id);
131
- $new_status = (string) $data['post_status'];
132
- /*
133
- * When a post has a status of `pending` or `draft`, the `get_permalink()` function
134
- * does not return a friendly permalink and therefore `autoClearPostCache()` will
135
- * have no way of building a path to the cache file that should be cleared as part of
136
- * this post status transition. To get around this, we temporarily store the permalink
137
- * in $self->pre_post_update_post_permalink for `autoClearPostCache()` to use.
138
- *
139
- * See also: <https://github.com/websharks/zencache/issues/441>
140
- */
141
- if (in_array($new_status, array('pending', 'draft'), true)) {
142
- $self->pre_post_update_post_permalink[$post_id] = get_permalink($post_id);
143
- }
144
- // Begin post status transition sub-routine now.
145
-
146
- if (!is_null($done = &$self->cacheKey('autoClearPostCacheTransition', array($old_status, $new_status, $post_id)))) {
147
- return $counter; // Already did this.
148
- }
149
- $done = true; // Flag as having been done.
150
-
151
- if (!$self->options['enable']) {
152
- return $counter; // Nothing to do.
153
- }
154
- if ($new_status === $old_status) {
155
- return $counter; // Nothing to do.
156
- }
157
- if (!($post_type = get_post_type($post_id))) {
158
- return $counter; // Nothing to do.
159
- }
160
- $post_statuses = $self->postStatuses();
161
- $unpublished_post_statuses = array_diff($post_statuses, array('publish'));
162
- $is_bbpress_post_type = in_array($post_type, $self->bbPressPostTypes(), true);
163
-
164
- if ($is_bbpress_post_type) {
165
- if (in_array($old_status, array('publish', 'private', 'closed', 'spam', 'hidden'), true)) {
166
- if (in_array($new_status, $unpublished_post_statuses, true)) {
167
- $counter += $self->autoClearPostCache($post_id, true);
168
- }
169
- }
170
- } elseif (in_array($old_status, array('publish', 'private'), true)) {
171
- if (in_array($new_status, $unpublished_post_statuses, true)) {
172
- $counter += $self->autoClearPostCache($post_id, true);
173
- }
174
- }
175
- return $counter;
176
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpSettingUtils.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears all cache files for current blog under various conditions;
6
- * used to check for conditions that don't have a hook that we can attach to.
7
- *
8
- * @since 150422 Rewrite.
9
- *
10
- * @attaches-to `admin_init` hook.
11
- */
12
- $self->autoClearCacheOnSettingChanges = function () use ($self) {
13
- $counter = 0; // Initialize.
14
- $pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
15
- $settings_updated = !empty($_REQUEST['settings-updated']);
16
-
17
- if (!is_null($done = &$self->cacheKey('autoClearCacheOnSettingChanges', array($pagenow, $settings_updated)))) {
18
- return $counter; // Already did this.
19
- }
20
- $done = true; // Flag as having been done.
21
-
22
- if ($pagenow === 'options-general.php' && $settings_updated) {
23
- $counter += $self->autoClearCache();
24
- } elseif ($pagenow === 'options-reading.php' && $settings_updated) {
25
- $counter += $self->autoClearCache();
26
- } elseif ($pagenow === 'options-discussion.php' && $settings_updated) {
27
- $counter += $self->autoClearCache();
28
- } elseif ($pagenow === 'options-permalink.php' && $settings_updated) {
29
- $counter += $self->autoClearCache();
30
- }
31
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpSitemapUtils.php DELETED
@@ -1,47 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files related to XML sitemaps.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @throws \Exception If a clear failure occurs.
10
- *
11
- * @return int Total files cleared by this routine (if any).
12
- *
13
- * @note Unlike many of the other `auto_` methods, this one is NOT currently
14
- * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
15
- */
16
- $self->autoClearXmlSitemapsCache = function () use ($self) {
17
- $counter = 0; // Initialize.
18
-
19
- if (!is_null($done = &$self->cacheKey('autoClearXmlSitemapsCache'))) {
20
- return $counter; // Already did this.
21
- }
22
- $done = true; // Flag as having been done.
23
-
24
- if (!$self->options['enable']) {
25
- return $counter; // Nothing to do.
26
- }
27
- if (!$self->options['cache_clear_xml_sitemaps_enable']) {
28
- return $counter; // Nothing to do.
29
- }
30
- if (!$self->options['cache_clear_xml_sitemap_patterns']) {
31
- return $counter; // Nothing to do.
32
- }
33
- if (!is_dir($cache_dir = $self->cacheDir())) {
34
- return $counter; // Nothing to do.
35
- }
36
- if (!($regex_frags = $self->buildHostCachePathRegexFragsFromWcUris($self->options['cache_clear_xml_sitemap_patterns'], ''))) {
37
- return $counter; // There are no patterns to look for.
38
- }
39
- $regex = $self->buildHostCachePathRegex('', '\/'.$regex_frags.'\.');
40
- $counter += $self->clearFilesFromHostCacheDir($regex);
41
-
42
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
43
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
44
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for XML sitemaps; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
45
- }
46
- return $counter;
47
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpTermUtils.php DELETED
@@ -1,139 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache files for terms associated with a post.
6
- *
7
- * @attaches-to `added_term_relationship` hook.
8
- * @attaches-to `delete_term_relationships` hook.
9
- *
10
- * @since 150422 Rewrite.
11
- *
12
- * @param int $post_id A WordPress post ID.
13
- * @param bool $force Defaults to a `FALSE` value.
14
- * Pass as TRUE if clearing should be done for `draft`, `pending`,
15
- * or `future` post statuses.
16
- *
17
- * @throws \Exception If a clear failure occurs.
18
- *
19
- * @return int Total files cleared by this routine (if any).
20
- *
21
- * @note In addition to the hooks this is attached to, it is also
22
- * called upon by {@link autoClearPostCache()}.
23
- */
24
- $self->autoClearPostTermsCache = function ($post_id, $force = false) use ($self) {
25
- $counter = 0; // Initialize.
26
- $enqueued_notices = 0; // Initialize.
27
-
28
- if (!($post_id = (integer) $post_id)) {
29
- return $counter; // Nothing to do.
30
- }
31
- if (!is_null($done = &$self->cacheKey('autoClearPostTermsCache', array($post_id, $force)))) {
32
- return $counter; // Already did this.
33
- }
34
- $done = true; // Flag as having been done.
35
-
36
- if (!$self->options['enable']) {
37
- return $counter; // Nothing to do.
38
- }
39
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
40
- return $counter; // Nothing to do.
41
- }
42
- if (!$self->options['cache_clear_term_category_enable'] && !$self->options['cache_clear_term_post_tag_enable'] && !$self->options['cache_clear_term_other_enable']) {
43
- return $counter; // Nothing to do.
44
- }
45
- if (!is_dir($cache_dir = $self->cacheDir())) {
46
- return $counter; // Nothing to do.
47
- }
48
- $post_status = get_post_status($post_id); // Cache this.
49
-
50
- if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
51
- && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
52
- && strpos(wp_get_referer(), '/post-new.php') !== false
53
- ) {
54
- $post_status = 'publish'; // A new post being published now.
55
- }
56
- if (in_array($post_status, array('inherit', 'auto-draft'), true)) {
57
- return $counter; // Nothing to do. Note: `inherit` = revision.
58
- }
59
- if (in_array($post_status, array('draft', 'pending', 'future'), true) && !$force) {
60
- return $counter; // Nothing to do; i.e., NOT forcing in this case.
61
- }
62
- /*
63
- * Build an array of available taxonomies for this post (as taxonomy objects).
64
- */
65
- $taxonomies = get_object_taxonomies(get_post($post_id), 'objects');
66
-
67
- if (!is_array($taxonomies)) {
68
- return $counter; // Nothing to do.
69
- }
70
- /*
71
- * Build an array of terms associated with this post for each taxonomy.
72
- * Also save taxonomy label information for Dashboard messaging later.
73
- */
74
- $terms = array();
75
- $taxonomy_labels = array();
76
-
77
- foreach ($taxonomies as $_taxonomy) {
78
- if (// Check if this is a taxonomy/term that we should clear.
79
- ($_taxonomy->name === 'category' && !$self->options['cache_clear_term_category_enable'])
80
- || ($_taxonomy->name === 'post_tag' && !$self->options['cache_clear_term_post_tag_enable'])
81
- || ($_taxonomy->name !== 'category' && $_taxonomy->name !== 'post_tag' && !$self->options['cache_clear_term_other_enable'])
82
- ) {
83
- continue; // Continue; nothing to do for this taxonomy.
84
- }
85
- if (is_array($_terms = wp_get_post_terms($post_id, $_taxonomy->name))) {
86
- $terms = array_merge($terms, $_terms);
87
- if (empty($_taxonomy->labels->singular_name) || $_taxonomy->labels->singular_name === '') {
88
- $taxonomy_labels[$_taxonomy->name] = $_taxonomy->name;
89
- } else {
90
- $taxonomy_labels[$_taxonomy->name] = $_taxonomy->labels->singular_name;
91
- }
92
- }
93
- }
94
- unset($_taxonomy, $_terms);
95
-
96
- if (empty($terms)) {
97
- return $counter; // Nothing to do.
98
- }
99
- /*
100
- * Build an array of terms with term names,
101
- * permalinks, and associated taxonomy labels.
102
- */
103
- $terms_to_clear = array();
104
- $_i = 0;
105
-
106
- foreach ($terms as $_term) {
107
- if (($_link = get_term_link($_term))) {
108
- $terms_to_clear[$_i]['permalink'] = $_link;
109
- $terms_to_clear[$_i]['term_name'] = $_term->name;
110
- if (!empty($taxonomy_labels[$_term->taxonomy])) {
111
- $terms_to_clear[$_i]['taxonomy_label'] = $taxonomy_labels[$_term->taxonomy];
112
- } else {
113
- $terms_to_clear[$_i]['taxonomy_label'] = $_term->taxonomy;
114
- }
115
- }
116
- ++$_i; // Array index counter.
117
- }
118
- unset($_term, $_link, $_i);
119
-
120
- if (empty($terms_to_clear)) {
121
- return $counter; // Nothing to do.
122
- }
123
- foreach ($terms_to_clear as $_term) {
124
- $_term_regex = $self->buildHostCachePathRegex($_term['permalink']);
125
- $_term_counter = $self->clearFilesFromHostCacheDir($_term_regex);
126
- $counter += $_term_counter; // Add to overall counter.
127
-
128
- if ($_term_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
129
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
130
- sprintf(__('<strong>%1$s:</strong> detected changes. Found %2$s in the cache for %3$s: <code>%4$s</code>; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($_term_counter)), esc_html($_term['taxonomy_label']), esc_html($_term['term_name'])));
131
- ++$enqueued_notices; // Increment enqueued notices counter.
132
- }
133
- }
134
- unset($_term, $_term_regex, $_term_counter); // Housekeeping.
135
-
136
- $counter += $self->autoClearXmlFeedsCache('post-terms', $post_id);
137
-
138
- return $counter;
139
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpUpdaterUtils.php DELETED
@@ -1,99 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears all cache files for current blog when WordPress core, or an active component, is upgraded.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @attaches-to `upgrader_process_complete` hook.
10
- *
11
- * @param \WP_Upgrader $upgrader_instance An instance of \WP_Upgrader.
12
- * Or, any class that extends \WP_Upgrader.
13
- * @param array $data Array of bulk item update data.
14
- *
15
- * This array may include one or more of the following keys:
16
- *
17
- * - `string` `$action` Type of action. Default 'update'.
18
- * - `string` `$type` Type of update process; e.g. 'plugin', 'theme', 'core'.
19
- * - `boolean` `$bulk` Whether the update process is a bulk update. Default true.
20
- * - `array` `$packages` Array of plugin, theme, or core packages to update.
21
- */
22
- $self->autoClearOnUpgraderProcessComplete = function (\WP_Upgrader $upgrader_instance, array $data) use ($self) {
23
- $counter = 0; // Initialize.
24
-
25
- switch (!empty($data['type']) ? $data['type'] : '') {
26
- case 'plugin': // Plugin upgrade.
27
-
28
- $multi_plugin_update = $single_plugin_update = false;
29
- $upgrading_active_plugin = false; // Initialize.
30
-
31
- if (!empty($data['bulk']) && !empty($data['plugins']) && is_array($data['plugins'])) {
32
- $multi_plugin_update = true;
33
- } elseif (!empty($data['plugin']) && is_string($data['plugin'])) {
34
- $single_plugin_update = true;
35
- }
36
- if ($multi_plugin_update) {
37
- foreach ($data['plugins'] as $_plugin) {
38
- if ($_plugin && is_string($_plugin) && is_plugin_active($_plugin)) {
39
- $upgrading_active_plugin = true;
40
- break; // Got what we need here.
41
- }
42
- }
43
- unset($_plugin); // Housekeeping.
44
- } elseif ($single_plugin_update && is_plugin_active($data['plugin'])) {
45
- $upgrading_active_plugin = true;
46
- }
47
- if ($upgrading_active_plugin) {
48
- $counter += $self->autoClearCache();
49
- }
50
- break; // Break switch.
51
-
52
- case 'theme': // Theme upgrade.
53
-
54
- $current_active_theme = wp_get_theme();
55
- $current_active_theme_parent = $current_active_theme->parent();
56
- $multi_theme_update = $single_theme_update = false;
57
- $upgrading_active_parent_theme = $upgrading_active_theme = false;
58
-
59
- if (!empty($data['bulk']) && !empty($data['themes']) && is_array($data['themes'])) {
60
- $multi_theme_update = true;
61
- } elseif (!empty($data['theme']) && is_string($data['theme'])) {
62
- $single_theme_update = true;
63
- }
64
- if ($multi_theme_update) {
65
- foreach ($data['themes'] as $_theme) {
66
- if (!$_theme || !is_string($_theme) || !($_theme_obj = wp_get_theme($_theme))) {
67
- continue; // Unable to acquire theme object instance.
68
- }
69
- if ($current_active_theme_parent && $current_active_theme_parent->get_stylesheet() === $_theme_obj->get_stylesheet()) {
70
- $upgrading_active_parent_theme = true;
71
- break; // Got what we needed here.
72
- } elseif ($current_active_theme->get_stylesheet() === $_theme_obj->get_stylesheet()) {
73
- $upgrading_active_theme = true;
74
- break; // Got what we needed here.
75
- }
76
- }
77
- unset($_theme, $_theme_obj); // Housekeeping.
78
- } elseif ($single_theme_update && ($_theme_obj = wp_get_theme($data['theme']))) {
79
- if ($current_active_theme_parent && $current_active_theme_parent->get_stylesheet() === $_theme_obj->get_stylesheet()) {
80
- $upgrading_active_parent_theme = true;
81
- } elseif ($current_active_theme->get_stylesheet() === $_theme_obj->get_stylesheet()) {
82
- $upgrading_active_theme = true;
83
- }
84
- }
85
- unset($_theme_obj); // Housekeeping.
86
-
87
- if ($upgrading_active_theme || $upgrading_active_parent_theme) {
88
- $counter += $self->autoClearCache();
89
- }
90
- break; // Break switch.
91
-
92
- case 'core': // Core upgrade.
93
- default: // Or any other sort of upgrade.
94
-
95
- $counter += $self->autoClearCache();
96
-
97
- break; // Break switch.
98
- }
99
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpUtils.php DELETED
@@ -1,341 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Used for temporarily storing the permalink for posts transitioning from
6
- * `publish` or `private` post status to `pending` or `draft` post status.
7
- *
8
- * @since 150422 Rewrite.
9
- *
10
- * @type array An associative array with the Post ID as the named key containing
11
- * the post permalink before the post has been transitioned.
12
- */
13
- $self->pre_post_update_post_permalink = array();
14
-
15
- /*
16
- * Wipes out all cache files.
17
- *
18
- * @since 150422 Rewrite.
19
- *
20
- * @param bool $manually TRUE if wiping is done manually.
21
- *
22
- * @throws \Exception If a wipe failure occurs.
23
- *
24
- * @return int Total files wiped by this routine.
25
- */
26
- $self->wipeCache = function ($manually = false) use ($self) {
27
- $counter = 0; // Initialize.
28
-
29
- if (!$manually && $self->disableAutoWipeCacheRoutines()) {
30
- return $counter; // Nothing to do.
31
- }
32
- @set_time_limit(1800); // @TODO Display a warning.
33
-
34
- if (is_dir($cache_dir = $self->cacheDir())) {
35
- $regex = $self->assembleCachePathRegex('', '.+');
36
- $counter += $self->wipeFilesFromCacheDir($regex);
37
- }
38
-
39
-
40
-
41
-
42
-
43
- return $counter;
44
- };
45
- $self->wipe_cache = $self->wipeCache; // Back compat.
46
-
47
- /*
48
- * Clears cache files (current blog).
49
- *
50
- * @since 150422 Rewrite.
51
- *
52
- * @param bool $manually TRUE if clearing is done manually.
53
- *
54
- * @throws \Exception If a clearing failure occurs.
55
- *
56
- * @return int Total files cleared by this routine.
57
- */
58
- $self->clearCache = function ($manually = false) use ($self) {
59
- $counter = 0; // Initialize.
60
-
61
- if (!$manually && $self->disableAutoClearCacheRoutines()) {
62
- return $counter; // Nothing to do.
63
- }
64
- @set_time_limit(1800); // @TODO Display a warning.
65
-
66
- if (is_dir($cache_dir = $self->cacheDir())) {
67
- $regex = $self->buildHostCachePathRegex('', '.+');
68
- $counter += $self->clearFilesFromHostCacheDir($regex);
69
- }
70
-
71
-
72
-
73
-
74
-
75
- return $counter;
76
- };
77
- $self->clear_cache = $self->clearCache; // Back compat.
78
-
79
- /*
80
- * Purges expired cache files (current blog).
81
- *
82
- * @since 150422 Rewrite.
83
- *
84
- * @param bool $manually TRUE if purging is done manually.
85
- *
86
- * @throws \Exception If a purge failure occurs.
87
- *
88
- * @return int Total files purged by this routine.
89
- */
90
- $self->purgeCache = function ($manually = false) use ($self) {
91
- $counter = 0; // Initialize.
92
-
93
- if (!$manually && $self->disableAutoPurgeCacheRoutines()) {
94
- return $counter; // Nothing to do.
95
- }
96
- @set_time_limit(1800); // @TODO Display a warning.
97
-
98
- if (is_dir($cache_dir = $self->cacheDir())) {
99
- $regex = $self->buildHostCachePathRegex('', '.+');
100
- $counter += $self->purgeFilesFromHostCacheDir($regex);
101
- }
102
-
103
- return $counter;
104
- };
105
- $self->purge_cache = $self->purgeCache; // Back compat.
106
-
107
- /*
108
- * Wurges (purges) all expired cache files; like wipe, but expired files only.
109
- *
110
- * @since 151002 Look at entire cache directory.
111
- *
112
- * @param bool $manually TRUE if wurging is done manually.
113
- *
114
- * @throws \Exception If a wurge failure occurs.
115
- *
116
- * @return int Total files wurged by this routine.
117
- */
118
- $self->wurgeCache = function ($manually = false) use ($self) {
119
- $counter = 0; // Initialize.
120
-
121
- if (!$manually && $self->disableAutoPurgeCacheRoutines()) {
122
- return $counter; // Nothing to do.
123
- }
124
- @set_time_limit(1800); // @TODO Display a warning.
125
-
126
- if (is_dir($cache_dir = $self->cacheDir())) {
127
- $regex = $self->assembleCachePathRegex('', '.+');
128
- $counter += $self->wurgeFilesFromCacheDir($regex);
129
- }
130
-
131
- return $counter;
132
- };
133
-
134
- /*
135
- * Automatically wipes out all cache files.
136
- *
137
- * @attaches-to Nothing at this time.
138
- *
139
- * @since 150422 Rewrite.
140
- *
141
- * @return int Total files wiped by this routine (if any).
142
- *
143
- * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
144
- * This is called upon whenever options are saved and/or restored though.
145
- */
146
- $self->autoWipeCache = function () use ($self) {
147
- $counter = 0; // Initialize.
148
-
149
- if (!is_null($done = &$self->cacheKey('autoWipeCache'))) {
150
- return $counter; // Already did this.
151
- }
152
- $done = true; // Flag as having been done.
153
-
154
- if (!$self->options['enable']) {
155
- return $counter; // Nothing to do.
156
- }
157
- if ($self->disableAutoWipeCacheRoutines()) {
158
- return $counter; // Nothing to do.
159
- }
160
- $counter += $self->wipeCache();
161
-
162
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
163
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/wipe.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
164
- sprintf(__('<strong>%1$s:</strong> detected significant changes. Found %2$s in the cache; auto-wiping.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
165
- }
166
- return $counter;
167
- };
168
-
169
- /*
170
- * Automatically clears all cache files (current host).
171
- *
172
- * @attaches-to `switch_theme` hook.
173
- *
174
- * @attaches-to `wp_create_nav_menu` hook.
175
- * @attaches-to `wp_update_nav_menu` hook.
176
- * @attaches-to `wp_delete_nav_menu` hook.
177
- *
178
- * @attaches-to `create_term` hook.
179
- * @attaches-to `edit_terms` hook.
180
- * @attaches-to `delete_term` hook.
181
- *
182
- * @attaches-to `add_link` hook.
183
- * @attaches-to `edit_link` hook.
184
- * @attaches-to `delete_link` hook.
185
- *
186
- * @since 150422 Rewrite.
187
- *
188
- * @return int Total files cleared by this routine (if any).
189
- *
190
- * @note This is also called upon during plugin activation.
191
- */
192
- $self->autoClearCache = function () use ($self) {
193
- $counter = 0; // Initialize.
194
-
195
- if (!is_null($done = &$self->cacheKey('autoClearCache'))) {
196
- return $counter; // Already did this.
197
- }
198
- $done = true; // Flag as having been done.
199
-
200
- if (!$self->options['enable']) {
201
- return $counter; // Nothing to do.
202
- }
203
- if ($self->disableAutoClearCacheRoutines()) {
204
- return $counter; // Nothing to do.
205
- }
206
- $counter += $self->clearCache();
207
-
208
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
209
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
210
- sprintf(__('<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache for this site; auto-clearing.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
211
- }
212
- return $counter;
213
- };
214
-
215
- /*
216
- * Automatically purges all cache files (current host).
217
- *
218
- * @attaches-to Nothing at this time.
219
- *
220
- * @since 151002 While working on directory stats.
221
- *
222
- * @return int Total files purged by this routine.
223
- *
224
- * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
225
- */
226
- $self->autoPurgeCache = function () use ($self) {
227
- $counter = 0; // Initialize.
228
-
229
- if (!is_null($done = &$self->cacheKey('autoPurgeCache'))) {
230
- return $counter; // Already did this.
231
- }
232
- $done = true; // Flag as having been done.
233
-
234
- if (!$self->options['enable']) {
235
- return $counter; // Nothing to do.
236
- }
237
- if ($self->disableAutoPurgeCacheRoutines()) {
238
- return $counter; // Nothing to do.
239
- }
240
- $counter += $self->purgeCache();
241
-
242
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
243
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
244
- sprintf(__('<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache for this site that were expired; auto-purging.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
245
- }
246
- return $counter;
247
- };
248
-
249
- /*
250
- * Automatically wurges all cache files.
251
- *
252
- * @attaches-to Nothing at this time.
253
- *
254
- * @since 151002 While working on directory stats.
255
- *
256
- * @return int Total files wurged by this routine.
257
- *
258
- * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
259
- */
260
- $self->autoWurgeCache = function () use ($self) {
261
- $counter = 0; // Initialize.
262
-
263
- if (!is_null($done = &$self->cacheKey('autoWurgeCache'))) {
264
- return $counter; // Already did this.
265
- }
266
- $done = true; // Flag as having been done.
267
-
268
- if (!$self->options['enable']) {
269
- return $counter; // Nothing to do.
270
- }
271
- if ($self->disableAutoPurgeCacheRoutines()) {
272
- return $counter; // Nothing to do.
273
- }
274
- $counter += $self->wurgeCache();
275
-
276
- if ($counter && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
277
- $self->enqueueNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
278
- sprintf(__('<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache that were expired; auto-purging.', 'comet-cache'), esc_html(NAME), esc_html($self->i18nFiles($counter))));
279
- }
280
- return $counter;
281
- };
282
-
283
- /*
284
- * Allows a site owner to disable the automatic cache wiping routines.
285
- *
286
- * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_wipe_cache_routines` to return TRUE,
287
- * in which case this method returns TRUE, otherwise it returns FALSE.
288
- *
289
- * @since 150422 Rewrite.
290
- *
291
- * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
292
- */
293
- $self->disableAutoWipeCacheRoutines = function () use ($self) {
294
- $is_disabled = (boolean) $self->applyWpFilters(GLOBAL_NS.'_disable_auto_wipe_cache_routines', false);
295
-
296
- if ($is_disabled && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
297
- $self->enqueueMainNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
298
- sprintf(__('<strong>%1$s:</strong> detected significant changes that would normally trigger cache wiping routines. However, cache wiping routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME)));
299
- }
300
- return $is_disabled;
301
- };
302
-
303
- /*
304
- * Allows a site owner to disable the automatic cache clearing routines.
305
- *
306
- * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_clear_cache_routines` to return TRUE,
307
- * in which case this method returns TRUE, otherwise it returns FALSE.
308
- *
309
- * @since 150422 Rewrite.
310
- *
311
- * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
312
- */
313
- $self->disableAutoClearCacheRoutines = function () use ($self) {
314
- $is_disabled = (boolean) $self->applyWpFilters(GLOBAL_NS.'_disable_auto_clear_cache_routines', false);
315
-
316
- if ($is_disabled && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
317
- $self->enqueueMainNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
318
- sprintf(__('<strong>%1$s:</strong> detected important site changes that would normally trigger cache clearing routines. However, cache clearing routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME)));
319
- }
320
- return $is_disabled;
321
- };
322
-
323
- /*
324
- * Allows a site owner to disable the automatic cache purging routines.
325
- *
326
- * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_purge_cache_routines` to return TRUE,
327
- * in which case this method returns TRUE, otherwise it returns FALSE.
328
- *
329
- * @since 151002 While working on directory stats.
330
- *
331
- * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
332
- */
333
- $self->disableAutoPurgeCacheRoutines = function () use ($self) {
334
- $is_disabled = (boolean) $self->applyWpFilters(GLOBAL_NS.'_disable_auto_purge_cache_routines', false);
335
-
336
- if ($is_disabled && is_admin() && (!IS_PRO || $self->options['change_notifications_enable'])) {
337
- $self->enqueueMainNotice('<img src="'.esc_attr($self->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
338
- sprintf(__('<strong>%1$s:</strong> detected important site changes that would normally trigger cache purging routines. However, cache purging routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME)));
339
- }
340
- return $is_disabled;
341
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Plugin/WcpWooCommerceUtils.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Automatically clears cache file for a WooCommerce Product when its stock is changed.
6
- *
7
- * @since 151220 Improving WooCommerce Compatibility.
8
- *
9
- * @attaches-to `woocommerce_product_set_stock` hook.
10
- *
11
- * @param \WC_Product $product A WooCommerce WC_Product object
12
- */
13
- $self->autoClearPostCacheOnWooCommerceSetStock = function ($product) use ($self) {
14
- $counter = 0; // Initialize.
15
-
16
- if (!is_null($done = &$self->cacheKey('autoClearPostCacheOnWooCommerceSetStock'))) {
17
- return $counter; // Already did this.
18
- }
19
- $done = true; // Flag as having been done.
20
-
21
- if(class_exists('\\WooCommerce')) {
22
- $counter += $self->autoClearPostCache($product->id);
23
- }
24
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/BlogUtils.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Get blog details.
6
- *
7
- * @since 150821 Improving multisite compat.
8
- *
9
- * @param integer $blog_id For which blog ID?
10
- *
11
- * @return \stdClass|null Blog details if possible.
12
- *
13
- * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
14
- */
15
- $self->blogDetails = function ($blog_id = 0) use ($self) {
16
- if (!is_multisite() || $self->isAdvancedCache()) {
17
- return null; // Not possible.
18
- }
19
- if (($blog_id = (integer) $blog_id) < 0) {
20
- $blog_id = (integer) get_current_site()->blog_id;
21
- }
22
- if (!$blog_id) {
23
- $blog_id = (integer) get_current_blog_id();
24
- }
25
- if (!$blog_id || $blog_id < 0) {
26
- return null; // Not possible.
27
- }
28
- $details = get_blog_details($blog_id);
29
-
30
- return is_object($details) ? $details : null;
31
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/CacheDirUtils.php DELETED
@@ -1,643 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Cache directory path.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $rel_path Relative path inside cache directory.
10
- *
11
- * @throws \Exception If unable to get cache directory.
12
- *
13
- * @return string Absolute path to cache directory.
14
- */
15
- $self->cacheDir = function ($rel_path = '') use ($self) {
16
- $rel_path = (string) $rel_path;
17
-
18
- if ($self->isAdvancedCache()) {
19
- $cache_dir = defined('COMET_CACHE_DIR') ? COMET_CACHE_DIR : '';
20
- } elseif (!empty($self->cache_sub_dir)) {
21
- $cache_dir = $self->wpContentBaseDirTo($self->cache_sub_dir);
22
- }
23
- if (empty($cache_dir)) {
24
- throw new \Exception(__('Unable to determine cache directory location.', 'comet-cache'));
25
- }
26
- return rtrim($cache_dir, '/').($rel_path ? '/'.ltrim($rel_path) : '');
27
- };
28
-
29
- /*
30
- * Wipe files from the cache directory (for all hosts/blogs);
31
- * i.e., those that match a specific regex pattern.
32
- *
33
- * @since 151002 While working on directory stats.
34
- *
35
- * @param string $regex A regex pattern; see {@link deleteFilesFromCacheDir()}.
36
- *
37
- * @return integer Total files wiped by this routine.
38
- */
39
- $self->wipeFilesFromCacheDir = function ($regex) use ($self) {
40
- return $self->deleteFilesFromCacheDir($regex);
41
- };
42
-
43
- /*
44
- * Clear files from the cache directory (for the current host);
45
- * i.e., those that match a specific regex pattern.
46
- *
47
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
48
- *
49
- * @param string $regex A regex pattern; see {@link deleteFilesFromHostCacheDir()}.
50
- *
51
- * @return integer Total files cleared by this routine (if any).
52
- */
53
- $self->clearFilesFromHostCacheDir = function ($regex) use ($self) {
54
- return $self->deleteFilesFromHostCacheDir($regex);
55
- };
56
-
57
- /*
58
- * Wurge (purge) files from the cache directory (for all hosts/blogs);
59
- * i.e., those that match a specific regex pattern.
60
- *
61
- * @since 151002 While working on directory stats.
62
- *
63
- * @param string $regex A regex pattern; see {@link deleteFilesFromCacheDir()}.
64
- *
65
- * @return integer Total files wurged by this routine.
66
- */
67
- $self->wurgeFilesFromCacheDir = function ($regex) use ($self) {
68
- return $self->deleteFilesFromCacheDir($regex, true);
69
- };
70
-
71
- /*
72
- * Purge files from the cache directory (for the current host);
73
- * i.e., those that match a specific regex pattern.
74
- *
75
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
76
- *
77
- * @param string $regex A regex pattern; see {@link deleteFilesFromHostCacheDir()}.
78
- *
79
- * @return integer Total files purged by this routine (if any).
80
- */
81
- $self->purgeFilesFromHostCacheDir = function ($regex) use ($self) {
82
- return $self->deleteFilesFromHostCacheDir($regex, true);
83
- };
84
-
85
- /*
86
- * Delete files from the cache directory (for all hosts/blogs);
87
- * i.e., those that match a specific regex pattern.
88
- *
89
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
90
- *
91
- * @param string $regex A `/[regex pattern]/`; relative to the cache directory.
92
- * e.g. `/^http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
93
- *
94
- * Or, this can also be a full/absolute regex pattern against an absolute path;
95
- * provided that it always starts with `/^`; including the full absolute cache/host directory path.
96
- * e.g. `/^\/cache\/dir\/http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
97
- *
98
- * @param boolean $check_max_age Check max age? i.e., use purge behavior?
99
- *
100
- * @return integer Total files deleted by this routine (if any).
101
- *
102
- * @throws \Exception If unable to delete a file for any reason.
103
- *
104
- * @TODO Optimize this for multisite networks w/ a LOT of child blogs.
105
- * @TODO Optimize this for extremely large sites. A LOT of files here could slow things down.
106
- * This class member is currently used in wiping and purging for a network. So there is the potential for a LOT of files in a single scan.
107
- * See also: <https://codex.wordpress.org/Function_Reference/wp_is_large_network>
108
- */
109
- $self->deleteFilesFromCacheDir = function ($regex, $check_max_age = false) use ($self) {
110
- $counter = 0; // Initialize.
111
-
112
- if (!($regex = (string) $regex)) {
113
- return $counter; // Nothing to do.
114
- }
115
- if (!is_dir($cache_dir = $self->cacheDir())) {
116
- return $counter; // Nothing to do.
117
- }
118
- $cache_dir = $self->nDirSeps($cache_dir);
119
-
120
- if ($check_max_age && $self->isAdvancedCache()) {
121
- throw new \Exception(__('Invalid argument; isAdvancedCache!', 'comet-cache'));
122
- }
123
- if ($check_max_age && !($max_age = strtotime('-'.$self->options['cache_max_age']))) {
124
- return $counter; // Invalid cache expiration time.
125
- }
126
- /* ------- Begin lock state... ----------- */
127
-
128
- $cache_lock = $self->cacheLock(); // Lock cache writes.
129
-
130
- clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
131
-
132
- $cache_dir_tmp = $self->addTmpSuffix($cache_dir); // Temporary directory.
133
-
134
- $cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
135
- $cache_dir_tmp_regex = '\\/'.ltrim($cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
136
- $cache_dir_tmp_regex = $self->strIreplaceOnce(preg_quote($cache_dir.'/', '/'), '', $cache_dir_tmp_regex);
137
-
138
- $cache_dir_tmp_regex = ltrim($cache_dir_tmp_regex, '^\\/');
139
- if (strpos($cache_dir_tmp_regex, '(?:\/') === 0 || strpos($cache_dir_tmp_regex, '(\/') === 0) {
140
- $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp, '/').$cache_dir_tmp_regex;
141
- } else {
142
- $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp.'/', '/').$cache_dir_tmp_regex;
143
- }
144
- # if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
145
- // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
146
-
147
- if (!rename($cache_dir, $cache_dir_tmp)) {
148
- throw new \Exception(sprintf(__('Unable to delete files. Rename failure on directory: `%1$s`.', 'comet-cache'), $cache_dir));
149
- }
150
- foreach (($_dir_regex_iteration = $self->dirRegexIteration($cache_dir_tmp, $cache_dir_tmp_regex)) as $_resource) {
151
- $_resource_type = $_resource->getType();
152
- $_sub_path_name = $_resource->getSubpathname();
153
- $_path_name = $_resource->getPathname();
154
-
155
- if ($_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
156
- continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
157
- // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
158
- }
159
- switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
160
-
161
- case 'link': // Symbolic links; i.e., 404 errors.
162
-
163
- if ($check_max_age && !empty($max_age) && is_file($_resource->getLinkTarget())) {
164
- if (($_lstat = lstat($_path_name)) && !empty($_lstat['mtime'])) {
165
- if ($_lstat['mtime'] >= $max_age) {
166
- break; // Break switch.
167
- }
168
- }
169
- }
170
- if (!unlink($_path_name)) {
171
- $self->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
172
- throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
173
- }
174
- ++$counter; // Increment counter for each link we delete.
175
-
176
- break; // Break switch handler.
177
-
178
- case 'file': // Regular files; i.e., not symlinks.
179
-
180
- if ($check_max_age && !empty($max_age)) {
181
- if ($_resource->getMTime() >= $max_age) {
182
- break; // Break switch.
183
- }
184
- }
185
- if (!unlink($_path_name)) {
186
- $self->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
187
- throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
188
- }
189
- ++$counter; // Increment counter for each file we delete.
190
-
191
- break; // Break switch handler.
192
-
193
- case 'dir': // A regular directory; i.e., not a symlink.
194
-
195
- if ($regex !== '/^.+/i') {
196
- break; // Not deleting everything.
197
- }
198
- if ($check_max_age && !empty($max_age)) {
199
- break; // Not deleting everything.
200
- }
201
- if (!rmdir($_path_name)) {
202
- $self->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
203
- throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
204
- }
205
- # $counter++; // Increment counter for each directory we delete. ~ NO don't do that here.
206
-
207
- break; // Break switch handler.
208
-
209
- default: // Something else that is totally unexpected here.
210
- $self->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
211
- throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
212
- }
213
- }
214
- unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name, $_lstat); // Housekeeping.
215
-
216
- if (!rename($cache_dir_tmp, $cache_dir)) {
217
- $self->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
218
- throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $cache_dir_tmp));
219
- }
220
- /* ------- End lock state... ------------- */
221
-
222
- $self->cacheUnlock($cache_lock); // Release.
223
-
224
- return $counter;
225
- };
226
-
227
- /*
228
- * Delete files from the cache directory (for the current host);
229
- * i.e., those that match a specific regex pattern.
230
- *
231
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
232
- *
233
- * @param string $regex A `/[regex pattern]/`; relative to the host cache directory.
234
- * e.g. `/^my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
235
- *
236
- * Or, this can also be a full/absolute regex pattern against an absolute path;
237
- * provided that it always starts with `/^`; including the full absolute cache/host directory path.
238
- * e.g. `/^\/cache\/dir\/http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
239
- *
240
- * @param boolean $check_max_age Check max age? i.e., use purge behavior?
241
- *
242
- * @param boolean $___considering_domain_mapping For internal use only.
243
- * @param boolean $___consider_domain_mapping_host_token For internal use only.
244
- * @param boolean $___consider_domain_mapping_host_base_dir_tokens For internal use only.
245
- *
246
- * @return integer Total files deleted by this routine (if any).
247
- *
248
- * @throws \Exception If unable to delete a file for any reason.
249
- */
250
- $self->deleteFilesFromHostCacheDir = function (
251
- $regex,
252
- $check_max_age = false,
253
- $___considering_domain_mapping = false,
254
- $___consider_domain_mapping_host_token = null,
255
- $___consider_domain_mapping_host_base_dir_tokens = null
256
- ) use ($self) {
257
- $counter = 0; // Initialize.
258
-
259
- if (!($regex = (string) $regex)) {
260
- return $counter; // Nothing to do.
261
- }
262
- if (!is_dir($cache_dir = $self->cacheDir())) {
263
- return $counter; // Nothing to do.
264
- }
265
- $cache_dir = $self->nDirSeps($cache_dir); // Normalize.
266
- $host_token = $current_host_token = $self->hostToken();
267
- $host_base_dir_tokens = $current_host_base_dir_tokens = $self->hostBaseDirTokens();
268
-
269
- if ($___considering_domain_mapping && isset($___consider_domain_mapping_host_token, $___consider_domain_mapping_host_base_dir_tokens)) {
270
- $host_token = (string) $___consider_domain_mapping_host_token;
271
- $host_base_dir_tokens = (string) $___consider_domain_mapping_host_base_dir_tokens;
272
- }
273
- if (!$host_token) { // Must have a host in the sub-routine below.
274
- throw new \Exception(__('Invalid argument; host token empty!', 'comet-cache'));
275
- }
276
- if ($check_max_age && $self->isAdvancedCache()) {
277
- throw new \Exception(__('Invalid argument; isAdvancedCache!', 'comet-cache'));
278
- }
279
- if ($check_max_age && !($max_age = strtotime('-'.$self->options['cache_max_age']))) {
280
- return $counter; // Invalid cache expiration time.
281
- }
282
- /* ------- Begin lock state... ----------- */
283
-
284
- $cache_lock = $self->cacheLock(); // Lock cache writes.
285
-
286
- clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
287
-
288
- foreach (array('http', 'https') as $_host_scheme) {
289
- $_host_url = $_host_scheme.'://'.$host_token.$host_base_dir_tokens;
290
- $_host_cache_path_flags = CACHE_PATH_NO_PATH_INDEX | CACHE_PATH_NO_QUV | CACHE_PATH_NO_EXT;
291
- $_host_cache_path = $self->buildCachePath($_host_url, '', '', $_host_cache_path_flags);
292
- $_host_cache_dir = $self->nDirSeps($cache_dir.'/'.$_host_cache_path); // Normalize.
293
-
294
- if (!$_host_cache_dir || !is_dir($_host_cache_dir)) {
295
- // On a multisite install this may have a cache sub-directory.
296
- // e.g., `http/example-com[[-base]-child1][[/base]/child1]` instead of `http/example-com`.
297
- continue; // Nothing to do.
298
- }
299
- $_host_cache_dir_tmp = $self->addTmpSuffix($_host_cache_dir); // Temporary directory.
300
-
301
- $_host_cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
302
- $_host_cache_dir_tmp_regex = '\\/'.ltrim($_host_cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
303
- $_host_cache_dir_tmp_regex = $self->strIreplaceOnce(preg_quote($_host_cache_path.'/', '/'), '', $_host_cache_dir_tmp_regex);
304
- $_host_cache_dir_tmp_regex = $self->strIreplaceOnce(preg_quote($_host_cache_dir.'/', '/'), '', $_host_cache_dir_tmp_regex);
305
-
306
- $_host_cache_dir_tmp_regex = ltrim($_host_cache_dir_tmp_regex, '^\\/');
307
- if (strpos($_host_cache_dir_tmp_regex, '(?:\/') === 0 || strpos($_host_cache_dir_tmp_regex, '(\/') === 0) {
308
- $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp, '/').$_host_cache_dir_tmp_regex;
309
- } else {
310
- $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp.'/', '/').$_host_cache_dir_tmp_regex;
311
- }
312
- #if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($_host_cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
313
- // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
314
-
315
- if (!rename($_host_cache_dir, $_host_cache_dir_tmp)) {
316
- throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $_host_cache_dir));
317
- }
318
- foreach (($_dir_regex_iteration = $self->dirRegexIteration($_host_cache_dir_tmp, $_host_cache_dir_tmp_regex)) as $_resource) {
319
- $_resource_type = $_resource->getType();
320
- $_sub_path_name = $_resource->getSubpathname();
321
- $_path_name = $_resource->getPathname();
322
-
323
- if ($_host_cache_dir === $cache_dir && $_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
324
- continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
325
- // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
326
- }
327
- switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
328
-
329
- case 'link': // Symbolic links; i.e., 404 errors.
330
-
331
- if ($check_max_age && !empty($max_age) && is_file($_resource->getLinkTarget())) {
332
- if (($_lstat = lstat($_path_name)) && !empty($_lstat['mtime'])) {
333
- if ($_lstat['mtime'] >= $max_age) {
334
- break; // Break switch.
335
- }
336
- }
337
- }
338
- if (!unlink($_path_name)) {
339
- $self->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
340
- throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
341
- }
342
- ++$counter; // Increment counter for each link we delete.
343
-
344
- break; // Break switch handler.
345
-
346
- case 'file': // Regular files; i.e., not symlinks.
347
-
348
- if ($check_max_age && !empty($max_age)) {
349
- if ($_resource->getMTime() >= $max_age) {
350
- break; // Break switch handler.
351
- }
352
- }
353
- if (!unlink($_path_name)) {
354
- $self->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
355
- throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
356
- }
357
- ++$counter; // Increment counter for each file we delete.
358
-
359
- break; // Break switch handler.
360
-
361
- case 'dir': // A regular directory; i.e., not a symlink.
362
-
363
- if ($regex !== '/^.+/i') {
364
- break; // Not deleting everything.
365
- }
366
- if ($check_max_age && !empty($max_age)) {
367
- break; // Not deleting everything.
368
- }
369
- if (!rmdir($_path_name)) {
370
- $self->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
371
- throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
372
- }
373
- # $counter++; // Increment counter for each directory we delete. ~ NO don't do that here.
374
-
375
- break; // Break switch handler.
376
-
377
- default: // Something else that is totally unexpected here.
378
- $self->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
379
- throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
380
- }
381
- }
382
- unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name, $_lstat); // Housekeeping.
383
-
384
- if (!rename($_host_cache_dir_tmp, $_host_cache_dir)) {
385
- $self->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
386
- throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $_host_cache_dir_tmp));
387
- }
388
- }
389
- unset($_host_scheme, $_host_url, $_host_cache_path_flags, $_host_cache_path, $_host_cache_dir, $_host_cache_dir_tmp, $_host_cache_dir_tmp_regex);
390
-
391
- /* ------- End lock state... ------------- */
392
-
393
- $self->cacheUnlock($cache_lock); // Release.
394
-
395
- /* ------- Include domain mapping variations also. ------- */
396
-
397
- if (!$___considering_domain_mapping && is_multisite() && $self->canConsiderDomainMapping()) {
398
- $domain_mapping_variations = array(); // Initialize array of domain variations.
399
-
400
- if (($_host_token_for_blog = $self->hostTokenForBlog())) {
401
- $_host_base_dir_tokens_for_blog = $self->hostBaseDirTokensForBlog();
402
- $domain_mapping_variations[] = array('host_token' => $_host_token_for_blog, 'host_base_dir_tokens' => $_host_base_dir_tokens_for_blog);
403
- } // The original blog host; i.e., without domain mapping.
404
- unset($_host_token_for_blog, $_host_base_dir_tokens_for_blog); // Housekeeping.
405
-
406
- foreach ($self->domainMappingBlogDomains() as $_domain_mapping_blog_domain) {
407
- if (($_domain_host_token_for_blog = $self->hostTokenForBlog(false, true, $_domain_mapping_blog_domain))) {
408
- $_domain_host_base_dir_tokens_for_blog = $self->hostBaseDirTokensForBlog(false, true); // This is only a formality.
409
- $domain_mapping_variations[] = array('host_token' => $_domain_host_token_for_blog, 'host_base_dir_tokens' => $_domain_host_base_dir_tokens_for_blog);
410
- }
411
- } // This includes all of the domain mappings configured for the current blog ID.
412
- unset($_domain_mapping_blog_domain, $_domain_host_token_for_blog, $_domain_host_base_dir_tokens_for_blog); // Housekeeping.
413
-
414
- foreach ($domain_mapping_variations as $_domain_mapping_variation) {
415
- if ($_domain_mapping_variation['host_token'] === $current_host_token && $_domain_mapping_variation['host_base_dir_tokens'] === $current_host_base_dir_tokens) {
416
- continue; // Exclude current tokens. They were already iterated above.
417
- }
418
- $counter += $self->deleteFilesFromHostCacheDir($regex, $check_max_age, true, $_domain_mapping_variation['host_token'], $_domain_mapping_variation['host_base_dir_tokens']);
419
- }
420
- unset($_domain_mapping_variation); // Housekeeping.
421
- }
422
- return $counter;
423
- };
424
-
425
- /*
426
- * Delete all files/dirs from a directory (for all schemes/hosts);
427
- * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
428
- *
429
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
430
- *
431
- * @param string $dir The directory from which to delete files/dirs.
432
- *
433
- * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
434
- * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
435
- * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
436
- *
437
- * @param boolean $delete_dir_too Delete parent? i.e., delete the `$dir` itself also?
438
- *
439
- * @return integer Total files/directories deleted by this routine (if any).
440
- *
441
- * @throws \Exception If unable to delete a file/directory for any reason.
442
- */
443
- $self->deleteAllFilesDirsIn = function ($dir, $delete_dir_too = false) use ($self) {
444
- $counter = 0; // Initialize.
445
-
446
- if (!($dir = trim((string) $dir)) || !is_dir($dir)) {
447
- return $counter; // Nothing to do.
448
- }
449
- $dir = $self->nDirSeps($dir);
450
- $dir_temp = $self->addTmpSuffix($dir);
451
- $wp_content_dir = $self->nDirSeps(WP_CONTENT_DIR);
452
- $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
453
-
454
- if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
455
- return $counter; // Security flag; do nothing in this case.
456
- }
457
- if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
458
- return $counter; // Security flag; do nothing in this case.
459
- }
460
- /* ------- Begin lock state... ----------- */
461
-
462
- $cache_lock = $self->cacheLock(); // Lock cache writes.
463
-
464
- clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
465
-
466
- if (!rename($dir, $dir_temp)) {
467
- throw new \Exception(sprintf(__('Unable to delete all files/dirs. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $dir));
468
- }
469
- foreach (($_dir_regex_iteration = $self->dirRegexIteration($dir_temp, '/.+/')) as $_resource) {
470
- $_resource_type = $_resource->getType();
471
- $_sub_path_name = $_resource->getSubpathname();
472
- $_path_name = $_resource->getPathname();
473
-
474
- switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
475
-
476
- case 'link': // Symbolic links; i.e., 404 errors.
477
-
478
- if (!unlink($_path_name)) {
479
- $self->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
480
- throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
481
- }
482
- ++$counter; // Increment counter for each link we delete.
483
-
484
- break; // Break switch handler.
485
-
486
- case 'file': // Regular files; i.e., not symlinks.
487
-
488
- if (!unlink($_path_name)) {
489
- $self->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
490
- throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
491
- }
492
- ++$counter; // Increment counter for each file we delete.
493
-
494
- break; // Break switch handler.
495
-
496
- case 'dir': // A regular directory; i.e., not a symlink.
497
-
498
- if (!rmdir($_path_name)) {
499
- $self->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
500
- throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
501
- }
502
- # ++$counter; // Increment counter for each directory we delete. ~ NO don't do that here.
503
-
504
- break; // Break switch handler.
505
-
506
- default: // Something else that is totally unexpected here.
507
- $self->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
508
- throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
509
- }
510
- }
511
- unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name); // Housekeeping.
512
-
513
- if (!rename($dir_temp, $dir)) {
514
- $self->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
515
- throw new \Exception(sprintf(__('Unable to delete all files/dirs. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $dir_temp));
516
- }
517
- if ($delete_dir_too) {
518
- if (!rmdir($dir)) {
519
- throw new \Exception(sprintf(__('Unable to delete directory: `%1$s`.', 'comet-cache'), $dir));
520
- }
521
- ++$counter; // Increment counter for each directory we delete.
522
- }
523
- /* ------- End lock state... ------------- */
524
-
525
- $self->cacheUnlock($cache_lock); // Release.
526
-
527
- return $counter;
528
- };
529
-
530
- /*
531
- * Erase all files/dirs from a directory (for all schemes/hosts);
532
- * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
533
- *
534
- * WARNING: This does NO LOCKING and NO ATOMIC deletions.
535
- *
536
- * @since 150821 Improving recovery under stress.
537
- *
538
- * @param string $dir The directory from which to erase files/dirs.
539
- *
540
- * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
541
- * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
542
- * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
543
- *
544
- * @param boolean $erase_dir_too Erase parent? i.e., erase the `$dir` itself also?
545
- *
546
- * @return integer Total files/directories erased by this routine (if any).
547
- *
548
- * @throws \Exception If unable to erase a file/directory for any reason.
549
- */
550
- $self->eraseAllFilesDirsIn = function ($dir, $erase_dir_too = false) use ($self) {
551
- $counter = 0; // Initialize.
552
-
553
- if (!($dir = trim((string) $dir)) || !is_dir($dir)) {
554
- return $counter; // Nothing to do.
555
- }
556
- $dir = $self->nDirSeps($dir);
557
- $wp_content_dir = $self->nDirSeps(WP_CONTENT_DIR);
558
- $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
559
-
560
- if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
561
- return $counter; // Security flag; do nothing in this case.
562
- }
563
- if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
564
- return $counter; // Security flag; do nothing in this case.
565
- }
566
- clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
567
-
568
- foreach (($_dir_regex_iteration = $self->dirRegexIteration($dir, '/.+/')) as $_resource) {
569
- $_resource_type = $_resource->getType();
570
- $_sub_path_name = $_resource->getSubpathname();
571
- $_path_name = $_resource->getPathname();
572
-
573
- switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
574
-
575
- case 'link': // Symbolic links; i.e., 404 errors.
576
-
577
- if (!unlink($_path_name)) {
578
- throw new \Exception(sprintf(__('Unable to erase symlink: `%1$s`.', 'comet-cache'), $_path_name));
579
- }
580
- ++$counter; // Increment counter for each link we erase.
581
-
582
- break; // Break switch handler.
583
-
584
- case 'file': // Regular files; i.e., not symlinks.
585
-
586
- if (!unlink($_path_name)) {
587
- throw new \Exception(sprintf(__('Unable to erase file: `%1$s`.', 'comet-cache'), $_path_name));
588
- }
589
- ++$counter; // Increment counter for each file we erase.
590
-
591
- break; // Break switch handler.
592
-
593
- case 'dir': // A regular directory; i.e., not a symlink.
594
-
595
- if (!rmdir($_path_name)) {
596
- throw new \Exception(sprintf(__('Unable to erase dir: `%1$s`.', 'comet-cache'), $_path_name));
597
- }
598
- # ++$counter; // Increment counter for each directory we erase. ~ NO don't do that here.
599
-
600
- break; // Break switch handler.
601
-
602
- default: // Something else that is totally unexpected here.
603
- throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
604
- }
605
- }
606
- unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name); // Housekeeping.
607
-
608
- if ($erase_dir_too) {
609
- if (!rmdir($dir)) {
610
- throw new \Exception(sprintf(__('Unable to erase directory: `%1$s`.', 'comet-cache'), $dir));
611
- }
612
- ++$counter; // Increment counter for each directory we erase.
613
- }
614
- return $counter;
615
- };
616
-
617
- /*
618
- * Try to erase all files/dirs from a directory (for all schemes/hosts);
619
- * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
620
- *
621
- * WARNING: This does NO LOCKING and NO ATOMIC deletions.
622
- *
623
- * @since 150821 Improving recovery under stress.
624
- *
625
- * @param string $dir The directory from which to erase files/dirs.
626
- *
627
- * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
628
- * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
629
- * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
630
- *
631
- * @param boolean $erase_dir_too Erase parent? i.e., erase the `$dir` itself also?
632
- *
633
- * @return integer Total files/directories erased by this routine (if any).
634
- */
635
- $self->tryErasingAllFilesDirsIn = function ($dir, $erase_dir_too = false) use ($self) {
636
- $counter = 0; // Initialize counter.
637
- try {
638
- $counter += $self->eraseAllFilesDirsIn($dir, $erase_dir_too);
639
- } catch (\Exception $exception) {
640
- // Fail softly.
641
- }
642
- return $counter;
643
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/CacheLockUtils.php DELETED
@@ -1,80 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Get an exclusive lock on the cache directory.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @return array Lock type & resource handle needed to unlock later or FALSE if disabled by filter.
10
- *
11
- * @throws \Exception If {@link \sem_get()} not available and there's
12
- * no writable tmp directory for {@link \flock()} either.
13
- *
14
- * @throws \Exception If unable to obtain an exclusive lock by any available means.
15
- *
16
- * @note This call is blocking; i.e. it will not return a lock until a lock becomes possible.
17
- * In short, this will block the caller until such time as write access becomes possible.
18
- */
19
- $self->cacheLock = function () use ($self) {
20
- if ($self->applyWpFilters(GLOBAL_NS.'\\share::disable_cache_locking', false)
21
- || $self->applyWpFilters(GLOBAL_NS.'_disable_cache_locking', false)) {
22
- return false; // Disabled cache locking.
23
- }
24
- if (!($wp_config_file = $self->findWpConfigFile())) {
25
- throw new \Exception(__('Unable to find the wp-config.php file.', 'comet-cache'));
26
- }
27
- $lock_type = 'flock'; // Default lock type.
28
- $lock_type = $self->applyWpFilters(GLOBAL_NS.'\\share::cache_lock_lock_type', $lock_type);
29
- $lock_type = $self->applyWpFilters(GLOBAL_NS.'_cache_lock_type', $lock_type);
30
-
31
- if (!in_array($lock_type, array('flock', 'sem'), true)) {
32
- $lock_type = 'flock'; // Default lock type.
33
- }
34
- if ($lock_type === 'sem' && $self->functionIsPossible('sem_get')) {
35
- if (($ipc_key = ftok($wp_config_file, 'w'))) {
36
- if (($resource = sem_get($ipc_key, 1)) && sem_acquire($resource)) {
37
- return array('type' => 'sem', 'resource' => $resource);
38
- }
39
- }
40
- }
41
- if (!($tmp_dir = $self->getTmpDir())) {
42
- throw new \Exception(__('No writable tmp directory.', 'comet-cache'));
43
- }
44
- $inode_key = fileinode($wp_config_file);
45
- $mutex = $tmp_dir.'/'.SLUG_TD.'-'.$inode_key.'.lock';
46
-
47
- if (!($resource = fopen($mutex, 'wb')) || !flock($resource, LOCK_EX)) {
48
- throw new \Exception(__('Unable to obtain an exclusive lock.', 'comet-cache'));
49
- }
50
-
51
- @chmod($mutex, 0666); // See https://git.io/v2WAt
52
-
53
- return array('type' => 'flock', 'resource' => $resource);
54
- };
55
-
56
- /*
57
- * Release an exclusive lock on the cache directory.
58
- *
59
- * @since 150422 Rewrite. Updated 151002 to remove the `array` typecast.
60
- *
61
- * @param array|mixed $lock Type & resource.
62
- */
63
- $self->cacheUnlock = function ($lock) use ($self) {
64
- if (!is_array($lock)) {
65
- return; // Not possible.
66
- // Or, they disabled cache locking.
67
- }
68
- if (empty($lock['type']) || empty($lock['resource'])) {
69
- return; // Not possible.
70
- }
71
- if (!is_resource($lock['resource'])) {
72
- return; // Not possible.
73
- }
74
- if ($lock['type'] === 'sem') {
75
- sem_release($lock['resource']);
76
- } elseif ($lock['type'] === 'flock') {
77
- flock($lock['resource'], LOCK_UN);
78
- fclose($lock['resource']);
79
- }
80
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/CachePathConsts.php DELETED
@@ -1,140 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- if (defined(__NAMESPACE__.'\\CACHE_PATH_DEFAULT')) {
5
- return; // Already defined these.
6
- }
7
- /**
8
- * Default cache path flags.
9
- *
10
- * @since 150422 Rewrite.
11
- *
12
- * @type int A bitmask.
13
- */
14
- const CACHE_PATH_DEFAULT = 0;
15
-
16
- /**
17
- * Use a domain-mapped cache path.
18
- *
19
- * @since 150821 Improving multisite compat.
20
- *
21
- * @type int Part of a bitmask.
22
- */
23
- const CACHE_PATH_CONSIDER_DOMAIN_MAPPING = 1;
24
-
25
- /**
26
- * Generate an unmapped cache path?
27
- *
28
- * @since 150821 Improving multisite compat.
29
- *
30
- * @type int Part of a bitmask.
31
- */
32
- const CACHE_PATH_REVERSE_DOMAIN_MAPPING = 2;
33
-
34
- /**
35
- * Exclude scheme from cache path.
36
- *
37
- * @since 150422 Rewrite.
38
- *
39
- * @type int Part of a bitmask.
40
- */
41
- const CACHE_PATH_NO_SCHEME = 4;
42
-
43
- /**
44
- * Exclude host (i.e. domain name) from cache path.
45
- *
46
- * @since 150422 Rewrite.
47
- *
48
- * @type int Part of a bitmask.
49
- */
50
- const CACHE_PATH_NO_HOST = 8;
51
-
52
- /**
53
- * Exclude path from cache path.
54
- *
55
- * @since 150422 Rewrite.
56
- *
57
- * @type int Part of a bitmask.
58
- */
59
- const CACHE_PATH_NO_PATH = 16;
60
-
61
- /**
62
- * Exclude path index (i.e. no default `index`) from cache path.
63
- *
64
- * @since 150422 Rewrite.
65
- *
66
- * @type int Part of a bitmask.
67
- */
68
- const CACHE_PATH_NO_PATH_INDEX = 32;
69
-
70
- /**
71
- * Exclude query, user & version salt from cache path.
72
- *
73
- * @since 150422 Rewrite.
74
- *
75
- * @type int Part of a bitmask.
76
- */
77
- const CACHE_PATH_NO_QUV = 64;
78
-
79
- /**
80
- * Exclude query string from cache path.
81
- *
82
- * @since 150422 Rewrite.
83
- *
84
- * @type int Part of a bitmask.
85
- */
86
- const CACHE_PATH_NO_QUERY = 128;
87
-
88
- /**
89
- * Exclude user token from cache path.
90
- *
91
- * @since 150422 Rewrite.
92
- *
93
- * @type int Part of a bitmask.
94
- */
95
- const CACHE_PATH_NO_USER = 256;
96
-
97
- /**
98
- * Exclude version salt from cache path.
99
- *
100
- * @since 150422 Rewrite.
101
- *
102
- * @type int Part of a bitmask.
103
- */
104
- const CACHE_PATH_NO_VSALT = 512;
105
-
106
- /**
107
- * Exclude extension from cache path.
108
- *
109
- * @since 150422 Rewrite.
110
- *
111
- * @type int Part of a bitmask.
112
- */
113
- const CACHE_PATH_NO_EXT = 1024;
114
-
115
- /**
116
- * Allow wildcards in the cache path.
117
- *
118
- * @since 150422 Rewrite.
119
- *
120
- * @type int Part of a bitmask.
121
- */
122
- const CACHE_PATH_ALLOW_WILDCARDS = 2048;
123
-
124
- /**
125
- * Allow watered-down regex in the cache path.
126
- *
127
- * @since 151114 Improving regex syntax.
128
- *
129
- * @type int Part of a bitmask.
130
- */
131
- const CACHE_PATH_ALLOW_WD_REGEX = 4096;
132
-
133
- /**
134
- * Default cache path regex suffix frag.
135
- *
136
- * @since 150422 Rewrite.
137
- *
138
- * @type string Default regex suffix frag used in cache path patterns.
139
- */
140
- const CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/CachePathUtils.php DELETED
@@ -1,351 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Cache-path suffix frag (regex).
6
- *
7
- * @since 151220 Enhancing translation support.
8
- *
9
- * @param string $regex_suffix_frag Existing regex suffix frag?
10
- *
11
- * @return string Cache-path suffix frag (regex).
12
- */
13
- $self->cachePathRegexSuffixFrag = function ($regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
14
- if ($regex_suffix_frag === CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) {
15
- return $self->cachePathRegexDefaultSuffixFrag();
16
- }
17
- return (string) $regex_suffix_frag;
18
- };
19
-
20
- /*
21
- * Default cache-path suffix frag (regex).
22
- *
23
- * @since 151220 Enhancing translation support.
24
- *
25
- * @return string Default cache-path suffix frag (regex).
26
- *
27
- * @TODO Use conditional to detect the AMP plugin (e.g., `isAmpInstalled()`) to avoid edge cases with the `|\/amp` regex here
28
- */
29
- $self->cachePathRegexDefaultSuffixFrag = function () use ($self) {
30
- if ($self->isPlugin() && !empty($GLOBALS['wp_rewrite'])){
31
- $pagination_base = $GLOBALS['wp_rewrite']->pagination_base;
32
- $comments_pagination_base = $GLOBALS['wp_rewrite']->comments_pagination_base;
33
- return '(?:\/index|\/amp)?(?:\.|\/(?:'.preg_quote($pagination_base, '/').'\/[0-9]+|'.preg_quote($comments_pagination_base, '/').'\-[0-9]+)[.\/])';
34
- } else {
35
- return '(?:\/index|\/amp)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])';
36
- }
37
- };
38
-
39
- /*
40
- * Converts a URL into a `cache/path` based on input `$flags`.
41
- *
42
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
43
- *
44
- * @param string $url The input URL to convert.
45
- * @param string $with_user_token Optional user token (if applicable).
46
- * @param string $with_version_salt Optional version salt (if applicable).
47
- * @param int $flags Optional flags. A bitmask via `CACHE_PATH_*` constants.
48
- *
49
- * @return string The resulting `cache/path` based on the input `$url` & `$flags`.
50
- */
51
- $self->buildCachePath = function ($url, $with_user_token = '', $with_version_salt = '', $flags = CACHE_PATH_DEFAULT) use ($self) {
52
- # Force parameter types.
53
-
54
- $url = trim((string) $url);
55
- $with_user_token = trim((string) $with_user_token);
56
- $with_version_salt = trim((string) $with_version_salt);
57
-
58
- # Initialize variables.
59
-
60
- $is_multisite = is_multisite();
61
- $can_consider_domain_mapping = $is_multisite && $self->canConsiderDomainMapping();
62
- $cache_path = ''; // Initialize cache path being built here.
63
-
64
- # Deal w/ domain mapping considerations.
65
-
66
- if ($flags & CACHE_PATH_CONSIDER_DOMAIN_MAPPING && $is_multisite && $can_consider_domain_mapping) {
67
- if ($flags & CACHE_PATH_REVERSE_DOMAIN_MAPPING) {
68
- $url = $self->domainMappingReverseUrlFilter($url);
69
- } else {
70
- $url = $self->domainMappingUrlFilter($url);
71
- }
72
- }
73
- # Validate the URL we have now.
74
-
75
- if (!$url || !($url_parts = $self->parseUrl($url))) {
76
- return ($cache_path = ''); // Not possible.
77
- }
78
- if (empty($url_parts['scheme']) || $url_parts['scheme'] === '//') {
79
- return ($cache_path = ''); // Not possible.
80
- }
81
- if (empty($url_parts['host'])) {
82
- return ($cache_path = ''); // Not possible.
83
- }
84
- # Initialize additional variables; based on the parsed URL.
85
-
86
- $is_url_domain_mapped = $is_multisite && $can_consider_domain_mapping && $self->domainMappingBlogId($url);
87
- $host_base_dir_tokens = $self->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
88
-
89
- $is_a_multisite_base_dir = $is_multisite && $host_base_dir_tokens && $host_base_dir_tokens !== '/' // Check?
90
- && stripos(!empty($url_parts['path']) ? rtrim($url_parts['path'], '/').'/' : '/', $host_base_dir_tokens) === 0;
91
-
92
- $is_a_multisite_base_dir_root = $is_multisite && $is_a_multisite_base_dir // Save time by using the previous check here.
93
- && strcasecmp(trim($host_base_dir_tokens, '/'), trim(!empty($url_parts['path']) ? $url_parts['path'] : '/', '/')) === 0;
94
-
95
- # Build and return the cache path.
96
-
97
- if (!($flags & CACHE_PATH_NO_SCHEME)) {
98
- $cache_path .= $url_parts['scheme'].'/';
99
- }
100
- if (!($flags & CACHE_PATH_NO_HOST)) {
101
- $cache_path .= $url_parts['host'].'/';
102
-
103
- // Put multisite sub-roots into a host directory of their own.
104
- // e.g., `example-com[[-base]-child1]` instead of `example-com`.
105
- if ($is_a_multisite_base_dir && $host_base_dir_tokens && $host_base_dir_tokens !== '/') {
106
- $host_base_dir_suffix = preg_replace('/[^a-z0-9.]/i', '-', rtrim($host_base_dir_tokens, '/'));
107
- $cache_path = rtrim($cache_path, '/').$host_base_dir_suffix.'/';
108
- }
109
- }
110
- if (!($flags & CACHE_PATH_NO_PATH)) {
111
- if (isset($url_parts['path'][201])) {
112
- $_path_tmp = '/'; // Initialize tmp path.
113
- foreach (explode('/', $url_parts['path']) as $_path_component) {
114
- if (!isset($_path_component[0])) {
115
- continue; // Empty.
116
- }
117
- if (isset($_path_component[201])) {
118
- $_path_component = 'lpc-'.sha1($_path_component);
119
- }
120
- $_path_tmp .= $_path_component.'/';
121
- }
122
- $url_parts['path'] = $_path_tmp; // Shorter components.
123
- unset($_path_component, $_path_tmp); // Housekeeping.
124
-
125
- if (isset($url_parts['path'][2001])) {
126
- $url_parts['path'] = '/lp-'.sha1($url_parts['path']).'/';
127
- }
128
- } // Now add the path and check for a possible root `index/` suffix.
129
- if (!empty($url_parts['path']) && strlen($url_parts['path'] = trim($url_parts['path'], '\\/'." \t\n\r\0\x0B"))) {
130
- $cache_path .= $url_parts['path'].'/'; // Add the path as it exists.
131
-
132
- if (!($flags & CACHE_PATH_NO_PATH_INDEX) && $is_multisite && $is_a_multisite_base_dir_root) {
133
- // We should build an `index/` when this ends with a multisite [[/base]/child1] root.
134
- // e.g., `http/example-com[[-base]-child1][[/base]/child1]` is a root directory.
135
- $cache_path .= 'index/'; // Use an index suffix.
136
- }
137
- } elseif (!($flags & CACHE_PATH_NO_PATH_INDEX)) {
138
- $cache_path .= 'index/';
139
- }
140
- }
141
- if ($self->isExtensionLoaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) {
142
- $cache_path = mb_strtolower($cache_path, 'UTF-8');
143
- }
144
- $cache_path = str_replace('.', '-', strtolower($cache_path));
145
-
146
- if (!($flags & CACHE_PATH_NO_QUV)) {
147
- if (!($flags & CACHE_PATH_NO_QUERY)) {
148
- if (isset($url_parts['query']) && $url_parts['query'] !== '') {
149
- $cache_path = rtrim($cache_path, '/').'.q/'.md5($url_parts['query']).'/';
150
- }
151
- }
152
- if (!($flags & CACHE_PATH_NO_USER)) {
153
- if ($with_user_token !== '') {
154
- $cache_path = rtrim($cache_path, '/').'.u/'.str_replace(array('/', '\\'), '-', $with_user_token).'/';
155
- }
156
- }
157
- if (!($flags & CACHE_PATH_NO_VSALT)) {
158
- if ($with_version_salt !== '') {
159
- $cache_path = rtrim($cache_path, '/').'.v/'.str_replace(array('/', '\\'), '-', $with_version_salt).'/';
160
- }
161
- }
162
- }
163
- $cache_path = trim(preg_replace(array('/\/+/', '/\.+/'), array('/', '.'), $cache_path), '/');
164
-
165
- if ($flags & CACHE_PATH_ALLOW_WD_REGEX) {
166
- $cache_path = preg_replace('/[^a-z0-9\/.*\^$]/i', '-', $cache_path);
167
- } elseif ($flags & CACHE_PATH_ALLOW_WILDCARDS) {
168
- $cache_path = preg_replace('/[^a-z0-9\/.*]/i', '-', $cache_path);
169
- } else {
170
- $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path);
171
- }
172
- if (!($flags & CACHE_PATH_NO_EXT)) {
173
- $cache_path .= '.html';
174
- }
175
- return $cache_path;
176
- };
177
-
178
- /*
179
- * Regex pattern for a call to `deleteFilesFromCacheDir()`.
180
- *
181
- * @since 151114 Updated to support an arbitrary URL instead of a regex frag.
182
- *
183
- * @param string $url The input URL to convert. This CAN be left empty when necessary.
184
- * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
185
- * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
186
- *
187
- * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
188
- * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
189
- * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
190
- * See also: {@link CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
191
- *
192
- * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
193
- */
194
- $self->buildCachePathRegex = function ($url, $regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
195
- $url = trim((string) $url);
196
- $regex_suffix_frag = $self->cachePathRegexSuffixFrag($regex_suffix_frag);
197
- $cache_path_regex = ''; // Initialize regex.
198
-
199
- if ($url) {
200
- $flags = CACHE_PATH_NO_SCHEME // Scheme added below.
201
- | CACHE_PATH_NO_PATH_INDEX | CACHE_PATH_NO_QUV | CACHE_PATH_NO_EXT;
202
- $cache_path = $self->buildCachePath($url, '', '', $flags); // Without the scheme.
203
- $cache_path_regex = isset($cache_path[0]) ? '\/https?\/'.preg_quote($cache_path, '/') : '';
204
- }
205
- return '/^'.$cache_path_regex.$regex_suffix_frag.'/i';
206
- };
207
-
208
- /*
209
- * Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
210
- *
211
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
212
- *
213
- * @param string $url The input URL to convert. This CAN be left empty when necessary.
214
- * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
215
- * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
216
- *
217
- * @param string $regex_suffix_frag Regex fragment to come after the relative cache/path regex frag.
218
- * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
219
- * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
220
- * See also: {@link CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
221
- *
222
- * @return string Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
223
- */
224
- $self->buildHostCachePathRegex = function ($url, $regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
225
- $url = trim((string) $url);
226
- $regex_suffix_frag = $self->cachePathRegexSuffixFrag($regex_suffix_frag);
227
- $abs_relative_cache_path_regex = ''; // Initialize regex.
228
- $is_url_domain_mapped = false; // Initialize.
229
-
230
- if ($url) {
231
- if (is_multisite() && $self->canConsiderDomainMapping()) {
232
- // Shortest possible URI; i.e., consider domain mapping.
233
- $url = $self->domainMappingUrlFilter($url);
234
- $is_url_domain_mapped = $url && $self->domainMappingBlogId($url);
235
- }
236
- if ($url && ($url_parts = $self->parseUrl($url)) && !empty($url_parts['host'])) {
237
- $flags = CACHE_PATH_NO_SCHEME | CACHE_PATH_NO_HOST
238
- | CACHE_PATH_NO_PATH_INDEX | CACHE_PATH_NO_QUV | CACHE_PATH_NO_EXT;
239
-
240
- $host_base_dir_tokens = $self->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
241
- $host_url = rtrim('http://'.$url_parts['host'].$host_base_dir_tokens, '/');
242
- $host_cache_path = $self->buildCachePath($host_url, '', '', $flags);
243
-
244
- $cache_path = $self->buildCachePath($url, '', '', $flags);
245
- $relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $cache_path);
246
-
247
- $abs_relative_cache_path = isset($relative_cache_path[0]) ? '/'.$relative_cache_path : '';
248
- $abs_relative_cache_path_regex = isset($abs_relative_cache_path[0]) ? preg_quote($abs_relative_cache_path, '/') : '';
249
- }
250
- }
251
- return '/^'.$abs_relative_cache_path_regex.$regex_suffix_frag.'/i';
252
- };
253
-
254
- /*
255
- * Regex pattern for a call to `deleteFilesFromCacheDir()`.
256
- *
257
- * @since 151114 Improving watered-down regex syntax.
258
- *
259
- * @param string $url The input URL to convert. This CAN be left empty when necessary.
260
- * This may also contain watered-down regex; i.e., `*^$` characters are OK here.
261
- * However, `^$` are discarded, as they are unnecessary in this context.
262
- *
263
- * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
264
- * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
265
- *
266
- * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
267
- * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
268
- * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
269
- * See also: {@link CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
270
- *
271
- * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
272
- */
273
- $self->buildCachePathRegexFromWcUrl = function ($url, $regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
274
- $url = trim((string) $url, '^$');
275
- $regex_suffix_frag = $self->cachePathRegexSuffixFrag($regex_suffix_frag);
276
- $cache_path_regex = ''; // Initialize regex.
277
-
278
- if ($url) { // After `^$` trimming above.
279
- $flags = CACHE_PATH_ALLOW_WILDCARDS | CACHE_PATH_NO_SCHEME
280
- | CACHE_PATH_NO_PATH_INDEX | CACHE_PATH_NO_QUV | CACHE_PATH_NO_EXT;
281
- $cache_path = $self->buildCachePath($url, '', '', $flags); // Without the scheme.
282
- $cache_path_regex = isset($cache_path[0]) ? '\/https?\/'.$self->wdRegexToActualRegexFrag($cache_path) : '';
283
- }
284
- return '/^'.$cache_path_regex.$regex_suffix_frag.'/i';
285
- };
286
-
287
- /*
288
- * Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
289
- *
290
- * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
291
- *
292
- * @param string $uris A line-delimited list of URIs. These may contain `*^$` also.
293
- * However, `^$` are discarded, as they are unnecessary in this context.
294
- *
295
- * @param string $regex_suffix_frag Regex fragment to come after each relative cache/path.
296
- * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
297
- * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
298
- * See also: {@link CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
299
- *
300
- * @return string Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
301
- */
302
- $self->buildHostCachePathRegexFragsFromWcUris = function ($uris, $regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
303
- $uris = trim((string) $uris);
304
- $regex_suffix_frag = $self->cachePathRegexSuffixFrag($regex_suffix_frag);
305
-
306
- $_self = $self; // Reference for the closure below.
307
- $flags = CACHE_PATH_ALLOW_WILDCARDS | CACHE_PATH_NO_SCHEME | CACHE_PATH_NO_HOST
308
- | CACHE_PATH_NO_PATH_INDEX | CACHE_PATH_NO_QUV | CACHE_PATH_NO_EXT;
309
-
310
- $host = 'doesnt-matter.foo.bar';
311
- $host_url = rtrim('http://'.$host, '/');
312
- $host_cache_path = $self->buildCachePath($host_url, '', '', $flags);
313
- $uri_patterns = array_unique(preg_split('/['."\r\n".']+/', $uris, -1, PREG_SPLIT_NO_EMPTY));
314
-
315
- foreach ($uri_patterns as $_key => &$_uri_pattern) {
316
- if (($_uri_pattern = trim($_uri_pattern, '^$'))) {
317
- $_cache_path = $_self->buildCachePath($host_url.'/'.trim($_uri_pattern, '/'), '', '', $flags);
318
- $_relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
319
- $_uri_pattern = $self->wdRegexToActualRegexFrag($_relative_cache_path);
320
- }
321
- if (!$_uri_pattern) {
322
- unset($uri_patterns[$_key]); // Remove it.
323
- }
324
- }
325
- unset($_key, $_uri_pattern, $_cache_path, $_relative_cache_path); // Housekeeping.
326
-
327
- return $uri_patterns ? '(?:'.implode('|', array_unique($uri_patterns)).')'.$regex_suffix_frag : '';
328
- };
329
-
330
- /*
331
- * Regex pattern for a call to `deleteFilesFromCacheDir()`.
332
- *
333
- * @since 151114 Moving this low-level routine into a method of a different name.
334
- *
335
- * @param string $regex_frag A regex fragment. This CAN be left empty when necessary.
336
- * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
337
- * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
338
- *
339
- * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
340
- * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
341
- * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
342
- * See also: {@link CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
343
- *
344
- * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
345
- */
346
- $self->assembleCachePathRegex = function ($regex_frag, $regex_suffix_frag = CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) use ($self) {
347
- $regex_frag = (string) $regex_frag;
348
- $regex_suffix_frag = $self->cachePathRegexSuffixFrag($regex_suffix_frag);
349
-
350
- return '/^'.$regex_frag.$regex_suffix_frag.'/i';
351
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/ConditionalUtils.php DELETED
@@ -1,358 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /**
5
- * PHP's language constructs.
6
- *
7
- * @type array PHP's language constructs.
8
- * Keys are currently unimportant. Subject to change.
9
- *
10
- * @since 160222 First documented version.
11
- */
12
- $self->php_constructs = [
13
- 'die' => 'die',
14
- 'echo' => 'echo',
15
- 'empty' => 'empty',
16
- 'exit' => 'exit',
17
- 'eval' => 'eval',
18
- 'include' => 'include',
19
- 'include_once' => 'include_once',
20
- 'isset' => 'isset',
21
- 'list' => 'list',
22
- 'require' => 'require',
23
- 'require_once' => 'require_once',
24
- 'return' => 'return',
25
- 'print' => 'print',
26
- 'unset' => 'unset',
27
- '__halt_compiler' => '__halt_compiler',
28
- ];
29
-
30
- /*
31
- * Is AdvancedCache class?
32
- *
33
- * @since 150821 Improving multisite compat.
34
- *
35
- * @return bool `TRUE` if this is the AdvancedCache class.
36
- */
37
- $self->isAdvancedCache = function () use ($self) {
38
- return $self instanceof AdvancedCache;
39
- };
40
-
41
- /*
42
- * Is Plugin class?
43
- *
44
- * @since 150821 Improving multisite compat.
45
- *
46
- * @return bool `TRUE` if this is the Plugin class.
47
- */
48
- $self->isPlugin = function () use ($self) {
49
- return $self instanceof Plugin;
50
- };
51
-
52
- /*
53
- * Is the current request method `POST`, `PUT` or `DELETE`?
54
- *
55
- * @since 150422 Rewrite.
56
- *
57
- * @return boolean `TRUE` if current request method is `POST`, `PUT` or `DELETE`.
58
- *
59
- * @note The return value of this function is cached to reduce overhead on repeat calls.
60
- */
61
- $self->isPostPutDeleteRequest = function () use ($self) {
62
- if (!is_null($is = &$self->staticKey('isPostPutDeleteRequest'))) {
63
- return $is; // Already cached this.
64
- }
65
- if (!empty($_POST)) {
66
- return ($is = true);
67
- }
68
- if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
69
- if (in_array(strtoupper($_SERVER['REQUEST_METHOD']), array('POST', 'PUT', 'DELETE'), true)) {
70
- return ($is = true);
71
- }
72
- }
73
- return ($is = false);
74
- };
75
-
76
- /*
77
- * Does the current request include an uncacheable query string?
78
- *
79
- * @since 151002 Improving Nginx support.
80
- *
81
- * @return boolean True if request includes an uncacheable query string.
82
- *
83
- * @note The return value of this function is cached to reduce overhead on repeat calls.
84
- */
85
- $self->requestContainsUncacheableQueryVars = function () use ($self) {
86
- if (!is_null($is = &$self->staticKey('requestContainsUncacheableQueryVars'))) {
87
- return $is; // Already cached this.
88
- }
89
- if (!empty($_GET) || !empty($_SERVER['QUERY_STRING'])) {
90
- $_get_count = !empty($_GET) ? count($_GET) : 0;
91
- $is_abc_only = $_get_count === 1 && isset($_GET[strtolower(SHORT_NAME).'ABC']);
92
- $is_nginx_q_only = $_get_count === 1 && isset($_GET['q']) && $self->isNginx();
93
- $is_ac_get_var_true = isset($_GET[strtolower(SHORT_NAME).'AC']) && filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN);
94
-
95
- if (!$is_abc_only && !$is_nginx_q_only && !$is_ac_get_var_true) {
96
- return ($is = true);
97
- }
98
- }
99
- return ($is = false);
100
- };
101
-
102
- /*
103
- * Is the current request method is uncacheable?
104
- *
105
- * @since 150422 Rewrite.
106
- *
107
- * @return boolean `TRUE` if current request method is uncacheable.
108
- *
109
- * @note The return value of this function is cached to reduce overhead on repeat calls.
110
- */
111
- $self->isUncacheableRequestMethod = function () use ($self) {
112
- if (!is_null($is = &$self->staticKey('isUncacheableRequestMethod'))) {
113
- return $is; // Already cached this.
114
- }
115
- if (!empty($_POST)) {
116
- return ($is = true);
117
- }
118
- if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
119
- if (!in_array(strtoupper($_SERVER['REQUEST_METHOD']), array('GET'), true)) {
120
- return ($is = true);
121
- }
122
- }
123
- return ($is = false);
124
- };
125
-
126
- /*
127
- * Should the current user should be considered a logged-in user?
128
- *
129
- * @since 150422 Rewrite.
130
- *
131
- * @return boolean `TRUE` if current user should be considered a logged-in user.
132
- *
133
- * @note The return value of this function is cached to reduce overhead on repeat calls.
134
- */
135
- $self->isLikeUserLoggedIn = function () use ($self) {
136
- if (!is_null($is = &$self->staticKey('isLikeUserLoggedIn'))) {
137
- return $is; // Already cached this.
138
- }
139
- if (defined('SID') && SID) {
140
- return ($is = true); // Session ID.
141
- }
142
- if (empty($_COOKIE)) {
143
- return ($is = false); // No cookies.
144
- }
145
- $regex_logged_in_cookies = '/^'; // Initialize.
146
-
147
- if (defined('LOGGED_IN_COOKIE') && LOGGED_IN_COOKIE) {
148
- $regex_logged_in_cookies .= preg_quote(LOGGED_IN_COOKIE, '/');
149
- } else { // Use the default hard-coded cookie prefix.
150
- $regex_logged_in_cookies .= 'wordpress_logged_in_';
151
- }
152
- $regex_logged_in_cookies .= '|comment_author_';
153
- $regex_logged_in_cookies .= '|wp[_\-]postpass_';
154
-
155
- $regex_logged_in_cookies .= '/'; // Close regex.
156
-
157
- foreach ($_COOKIE as $_key => $_value) {
158
- if ($_value && preg_match($regex_logged_in_cookies, $_key)) {
159
- return ($is = true); // Like a logged-in user.
160
- }
161
- } unset($_key, $_value); // Housekeeping.
162
-
163
- return ($is = false);
164
- };
165
-
166
- /*
167
- * Are we in a LOCALHOST environment?
168
- *
169
- * @since 150422 Rewrite.
170
- *
171
- * @return boolean `TRUE` if we are in a LOCALHOST environment.
172
- *
173
- * @note The return value of this function is cached to reduce overhead on repeat calls.
174
- */
175
- $self->isLocalhost = function () use ($self) {
176
- if (!is_null($is = &$self->staticKey('isLocalhost'))) {
177
- return $is; // Already cached this.
178
- }
179
- if (defined('LOCALHOST')) {
180
- return ($is = (boolean) LOCALHOST);
181
- }
182
- if (preg_match('/\b(?:localhost|127\.0\.0\.1)\b/i', $self->hostToken())) {
183
- return ($is = true);
184
- }
185
- return ($is = false);
186
- };
187
-
188
-
189
-
190
- /*
191
- * Is the current request for a feed?
192
- *
193
- * @since 150422 Rewrite.
194
- *
195
- * @return boolean `TRUE` if the current request is for a feed.
196
- *
197
- * @note The return value of this function is cached to reduce overhead on repeat calls.
198
- */
199
- $self->isFeed = function () use ($self) {
200
- if (!is_null($is = &$self->staticKey('isFeed'))) {
201
- return $is; // Already cached this.
202
- }
203
- if (isset($_REQUEST['feed'])) {
204
- return ($is = true);
205
- }
206
- if (!empty($_SERVER['REQUEST_URI']) && is_string($_SERVER['REQUEST_URI'])) {
207
- if (preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) {
208
- return ($is = true);
209
- }
210
- }
211
- return ($is = false);
212
- };
213
-
214
- /*
215
- * Is a document/string an HTML/XML doc; or no?
216
- *
217
- * @since 150422 Rewrite.
218
- *
219
- * @param string $doc Input string/document to check.
220
- *
221
- * @return boolean True if `$doc` is an HTML/XML doc type.
222
- */
223
- $self->isHtmlXmlDoc = function ($doc) use ($self) {
224
- $doc = trim((string) $doc);
225
- $doc_hash = sha1($doc);
226
-
227
- if (!is_null($is = &$self->staticKey('isHtmlXmlDoc', $doc_hash))) {
228
- return $is; // Already cached this.
229
- }
230
- if (stripos($doc, '</html>') !== false) {
231
- return ($is = true);
232
- }
233
- if (stripos($doc, '<?xml') === 0) {
234
- return ($is = true);
235
- }
236
- return ($is = false);
237
- };
238
-
239
- /*
240
- * Does the current request have a cacheable content type?
241
- *
242
- * @since 150422 Rewrite.
243
- *
244
- * @return boolean `TRUE` if the current request has a cacheable content type.
245
- *
246
- * @note The return value of this function is cached to reduce overhead on repeat calls.
247
- *
248
- * @warning Do NOT call upon this method until the end of a script execution.
249
- */
250
- $self->hasACacheableContentType = function () use ($self) {
251
- if (!is_null($is = &$self->staticKey('hasACacheableContentType'))) {
252
- return $is; // Already cached this.
253
- }
254
- foreach ($self->headersList() as $_key => $_header) {
255
- if (stripos($_header, 'Content-Type:') === 0) {
256
- $content_type = $_header; // Last one.
257
- }
258
- } unset($_key, $_header); // Housekeeping.
259
-
260
- if (isset($content_type[0]) && stripos($content_type, 'html') === false
261
- && stripos($content_type, 'xml') === false && stripos($content_type, GLOBAL_NS) === false) {
262
- return ($is = false); // Do NOT cache data sent by scripts serving other MIME types.
263
- }
264
- return ($is = true);
265
- };
266
-
267
- /*
268
- * Does the current request have a cacheable HTTP status code?
269
- *
270
- * @since 150422 Rewrite.
271
- *
272
- * @return boolean `TRUE` if the current request has a cacheable HTTP status code.
273
- *
274
- * @note The return value of this function is cached to reduce overhead on repeat calls.
275
- *
276
- * @warning Do NOT call upon this method until the end of a script execution.
277
- */
278
- $self->hasACacheableStatus = function () use ($self) {
279
- if (!is_null($is = &$self->staticKey('hasACacheableStatus'))) {
280
- return $is; // Already cached this.
281
- }
282
- if (($http_status = (string) $self->httpStatus()) && $http_status[0] !== '2' && $http_status !== '404') {
283
- return ($is = false); // A non-2xx & non-404 status code.
284
- }
285
- foreach ($self->headersList() as $_key => $_header) {
286
- if (preg_match('/^(?:Retry\-After\:\s+(?P<retry>.+)|Status\:\s+(?P<status>[0-9]+)|HTTP\/[0-9]+(?:\.[0-9]+)?\s+(?P<http_status>[0-9]+))/i', $_header, $_m)) {
287
- if (!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404')
288
- || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404')
289
- ) {
290
- return ($is = false); // Not a cacheable status.
291
- }
292
- }
293
- } unset($_key, $_header); // Housekeeping.
294
-
295
- return ($is = true);
296
- };
297
-
298
- /*
299
- * Checks if a PHP extension is loaded up.
300
- *
301
- * @since 150422 Rewrite.
302
- *
303
- * @param string $extension A PHP extension slug (i.e. extension name).
304
- *
305
- * @return boolean `TRUE` if the extension is loaded.
306
- *
307
- * @note The return value of this function is cached to reduce overhead on repeat calls.
308
- */
309
- $self->isExtensionLoaded = function ($extension) use ($self) {
310
- $extension = (string) $extension;
311
-
312
- if (!is_null($is = &$self->staticKey('isExtensionLoaded', $extension))) {
313
- return $is; // Already cached this.
314
- }
315
- return ($is = (boolean) extension_loaded($extension));
316
- };
317
-
318
- /*
319
- * Is a particular function possible in every way?
320
- *
321
- * @since 150422 Rewrite.
322
- *
323
- * @param string $function A PHP function (or user function) to check.
324
- *
325
- * @return string `TRUE` if the function is possible.
326
- *
327
- * @note This checks (among other things) if the function exists and that it's callable.
328
- * It also checks the currently configured `disable_functions` and `suhosin.executor.func.blacklist`.
329
- */
330
- $self->functionIsPossible = function ($function) use ($self) {
331
- $function = (string) $function;
332
-
333
- if (!is_null($is = &$self->staticKey('functionIsPossible', $function))) {
334
- return $is; // Already cached this.
335
- }
336
- if (is_null($disabled_functions = &$self->staticKey('functionIsPossible_disabled_functions'))) {
337
- $disabled_functions = array(); // Initialize disabled/blacklisted functions.
338
-
339
- if (($disable_functions = trim(ini_get('disable_functions')))) {
340
- $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($disable_functions), -1, PREG_SPLIT_NO_EMPTY));
341
- }
342
- if (($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) {
343
- $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($blacklist_functions), -1, PREG_SPLIT_NO_EMPTY));
344
- }
345
- if(filter_var(ini_get('suhosin.executor.disable_eval'), FILTER_VALIDATE_BOOLEAN)) {
346
- $disabled_functions = array_merge($disabled_functions, array('eval'));
347
- }
348
- }
349
- if (!function_exists($function) || !is_callable($function)) {
350
- if(!in_array($function, $self->php_constructs, true)) { // A language construct
351
- return ($is = false); // Not possible.
352
- }
353
- }
354
- if ($disabled_functions && in_array(strtolower($function), $disabled_functions, true)) {
355
- return ($is = false); // Not possible.
356
- }
357
- return ($is = true);
358
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/DomainMappingUtils.php DELETED
@@ -1,264 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Can consider domain mapping?
6
- *
7
- * @since 150821 Improving multisite compat.
8
- *
9
- * @return bool `TRUE` if we can consider domain mapping.
10
- *
11
- * @note The return value of this function is cached to reduce overhead on repeat calls.
12
- */
13
- $self->canConsiderDomainMapping = function () use ($self) {
14
- if (!is_null($can = &$self->staticKey('canConsiderDomainMapping'))) {
15
- return $can; // Already cached this.
16
- }
17
- if (!$self->isAdvancedCache() && is_multisite() && $self->hostBaseToken() === '/'
18
- && defined('SUNRISE_LOADED') && SUNRISE_LOADED && !empty($GLOBALS['dm_domain'])) {
19
- return ($can = true); // Can consider.
20
- }
21
- return ($can = false); // Cannot consider.
22
- };
23
-
24
- /*
25
- * Domain mapping?
26
- *
27
- * @since 150821 Improving multisite compat.
28
- *
29
- * @return integer Domain mapping ID; else `0` (false).
30
- *
31
- * @note The return value of this function is cached to reduce overhead on repeat calls.
32
- */
33
- $self->isDomainMapping = function () use ($self) {
34
- if (!is_null($is = &$self->staticKey('isDomainMapping'))) {
35
- return $is; // Already cached this.
36
- }
37
- if (!$self->isAdvancedCache() && is_multisite() && $self->canConsiderDomainMapping()
38
- && defined('DOMAIN_MAPPING') && DOMAIN_MAPPING && !empty($GLOBALS['domain_mapping_id'])) {
39
- return ($is = (integer) $GLOBALS['domain_mapping_id']); // Blog ID.
40
- }
41
- return ($is = 0); // Not domain mapping.
42
- };
43
-
44
- /*
45
- * Filters a URL in order to apply domain mapping.
46
- *
47
- * @since 150821 Improving multisite compat.
48
- *
49
- * @param string $url The input URL to filter.
50
- *
51
- * @return string The filtered URL; else the original URL.
52
- *
53
- * @note The return value of this function is NOT cached, but inner portions are.
54
- */
55
- $self->domainMappingUrlFilter = function ($url) use ($self) {
56
- $original_url = (string) $url; // Preserve.
57
- $url = trim((string) $url);
58
-
59
- if (!is_multisite() || !$self->canConsiderDomainMapping()) {
60
- return $original_url; // Not possible.
61
- }
62
- if (!$url || !($url_parts = $self->parseUrl($url))) {
63
- return $original_url; // Not possible.
64
- }
65
- if (empty($url_parts['host'])) {
66
- return $original_url; // Not possible.
67
- }
68
- $blog_domain = strtolower($url_parts['host']); // In the unfiltered URL.
69
- $blog_path = $self->hostDirToken(false, false, !empty($url_parts['path']) ? $url_parts['path'] : '/');
70
-
71
- if (!($blog_id = (integer) get_blog_id_from_url($blog_domain, $blog_path))) {
72
- return $original_url; // Not possible.
73
- }
74
- if (!($domain = $self->domainMappingBlogDomain($blog_id)) || $domain === $blog_domain) {
75
- return $original_url; // Not applicable.
76
- }
77
- $url_parts['host'] = $domain; // Filter the URL now.
78
- if (!empty($url_parts['path']) && $url_parts['path'] !== '/') {
79
- if (($host_base_dir_tokens = trim($self->hostBaseDirTokens(false, false, $url_parts['path']), '/'))) {
80
- $url_parts['path'] = preg_replace('/^\/'.preg_quote($host_base_dir_tokens, '/').'(\/|$)/i', '${1}', $url_parts['path']);
81
- }
82
- }
83
- return ($url = $self->unParseUrl($url_parts));
84
- };
85
-
86
- /*
87
- * Filters a URL in order to remove domain mapping.
88
- *
89
- * @since 150821 Improving multisite compat.
90
- *
91
- * @param string $url The input URL to filter.
92
- *
93
- * @return string The filtered URL; else the original URL.
94
- *
95
- * @note The return value of this function is NOT cached, but inner portions are.
96
- */
97
- $self->domainMappingReverseUrlFilter = function ($url) use ($self) {
98
- $original_url = (string) $url; // Preserve.
99
- $url = trim((string) $url);
100
-
101
- if (!is_multisite() || !$self->canConsiderDomainMapping()) {
102
- return $original_url; // Not possible.
103
- }
104
- if (!$url || !($url_parts = $self->parseUrl($url))) {
105
- return $original_url; // Not possible.
106
- }
107
- if (empty($url_parts['host'])) {
108
- return $original_url; // Not possible.
109
- }
110
- if (!($blog_id = $self->domainMappingBlogId('', $url_parts['host']))) {
111
- return $original_url; // No a domain in the map.
112
- }
113
- if (!($blog_details = $self->blogDetails($blog_id))) {
114
- return $original_url; // Not possible.
115
- }
116
- $url_parts['host'] = $blog_details->domain; // Filter the URL now.
117
- if (($host_base_dir_tokens = trim($self->hostBaseDirTokens(false, false, $blog_details->path), '/'))) {
118
- $url_parts['path'] = '/'.$host_base_dir_tokens.'/'.ltrim(@$url_parts['path'], '/');
119
- }
120
- return ($url = $self->unParseUrl($url_parts));
121
- };
122
-
123
- /*
124
- * Converts a host into a mapped blog ID.
125
- *
126
- * @since 150821 Improving multisite compat.
127
- *
128
- * @param string $url URL containing the domain to convert.
129
- * @param string $domain The domain to convert. Override URL is provided.
130
- *
131
- * @return integer The mapped blog ID; else `0` on failure.
132
- *
133
- * @note The return value of this function is cached to reduce overhead on repeat calls.
134
- */
135
- $self->domainMappingBlogId = function ($url = '', $domain = '') use ($self) {
136
- $domain = (string) $domain;
137
- $url = $domain ? '' : (string) $url;
138
-
139
- if (!is_multisite() || !$self->canConsiderDomainMapping()) {
140
- return 0; // Not possible/applicable.
141
- }
142
- if ($url === 'network' || $domain === 'network') {
143
- $domain = (string) get_current_site()->domain;
144
- }
145
- if (!$domain && $url && $url !== 'network') {
146
- $domain = $self->parseUrl($url, PHP_URL_HOST);
147
- }
148
- if (!$url && !$domain && ($blog_details = $self->blogDetails())) {
149
- $domain = $blog_details->domain;
150
- }
151
- $domain = strtolower(preg_replace('/^www\./i', '', $domain));
152
-
153
- if (!$domain || strpos($domain, '.') === false) {
154
- return 0; // Not possible.
155
- }
156
- if (!is_null($blog_id = &$self->staticKey('domainMappingBlogId', $domain))) {
157
- return $blog_id; // Already cached this.
158
- }
159
- $wpdb = $self->wpdb(); // WordPress database class.
160
- $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
161
- $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
162
-
163
- if (!$enforcing_primary_domain) {
164
- $blog_id = (integer) $wpdb->get_var('SELECT `blog_id` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC, `active` DESC LIMIT 1');
165
- } else {
166
- $blog_id = (integer) $wpdb->get_var('SELECT `blog_id` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') AND `active` = \'1\' ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
167
- }
168
- $wpdb->suppress_errors($suppressing_errors); // Restore.
169
-
170
- return ($blog_id = (integer) $blog_id);
171
- };
172
-
173
- /*
174
- * Converts a blog ID into a mapped domain.
175
- *
176
- * @since 150821 Improving multisite compat.
177
- *
178
- * @param integer $blog_id The blog ID.
179
- *
180
- * @param boolean $fallback Fallback on blog's domain?
181
- *
182
- * @return string The mapped domain, else an empty string.
183
- *
184
- * @note The return value of this function is cached to reduce overhead on repeat calls.
185
- */
186
- $self->domainMappingBlogDomain = function ($blog_id = 0, $fallback = false) use ($self) {
187
- if (!is_multisite() || !$self->canConsiderDomainMapping()) {
188
- return ''; // Not possible/applicable.
189
- }
190
- if (($blog_id = (integer) $blog_id) < 0) {
191
- $blog_id = (integer) get_current_site()->blog_id;
192
- }
193
- if (!$blog_id) {
194
- $blog_id = (integer) get_current_blog_id();
195
- }
196
- if (!$blog_id || $blog_id < 0) {
197
- return ''; // Not possible.
198
- }
199
- if (!is_null($domain = &$self->staticKey('domainMappingBlogDomain', $blog_id))) {
200
- return $domain; // Already cached this.
201
- }
202
- $wpdb = $self->wpdb(); // WordPress database class.
203
- $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
204
- $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
205
-
206
- if (!$enforcing_primary_domain) {
207
- if ($self->isDomainMapping() === $blog_id) {
208
- $domain = $self->hostToken();
209
- $domain = preg_replace('/^www\./i', '', $domain);
210
- $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
211
- } elseif (($domains = $self->domainMappingBlogDomains($blog_id))) {
212
- $domain = $domains[0]; // Use the first of all possible domains.
213
- }
214
- } else { // A single primary domain in this case; i.e., `active` = primary.
215
- $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' AND `active` = \'1\' LIMIT 1');
216
- }
217
- if (!$domain && $fallback && ($blog_details = $self->blogDetails($blog_id))) {
218
- $domain = $blog_details->domain; // Use original domain.
219
- }
220
- $wpdb->suppress_errors($suppressing_errors); // Restore.
221
-
222
- return ($domain = strtolower((string) $domain));
223
- };
224
-
225
- /*
226
- * Converts a blog ID into mapped domains (plural).
227
- *
228
- * @since 150821 Improving multisite compat.
229
- *
230
- * @param integer $blog_id The blog ID.
231
- *
232
- * @return array Mapped domains; else an empty array.
233
- *
234
- * @note The return value of this function is cached to reduce overhead on repeat calls.
235
- */
236
- $self->domainMappingBlogDomains = function ($blog_id = 0) use ($self) {
237
- if (!is_multisite() || !$self->canConsiderDomainMapping()) {
238
- return array(); // Not possible/applicable.
239
- }
240
- if (($blog_id = (integer) $blog_id) < 0) {
241
- $blog_id = (integer) get_current_site()->blog_id;
242
- }
243
- if (!$blog_id) {
244
- $blog_id = (integer) get_current_blog_id();
245
- }
246
- if (!$blog_id || $blog_id < 0) {
247
- return array(); // Not possible.
248
- }
249
- if (!is_null($domains = &$self->staticKey('domainMappingBlogDomains', $blog_id))) {
250
- return $domains; // Already cached this.
251
- }
252
- $wpdb = $self->wpdb(); // WordPress database class.
253
- $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
254
- $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
255
-
256
- if (!$enforcing_primary_domain) { // Not enforcing a primary domain, so let's pull all of the domains.
257
- $domains = $wpdb->get_col('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' ORDER BY `active` DESC');
258
- } else { // Primary domains in this case; i.e., `active` = primary.
259
- $domains = $wpdb->get_col('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' AND `active` = \'1\'');
260
- }
261
- $wpdb->suppress_errors($suppressing_errors); // Restore.
262
-
263
- return ($domains = array_unique(array_map('strtolower', (array) $domains)));
264
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/EscapeUtils.php DELETED
@@ -1,17 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Escape single quotes.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $string Input string to escape.
10
- * @param integer $times Optional. Defaults to one escape char; e.g. `\'`.
11
- * If you need to escape more than once, set this to something > `1`.
12
- *
13
- * @return string Escaped string; e.g. `Raam\'s the lead developer`.
14
- */
15
- $self->escSq = function ($string, $times = 1) use ($self) {
16
- return str_replace("'", str_repeat('\\', abs($times))."'", (string) $string);
17
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/FsUtils.php DELETED
@@ -1,323 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Normalizes directory/file separators.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $dir_file Directory/file path.
10
- *
11
- * @param boolean $allow_trailing_slash Defaults to FALSE.
12
- * If TRUE; and `$dir_file` contains a trailing slash; we'll leave it there.
13
- *
14
- * @return string Normalized directory/file path.
15
- */
16
- $self->nDirSeps = function ($dir_file, $allow_trailing_slash = false) use ($self) {
17
- $dir_file = (string) $dir_file;
18
-
19
- if (!isset($dir_file[0])) {
20
- return ''; // Catch empty string.
21
- }
22
- if (strpos($dir_file, '://' !== false)) {
23
- if (preg_match('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', $dir_file, $stream_wrapper)) {
24
- $dir_file = preg_replace('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', '', $dir_file);
25
- }
26
- }
27
- if (strpos($dir_file, ':' !== false)) {
28
- if (preg_match('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', $dir_file)) {
29
- $dir_file = preg_replace_callback('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', create_function('$m', 'return strtoupper($m[0]);'), $dir_file);
30
- }
31
- }
32
- $dir_file = preg_replace('/\/+/', '/', str_replace(array(DIRECTORY_SEPARATOR, '\\', '/'), '/', $dir_file));
33
- $dir_file = ($allow_trailing_slash) ? $dir_file : rtrim($dir_file, '/'); // Strip trailing slashes.
34
-
35
- if (!empty($stream_wrapper[0])) {
36
- $dir_file = strtolower($stream_wrapper[0]).$dir_file;
37
- }
38
- return $dir_file; // Normalized now.
39
- };
40
-
41
- /*
42
- * Acquires system tmp directory path.
43
- *
44
- * @since 150422 Rewrite.
45
- *
46
- * @return string System tmp directory path; else an empty string.
47
- */
48
- $self->getTmpDir = function () use ($self) {
49
- if (!is_null($dir = &$self->staticKey('getTmpDir'))) {
50
- return $dir; // Already cached this.
51
- }
52
- $possible_dirs = array(); // Initialize.
53
-
54
- if (defined('WP_TEMP_DIR')) {
55
- $possible_dirs[] = (string) WP_TEMP_DIR;
56
- }
57
- if ($self->functionIsPossible('sys_get_temp_dir')) {
58
- $possible_dirs[] = (string) sys_get_temp_dir();
59
- }
60
- $possible_dirs[] = (string) ini_get('upload_tmp_dir');
61
-
62
- if (!empty($_SERVER['TEMP'])) {
63
- $possible_dirs[] = (string) $_SERVER['TEMP'];
64
- }
65
- if (!empty($_SERVER['TMPDIR'])) {
66
- $possible_dirs[] = (string) $_SERVER['TMPDIR'];
67
- }
68
- if (!empty($_SERVER['TMP'])) {
69
- $possible_dirs[] = (string) $_SERVER['TMP'];
70
- }
71
- if (stripos(PHP_OS, 'win') === 0) {
72
- $possible_dirs[] = 'C:/Temp';
73
- }
74
- if (stripos(PHP_OS, 'win') !== 0) {
75
- $possible_dirs[] = '/tmp';
76
- }
77
- if (defined('WP_CONTENT_DIR')) {
78
- $possible_dirs[] = (string) WP_CONTENT_DIR;
79
- }
80
- foreach ($possible_dirs as $_key => $_dir) {
81
- if (($_dir = trim((string) $_dir)) && @is_dir($_dir) && @is_writable($_dir)) {
82
- return ($dir = $self->nDirSeps($_dir));
83
- }
84
- }
85
- unset($_key, $_dir); // Housekeeping.
86
-
87
- return ($dir = '');
88
- };
89
-
90
- /*
91
- * Finds absolute server path to `/wp-config.php` file.
92
- *
93
- * @since 150422 Rewrite.
94
- *
95
- * @return string Absolute server path to `/wp-config.php` file;
96
- * else an empty string if unable to locate the file.
97
- */
98
- $self->findWpConfigFile = function () use ($self) {
99
- if (!is_null($file = &$self->staticKey('findWpConfigFile'))) {
100
- return $file; // Already cached this.
101
- }
102
- $file = ''; // Initialize.
103
-
104
- if (is_file($abspath_wp_config = ABSPATH.'wp-config.php')) {
105
- $file = $abspath_wp_config;
106
- } elseif (is_file($dirname_abspath_wp_config = dirname(ABSPATH).'/wp-config.php')) {
107
- $file = $dirname_abspath_wp_config;
108
- }
109
- return $file;
110
- };
111
-
112
- /*
113
- * Adds a tmp name suffix to a directory/file path.
114
- *
115
- * @since 150422 Rewrite.
116
- *
117
- * @param string $dir_file An input directory or file path.
118
- *
119
- * @return string The original `$dir_file` with a tmp name suffix.
120
- */
121
- $self->addTmpSuffix = function ($dir_file) use ($self) {
122
- $dir_file = (string) $dir_file;
123
- $dir_file = rtrim($dir_file, DIRECTORY_SEPARATOR.'\\/');
124
-
125
- return $dir_file.'-'.str_replace('.', '', uniqid('', true)).'-tmp';
126
- };
127
-
128
- /*
129
- * Recursive directory iterator based on a regex pattern.
130
- *
131
- * @since 150422 Rewrite.
132
- *
133
- * @param string $dir An absolute server directory path.
134
- * @param string $regex A regex pattern; compares to each full file path.
135
- *
136
- * @return \RegexIterator Navigable with {@link \foreach()}; where each item
137
- * is a {@link \RecursiveDirectoryIterator}.
138
- */
139
- $self->dirRegexIteration = function ($dir, $regex = '') use ($self) {
140
- $dir = (string) $dir;
141
- $regex = (string) $regex;
142
-
143
- $dir_iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS);
144
- $iterator_iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST);
145
-
146
- if ($regex && $regex !== '/.*/' && $regex !== '/.+/') { // Apply regex filter?
147
- // @TODO Optimize calls to this method in order to avoid the regex iterator when not necessary.
148
- return new \RegexIterator($iterator_iterator, $regex, \RegexIterator::MATCH, \RegexIterator::USE_KEY);
149
- }
150
- return $iterator_iterator; // Iterate everything.
151
- };
152
-
153
- /*
154
- * Abbreviated byte notation for file sizes.
155
- *
156
- * @since 151002 Adding a few statistics.
157
- *
158
- * @param float $bytes File size in bytes. A (float) value.
159
- * @param integer $precision Number of decimals to use.
160
- *
161
- * @return string Byte notation.
162
- */
163
- $self->bytesAbbr = function ($bytes, $precision = 2) use ($self) {
164
- $bytes = max(0.0, (float) $bytes);
165
- $precision = max(0, (integer) $precision);
166
- $units = array('bytes', 'kbs', 'MB', 'GB', 'TB');
167
-
168
- $power = floor(($bytes ? log($bytes) : 0) / log(1024));
169
- $abbr_bytes = round($bytes / pow(1024, $power), $precision);
170
- $abbr = $units[min($power, count($units) - 1)];
171
-
172
- if ($abbr_bytes === (float) 1 && $abbr === 'bytes') {
173
- $abbr = 'byte'; // Quick fix.
174
- } elseif ($abbr_bytes === (float) 1 && $abbr === 'kbs') {
175
- $abbr = 'kb'; // Quick fix.
176
- }
177
- return $abbr_bytes.' '.$abbr;
178
- };
179
-
180
- /*
181
- * Converts an abbreviated byte notation into bytes.
182
- *
183
- * @since 151002 Adding a few statistics.
184
- *
185
- * @param string $string A string value in byte notation.
186
- *
187
- * @return float A float indicating the number of bytes.
188
- */
189
- $self->abbrBytes = function ($string) use ($self) {
190
- $string = (string) $string;
191
- $regex = '/^(?P<value>[0-9\.]+)\s*(?P<modifier>bytes|byte|kbs|kb|k|mb|m|gb|g|tb|t)$/i';
192
-
193
- if (!preg_match($regex, $string, $_m)) {
194
- return (float) 0;
195
- }
196
- $value = (float) $_m['value'];
197
- $modifier = strtolower($_m['modifier']);
198
- unset($_m); // Housekeeping.
199
-
200
- switch ($modifier) {
201
- case 't':
202
- case 'tb':
203
- $value *= 1024;
204
- // Fall through.
205
- case 'g':
206
- case 'gb':
207
- $value *= 1024;
208
- // Fall through.
209
- case 'm':
210
- case 'mb':
211
- $value *= 1024;
212
- // Fall through.
213
- case 'k':
214
- case 'kb':
215
- case 'kbs':
216
- $value *= 1024;
217
- }
218
- return (float) $value;
219
- };
220
-
221
- /*
222
- * Directory stats.
223
- *
224
- * @since 151002 Adding a few statistics.
225
- *
226
- * @param string $dir An absolute server directory path.
227
- * @param string $regex A regex pattern; compares to each full file path.
228
- * @param boolean $include_paths Include array of all scanned file paths?
229
- * @param boolean $check_disk Also check disk statistics?
230
- * @param boolean $no_cache Do not read/write cache?
231
- *
232
- * @return array Directory stats.
233
- */
234
- $self->getDirRegexStats = function ($dir, $regex = '', $include_paths = false, $check_disk = true, $no_cache = false) use ($self) {
235
- $dir = (string) $dir; // Force string.
236
- $cache_keys = array($dir, $regex, $include_paths, $check_disk);
237
- if (!$no_cache && !is_null($stats = &$self->staticKey('getDirRegexStats', $cache_keys))) {
238
- return $stats; // Already cached this.
239
- }
240
- $stats = array(
241
- 'total_size' => 0,
242
- 'total_resources' => 0,
243
- 'total_links_files' => 0,
244
-
245
- 'total_links' => 0,
246
- 'link_subpaths' => array(),
247
-
248
- 'total_files' => 0,
249
- 'file_subpaths' => array(),
250
-
251
- 'total_dirs' => 0,
252
- 'dir_subpaths' => array(),
253
-
254
- 'disk_total_space' => 0,
255
- 'disk_free_space' => 0,
256
- );
257
- if (!$dir || !is_dir($dir)) {
258
- return $stats; // Not possible.
259
- }
260
- $short_name_lc = strtolower(SHORT_NAME); // Once only.
261
-
262
- foreach ($self->dirRegexIteration($dir, $regex) as $_resource) {
263
- $_resource_sub_path = $_resource->getSubpathname();
264
- $_resource_basename = basename($_resource_sub_path);
265
-
266
- if ($_resource_basename === '.DS_Store') {
267
- continue; // Ignore `.htaccess`.
268
- }
269
- if ($_resource_basename === '.htaccess') {
270
- continue; // Ignore `.htaccess`.
271
- }
272
- if (stripos($_resource_sub_path, $short_name_lc.'-') === 0) {
273
- continue; // Ignore [SHORT_NAME] files in base.
274
- }
275
- switch ($_resource->getType()) { // `link`, `file`, `dir`.
276
- case 'link':
277
- if ($include_paths) {
278
- $stats['link_subpaths'][] = $_sub_path;
279
- }
280
- ++$stats['total_resources'];
281
- ++$stats['total_links_files'];
282
- ++$stats['total_links'];
283
-
284
- break; // Break switch.
285
-
286
- case 'file':
287
- if ($include_paths) {
288
- $stats['file_subpaths'][] = $_sub_path;
289
- }
290
- $stats['total_size'] += $_resource->getSize();
291
- ++$stats['total_resources'];
292
- ++$stats['total_links_files'];
293
- ++$stats['total_files'];
294
-
295
- break; // Break switch.
296
-
297
- case 'dir':
298
- if ($include_paths) {
299
- $stats['dir_subpaths'][] = $_sub_path;
300
- }
301
- ++$stats['total_resources'];
302
- ++$stats['total_dirs'];
303
-
304
- break; // Break switch.
305
- }
306
- }
307
- unset($_resource, $_resource_sub_path, $_resource_basename); // Housekeeping.
308
-
309
- if ($check_disk) { // Check disk also?
310
- $stats['disk_total_space'] = disk_total_space($dir);
311
- $stats['disk_free_space'] = disk_free_space($dir);
312
- }
313
- return $stats;
314
- };
315
-
316
- /*
317
- * Apache `.htaccess` rules that deny public access to the contents of a directory.
318
- *
319
- * @since 150422 Rewrite.
320
- *
321
- * @var string `.htaccess` fules.
322
- */
323
- $self->htaccess_deny = "<IfModule authz_core_module>\n\tRequire all denied\n</IfModule>\n<IfModule !authz_core_module>\n\tdeny from all\n</IfModule>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/HookUtils.php DELETED
@@ -1,249 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Array of hooks.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @type array An array of hooks.
10
- */
11
- $self->hooks = array();
12
-
13
- /*
14
- * Assigns an ID to each callable attached to a hook/filter.
15
- *
16
- * @since 150422 Rewrite.
17
- *
18
- * @param string|callable|mixed $function A string or a callable.
19
- *
20
- * @return string Hook ID for the given `$function`.
21
- *
22
- * @throws \Exception If the hook/function is invalid (i.e. it's not possible to generate an ID).
23
- */
24
- $self->hookId = function ($function) use ($self) {
25
- if (is_string($function)) {
26
- return $function;
27
- }
28
- if (is_object($function)) {
29
- $function = array($function, '');
30
- } else {
31
- $function = (array) $function;
32
- }
33
- if (isset($function[0], $function[1])) {
34
- if (is_object($function[0])) {
35
- return spl_object_hash($function[0]).$function[1];
36
- } elseif (is_string($function[0])) {
37
- return $function[0].'::'.$function[1];
38
- }
39
- }
40
- throw new \Exception(__('Invalid hook.', 'comet-cache'));
41
- };
42
-
43
- /*
44
- * Adds a new hook (works with both actions & filters).
45
- *
46
- * @since 150422 Rewrite.
47
- *
48
- * @param string $hook The name of a hook to attach to.
49
- * @param string|callable|mixed $function A string or a callable.
50
- * @param integer $priority Hook priority; defaults to `10`.
51
- * @param integer $accepted_args Max number of args that should be passed to the `$function`.
52
- *
53
- * @return boolean This always returns a `TRUE` value.
54
- */
55
- $self->addHook = function ($hook, $function, $priority = 10, $accepted_args = 1) use ($self) {
56
- $hook = (string) $hook;
57
- if (stripos($hook, 'zencache') === 0) {
58
- $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
59
- }
60
- $priority = (integer) $priority;
61
- $accepted_args = max(0, (integer) $accepted_args);
62
- $hook_id = $self->hookId($function);
63
-
64
- $self->hooks[$hook][$priority][$hook_id] = array(
65
- 'function' => $function,
66
- 'accepted_args' => $accepted_args,
67
- );
68
- return true; // Always returns true.
69
- };
70
-
71
- /*
72
- * Adds a new action hook.
73
- *
74
- * @since 150422 Rewrite.
75
- *
76
- * @return boolean This always returns a `TRUE` value.
77
- */
78
- $self->addAction = function () use ($self) {
79
- return call_user_func_array(array($self, 'addHook'), func_get_args());
80
- };
81
- $self->add_action = $self->addAction; // Back compat.
82
-
83
- /*
84
- * Adds a new filter.
85
- *
86
- * @since 150422 Rewrite.
87
- *
88
- * @return boolean This always returns a `TRUE` value.
89
- */
90
- $self->addFilter = function () use ($self) {
91
- return call_user_func_array(array($self, 'addHook'), func_get_args());
92
- };
93
- $self->add_filter = $self->addFilter; // Back compat.
94
-
95
- /*
96
- * Removes a hook (works with both actions & filters).
97
- *
98
- * @since 150422 Rewrite.
99
- *
100
- * @param string $hook The name of a hook to remove.
101
- * @param string|callable|mixed $function A string or a callable.
102
- * @param integer $priority Hook priority; defaults to `10`.
103
- *
104
- * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason.
105
- */
106
- $self->removeHook = function ($hook, $function, $priority = 10) use ($self) {
107
- $hook = (string) $hook;
108
- if (stripos($hook, 'zencache') === 0) {
109
- $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
110
- }
111
- $priority = (integer) $priority;
112
- $hook_id = $self->hookId($function);
113
-
114
- if (!isset($self->hooks[$hook][$priority][$hook_id])) {
115
- return false; // Nothing to remove.
116
- }
117
- unset($self->hooks[$hook][$priority][$hook_id]);
118
-
119
- if (!$self->hooks[$hook][$priority]) {
120
- unset($self->hooks[$hook][$priority]);
121
- }
122
- return true; // Existed before it was removed.
123
- };
124
-
125
- /*
126
- * Removes an action.
127
- *
128
- * @since 150422 Rewrite.
129
- *
130
- * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason.
131
- */
132
- $self->removeAction = function () use ($self) {
133
- return call_user_func_array(array($self, 'removeHook'), func_get_args());
134
- };
135
-
136
- /*
137
- * Removes a filter.
138
- *
139
- * @since 150422 Rewrite.
140
- *
141
- * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason.
142
- */
143
- $self->removeFilter = function () use ($self) {
144
- return call_user_func_array(array($self, 'removeHook'), func_get_args());
145
- };
146
-
147
- /*
148
- * Runs any callables attached to an action.
149
- *
150
- * @since 150422 Rewrite.
151
- *
152
- * @param string $hook The name of an action hook.
153
- */
154
- $self->doAction = function ($hook) use ($self) {
155
- $hook = (string) $hook;
156
- if (empty($self->hooks[$hook])) {
157
- return; // No hooks.
158
- }
159
- $hook_actions = $self->hooks[$hook];
160
- $args = func_get_args();
161
- ksort($hook_actions);
162
-
163
- foreach ($hook_actions as $_hook_action) {
164
- foreach ($_hook_action as $_action) {
165
- if (!isset($_action['function'], $_action['accepted_args'])) {
166
- continue; // Not a valid filter in this case.
167
- }
168
- call_user_func_array($_action['function'], array_slice($args, 1, $_action['accepted_args']));
169
- }
170
- }
171
- unset($_hook_action, $_action); // Housekeeping.
172
- };
173
-
174
- /*
175
- * Runs any callables attached to a filter.
176
- *
177
- * @since 150422 Rewrite.
178
- *
179
- * @param string $hook The name of a filter hook.
180
- * @param mixed $value The value to filter.
181
- *
182
- * @return mixed The filtered `$value`.
183
- */
184
- $self->applyFilters = function ($hook, $value) use ($self) {
185
- $hook = (string) $hook;
186
- if (empty($self->hooks[$hook])) {
187
- return $value; // No hooks.
188
- }
189
- $hook_filters = $self->hooks[$hook];
190
- $args = func_get_args();
191
- ksort($hook_filters);
192
-
193
- foreach ($hook_filters as $_hook_filter) {
194
- foreach ($_hook_filter as $_filter) {
195
- if (!isset($_filter['function'], $_filter['accepted_args'])) {
196
- continue; // Not a valid filter in this case.
197
- }
198
- $args[1] = $value; // Continously update the argument `$value`.
199
- $value = call_user_func_array($_filter['function'], array_slice($args, 1, $_filter['accepted_args']));
200
- }
201
- }
202
- unset($_hook_filter, $_filter); // Housekeeping.
203
-
204
- return $value; // With applied filters.
205
- };
206
-
207
- /*
208
- * Does an action w/ back compat. for ZenCache.
209
- *
210
- * @since 150422 Rewrite.
211
- *
212
- * @param string $hook The hook to apply.
213
- */
214
- $self->doWpAction = function ($hook) use ($self) {
215
- $hook = (string) $hook;
216
- $args = func_get_args();
217
- call_user_func_array('do_action', $args);
218
-
219
- if (stripos($hook, GLOBAL_NS) === 0) {
220
- $zencache_filter = 'zencache'.substr($hook, strlen(GLOBAL_NS));
221
- $zencache_args = $args; // Use a copy of the args.
222
- $zencache_args[0] = $zencache_filter;
223
- call_user_func_array('do_action', $zencache_args);
224
- }
225
- };
226
-
227
- /*
228
- * Applies filters w/ back compat. for ZenCache.
229
- *
230
- * @since 150422 Rewrite.
231
- *
232
- * @param string $hook The hook to apply.
233
- *
234
- * @return mixed The filtered value.
235
- */
236
- $self->applyWpFilters = function ($hook) use ($self) {
237
- $hook = (string) $hook;
238
- $args = func_get_args();
239
- $value = call_user_func_array('apply_filters', $args);
240
-
241
- if (stripos($hook, GLOBAL_NS) === 0) {
242
- $zencache_hook = 'zencache'.substr($hook, strlen(GLOBAL_NS));
243
- $zencache_args = $args; // Use a copy of the args.
244
- $zencache_args[0] = $zencache_hook;
245
- $zencache_args[1] = $value; // Filtered value.
246
- $value = call_user_func_array('apply_filters', $zencache_args);
247
- }
248
- return $value; // Filtered value.
249
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/HttpUtils.php DELETED
@@ -1,166 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Current HTTP protocol.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @return string Current HTTP protocol.
10
- */
11
- $self->httpProtocol = function () use ($self) {
12
- if (!is_null($protocol = &$self->staticKey('httpProtocol'))) {
13
- return $protocol; // Already cached this.
14
- }
15
- if (!empty($_SERVER['SERVER_PROTOCOL']) && is_string($_SERVER['SERVER_PROTOCOL'])) {
16
- $protocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
17
- }
18
- if (!$protocol || stripos($protocol, 'HTTP/') !== 0) {
19
- $protocol = 'HTTP/1.0'; // Default value.
20
- }
21
- return $protocol;
22
- };
23
-
24
- /*
25
- * PHP {@link headers_list()} + HTTP status.
26
- *
27
- * @since 150422 Rewrite.
28
- *
29
- * @return array PHP {@link headers_list()} + HTTP status.
30
- *
31
- * @warning Do NOT call until end of script execution.
32
- */
33
- $self->headersList = function () use ($self) {
34
- if (!is_null($headers = &$self->staticKey('headersList'))) {
35
- return $headers; // Already cached this.
36
- }
37
- $headers = headers_list(); // Lacks status.
38
-
39
- if (($status = (string) $self->httpStatus())) {
40
- array_unshift($headers, $self->httpProtocol().' '.$status);
41
- }
42
- return $headers;
43
- };
44
-
45
- /*
46
- * PHP {@link headers_list()} + HTTP status.
47
- *
48
- * @since 150422 Rewrite.
49
- *
50
- * @return array PHP {@link headers_list()} + HTTP status.
51
- *
52
- * @warning Do NOT call until end of script execution.
53
- */
54
- $self->cacheableHeadersList = function () use ($self) {
55
- if (!is_null($headers = &$self->staticKey('cacheableHeadersList'))) {
56
- return $headers; // Already cached this.
57
- }
58
- $headers = headers_list(); // Lacks status.
59
-
60
- $cacheable_headers = array(
61
- 'Access-Control-Allow-Origin',
62
- 'Accept-Ranges',
63
- 'Age',
64
- 'Allow',
65
- 'Cache-Control',
66
- 'Connection',
67
- 'Content-Encoding',
68
- 'Content-Language',
69
- 'Content-Length',
70
- 'Content-Location',
71
- 'Content-MD5',
72
- 'Content-Disposition',
73
- 'Content-Range',
74
- 'Content-Type',
75
- 'Date',
76
- 'ETag',
77
- 'Expires',
78
- 'Last-Modified',
79
- 'Link',
80
- 'Location',
81
- 'P3P',
82
- 'Pragma',
83
- 'Proxy-Authenticate',
84
- 'Refresh',
85
- 'Retry-After',
86
- 'Server',
87
- 'Status',
88
- 'Strict-Transport-Security',
89
- 'Trailer',
90
- 'Transfer-Encoding',
91
- 'Upgrade',
92
- 'Vary',
93
- 'Via',
94
- 'Warning',
95
- 'WWW-Authenticate',
96
- 'X-Frame-Options',
97
- 'Public-Key-Pins',
98
- 'X-XSS-Protection',
99
- 'Content-Security-Policy',
100
- 'X-Content-Security-Policy',
101
- 'X-WebKit-CSP',
102
- 'X-Content-Type-Options',
103
- 'X-Powered-By',
104
- 'X-UA-Compatible',
105
- );
106
- $cacheable_headers = array_map('strtolower', $cacheable_headers);
107
-
108
- foreach ($headers as $_key => $_header) {
109
- $_header = strtolower((string) strstr($_header, ':', true));
110
- if (!$_header || !in_array($_header, $cacheable_headers, true)) {
111
- unset($headers[$_key]);
112
- }
113
- }
114
- unset($_key, $_header); // Housekeeping.
115
-
116
- if (($status = (string) $self->httpStatus())) {
117
- array_unshift($headers, $self->httpProtocol().' '.$status);
118
- }
119
- return $headers;
120
- };
121
-
122
- /*
123
- * HTTP status code.
124
- *
125
- * @since 150422 Rewrite.
126
- *
127
- * @return integer HTTP status code.
128
- *
129
- * @warning Do NOT call until end of script execution.
130
- *
131
- * @note Automatically updates HTTP status-related flags.
132
- */
133
- $self->httpStatus = function () use ($self) {
134
- if (!is_null($status = &$self->staticKey('httpStatus'))) {
135
- return $status; // Already cached this.
136
- }
137
- $status = 0; // Initialize.
138
- $has_property_is_404 = property_exists($self, 'is_404');
139
- $has_property_http_status = property_exists($self, 'http_status');
140
-
141
- if ($has_property_is_404 && $self->{'is_404'}) {
142
- $status = 404; // WordPress said so.
143
- } elseif ($self->functionIsPossible('http_response_code') && ($code = (integer) http_response_code())) {
144
- $status = (integer) $code; // {@link \http_response_code()} available since PHP v5.4.
145
- } elseif ($has_property_http_status && (integer) $self->{'http_status'}) {
146
- $status = (integer) $self->{'http_status'}; // {@link \status_header()} filter.
147
- }
148
- if ($status && $has_property_http_status) {
149
- $self->{'http_status'} = $status; // Prefer over {@link status_header()}.
150
- }
151
- if ($status === 404 && $has_property_is_404) {
152
- $self->{'is_404'} = true; // Prefer over {@link is_404()}.
153
- }
154
- return $status;
155
- };
156
- /*
157
- * Sends no-cache headers.
158
- *
159
- * @since 151220 Enhancing no-cache headers.
160
- */
161
- $self->sendNoCacheHeaders = function() use($self) {
162
- header_remove('Last-Modified');
163
- header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
164
- header('Cache-Control: no-cache, must-revalidate, max-age=0');
165
- header('Pragma: no-cache');
166
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/I18nUtils.php DELETED
@@ -1,44 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * `X file` or `X files`, translated w/ singlular/plural context.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param integer $counter Total files; i.e. the counter.
10
- *
11
- * @return string The phrase `X file` or `X files`.
12
- */
13
- $self->i18nFiles = function ($counter) use ($self) {
14
- $counter = (integer) $counter;
15
- return sprintf(_n('%1$s file', '%1$s files', $counter, 'comet-cache'), $counter);
16
- };
17
-
18
- /*
19
- * `X directory` or `X directories`, translated w/ singlular/plural context.
20
- *
21
- * @since 150422 Rewrite.
22
- *
23
- * @param integer $counter Total directories; i.e. the counter.
24
- *
25
- * @return string The phrase `X directory` or `X directories`.
26
- */
27
- $self->i18nDirs = function ($counter) use ($self) {
28
- $counter = (integer) $counter;
29
- return sprintf(_n('%1$s directory', '%1$s directories', $counter, 'comet-cache'), $counter);
30
- };
31
-
32
- /*
33
- * `X file/directory` or `X files/directories`, translated w/ singlular/plural context.
34
- *
35
- * @since 150422 Rewrite.
36
- *
37
- * @param integer $counter Total files/directories; i.e. the counter.
38
- *
39
- * @return string The phrase `X file/directory` or `X files/directories`.
40
- */
41
- $self->i18nFilesDirs = function ($counter) use ($self) {
42
- $counter = (integer) $counter;
43
- return sprintf(_n('%1$s file/directory', '%1$s files/directories', $counter, 'comet-cache'), $counter);
44
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/IpAddrUtils.php DELETED
@@ -1,83 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Get the current visitor's real IP address.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @return string Real IP address, else `unknown` on failure.
10
- *
11
- * @note This supports both IPv4 and IPv6 addresses.
12
- * @note See my tests against this here: http://3v4l.org/fVWUp
13
- */
14
- $self->currentIp = function () use ($self) {
15
- if (!is_null($ip = &$self->staticKey('currentIp'))) {
16
- return $ip; // Already cached this.
17
- }
18
- $sources = array(
19
- 'HTTP_CF_CONNECTING_IP',
20
- 'HTTP_CLIENT_IP',
21
- 'HTTP_X_FORWARDED_FOR',
22
- 'HTTP_X_FORWARDED',
23
- 'HTTP_X_CLUSTER_CLIENT_IP',
24
- 'HTTP_FORWARDED_FOR',
25
- 'HTTP_FORWARDED',
26
- 'HTTP_VIA',
27
- 'REMOTE_ADDR',
28
- );
29
- $sources = $self->applyFilters(GLOBAL_NS.'\\share::current_ip_sources', $sources);
30
- $sources = $self->applyFilters(GLOBAL_NS.'_current_ip_sources', $sources);
31
-
32
- $prioritize_remote_addr = false; // Off by default; can be filtered however.
33
- $prioritize_remote_addr = $self->applyFilters(GLOBAL_NS.'\\share::current_ip_prioritize_remote_addr', $prioritize_remote_addr);
34
- $prioritize_remote_addr = $self->applyFilters(GLOBAL_NS.'_current_ip_prioritize_remote_addr', $prioritize_remote_addr);
35
-
36
- if (!empty($_SERVER['REMOTE_ADDR']) && $prioritize_remote_addr) {
37
- if (($_valid_public_ip = $self->validPublicIp((string) $_SERVER['REMOTE_ADDR']))) {
38
- return ($ip = $_valid_public_ip);
39
- }
40
- unset($_valid_public_ip); // Housekeeping.
41
- }
42
- foreach ($sources as $_key => $_source) {
43
- if (!empty($_SERVER[$_source])) {
44
- if (($_valid_public_ip = $self->validPublicIp((string) $_SERVER[$_source]))) {
45
- return ($ip = $_valid_public_ip);
46
- }
47
- }
48
- unset($_key, $_source, $_valid_public_ip); // Housekeeping.
49
- }
50
- if (!empty($_SERVER['REMOTE_ADDR'])) {
51
- return ($ip = strtolower((string) $_SERVER['REMOTE_ADDR']));
52
- }
53
- return ($ip = 'unknown'); // Not possible.
54
- };
55
-
56
- /*
57
- * Gets a valid/public IP address.
58
- *
59
- * @since 150422 Rewrite.
60
- *
61
- * @param string $list_of_possible_ips A single IP, or a comma-delimited list of IPs.
62
- *
63
- * @return string A valid/public IP address (if one is found), else an empty string.
64
- *
65
- * @note This supports both IPv4 and IPv6 addresses.
66
- * @note See my tests against this here: http://3v4l.org/fVWUp
67
- */
68
- $self->validPublicIp = function ($list_of_possible_ips) use ($self) {
69
- if (!$list_of_possible_ips || !is_string($list_of_possible_ips)) {
70
- return ''; // Empty or invalid data.
71
- }
72
- if (!($list_of_possible_ips = trim($list_of_possible_ips))) {
73
- return ''; // Not possible; i.e., empty string.
74
- }
75
- foreach (preg_split('/[\s;,]+/', $list_of_possible_ips, -1, PREG_SPLIT_NO_EMPTY) as $_key => $_possible_ip) {
76
- if (($_valid_public_ip = filter_var(strtolower($_possible_ip), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))) {
77
- return $_valid_public_ip; // A valid public IPv4 or IPv6 address.
78
- }
79
- }
80
- unset($_key, $_possible_ip, $_valid_public_ip); // Housekeeping.
81
-
82
- return ''; // Default return value.
83
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/PatternUtils.php DELETED
@@ -1,48 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Convert line-delimited patterns to a regex.
6
- *
7
- * @since 151114 Enhancing exclusion pattern support.
8
- *
9
- * @param string $patterns Line-delimited list of patterns.
10
- *
11
- * @return string A `/(?:list|of|regex)/i` patterns.
12
- */
13
- $self->lineDelimitedPatternsToRegex = function ($patterns) use ($self) {
14
- $regex = ''; // Initialize list of regex patterns.
15
- $patterns = (string) $patterns;
16
-
17
- if (($patterns = preg_split('/['."\r\n".']+/', $patterns, -1, PREG_SPLIT_NO_EMPTY))) {
18
- $regex = '/(?:'.implode('|', array_map($self->wdRegexToActualRegexFrag, $patterns)).')/i';
19
- }
20
- return $regex;
21
- };
22
-
23
- /*
24
- * Convert watered-down regex to actual regex.
25
- *
26
- * @since 151114 Enhancing exclusion pattern support.
27
- *
28
- * @param string $string Input watered-down regex to convert.
29
- *
30
- * @return string Actual regex pattern after conversion.
31
- */
32
- $self->wdRegexToActualRegexFrag = function ($string) use ($self) {
33
- return preg_replace(
34
- array(
35
- '/\\\\\^/',
36
- '/\\\\\*\\\\\*/',
37
- '/\\\\\*/',
38
- '/\\\\\$/',
39
- ),
40
- array(
41
- '^', // Beginning of line.
42
- '.*?', // Zero or more chars.
43
- '[^\/]*?', // Zero or more chars != /.
44
- '$', // End of line.
45
- ),
46
- preg_quote((string) $string, '/')
47
- );
48
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/ReplaceUtils.php DELETED
@@ -1,43 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * String replace ONE time.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $needle A string to search/replace.
10
- * @param string $replace What to replace `$needle` with.
11
- * @param string $haystack The string/haystack to search in.
12
- *
13
- * @param boolean $caSe_insensitive Defaults to a `FALSE` value.
14
- * Pass this as `TRUE` to a caSe-insensitive search/replace.
15
- *
16
- * @return string The `$haystack`, with `$needle` replaced with `$replace` ONE time only.
17
- */
18
- $self->strReplaceOnce = function ($needle, $replace, $haystack, $caSe_insensitive = false) use ($self) {
19
- $needle = (string) $needle;
20
- $replace = (string) $replace;
21
- $haystack = (string) $haystack;
22
- $caSe_strpos = $caSe_insensitive ? 'stripos' : 'strpos';
23
-
24
- if (($needle_strpos = $caSe_strpos($haystack, $needle)) === false) {
25
- return $haystack; // Nothing to replace.
26
- }
27
- return (string) substr_replace($haystack, $replace, $needle_strpos, strlen($needle));
28
- };
29
-
30
- /*
31
- * String replace ONE time (caSe-insensitive).
32
- *
33
- * @since 150422 Rewrite.
34
- *
35
- * @param string $needle A string to search/replace.
36
- * @param string $replace What to replace `$needle` with.
37
- * @param string $haystack The string/haystack to search in.
38
- *
39
- * @return string The `$haystack`, with `$needle` replaced with `$replace` ONE time only.
40
- */
41
- $self->strIreplaceOnce = function ($needle, $replace, $haystack) use ($self) {
42
- return $self->strReplaceOnce($needle, $replace, $haystack, true);
43
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/ServerUtils.php DELETED
@@ -1,65 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Is running on Apache?
6
- *
7
- * @since 151002 This is Apache?
8
- *
9
- * @return bool True if running Apache.
10
- */
11
- $self->isApache = function () use ($self) {
12
- if (!is_null($is = &$self->staticKey('isApache'))) {
13
- return $is; // Already cached this.
14
- }
15
- if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
16
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
17
- return ($is = true);
18
- }
19
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
20
- return ($is = true);
21
- }
22
- }
23
- return ($is = false);
24
- };
25
-
26
- /*
27
- * Is running on Nginx?
28
- *
29
- * @since 151002 This is Nginx?
30
- *
31
- * @return bool True if running Nginx.
32
- */
33
- $self->isNginx = function () use ($self) {
34
- if (!is_null($is = &$self->staticKey('isNginx'))) {
35
- return $is; // Already cached this.
36
- }
37
- if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
38
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
39
- return ($is = true);
40
- }
41
- }
42
- return ($is = false);
43
- };
44
-
45
- /*
46
- * Is running on Windows IIS?
47
- *
48
- * @since 151002 This is Windows IIS?
49
- *
50
- * @return bool True if running Windows IIS.
51
- */
52
- $self->isIis = function () use ($self) {
53
- if (!is_null($is = &$self->staticKey('isIis'))) {
54
- return $is; // Already cached this.
55
- }
56
- if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
57
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) {
58
- return ($is = true);
59
- }
60
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) {
61
- return ($is = true);
62
- }
63
- }
64
- return ($is = false);
65
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/StringUtils.php DELETED
@@ -1,87 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Clips string(s) to X chars deeply.
6
- *
7
- * @since 151114 Adding string utils.
8
- *
9
- * @param mixed $value Any input value.
10
- * @param int $max_length Defaults to a value of `80`.
11
- * @param bool $force_ellipsis Defaults to a value of `FALSE`.
12
- *
13
- * @return string|array|object Clipped value.
14
- */
15
- $self->clip = function ($value, $max_length = 80, $force_ellipsis = false) use ($self) {
16
- if (is_array($value) || is_object($value)) {
17
- foreach ($value as $_key => &$_value) {
18
- $_value = $self->clip($_value, $max_length, $force_ellipsis);
19
- }
20
- unset($_key, $_value); // Housekeeping.
21
-
22
- return $value;
23
- }
24
- if (!($string = (string) $value)) {
25
- return $string; // Empty.
26
- }
27
- $max_length = max(4, $max_length);
28
-
29
- $string = strip_tags($string);
30
- $string = preg_replace('/\s+/', ' ', strip_tags($string));
31
- $string = trim($string); // Trim it up now.
32
-
33
- if (strlen($string) > $max_length) {
34
- $string = (string) substr($string, 0, $max_length - 3).'...';
35
- } elseif ($force_ellipsis && strlen($string) + 3 > $max_length) {
36
- $string = (string) substr($string, 0, $max_length - 3).'...';
37
- } else {
38
- $string .= $force_ellipsis ? '...' : '';
39
- }
40
- return $string;
41
- };
42
-
43
- /*
44
- * Mid-clips string(s) to X chars deeply.
45
- *
46
- * @since 151114 Adding string utils.
47
- *
48
- * @param mixed $value Any input value.
49
- * @param int $max_length Defaults to a value of `80`.
50
- *
51
- * @return string|array|object Mid-clipped value.
52
- */
53
- $self->midClip = function ($value, $max_length = 80) use ($self) {
54
- if (is_array($value) || is_object($value)) {
55
- foreach ($value as $_key => &$_value) {
56
- $_value = $self->midClip($_value, $max_length);
57
- }
58
- unset($_key, $_value); // Housekeeping.
59
-
60
- return $value;
61
- }
62
- if (!($string = (string) $value)) {
63
- return $string; // Empty.
64
- }
65
- $max_length = max(4, $max_length);
66
-
67
- $string = strip_tags($string);
68
- $string = preg_replace('/\s+/', ' ', strip_tags($string));
69
- $string = trim($string); // Trim it up now.
70
-
71
- if (strlen($string) <= $max_length) {
72
- return $string; // Nothing to do.
73
- }
74
- $full_string = $string;
75
- $half_max_length = floor($max_length / 2);
76
-
77
- $first_clip = $half_max_length - 3;
78
- $string = $first_clip >= 1 // Something?
79
- ? substr($full_string, 0, $first_clip).'...'
80
- : '...'; // Ellipsis only.
81
-
82
- $second_clip = strlen($full_string) - ($max_length - strlen($string));
83
- $string .= $second_clip >= 0 && $second_clip >= $first_clip
84
- ? substr($full_string, $second_clip) : '';
85
-
86
- return $string;
87
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/SysUtils.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * System load averages.
6
- *
7
- * @since 151002 Adding cache directory statistics.
8
- *
9
- * @return array System load averages.
10
- */
11
- $self->sysLoadAverages = function () use ($self) {
12
- if (!is_null($averages = &$self->cacheKey('sysLoadAverages'))) {
13
- return $averages; // Already cached these.
14
- }
15
- if (!$self->functionIsPossible('sys_getloadavg')) {
16
- return ($averages = array());
17
- }
18
- if (!is_array($averages = sys_getloadavg()) || !$averages) {
19
- return ($averages = array());
20
- }
21
- $averages = array_map('floatval', $averages);
22
- $averages = array_slice($averages, 0, 3);
23
- // i.e., 1m, 5m, 15m; see: <http://jas.xyz/1gWyJLt>
24
-
25
- return $averages;
26
- };
27
-
28
- /*
29
- * System memory info.
30
- *
31
- * @since 151002 Adding cache directory statistics.
32
- *
33
- * @return \stdClass|boolean System memory info.
34
- */
35
- $self->sysMemoryStatus = function () use ($self) {
36
- if (!is_null($status = &$self->cacheKey('sysMemoryStatus'))) {
37
- return $status; // Already cached this.
38
- }
39
- if (!$self->functionIsPossible('shell_exec')) {
40
- return ($status = false);
41
- }
42
- if (!($free = trim((string) @shell_exec('free')))) {
43
- return ($status = false);
44
- }
45
- if (!($free_lines = explode("\n", $free))) {
46
- return ($status = false);
47
- }
48
- if (empty($free_lines[1])) {
49
- return ($status = false);
50
- }
51
- if (!($memory = explode(' ', $free_lines[1]))) {
52
- return ($status = false);
53
- }
54
- if (!($memory = array_merge(array_filter($memory)))) {
55
- return ($status = false);
56
- }
57
- if (!isset($memory[1], $memory[2])) {
58
- return ($status = false);
59
- }
60
- if (($total = (integer) $memory[1]) <= 0) {
61
- return ($status = false);
62
- }
63
- $used = (integer) $memory[2];
64
- $percent = $used / $total * 100;
65
- $percentage = sprintf(__('%s%%', 'comet-cache'), number_format($percent, 2, '.', ''));
66
- $status = (object) compact('total', 'used', 'percent', 'percentage');
67
-
68
- return $status;
69
- };
70
-
71
- /*
72
- * System opcache status/details.
73
- *
74
- * @since 151002 Adding cache directory statistics.
75
- *
76
- * @return \stdClass|boolean System opcache status/details.
77
- */
78
- $self->sysOpcacheStatus = function () use ($self) {
79
- if (!is_null($status = &$self->cacheKey('sysOpcacheStatus'))) {
80
- return $status; // Already cached this.
81
- }
82
- if (!$self->functionIsPossible('opcache_get_status')) {
83
- return ($status = false);
84
- }
85
- if (!is_array($status = opcache_get_status(false)) || !$status) {
86
- return ($status = false);
87
- }
88
- if (empty($status['opcache_enabled'])) {
89
- return ($status = false);
90
- }
91
- return json_decode(json_encode($status));
92
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/TokenUtils.php DELETED
@@ -1,300 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
-
5
-
6
- /*
7
- * Current host.
8
- *
9
- * @since 150422 Rewrite.
10
- *
11
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
12
- * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
13
- *
14
- * @param boolean $consider_domain_mapping Consider?
15
- *
16
- * @param string $consider_domain_mapping_domain A specific domain?
17
- *
18
- * @return string Current host.
19
- *
20
- * @note The return value of this function is cached to reduce overhead on repeat calls.
21
- */
22
- $self->hostToken = function ($dashify = false, $consider_domain_mapping = false, $consider_domain_mapping_domain = '') use ($self) {
23
- if (!is_null($token = &$self->staticKey('hostToken', array($dashify, $consider_domain_mapping, $consider_domain_mapping_domain)))) {
24
- return $token; // Already cached this.
25
- }
26
- $token = ''; // Initialize token value.
27
-
28
- if (!is_multisite() || $self->isAdvancedCache()) {
29
- $token = (string) $_SERVER['HTTP_HOST'];
30
- } elseif ($consider_domain_mapping && $self->canConsiderDomainMapping()) {
31
- if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
32
- $token = $consider_domain_mapping_domain;
33
- } elseif ($self->isDomainMapping()) {
34
- $token = (string) $_SERVER['HTTP_HOST'];
35
- } else { // For the current blog ID.
36
- $token = $self->domainMappingUrlFilter($self->currentUrl());
37
- $token = $self->parseUrl($token, PHP_URL_HOST);
38
- }
39
- }
40
- if (!$token) { // Use default?
41
- $token = (string) $_SERVER['HTTP_HOST'];
42
- }
43
- if ($token) { // Have token?
44
- $token = strtolower($token);
45
- if ($dashify) { // Dashify it?
46
- $token = preg_replace('/[^a-z0-9]/i', '-', $token);
47
- $token = trim($token, '-');
48
- }
49
- }
50
- return $token;
51
- };
52
-
53
- /*
54
- * Host for a specific blog.
55
- *
56
- * @since 150821 Improving multisite compat.
57
- *
58
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
59
- * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
60
- *
61
- * @param boolean $consider_domain_mapping Consider?
62
- *
63
- * @param string $consider_domain_mapping_domain A specific domain?
64
- *
65
- * @param boolean $fallback Fallback on blog's domain when mapping?
66
- *
67
- * @param integer $blog_id For which blog ID?
68
- *
69
- * @return string Host for a specific blog.
70
- *
71
- * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
72
- */
73
- $self->hostTokenForBlog = function ($dashify = false, $consider_domain_mapping = false, $consider_domain_mapping_domain = '', $fallback = false, $blog_id = 0) use ($self) {
74
- if (!is_multisite() || $self->isAdvancedCache()) {
75
- return $self->hostToken($dashify, $consider_domain_mapping, $consider_domain_mapping_domain);
76
- }
77
- $token = ''; // Initialize token value.
78
-
79
- if ($consider_domain_mapping && $self->canConsiderDomainMapping()) {
80
- if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
81
- $token = $consider_domain_mapping_domain; // Force this value.
82
- } else {
83
- $token = $self->domainMappingBlogDomain($blog_id, $fallback);
84
- }
85
- } elseif (($blog_details = $self->blogDetails($blog_id))) {
86
- $token = $blog_details->domain; // Unmapped domain.
87
- }
88
- if ($token) { // Have token?
89
- $token = strtolower($token);
90
- if ($dashify) { // Dashify it?
91
- $token = preg_replace('/[^a-z0-9]/i', '-', $token);
92
- $token = trim($token, '-');
93
- }
94
- }
95
- return $token;
96
- };
97
-
98
- /*
99
- * Current site's base directory.
100
- *
101
- * @since 150422 Rewrite.
102
- *
103
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
104
- * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`.
105
- *
106
- * @param boolean $consider_domain_mapping Consider?
107
- *
108
- * @return string Current site's base directory.
109
- *
110
- * @note The return value of this function is cached to reduce overhead on repeat calls.
111
- */
112
- $self->hostBaseToken = function ($dashify = false, $consider_domain_mapping = false) use ($self) {
113
- if (!is_null($token = &$self->staticKey('hostBaseToken', array($dashify, $consider_domain_mapping)))) {
114
- return $token; // Already cached this.
115
- }
116
- $token = '/'; // Assume NOT multisite; or own domain.
117
-
118
- if (!is_multisite()) {
119
- return $token; // Not applicable.
120
- }
121
- if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
122
- return $token; // Not applicable.
123
- }
124
- if ($consider_domain_mapping && $self->canConsiderDomainMapping()) {
125
- return $token; // Not applicable.
126
- }
127
- if (defined('PATH_CURRENT_SITE')) {
128
- $token = (string) PATH_CURRENT_SITE;
129
- }
130
- $token = trim($token, '\\/'." \t\n\r\0\x0B");
131
- $token = isset($token[0]) ? '/'.$token.'/' : '/';
132
-
133
- if ($token !== '/' && $dashify) {
134
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
135
- $token = trim($token, '-');
136
- }
137
- return $token;
138
- };
139
-
140
- /*
141
- * Current blog's sub-directory.
142
- *
143
- * @since 150422 Rewrite.
144
- *
145
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
146
- * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`.
147
- *
148
- * @param boolean $consider_domain_mapping Consider?
149
- *
150
- * @param string $path Defaults to the current URI path.
151
- *
152
- * @return string Current blog's sub-directory.
153
- *
154
- * @note The return value of this function is cached to reduce overhead on repeat calls.
155
- */
156
- $self->hostDirToken = function ($dashify = false, $consider_domain_mapping = false, $path = null) use ($self) {
157
- if (!isset($path)) { // Use current/default path?
158
- $path = (string) $self->parseUrl($_SERVER['REQUEST_URI'], PHP_URL_PATH);
159
- }
160
- $path = '/'.ltrim((string) $path, '/'); // Force leading slash.
161
-
162
- if (!is_null($token = &$self->staticKey('hostDirToken', array($dashify, $consider_domain_mapping, $path)))) {
163
- return $token; // Already cached this.
164
- }
165
- $token = '/'; // Assume NOT multisite; or own domain.
166
-
167
- if (!is_multisite()) {
168
- return $token; // Not applicable.
169
- }
170
- if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
171
- return $token; // Not applicable.
172
- }
173
- if ($consider_domain_mapping && $self->canConsiderDomainMapping()) {
174
- return $token; // Not applicable.
175
- }
176
- if ($path && $path !== '/' && ($host_base_token = trim($self->hostBaseToken(), '/'))) {
177
- $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
178
- } else {
179
- $path_minus_base = $path; // Default value.
180
- }
181
- list($token) = explode('/', trim($path_minus_base, '/'));
182
- $token = trim($token, '\\/'." \t\n\r\0\x0B");
183
- $token = isset($token[0]) ? '/'.$token.'/' : '/';
184
-
185
- if ($token !== '/') { // Perhaps NOT the main site?
186
- $blog_paths_file = $self->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
187
- if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
188
- $token = '/'; // NOT a real/valid child blog path.
189
- }
190
- }
191
- if ($token !== '/' && $dashify) {
192
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
193
- $token = trim($token, '-');
194
- }
195
- return $token;
196
- };
197
-
198
- /*
199
- * A blog's sub-directory.
200
- *
201
- * @since 150821 Improving multisite compat.
202
- *
203
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
204
- * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
205
- *
206
- * @param boolean $consider_domain_mapping Consider?
207
- *
208
- * @param integer $blog_id For which blog ID?
209
- *
210
- * @return string A blog's sub-directory.
211
- *
212
- * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
213
- */
214
- $self->hostDirTokenForBlog = function ($dashify = false, $consider_domain_mapping = false, $blog_id = 0) use ($self) {
215
- if (!is_multisite() || $self->isAdvancedCache()) {
216
- return $self->hostDirToken($dashify, $consider_domain_mapping);
217
- }
218
- $token = '/'; // Initialize token value.
219
-
220
- if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
221
- return $token; // Not applicable.
222
- }
223
- if ($consider_domain_mapping && $self->canConsiderDomainMapping()) {
224
- return $token; // Not applicable.
225
- }
226
- if (($blog_details = $self->blogDetails($blog_id))) {
227
- $path = $blog_details->path; // e.g., `[/base]/path/` (includes base).
228
- if ($path && $path !== '/' && ($host_base_token = trim($self->hostBaseToken(), '/'))) {
229
- $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
230
- } else {
231
- $path_minus_base = $path; // Default value.
232
- }
233
- list($token) = explode('/', trim($path_minus_base, '/'));
234
- }
235
- $token = trim($token, '\\/'." \t\n\r\0\x0B");
236
- $token = isset($token[0]) ? '/'.$token.'/' : '/';
237
-
238
- if ($token !== '/') { // Perhaps NOT the main site?
239
- $blog_paths_file = $self->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
240
- if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
241
- $token = '/'; // NOT a real/valid child blog path.
242
- }
243
- }
244
- if ($token !== '/' && $dashify) {
245
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
246
- $token = trim($token, '-');
247
- }
248
- return $token;
249
- };
250
-
251
- /*
252
- * Current site's base directory & current blog's sub-directory.
253
- *
254
- * @since 150422 Rewrite.
255
- *
256
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
257
- * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`.
258
- *
259
- * @param boolean $consider_domain_mapping Consider?
260
- *
261
- * @param string $path Defaults to the current URI path.
262
- *
263
- * @return string Current site's base directory & current blog's sub-directory.
264
- *
265
- * @note The return value of this function is cached to reduce overhead on repeat calls.
266
- */
267
- $self->hostBaseDirTokens = function ($dashify = false, $consider_domain_mapping = false, $path = null) use ($self) {
268
- if (!is_null($tokens = &$self->staticKey('hostBaseDirTokens', array($dashify, $consider_domain_mapping, $path)))) {
269
- return $tokens; // Already cached this.
270
- }
271
- $tokens = $self->hostBaseToken($dashify, $consider_domain_mapping);
272
- $tokens .= $self->hostDirToken($dashify, $consider_domain_mapping, $path);
273
-
274
- return ($tokens = preg_replace('/\/+/', '/', $tokens));
275
- };
276
-
277
- /*
278
- * A site's base directory & a blog's sub-directory.
279
- *
280
- * @since 150821 Improving multisite compat.
281
- *
282
- * @param boolean $dashify Optional, defaults to a `FALSE` value.
283
- * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`.
284
- *
285
- * @param boolean $consider_domain_mapping Consider?
286
- *
287
- * @param integer $blog_id For which blog ID?
288
- *
289
- * @return string A site's base directory & a blog's sub-directory.
290
- *
291
- * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
292
- */
293
- $self->hostBaseDirTokensForBlog = function ($dashify = false, $consider_domain_mapping = false, $blog_id = 0) use ($self) {
294
- $tokens = $self->hostBaseToken($dashify, $consider_domain_mapping);
295
- $tokens .= $self->hostDirTokenForBlog($dashify, $consider_domain_mapping, $blog_id);
296
-
297
- return ($tokens = preg_replace('/\/+/', '/', $tokens));
298
- };
299
-
300
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/TrimUtils.php DELETED
@@ -1,36 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Trims strings deeply.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param mixed $values Any value can be converted into a trimmed string.
10
- * Actually, objects can't, but this recurses into objects.
11
- *
12
- * @param string $chars Specific chars to trim.
13
- * Defaults to PHP's trim: " \r\n\t\0\x0B". Use an empty string to bypass.
14
- *
15
- * @param string $extra_chars Additional chars to trim.
16
- *
17
- * @return string|array|object Trimmed string, array, object.
18
- */
19
- $self->trimDeep = function ($values, $chars = '', $extra_chars = '') use ($self) {
20
- if (is_array($values) || is_object($values)) {
21
- foreach ($values as $_key => &$_values) {
22
- $_values = $self->trimDeep($_values, $chars, $extra_chars);
23
- }
24
- unset($_key, $_values); // Housekeeping.
25
-
26
- return $values;
27
- }
28
- $string = (string) $values;
29
- $chars = (string) $chars;
30
- $extra_chars = (string) $extra_chars;
31
-
32
- $chars = isset($chars[0]) ? $chars : " \r\n\t\0\x0B";
33
- $chars = $chars.$extra_chars; // Concatenate.
34
-
35
- return trim($string, $chars);
36
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/closures/Shared/UrlUtils.php DELETED
@@ -1,131 +0,0 @@
1
- <?php
2
- namespace WebSharks\CometCache;
3
-
4
- /*
5
- * Parses a URL.
6
- *
7
- * @since 150821 Improving multisite compat.
8
- *
9
- * @param string $url_uri_qsl Input URL, URI, or query string w/ a leading `?`.
10
- * @param int $component Optional component to retrieve.
11
- *
12
- * @return array|string|int|null Array, else `string|int|null` component value.
13
- */
14
- $self->parseUrl = function ($url_uri_qsl, $component = -1) use ($self) {
15
- $url_uri_qsl = (string) $url_uri_qsl;
16
- $component = (integer) $component;
17
- ${'//'} = strpos($url_uri_qsl, '//') === 0;
18
-
19
- if ($url_uri_qsl && strpos($url_uri_qsl, '&amp;') !== false) {
20
- $url_uri_qsl = str_replace('&amp;', '&', $url_uri_qsl);
21
- }
22
- if ($component > -1) {
23
- if (${'//'} && $component === PHP_URL_SCHEME) {
24
- return ($part = '//');
25
- }
26
- return ($part = parse_url($url_uri_qsl, $component));
27
- } else {
28
- if (!is_array($parts = parse_url($url_uri_qsl))) {
29
- return ($parts = array());
30
- }
31
- if (${'//'}) {
32
- $parts['scheme'] = '//';
33
- }
34
- return $parts;
35
- }
36
- };
37
-
38
- /*
39
- * Unparses a URL.
40
- *
41
- * @since 150821 Improving multisite compat.
42
- *
43
- * @param array $parts Input URL parts.
44
- *
45
- * @return string Unparsed URL in string format.
46
- */
47
- $self->unParseUrl = function (array $parts) use ($self) {
48
- $scheme = '';
49
- $host = '';
50
- $port = '';
51
- $user = '';
52
- $pass = '';
53
- $path = '';
54
- $query = '';
55
- $fragment = '';
56
-
57
- if (!empty($parts['scheme'])) {
58
- if ($parts['scheme'] === '//') {
59
- $scheme = $parts['scheme'];
60
- } else {
61
- $scheme = $parts['scheme'].'://';
62
- }
63
- }
64
- if (!empty($parts['host'])) {
65
- $host = $parts['host'];
66
- }
67
- if (!empty($parts['port'])) {
68
- $port = ':'.$parts['port'];
69
- }
70
- if (!empty($parts['user'])) {
71
- $user = $parts['user'];
72
- }
73
- if (!empty($parts['pass'])) {
74
- $pass = $parts['pass'];
75
- }
76
- if ($user || $pass) {
77
- $pass .= '@';
78
- }
79
- if (!empty($parts['path'])) {
80
- $path = '/'.ltrim($parts['path'], '/');
81
- }
82
- if (!empty($parts['query'])) {
83
- $query = '?'.$parts['query'];
84
- }
85
- if (!empty($parts['fragment'])) {
86
- $fragment = '#'.$parts['fragment'];
87
- }
88
- return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
89
- };
90
-
91
- /*
92
- * Is the current request over SSL?
93
- *
94
- * @since 150422 Rewrite.
95
- *
96
- * @return boolean `TRUE` if the current request is over SSL.
97
- *
98
- * @note The return value of this function is cached to reduce overhead on repeat calls.
99
- */
100
- $self->isSsl = function () use ($self) {
101
- if (!is_null($is = &$self->staticKey('isSsl'))) {
102
- return $is; // Already cached this.
103
- }
104
- if (!empty($_SERVER['SERVER_PORT'])) {
105
- if ((integer) $_SERVER['SERVER_PORT'] === 443) {
106
- return ($is = true);
107
- }
108
- }
109
- if (!empty($_SERVER['HTTPS'])) {
110
- if (filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN)) {
111
- return ($is = true);
112
- }
113
- }
114
- if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
115
- if (strcasecmp((string) $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) {
116
- return ($is = true);
117
- }
118
- }
119
- return ($is = false);
120
- };
121
-
122
- /*
123
- * Current URL.
124
- *
125
- * @since 150821 Improving multisite compat.
126
- *
127
- * @return string Current URL.
128
- */
129
- $self->currentUrl = function () use ($self) {
130
- return ($self->isSsl() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
131
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/functions/i18n-utils.php CHANGED
@@ -1,22 +1,37 @@
1
  <?php
2
- namespace WebSharks\CometCache;
3
 
4
- /**
5
- * Polyfill for {@link \__()}.
6
- *
7
- * @since 150422 Rewrite.
8
- *
9
- * @param string $string String to translate.
10
- * @param string $text_domain Plugin text domain.
11
- *
12
- * @return string Possibly translated string.
13
- */
14
- function __($string, $text_domain)
15
- {
16
- static $exists; // Cache.
17
 
18
- if ($exists || ($exists = function_exists('__'))) {
19
- return \__($string, $text_domain);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
- return $string; // Not possible (yet).
22
  }
1
  <?php
2
+ namespace WebSharks\CometCache {
3
 
4
+ /**
5
+ * Polyfill for {@link \__()}.
6
+ *
7
+ * @since 150422 Rewrite.
8
+ *
9
+ * @param string $string String to translate.
10
+ * @param string $text_domain Plugin text domain.
11
+ *
12
+ * @return string Possibly translated string.
13
+ */
14
+ function __($string, $text_domain)
15
+ {
16
+ static $exists; // Cache.
17
 
18
+ if ($exists || ($exists = function_exists('__'))) {
19
+ return \__($string, $text_domain);
20
+ }
21
+ return $string; // Not possible (yet).
22
+ }
23
+ }
24
+ namespace WebSharks\CometCache\Traits\Ac {
25
+
26
+ function __($string, $text_domain)
27
+ {
28
+ return \WebSharks\CometCache\__($string, $text_domain);
29
+ }
30
+ }
31
+ namespace WebSharks\CometCache\Traits\Shared {
32
+
33
+ function __($string, $text_domain)
34
+ {
35
+ return \WebSharks\CometCache\__($string, $text_domain);
36
  }
 
37
  }
src/includes/functions/wp-cache-postload.php CHANGED
@@ -26,7 +26,7 @@ function wp_cache_postload()
26
  $advanced_cache->maybeSetDebugInfoPostload();
27
  }
28
  if (!empty($advanced_cache->postload['wp_main_query'])) {
29
- add_action('wp', array($advanced_cache, 'wpMainQueryPostload'), PHP_INT_MAX);
30
  }
31
  $advanced_cache->doWpAction('after_'.$GLOBAL_NS.'_'.__FUNCTION__, get_defined_vars());
32
  $advanced_cache->doWpAction($GLOBAL_NS.'_'.__FUNCTION__.'_complete', get_defined_vars());
26
  $advanced_cache->maybeSetDebugInfoPostload();
27
  }
28
  if (!empty($advanced_cache->postload['wp_main_query'])) {
29
+ add_action('wp', [$advanced_cache, 'wpMainQueryPostload'], PHP_INT_MAX);
30
  }
31
  $advanced_cache->doWpAction('after_'.$GLOBAL_NS.'_'.__FUNCTION__, get_defined_vars());
32
  $advanced_cache->doWpAction($GLOBAL_NS.'_'.__FUNCTION__.'_complete', get_defined_vars());
src/includes/interfaces/Shared/CachePathConsts.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Interfaces\Shared;
3
+
4
+ interface CachePathConsts
5
+ {
6
+ /**
7
+ * Default cache path flags.
8
+ *
9
+ * @since 150422 Rewrite.
10
+ *
11
+ * @type int A bitmask.
12
+ */
13
+ const CACHE_PATH_DEFAULT = 0;
14
+
15
+ /**
16
+ * Use a domain-mapped cache path.
17
+ *
18
+ * @since 150821 Improving multisite compat.
19
+ *
20
+ * @type int Part of a bitmask.
21
+ */
22
+ const CACHE_PATH_CONSIDER_DOMAIN_MAPPING = 1;
23
+
24
+ /**
25
+ * Generate an unmapped cache path?
26
+ *
27
+ * @since 150821 Improving multisite compat.
28
+ *
29
+ * @type int Part of a bitmask.
30
+ */
31
+ const CACHE_PATH_REVERSE_DOMAIN_MAPPING = 2;
32
+
33
+ /**
34
+ * Exclude scheme from cache path.
35
+ *
36
+ * @since 150422 Rewrite.
37
+ *
38
+ * @type int Part of a bitmask.
39
+ */
40
+ const CACHE_PATH_NO_SCHEME = 4;
41
+
42
+ /**
43
+ * Exclude host (i.e. domain name) from cache path.
44
+ *
45
+ * @since 150422 Rewrite.
46
+ *
47
+ * @type int Part of a bitmask.
48
+ */
49
+ const CACHE_PATH_NO_HOST = 8;
50
+
51
+ /**
52
+ * Exclude path from cache path.
53
+ *
54
+ * @since 150422 Rewrite.
55
+ *
56
+ * @type int Part of a bitmask.
57
+ */
58
+ const CACHE_PATH_NO_PATH = 16;
59
+
60
+ /**
61
+ * Exclude path index (i.e. no default `index`) from cache path.
62
+ *
63
+ * @since 150422 Rewrite.
64
+ *
65
+ * @type int Part of a bitmask.
66
+ */
67
+ const CACHE_PATH_NO_PATH_INDEX = 32;
68
+
69
+ /**
70
+ * Exclude query, user & version salt from cache path.
71
+ *
72
+ * @since 150422 Rewrite.
73
+ *
74
+ * @type int Part of a bitmask.
75
+ */
76
+ const CACHE_PATH_NO_QUV = 64;
77
+
78
+ /**
79
+ * Exclude query string from cache path.
80
+ *
81
+ * @since 150422 Rewrite.
82
+ *
83
+ * @type int Part of a bitmask.
84
+ */
85
+ const CACHE_PATH_NO_QUERY = 128;
86
+
87
+ /**
88
+ * Exclude user token from cache path.
89
+ *
90
+ * @since 150422 Rewrite.
91
+ *
92
+ * @type int Part of a bitmask.
93
+ */
94
+ const CACHE_PATH_NO_USER = 256;
95
+
96
+ /**
97
+ * Exclude version salt from cache path.
98
+ *
99
+ * @since 150422 Rewrite.
100
+ *
101
+ * @type int Part of a bitmask.
102
+ */
103
+ const CACHE_PATH_NO_VSALT = 512;
104
+
105
+ /**
106
+ * Exclude extension from cache path.
107
+ *
108
+ * @since 150422 Rewrite.
109
+ *
110
+ * @type int Part of a bitmask.
111
+ */
112
+ const CACHE_PATH_NO_EXT = 1024;
113
+
114
+ /**
115
+ * Allow wildcards in the cache path.
116
+ *
117
+ * @since 150422 Rewrite.
118
+ *
119
+ * @type int Part of a bitmask.
120
+ */
121
+ const CACHE_PATH_ALLOW_WILDCARDS = 2048;
122
+
123
+ /**
124
+ * Allow watered-down regex in the cache path.
125
+ *
126
+ * @since 151114 Improving regex syntax.
127
+ *
128
+ * @type int Part of a bitmask.
129
+ */
130
+ const CACHE_PATH_ALLOW_WD_REGEX = 4096;
131
+
132
+ /**
133
+ * Default cache path regex suffix frag.
134
+ *
135
+ * @since 150422 Rewrite.
136
+ *
137
+ * @type string Default regex suffix frag used in cache path patterns.
138
+ */
139
+ const CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG = null;
140
+ }
src/includes/interfaces/Shared/NcDebugConsts.php ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Interfaces\Shared;
3
+
4
+ interface NcDebugConsts
5
+ {
6
+ /**
7
+ * No-cache because of the current {@link \PHP_SAPI}.
8
+ *
9
+ * @since 140422 First documented version.
10
+ *
11
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
12
+ */
13
+ const NC_DEBUG_PHP_SAPI_CLI = 'nc_debug_php_sapi_cli';
14
+
15
+ /**
16
+ * No-cache because of a missing http host.
17
+ *
18
+ * @since 140422 First documented version.
19
+ *
20
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
21
+ */
22
+ const NC_DEBUG_NO_SERVER_HTTP_HOST = 'nc_debug_no_server_http_host';
23
+
24
+ /**
25
+ * No-cache because of a missing `$_SERVER['REQUEST_URI']`.
26
+ *
27
+ * @since 140422 First documented version.
28
+ *
29
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
30
+ */
31
+ const NC_DEBUG_NO_SERVER_REQUEST_URI = 'nc_debug_no_server_request_uri';
32
+
33
+ /**
34
+ * No-cache because the {@link \COMET_CACHE_ALLOWED} constant says not to.
35
+ *
36
+ * @since 140422 First documented version.
37
+ *
38
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
39
+ */
40
+ const NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT = 'nc_debug_comet_cache_allowed_constant';
41
+
42
+ /**
43
+ * No-cache because the `$_SERVER['COMET_CACHE_ALLOWED']` environment variable says not to.
44
+ *
45
+ * @since 140422 First documented version.
46
+ *
47
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
48
+ */
49
+ const NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR = 'nc_debug_comet_cache_allowed_server_var';
50
+
51
+ /**
52
+ * No-cache because the {@link \DONOTCACHEPAGE} constant says not to.
53
+ *
54
+ * @since 140422 First documented version.
55
+ *
56
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
57
+ */
58
+ const NC_DEBUG_DONOTCACHEPAGE_CONSTANT = 'nc_debug_donotcachepage_constant';
59
+
60
+ /**
61
+ * No-cache because the `$_SERVER['DONOTCACHEPAGE']` environment variable says not to.
62
+ *
63
+ * @since 140422 First documented version.
64
+ *
65
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
66
+ */
67
+ const NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR = 'nc_debug_donotcachepage_server_var';
68
+
69
+ /**
70
+ * No-cache because the current request includes the `?[SHORT_NAME]AC=0` parameter.
71
+ *
72
+ * @since 140422 First documented version.
73
+ *
74
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
75
+ */
76
+ const NC_DEBUG_AC_GET_VAR = 'nc_debug_ac_get_var';
77
+
78
+ /**
79
+ * No-cache because the current request method is `POST|PUT|DELETE`.
80
+ *
81
+ * @since 140422 First documented version.
82
+ *
83
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
84
+ */
85
+ const NC_DEBUG_UNCACHEABLE_REQUEST = 'nc_debug_post_put_del_request';
86
+
87
+ /**
88
+ * No-cache because the current request originated from the server itself.
89
+ *
90
+ * @since 140422 First documented version.
91
+ *
92
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
93
+ */
94
+ const NC_DEBUG_SELF_SERVE_REQUEST = 'nc_debug_self_serve_request';
95
+
96
+ /**
97
+ * No-cache because the current request is for a feed.
98
+ *
99
+ * @since 140422 First documented version.
100
+ *
101
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
102
+ */
103
+ const NC_DEBUG_FEED_REQUEST = 'nc_debug_feed_request';
104
+
105
+ /**
106
+ * No-cache because the current request is systematic.
107
+ *
108
+ * @since 140422 First documented version.
109
+ *
110
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
111
+ */
112
+ const NC_DEBUG_WP_SYSTEMATICS = 'nc_debug_wp_systematics';
113
+
114
+ /**
115
+ * No-cache because the current request is for an administrative area.
116
+ *
117
+ * @since 140422 First documented version.
118
+ *
119
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
120
+ */
121
+ const NC_DEBUG_WP_ADMIN = 'nc_debug_wp_admin';
122
+
123
+ /**
124
+ * No-cache because the current request is multisite `/files/`.
125
+ *
126
+ * @since 140422 First documented version.
127
+ *
128
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
129
+ */
130
+ const NC_DEBUG_MS_FILES = 'nc_debug_ms_files';
131
+
132
+ /**
133
+ * No-cache because the current user is like a logged-in user.
134
+ *
135
+ * @since 140422 First documented version.
136
+ *
137
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
138
+ */
139
+ const NC_DEBUG_IS_LIKE_LOGGED_IN_USER = 'nc_debug_is_like_logged_in_user';
140
+
141
+ /**
142
+ * No-cache because the current user is logged into the site.
143
+ *
144
+ * @since 140422 First documented version.
145
+ *
146
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
147
+ */
148
+ const NC_DEBUG_IS_LOGGED_IN_USER = 'nc_debug_is_logged_in_user';
149
+
150
+ /**
151
+ * No-cache because the current user is logged into the site and the current page contains an `nonce`.
152
+ *
153
+ * @since 151220 Enhancing logged-in user caching support.
154
+ *
155
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
156
+ */
157
+ const NC_DEBUG_IS_LOGGED_IN_USER_NONCE = 'nc_debug_is_logged_in_user_nonce';
158
+
159
+ /**
160
+ * No-cache because the current page contains an `nonce`.
161
+ *
162
+ * @since 151220 Enhancing `nonce` detection.
163
+ *
164
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
165
+ */
166
+ const NC_DEBUG_PAGE_CONTAINS_NONCE = 'nc_debug_page_contains_nonce';
167
+
168
+ /**
169
+ * No-cache because it was not possible to acquire a user token.
170
+ *
171
+ * @since 140422 First documented version.
172
+ *
173
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
174
+ */
175
+ const NC_DEBUG_NO_USER_TOKEN = 'nc_debug_no_user_token';
176
+
177
+ /**
178
+ * No-cache because the current request contains a query string.
179
+ *
180
+ * @since 140422 First documented version.
181
+ *
182
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
183
+ */
184
+ const NC_DEBUG_GET_REQUEST_QUERIES = 'nc_debug_get_request_queries';
185
+
186
+ /**
187
+ * No-cache because it's a preview.
188
+ *
189
+ * @since 151114 Adding support for preview detection.
190
+ *
191
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
192
+ */
193
+ const NC_DEBUG_PREVIEW = 'nc_debug_preview';
194
+
195
+ /**
196
+ * No-cache because the current request excluded by its URI.
197
+ *
198
+ * @since 140422 First documented version.
199
+ *
200
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
201
+ */
202
+ const NC_DEBUG_EXCLUDED_URIS = 'nc_debug_excluded_uris';
203
+
204
+ /**
205
+ * No-cache because the current user-agent is excluded.
206
+ *
207
+ * @since 140422 First documented version.
208
+ *
209
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
210
+ */
211
+ const NC_DEBUG_EXCLUDED_AGENTS = 'nc_debug_excluded_agents';
212
+
213
+ /**
214
+ * No-cache because the current HTTP referrer is excluded.
215
+ *
216
+ * @since 140422 First documented version.
217
+ *
218
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
219
+ */
220
+ const NC_DEBUG_EXCLUDED_REFS = 'nc_debug_excluded_refs';
221
+
222
+ /**
223
+ * No-cache because the current request is a 404 error.
224
+ *
225
+ * @since 140422 First documented version.
226
+ *
227
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
228
+ */
229
+ const NC_DEBUG_404_REQUEST = 'nc_debug_404_request';
230
+
231
+ /**
232
+ * No-cache because the requested page is currently in maintenance mode.
233
+ *
234
+ * @since 140422 First documented version.
235
+ *
236
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
237
+ */
238
+ const NC_DEBUG_MAINTENANCE_PLUGIN = 'nc_debug_maintenance_plugin';
239
+
240
+ /**
241
+ * No-cache because the current request is being compressed by an incompatible ZLIB coding type.
242
+ *
243
+ * @since 140422 First documented version.
244
+ *
245
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
246
+ */
247
+ const NC_DEBUG_OB_ZLIB_CODING_TYPE = 'nc_debug_ob_zlib_coding_type';
248
+
249
+ /**
250
+ * No-cache because the current request resulted in a WP error message.
251
+ *
252
+ * @since 140422 First documented version.
253
+ *
254
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
255
+ */
256
+ const NC_DEBUG_WP_ERROR_PAGE = 'nc_debug_wp_error_page';
257
+
258
+ /**
259
+ * No-cache because the current request is serving an uncacheable content type.
260
+ *
261
+ * @since 140422 First documented version.
262
+ *
263
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
264
+ */
265
+ const NC_DEBUG_UNCACHEABLE_CONTENT_TYPE = 'nc_debug_uncacheable_content_type';
266
+
267
+ /**
268
+ * No-cache because the current request sent a non-2xx & non-404 status code.
269
+ *
270
+ * @since 140422 First documented version.
271
+ *
272
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
273
+ */
274
+ const NC_DEBUG_UNCACHEABLE_STATUS = 'nc_debug_uncacheable_status';
275
+
276
+ /**
277
+ * No-cache because this is a new 404 error that we are symlinking.
278
+ *
279
+ * @since 140422 First documented version.
280
+ *
281
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
282
+ */
283
+ const NC_DEBUG_1ST_TIME_404_SYMLINK = 'nc_debug_1st_time_404_symlink';
284
+
285
+ /**
286
+ * No-cache because we detected an early buffer termination.
287
+ *
288
+ * @since 140605 Improving output buffer.
289
+ *
290
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
291
+ */
292
+ const NC_DEBUG_EARLY_BUFFER_TERMINATION = 'nc_debug_early_buffer_termination';
293
+ }
src/includes/plugin.php CHANGED
@@ -6,17 +6,19 @@
6
  */
7
  namespace WebSharks\CometCache;
8
 
 
 
9
  if (!defined('WPINC')) {
10
  exit('Do NOT access this file directly: '.basename(__FILE__));
11
  }
12
- require_once dirname(__FILE__).'/stub.php';
13
 
14
- if (!Conflicts::check()) {
15
- $GLOBALS[GLOBAL_NS] = new Plugin();
16
- $GLOBALS['zencache'] = $GLOBALS[GLOBAL_NS]; // Back compat.
17
  $GLOBALS['quick_cache'] = $GLOBALS[GLOBAL_NS]; // Back compat.
18
 
19
- add_action('plugins_loaded', function() {
20
- require_once dirname(__FILE__).'/api.php';
21
  });
22
  }
6
  */
7
  namespace WebSharks\CometCache;
8
 
9
+ use WebSharks\CometCache\Classes;
10
+
11
  if (!defined('WPINC')) {
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
14
+ require_once __DIR__.'/stub.php';
15
 
16
+ if (!Classes\Conflicts::check()) {
17
+ $GLOBALS[GLOBAL_NS] = new Classes\Plugin();
18
+ $GLOBALS['zencache'] = $GLOBALS[GLOBAL_NS]; // Back compat.
19
  $GLOBALS['quick_cache'] = $GLOBALS[GLOBAL_NS]; // Back compat.
20
 
21
+ add_action('plugins_loaded', function () {
22
+ require_once __DIR__.'/api.php';
23
  });
24
  }
src/includes/stub.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * Stub.
4
  *
@@ -9,11 +10,11 @@ namespace WebSharks\CometCache;
9
  if (!defined('WPINC')) {
10
  exit('Do NOT access this file directly: '.basename(__FILE__));
11
  }
12
- require_once dirname(dirname(__FILE__)).'/vendor/autoload.php';
13
- require_once dirname(__FILE__).'/functions/i18n-utils.php';
14
 
15
- ${__FILE__}['version'] = '160227'; //version//
16
- ${__FILE__}['plugin'] = dirname(dirname(dirname(__FILE__)));
17
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
18
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
19
  ${__FILE__}['is_pro'] = strtolower(basename(${__FILE__}['ns_path'])) === 'pro';
@@ -27,9 +28,24 @@ define(__NAMESPACE__.'\\VERSION', ${__FILE__}['version']);
27
  define(__NAMESPACE__.'\\PLUGIN_FILE', ${__FILE__}['plugin']);
28
  define(__NAMESPACE__.'\\IS_PRO', ${__FILE__}['is_pro']);
29
 
 
 
 
 
 
 
 
 
 
 
30
  unset(${__FILE__}); // Housekeeping.
31
 
32
  // Fixes PHP Fatal error with upgrades from v160211
33
- class_alias(__NAMESPACE__.'\\AdvCacheBackCompat', 'WebSharks\\Comet_Cache\\AdvCacheBackCompat');
34
- class_alias(__NAMESPACE__.'\\AdvancedCache', 'WebSharks\\Comet_Cache\\AdvancedCache');
 
 
 
 
 
35
 
1
  <?php
2
+ // @codingStandardsIgnoreFile
3
  /**
4
  * Stub.
5
  *
10
  if (!defined('WPINC')) {
11
  exit('Do NOT access this file directly: '.basename(__FILE__));
12
  }
13
+ require_once dirname(__DIR__).'/vendor/autoload.php';
14
+ require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
+ ${__FILE__}['version'] = '160416'; //version//
17
+ ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
20
  ${__FILE__}['is_pro'] = strtolower(basename(${__FILE__}['ns_path'])) === 'pro';
28
  define(__NAMESPACE__.'\\PLUGIN_FILE', ${__FILE__}['plugin']);
29
  define(__NAMESPACE__.'\\IS_PRO', ${__FILE__}['is_pro']);
30
 
31
+ foreach (['Classes', 'Traits\\Shared', 'Traits\\Ac', 'Traits\\Plugin', 'Interfaces\\Shared'] as ${__FILE__}['_sub_namespace']) {
32
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\SHORT_NAME', SHORT_NAME);
33
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\NAME', NAME);
34
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\DOMAIN', DOMAIN);
35
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\GLOBAL_NS', GLOBAL_NS);
36
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\SLUG_TD', 'comet-cache');
37
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\VERSION', VERSION);
38
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\PLUGIN_FILE', PLUGIN_FILE);
39
+ define(__NAMESPACE__.'\\'.${__FILE__}['_sub_namespace'].'\\IS_PRO', IS_PRO);
40
+ }
41
  unset(${__FILE__}); // Housekeeping.
42
 
43
  // Fixes PHP Fatal error with upgrades from v160211
44
+ class_alias(__NAMESPACE__.'\\Classes\\AdvCacheBackCompat', 'WebSharks\\Comet_Cache\\AdvCacheBackCompat');
45
+ class_alias(__NAMESPACE__.'\\Classes\\AdvancedCache', 'WebSharks\\Comet_Cache\\AdvancedCache');
46
+
47
+
48
+ // Fixes PHP Fatal error with upgrades from v160227
49
+ class_alias(__NAMESPACE__.'\\Classes\\AdvCacheBackCompat', 'WebSharks\\CometCache\\AdvCacheBackCompat');
50
+ class_alias(__NAMESPACE__.'\\Classes\\AdvancedCache', 'WebSharks\\CometCache\\AdvancedCache');
51
 
src/includes/templates/advanced-cache.txt CHANGED
@@ -6,6 +6,8 @@
6
  */
7
  namespace WebSharks\CometCache;
8
 
 
 
9
  if (!defined('WPINC')) {
10
  exit('Do NOT access this file directly: '.basename(__FILE__));
11
  }
@@ -33,8 +35,8 @@ if (defined('WP_DEBUG') && WP_DEBUG) {
33
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
34
  return; // Unable to find postload function(s). Fail softly.
35
  }
36
- AdvCacheBackCompat::zenCacheConstants();
37
- AdvCacheBackCompat::zcRequestVars();
38
 
39
  if (!defined('COMET_CACHE_PRO')) {
40
  /**
@@ -218,9 +220,13 @@ if (!defined('COMET_CACHE_404_CACHE_FILENAME')) {
218
 
219
 
220
 
221
- $GLOBALS[GLOBAL_NS.'_advanced_cache'] = new AdvancedCache();
222
  $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
223
  if (!isset($GLOBALS['zencache__advanced_cache'])) {
224
  $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
225
  $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
226
  }
 
 
 
 
6
  */
7
  namespace WebSharks\CometCache;
8
 
9
+ use WebSharks\CometCache\Classes;
10
+
11
  if (!defined('WPINC')) {
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
35
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
36
  return; // Unable to find postload function(s). Fail softly.
37
  }
38
+ Classes\AdvCacheBackCompat::zenCacheConstants();
39
+ Classes\AdvCacheBackCompat::zcRequestVars();
40
 
41
  if (!defined('COMET_CACHE_PRO')) {
42
  /**
220
 
221
 
222
 
223
+ $GLOBALS[GLOBAL_NS.'_advanced_cache'] = new Classes\AdvancedCache();
224
  $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
225
  if (!isset($GLOBALS['zencache__advanced_cache'])) {
226
  $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
227
  $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
228
  }
229
+ if (!isset($GLOBALS['quick_cache__advanced_cache'])) {
230
+ $GLOBALS['quick_cache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
231
+ $GLOBALS['quick_cache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
232
+ }
src/includes/traits/Ac/AbortUtils.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait AbortUtils
7
+ {
8
+ /**
9
+ * Ignores user aborts; when/if the Auto-Cache Engine is running.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ */
13
+ public function maybeIgnoreUserAbort()
14
+ {
15
+
16
+ }
17
+ }
src/includes/traits/Ac/AcPluginUtils.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait AcPluginUtils
7
+ {
8
+ /**
9
+ * Loads any advanced cache plugin files found inside `/wp-content/ac-plugins`.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ */
13
+ public function loadAcPlugins()
14
+ {
15
+ if (!is_dir(WP_CONTENT_DIR.'/ac-plugins')) {
16
+ return; // Nothing to do here.
17
+ }
18
+ $GLOBALS[GLOBAL_NS.'_advanced_cache'] = $this; // Self reference.
19
+ $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
20
+ if (!isset($GLOBALS['zencache__advanced_cache'])) {
21
+ $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
22
+ $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
23
+ }
24
+ foreach ((array) glob(WP_CONTENT_DIR.'/ac-plugins/*.php') as $_ac_plugin) {
25
+ if (is_file($_ac_plugin)) {
26
+ include_once $_ac_plugin;
27
+ }
28
+ }
29
+ unset($_ac_plugin); // Houskeeping.
30
+ }
31
+ }
src/includes/traits/Ac/BrowserUtils.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait BrowserUtils
7
+ {
8
+ /**
9
+ * Sends no-cache headers (if applicable).
10
+ *
11
+ * @since 150422 Rewrite. Enhanced/altered 151220.
12
+ */
13
+ public function maybeStopBrowserCaching()
14
+ {
15
+ switch ((bool) COMET_CACHE_ALLOW_BROWSER_CACHE) {
16
+
17
+ case true: // If global config allows, check exclusions.
18
+
19
+ if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
20
+ if (!filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
21
+ return $this->sendNoCacheHeaders(); // Disallow.
22
+ } // Else, allow client-side caching; because `ABC` is a true-ish value.
23
+ // ↑ Note that exclusion patterns are ignored in this case, in favor of `ABC`.
24
+ } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI'])) {
25
+ return $this->sendNoCacheHeaders(); // Disallow.
26
+ }
27
+ return; // Allow browser caching; default behavior in this mode.
28
+
29
+ case false: // Global config disallows; check inclusions.
30
+
31
+ if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
32
+ if (filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
33
+ return; // Allow, because `ABC` is a false-ish value.
34
+ } // Else, disallow client-side caching; because `ABC` is a true-ish value.
35
+ // ↑ Note that inclusion patterns are ignored in this case, in favor of `ABC`.
36
+ }
37
+ return $this->sendNoCacheHeaders(); // Disallow; default behavior in this mode.
38
+ }
39
+ }
40
+ }
src/includes/traits/Ac/NcDebugUtils.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait NcDebugUtils
7
+ {
8
+ /**
9
+ * An array of debug info.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @type array An array of debug info; i.e. `reason_code` and `reason` (optional).
14
+ */
15
+ public $debug_info = ['reason_code' => '', 'reason' => ''];
16
+
17
+ /**
18
+ * Used to setup debug info (if enabled).
19
+ *
20
+ * @since 150422 Rewrite.
21
+ *
22
+ * @param string $reason_code One of the `NC_DEBUG_` constants.
23
+ * @param string $reason Optionally override the built-in description with a custom message.
24
+ */
25
+ public function maybeSetDebugInfo($reason_code, $reason = '')
26
+ {
27
+ if (!COMET_CACHE_DEBUGGING_ENABLE) {
28
+ return; // Nothing to do.
29
+ }
30
+ $reason = (string) $reason;
31
+ if (!($reason_code = (string) $reason_code)) {
32
+ return; // Not applicable.
33
+ }
34
+ $this->debug_info = ['reason_code' => $reason_code, 'reason' => $reason];
35
+ }
36
+
37
+ /**
38
+ * Echoes `NC_DEBUG_` info in the WordPress `shutdown` phase (if applicable).
39
+ *
40
+ * @since 150422 Rewrite.
41
+ *
42
+ * @attaches-to `shutdown` hook in WordPress w/ a late priority.
43
+ */
44
+ public function maybeEchoNcDebugInfo()
45
+ {
46
+ if (!COMET_CACHE_DEBUGGING_ENABLE) {
47
+ return; // Nothing to do.
48
+ }
49
+ if (is_admin()) {
50
+ return; // Not applicable.
51
+ }
52
+ if (strcasecmp(PHP_SAPI, 'cli') === 0) {
53
+ return; // Let's not run the risk here.
54
+ }
55
+ if ($this->debug_info && $this->hasACacheableContentType() && $this->is_a_wp_content_type) {
56
+ echo (string) $this->maybeGetNcDebugInfo($this->debug_info['reason_code'], $this->debug_info['reason']);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Gets `NC_DEBUG_` info (if applicable).
62
+ *
63
+ * @since 150422 Rewrite.
64
+ *
65
+ * @param string $reason_code One of the `NC_DEBUG_` constants.
66
+ * @param string $reason Optional; to override the default description with a custom message.
67
+ *
68
+ * @return string The debug info; i.e. full description (if applicable).
69
+ */
70
+ public function maybeGetNcDebugInfo($reason_code = '', $reason = '')
71
+ {
72
+ if (!COMET_CACHE_DEBUGGING_ENABLE) {
73
+ return ''; // Not applicable.
74
+ }
75
+ $reason = (string) $reason;
76
+ if (!($reason_code = (string) $reason_code)) {
77
+ return ''; // Not applicable.
78
+ }
79
+ if (!$reason) {
80
+ switch ($reason_code) {
81
+ case $this::NC_DEBUG_PHP_SAPI_CLI:
82
+ $reason = __('because `PHP_SAPI` reports that you are currently running from the command line.', 'comet-cache');
83
+ break; // Break switch handler.
84
+
85
+ case $this::NC_DEBUG_NO_SERVER_HTTP_HOST:
86
+ $reason = __('because `$_SERVER[\'HTTP_HOST\']` is missing from your server configuration.', 'comet-cache');
87
+ break; // Break switch handler.
88
+
89
+ case $this::NC_DEBUG_NO_SERVER_REQUEST_URI:
90
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` is missing from your server configuration.', 'comet-cache');
91
+ break; // Break switch handler.
92
+
93
+ case $this::NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT:
94
+ if ($this->functionIsPossible('did_action') && did_action('ws_plugin__s2member_during_no_cache_constants')) {
95
+ $reason = __('because the s2Member plugin set the PHP constant `COMET_CACHE_ALLOWED` to a boolean-ish `FALSE` value at runtime. The s2Member plugin is serving content that must remain dynamic on this particular page, and therefore this page was intentionally not cached for a very good reason.', 'comet-cache');
96
+ } else {
97
+ $reason = __('because the PHP constant `COMET_CACHE_ALLOWED` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
98
+ }
99
+ break; // Break switch handler.
100
+
101
+ case $this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR:
102
+ $reason = __('because the environment variable `$_SERVER[\'COMET_CACHE_ALLOWED\']` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
103
+ break; // Break switch handler.
104
+
105
+ case $this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT:
106
+ $reason = __('because the PHP constant `DONOTCACHEPAGE` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
107
+ break; // Break switch handler.
108
+
109
+ case $this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR:
110
+ $reason = __('because the environment variable `$_SERVER[\'DONOTCACHEPAGE\']` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it\'s usually for a very good reason.', 'comet-cache');
111
+ break; // Break switch handler.
112
+
113
+ case $this::NC_DEBUG_AC_GET_VAR:
114
+ $reason = sprintf(__('because `$_GET[\'%1$sAC\']` is set to a boolean-ish FALSE value.', 'comet-cache'), strtolower(SHORT_NAME));
115
+ break; // Break switch handler.
116
+
117
+ case $this::NC_DEBUG_UNCACHEABLE_REQUEST:
118
+ $reason = __('because `$_SERVER[\'REQUEST_METHOD\']` is `POST`, `PUT`, `DELETE`, `HEAD`, `OPTIONS`, `TRACE` or `CONNECT`. These request methods should never (ever) be cached in any way.', 'comet-cache');
119
+ break; // Break switch handler.
120
+
121
+ case $this::NC_DEBUG_SELF_SERVE_REQUEST:
122
+ $reason = __('because `[current IP address]` === `$_SERVER[\'SERVER_ADDR\']`; i.e. a self-serve request. DEVELOPER TIP: if you are testing on a localhost installation, please add `define(\'LOCALHOST\', TRUE);` to your `/wp-config.php` file while you run tests :-) Remove it (or set it to a `FALSE` value) once you go live on the web.', 'comet-cache');
123
+ break; // Break switch handler.
124
+
125
+ case $this::NC_DEBUG_FEED_REQUEST:
126
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a `/feed`; and the configuration of this site says not to cache XML-based feeds.', 'comet-cache');
127
+ break; // Break switch handler.
128
+
129
+ case $this::NC_DEBUG_WP_SYSTEMATICS:
130
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a `wp-` or `xmlrpc` file; i.e. a WordPress systematic file. WordPress systematics are never (ever) cached in any way.', 'comet-cache');
131
+ break; // Break switch handler.
132
+
133
+ case $this::NC_DEBUG_WP_ADMIN:
134
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` or the `is_admin()` function indicates this is an administrative area of the site.', 'comet-cache');
135
+ break; // Break switch handler.
136
+
137
+ case $this::NC_DEBUG_MS_FILES:
138
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` indicates this is a Multisite Network; and this was a request for `/files/*`, not a page.', 'comet-cache');
139
+ break; // Break switch handler.
140
+
141
+ case $this::NC_DEBUG_IS_LOGGED_IN_USER:
142
+ case $this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER:
143
+ $reason = __('because the current user visiting this page (usually YOU), appears to be logged-in. The current configuration says NOT to cache pages for logged-in visitors. This message may also appear if you have an active PHP session on this site, or if you\'ve left (or replied to) a comment recently. If this message continues, please clear your cookies and try again.', 'comet-cache');
144
+ break; // Break switch handler.
145
+
146
+ case $this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE:
147
+ $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. While your current configuration states that pages SHOULD be cache for logged-in visitors, `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
148
+ break; // Break switch handler.
149
+
150
+ case $this::NC_DEBUG_PAGE_CONTAINS_NONCE:
151
+ $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. Note that `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
152
+ break; // Break switch handler.
153
+
154
+ case $this::NC_DEBUG_NO_USER_TOKEN:
155
+ $reason = sprintf(__('because the current user appeared to be logged into the site (in one way or another); but %1$s was unable to formulate a User Token for them. Please report this as a possible bug.', 'comet-cache'), NAME);
156
+ break; // Break switch handler.
157
+
158
+ case $this::NC_DEBUG_GET_REQUEST_QUERIES:
159
+ $reason = __('because `$_GET` contains query string data. The current configuration says NOT to cache GET requests with a query string.', 'comet-cache');
160
+ break; // Break switch handler.
161
+
162
+ case $this::NC_DEBUG_PREVIEW:
163
+ $reason = __('because `$_REQUEST` indicates this is simply a preview of something to come.', 'comet-cache');
164
+ break; // Break switch handler.
165
+
166
+ case $this::NC_DEBUG_EXCLUDED_URIS:
167
+ $reason = __('because `$_SERVER[\'REQUEST_URI\']` matches a configured URI Exclusion Pattern on this installation.', 'comet-cache');
168
+ break; // Break switch handler.
169
+
170
+ case $this::NC_DEBUG_EXCLUDED_AGENTS:
171
+ $reason = __('because `$_SERVER[\'HTTP_USER_AGENT\']` matches a configured User-Agent Exclusion Pattern on this installation.', 'comet-cache');
172
+ break; // Break switch handler.
173
+
174
+ case $this::NC_DEBUG_EXCLUDED_REFS:
175
+ $reason = __('because `$_SERVER[\'HTTP_REFERER\']` and/or `$_GET[\'_wp_http_referer\']` matches a configured HTTP Referrer Exclusion Pattern on this installation.', 'comet-cache');
176
+ break; // Break switch handler.
177
+
178
+ case $this::NC_DEBUG_404_REQUEST:
179
+ $reason = __('because the WordPress `is_404()` Conditional Tag says the current page is a 404 error. The current configuration says NOT to cache 404 errors.', 'comet-cache');
180
+ break; // Break switch handler.
181
+
182
+ case $this::NC_DEBUG_MAINTENANCE_PLUGIN:
183
+ $reason = __('because a plugin running on this installation says this page is in Maintenance Mode; i.e. is not available publicly at this time.', 'comet-cache');
184
+ break; // Break switch handler.
185
+
186
+ case $this::NC_DEBUG_OB_ZLIB_CODING_TYPE:
187
+ $reason = sprintf(__('because %1$s is unable to cache already-compressed output. Please use `mod_deflate` w/ Apache; or use `zlib.output_compression` in your `php.ini` file. %1$s is NOT compatible with `ob_gzhandler()` and others like this.', 'comet-cache'), NAME);
188
+ break; // Break switch handler.
189
+
190
+ case $this::NC_DEBUG_WP_ERROR_PAGE:
191
+ $reason = __('because the contents of this document contain `<body id="error-page">`, which indicates this is an auto-generated WordPress error message.', 'comet-cache');
192
+ break; // Break switch handler.
193
+
194
+ case $this::NC_DEBUG_UNCACHEABLE_CONTENT_TYPE:
195
+ $reason = __('because a `Content-Type:` header was set via PHP at runtime. The header contains a MIME type which is NOT a variation of HTML or XML. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins.', 'comet-cache');
196
+ break; // Break switch handler.
197
+
198
+ case $this::NC_DEBUG_UNCACHEABLE_STATUS:
199
+ $reason = __('because a `Status:` header (or an `HTTP/` header) was set via PHP at runtime. The header contains a non-`2xx` status code. This indicates the current page was not loaded successfully. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins.', 'comet-cache');
200
+ break; // Break switch handler.
201
+
202
+ case $this::NC_DEBUG_1ST_TIME_404_SYMLINK:
203
+ $reason = sprintf(__('because the WordPress `is_404()` Conditional Tag says the current page is a 404 error; and this is the first time it\'s happened on this page. Your current configuration says that 404 errors SHOULD be cached, so %1$s built a cached symlink which points future requests for this location to your already-cached 404 error document. If you reload this page (assuming you don\'t clear the cache before you do so); you should get a cached version of your 404 error document. This message occurs ONCE for each new/unique 404 error request.', 'comet-cache'), NAME);
204
+ break; // Break switch handler.
205
+
206
+ case $this::NC_DEBUG_EARLY_BUFFER_TERMINATION:
207
+ $reason = sprintf(__('because %1$s detected an early output buffer termination. This may happen when a theme/plugin ends, cleans, or flushes all output buffers before reaching the PHP shutdown phase. It\'s not always a bad thing. Sometimes it is necessary for a theme/plugin to do this. However, in this scenario it is NOT possible to cache the output; since %1$s is effectively disabled at runtime when this occurs.', 'comet-cache'), NAME);
208
+ break; // Break switch handler.
209
+
210
+ default: // Default case handler.
211
+ $reason = __('due to an unexpected behavior in the application. Please report this as a bug!', 'comet-cache');
212
+ break; // Break switch handler.
213
+ }
214
+ }
215
+ return "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s is NOT caching this page, %2$s', 'comet-cache'), NAME, $reason)).' -->';
216
+ }
217
+ }
src/includes/traits/Ac/ObUtils.php ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ObUtils
7
+ {
8
+ /**
9
+ * Calculated protocol; one of `http://` or `https://`.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @type float One of `http://` or `https://`.
14
+ */
15
+ public $protocol = '';
16
+
17
+ /**
18
+ * Host token for this request.
19
+ *
20
+ * @since 150821 Improving multisite compat.
21
+ *
22
+ * @type string Host token for this request.
23
+ */
24
+ public $host_token = '';
25
+
26
+ /**
27
+ * Host base/dir tokens for this request.
28
+ *
29
+ * @since 150821 Improving multisite compat.
30
+ *
31
+ * @type string Host base/dir tokens for this request.
32
+ */
33
+ public $host_base_dir_tokens = '';
34
+
35
+ /**
36
+ * Calculated version salt; set by site configuration data.
37
+ *
38
+ * @since 150422 Rewrite.
39
+ *
40
+ * @type string|mixed Any scalar value does fine.
41
+ */
42
+ public $version_salt = '';
43
+
44
+ /**
45
+ * Relative cache path for the current request.
46
+ *
47
+ * @since 150422 Rewrite.
48
+ *
49
+ * @type string Cache path for the current request.
50
+ */
51
+ public $cache_path = '';
52
+
53
+ /**
54
+ * Absolute cache file path for the current request.
55
+ *
56
+ * @since 150422 Rewrite.
57
+ *
58
+ * @type string Absolute cache file path for the current request.
59
+ */
60
+ public $cache_file = '';
61
+
62
+ /**
63
+ * Relative 404 cache path for the current request.
64
+ *
65
+ * @since 150422 Rewrite.
66
+ *
67
+ * @type string 404 cache path for the current request.
68
+ */
69
+ public $cache_path_404 = '';
70
+
71
+ /**
72
+ * Absolute 404 cache file path for the current request.
73
+ *
74
+ * @since 150422 Rewrite.
75
+ *
76
+ * @type string Absolute 404 cache file path for the current request.
77
+ */
78
+ public $cache_file_404 = '';
79
+
80
+ /**
81
+ * Version salt followed by the current request location.
82
+ *
83
+ * @since 150422 Rewrite.
84
+ *
85
+ * @type string Version salt followed by the current request location.
86
+ */
87
+ public $salt_location = '';
88
+
89
+ /**
90
+ * Calculated max age; i.e., before expiration.
91
+ *
92
+ * @since 151002 Load average checks in pro version.
93
+ *
94
+ * @type int Calculated max age; i.e., before expiration.
95
+ */
96
+ public $cache_max_age = 0;
97
+
98
+ /**
99
+ * Start output buffering (if applicable); or serve a cache file (if possible).
100
+ *
101
+ * @since 150422 Rewrite.
102
+ *
103
+ * @note This is a vital part of Comet Cache. This method serves existing (fresh) cache files.
104
+ * It is also responsible for beginning the process of collecting the output buffer.
105
+ */
106
+ public function maybeStartOutputBuffering()
107
+ {
108
+ if (strcasecmp(PHP_SAPI, 'cli') === 0) {
109
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_PHP_SAPI_CLI);
110
+ }
111
+ if (empty($_SERVER['HTTP_HOST']) || !$this->hostToken()) {
112
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_NO_SERVER_HTTP_HOST);
113
+ }
114
+ if (empty($_SERVER['REQUEST_URI'])) {
115
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_NO_SERVER_REQUEST_URI);
116
+ }
117
+ if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
118
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
119
+ }
120
+ if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
121
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
122
+ }
123
+ if (defined('DONOTCACHEPAGE')) {
124
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
125
+ }
126
+ if (isset($_SERVER['DONOTCACHEPAGE'])) {
127
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
128
+ }
129
+ if (isset($_GET[strtolower(SHORT_NAME).'AC']) && !filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN)) {
130
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_AC_GET_VAR);
131
+ }
132
+ if ($this->isUncacheableRequestMethod()) {
133
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_REQUEST);
134
+ }
135
+ if (isset($_SERVER['SERVER_ADDR']) && $this->currentIp() === $_SERVER['SERVER_ADDR']) {
136
+ if ((!IS_PRO || !$this->isAutoCacheEngine()) && !$this->isLocalhost()) {
137
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_SELF_SERVE_REQUEST);
138
+ }
139
+ }
140
+ if (!COMET_CACHE_FEEDS_ENABLE && $this->isFeed()) {
141
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_FEED_REQUEST);
142
+ }
143
+ if (preg_match('/\/(?:wp\-[^\/]+|xmlrpc)\.php(?:[?]|$)/i', $_SERVER['REQUEST_URI'])) {
144
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_SYSTEMATICS);
145
+ }
146
+ if (is_admin() || preg_match('/\/wp-admin(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
147
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ADMIN);
148
+ }
149
+ if (is_multisite() && preg_match('/\/files(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
150
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_MS_FILES);
151
+ }
152
+ if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
153
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
154
+ }
155
+ if (!COMET_CACHE_GET_REQUESTS && $this->requestContainsUncacheableQueryVars()) {
156
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_GET_REQUEST_QUERIES);
157
+ }
158
+ if (!empty($_REQUEST['preview'])) {
159
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_PREVIEW);
160
+ }
161
+ if (COMET_CACHE_EXCLUDE_URIS && preg_match(COMET_CACHE_EXCLUDE_URIS, $_SERVER['REQUEST_URI'])) {
162
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_URIS);
163
+ }
164
+ if (COMET_CACHE_EXCLUDE_AGENTS && !empty($_SERVER['HTTP_USER_AGENT']) && (!IS_PRO || !$this->isAutoCacheEngine())) {
165
+ if (preg_match(COMET_CACHE_EXCLUDE_AGENTS, $_SERVER['HTTP_USER_AGENT'])) {
166
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_AGENTS);
167
+ }
168
+ }
169
+ if (COMET_CACHE_EXCLUDE_REFS && !empty($_REQUEST['_wp_http_referer'])) {
170
+ if (preg_match(COMET_CACHE_EXCLUDE_REFS, stripslashes($_REQUEST['_wp_http_referer']))) {
171
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
172
+ }
173
+ }
174
+ if (COMET_CACHE_EXCLUDE_REFS && !empty($_SERVER['HTTP_REFERER'])) {
175
+ if (preg_match(COMET_CACHE_EXCLUDE_REFS, $_SERVER['HTTP_REFERER'])) {
176
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
177
+ }
178
+ }
179
+ $this->protocol = $this->isSsl() ? 'https://' : 'http://';
180
+ $this->host_token = $this->hostToken();
181
+ $this->host_base_dir_tokens = $this->hostBaseDirTokens();
182
+
183
+ $this->version_salt = ''; // Initialize the version salt.
184
+
185
+ $this->version_salt = $this->applyFilters(get_class($this).'__version_salt', $this->version_salt);
186
+ $this->version_salt = $this->applyFilters(GLOBAL_NS.'_version_salt', $this->version_salt);
187
+
188
+ $this->cache_path = $this->buildCachePath($this->protocol.$this->host_token.$_SERVER['REQUEST_URI'], '', $this->version_salt);
189
+ $this->cache_file = COMET_CACHE_DIR.'/'.$this->cache_path; // Not considering a user cache. That's done in the postload phase.
190
+
191
+ $this->cache_path_404 = $this->buildCachePath($this->protocol.$this->host_token.rtrim($this->host_base_dir_tokens, '/').'/'.COMET_CACHE_404_CACHE_FILENAME);
192
+ $this->cache_file_404 = COMET_CACHE_DIR.'/'.$this->cache_path_404; // Not considering a user cache at all here--ever.
193
+
194
+ $this->salt_location = ltrim($this->version_salt.' '.$this->protocol.$this->host_token.$_SERVER['REQUEST_URI']);
195
+
196
+ $this->cache_max_age = strtotime('-'.COMET_CACHE_MAX_AGE);
197
+
198
+ if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN === 'postload' && $this->isLikeUserLoggedIn()) {
199
+ $this->postload['when_logged_in'] = true; // Enable postload check.
200
+ } elseif (is_file($this->cache_file) && (!$this->cache_max_age || filemtime($this->cache_file) >= $this->cache_max_age)) {
201
+ list($headers, $cache) = explode('<!--headers-->', file_get_contents($this->cache_file), 2);
202
+
203
+ $headers_list = $this->headersList();
204
+ foreach (unserialize($headers) as $_header) {
205
+ if (!in_array($_header, $headers_list, true) && stripos($_header, 'Last-Modified:') !== 0) {
206
+ header($_header); // Only cacheable/safe headers are stored in the cache.
207
+ }
208
+ }
209
+ unset($_header); // Just a little housekeeping.
210
+
211
+ if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
212
+ $total_time = number_format(microtime(true) - $this->timer, 5, '.', '');
213
+ $cache .= "\n".'<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->';
214
+ // translators: This string is actually NOT translatable because the `__()` function is not available at this point in the processing.
215
+ $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s fully functional :-) Cache file served for (%2$s) in %3$s seconds, on: %4$s.', 'comet-cache'), NAME, $this->salt_location, $total_time, date('M jS, Y @ g:i a T'))).' -->';
216
+ }
217
+ exit($cache); // Exit with cache contents.
218
+ } else {
219
+ ob_start([$this, 'outputBufferCallbackHandler']);
220
+ }
221
+ return; // Return value not applicable.
222
+ }
223
+
224
+ /**
225
+ * Output buffer handler; i.e. the cache file generator.
226
+ *
227
+ * @note We CANNOT depend on any WP functionality here; it will cause problems.
228
+ * Anything we need from WP should be saved in the postload phase as a scalar value.
229
+ *
230
+ * @since 150422 Rewrite.
231
+ *
232
+ * @param string $buffer The buffer from {@link \ob_start()}.
233
+ * @param int $phase A set of bitmask flags.
234
+ *
235
+ * @throws \Exception If unable to handle output buffering for any reason.
236
+ *
237
+ * @return string|bool The output buffer, or `FALSE` to indicate no change.
238
+ *
239
+ * @attaches-to {@link \ob_start()}
240
+ */
241
+ public function outputBufferCallbackHandler($buffer, $phase)
242
+ {
243
+ if (!($phase & PHP_OUTPUT_HANDLER_END)) {
244
+ throw new \Exception(sprintf(__('Unexpected OB phase: `%1$s`.', 'comet-cache'), $phase));
245
+ }
246
+ Classes\AdvCacheBackCompat::zenCacheConstants();
247
+
248
+ $cache = trim((string) $buffer);
249
+
250
+ if (!isset($cache[0])) {
251
+ return false; // Don't cache an empty buffer.
252
+ }
253
+ if (!isset($GLOBALS[GLOBAL_NS.'_shutdown_flag'])) {
254
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_EARLY_BUFFER_TERMINATION);
255
+ }
256
+ if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
257
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
258
+ }
259
+ if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
260
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
261
+ }
262
+ if (defined('DONOTCACHEPAGE')) {
263
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
264
+ }
265
+ if (isset($_SERVER['DONOTCACHEPAGE'])) {
266
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
267
+ }
268
+ if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->is_user_logged_in) {
269
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER);
270
+ }
271
+ if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
272
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
273
+ }
274
+ if (!COMET_CACHE_CACHE_NONCE_VALUES && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/', $cache)) {
275
+ if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->isLikeUserLoggedIn()) {
276
+ if (!COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN) {
277
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE);
278
+ }
279
+ } else { // Use the default debug notice for nonce conflicts.
280
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_PAGE_CONTAINS_NONCE);
281
+ } // An nonce makes the page dynamic; i.e., NOT cache compatible.
282
+ }
283
+ if ($this->is_404 && !COMET_CACHE_CACHE_404_REQUESTS) {
284
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_404_REQUEST);
285
+ }
286
+ if (stripos($cache, '<body id="error-page">') !== false) {
287
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ERROR_PAGE);
288
+ }
289
+ if (!$this->hasACacheableContentType()) {
290
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_CONTENT_TYPE);
291
+ }
292
+ if (!$this->hasACacheableStatus()) {
293
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_STATUS);
294
+ }
295
+ if ($this->is_maintenance) {
296
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_MAINTENANCE_PLUGIN);
297
+ }
298
+ if ($this->functionIsPossible('zlib_get_coding_type') && zlib_get_coding_type()
299
+ && (!($zlib_oc = ini_get('zlib.output_compression')) || !filter_var($zlib_oc, FILTER_VALIDATE_BOOLEAN))
300
+ ) {
301
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_OB_ZLIB_CODING_TYPE);
302
+ }
303
+ # Lock the cache directory while writes take place here.
304
+
305
+ $cache_lock = $this->cacheLock(); // Lock cache directory.
306
+
307
+ # Construct a temp file for atomic cache writes.
308
+
309
+ $cache_file_tmp = $this->addTmpSuffix($this->cache_file);
310
+
311
+ # Cache directory checks. The cache file directory is created here if necessary.
312
+
313
+ if (!is_dir(COMET_CACHE_DIR) && mkdir(COMET_CACHE_DIR, 0775, true) && !is_file(COMET_CACHE_DIR.'/.htaccess')) {
314
+ file_put_contents(COMET_CACHE_DIR.'/.htaccess', $this->htaccess_deny);
315
+ }
316
+ if (!is_dir($cache_file_dir = dirname($this->cache_file))) {
317
+ $cache_file_dir_writable = mkdir($cache_file_dir, 0775, true);
318
+ }
319
+ if (empty($cache_file_dir_writable) && !is_writable($cache_file_dir)) {
320
+ throw new \Exception(sprintf(__('Cache directory not writable. %1$s needs this directory please: `%2$s`. Set permissions to `755` or higher; `777` might be needed in some cases.', 'comet-cache'), NAME, $cache_file_dir));
321
+ }
322
+ # This is where a new 404 request might be detected for the first time.
323
+
324
+ if ($this->is_404 && is_file($this->cache_file_404)) {
325
+ if (!(symlink($this->cache_file_404, $cache_file_tmp) && rename($cache_file_tmp, $this->cache_file))) {
326
+ throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $this->cache_file, $this->cache_file_404, COMET_CACHE_DIR));
327
+ }
328
+ $this->cacheUnlock($cache_lock); // Release.
329
+ return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_1ST_TIME_404_SYMLINK);
330
+ }
331
+ /* ------- Otherwise, we need to construct & store a new cache file. ----------------------------------------------- */
332
+
333
+
334
+
335
+ if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
336
+ $total_time = number_format(microtime(true) - $this->timer, 5, '.', ''); // Based on the original timer.
337
+ $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file path: %2$s', 'comet-cache'), NAME, str_replace(WP_CONTENT_DIR, '', $this->is_404 ? $this->cache_file_404 : $this->cache_file))).' -->';
338
+ $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file built for (%2$s%3$s) in %4$s seconds, on: %5$s.', 'comet-cache'), NAME, $this->is_404 ? '404 [error document]' : $this->salt_location, (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->user_token ? '; '.sprintf(__('user token: %1$s', 'comet-cache'), $this->user_token) : ''), $total_time, date('M jS, Y @ g:i a T'))).' -->';
339
+ $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('This %1$s file will auto-expire (and be rebuilt) on: %2$s (based on your configured expiration time).', 'comet-cache'), NAME, date('M jS, Y @ g:i a T', strtotime('+'.COMET_CACHE_MAX_AGE)))).' -->';
340
+ }
341
+ if ($this->is_404) {
342
+ if (file_put_contents($cache_file_tmp, serialize($this->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $this->cache_file_404)) {
343
+ if (!(symlink($this->cache_file_404, $cache_file_tmp) && rename($cache_file_tmp, $this->cache_file))) {
344
+ throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $this->cache_file, $this->cache_file_404, COMET_CACHE_DIR));
345
+ }
346
+ $this->cacheUnlock($cache_lock); // Release.
347
+ return $cache; // Return the newly built cache; with possible debug information also.
348
+ }
349
+ } elseif (file_put_contents($cache_file_tmp, serialize($this->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $this->cache_file)) {
350
+ $this->cacheUnlock($cache_lock); // Release.
351
+ return $cache; // Return the newly built cache; with possible debug information also.
352
+ }
353
+ @unlink($cache_file_tmp); // Clean this up (if it exists); and throw an exception with information for the site owner.
354
+ throw new \Exception(sprintf(__('%1$s: failed to write cache file for: `%2$s`; possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), NAME, $_SERVER['REQUEST_URI'], COMET_CACHE_DIR));
355
+ }
356
+ }
src/includes/traits/Ac/PostloadUtils.php ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait PostloadUtils
7
+ {
8
+ /**
9
+ * Have we caught the main WP loaded being loaded yet?
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @type bool `TRUE` if main query has been loaded; else `FALSE`.
14
+ *
15
+ * @see wpMainQueryPostload()
16
+ */
17
+ public $is_wp_loaded_query = false;
18
+
19
+ /**
20
+ * Is the current request a WordPress 404 error?
21
+ *
22
+ * @since 150422 Rewrite.
23
+ *
24
+ * @type bool `TRUE` if is a 404 error; else `FALSE`.
25
+ *
26
+ * @see wpMainQueryPostload()
27
+ */
28
+ public $is_404 = false;
29
+
30
+ /**
31
+ * Last HTTP status code passed through {@link \status_header}.
32
+ *
33
+ * @since 150422 Rewrite.
34
+ *
35
+ * @type int Last HTTP status code (if applicable).
36
+ *
37
+ * @see maybeFilterStatusHeaderPostload()
38
+ */
39
+ public $http_status = 0;
40
+
41
+ /**
42
+ * Is the current request a WordPress content type?
43
+ *
44
+ * @since 150422 Rewrite.
45
+ *
46
+ * @type bool `TRUE` if is a WP content type.
47
+ *
48
+ * @see wpMainQueryPostload()
49
+ */
50
+ public $is_a_wp_content_type = false;
51
+
52
+ /**
53
+ * Current WordPress {@link \content_url()}.
54
+ *
55
+ * @since 150422 Rewrite.
56
+ *
57
+ * @type string Current WordPress {@link \content_url()}.
58
+ *
59
+ * @see wpMainQueryPostload()
60
+ */
61
+ public $content_url = '';
62
+
63
+ /**
64
+ * Flag for {@link \is_user_loged_in()}.
65
+ *
66
+ * @since 150422 Rewrite.
67
+ *
68
+ * @type bool `TRUE` if {@link \is_user_loged_in()} else `FALSE`.
69
+ *
70
+ * @see wpMainQueryPostload()
71
+ */
72
+ public $is_user_logged_in = false;
73
+
74
+ /**
75
+ * Flag for {@link \is_maintenance()}.
76
+ *
77
+ * @since 150422 Rewrite.
78
+ *
79
+ * @type bool `TRUE` if {@link \is_maintenance()} else `FALSE`.
80
+ *
81
+ * @see wpMainQueryPostload()
82
+ */
83
+ public $is_maintenance = false;
84
+
85
+ /**
86
+ * Array of data targeted at the postload phase.
87
+ *
88
+ * @since 150422 Rewrite.
89
+ *
90
+ * @type array Data and/or flags that work with various postload handlers.
91
+ */
92
+ public $postload = [
93
+
94
+ 'filter_status_header' => true,
95
+ 'wp_main_query' => true,
96
+ 'set_debug_info' => COMET_CACHE_DEBUGGING_ENABLE,
97
+ ];
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+ /**
108
+ * Filters WP {@link \status_header()} (if applicable).
109
+ *
110
+ * @since 150422 Rewrite.
111
+ */
112
+ public function maybeFilterStatusHeaderPostload()
113
+ {
114
+ if (empty($this->postload['filter_status_header'])) {
115
+ return; // Nothing to do in this case.
116
+ }
117
+
118
+ add_filter(
119
+ 'status_header',
120
+ function ($status_header, $status_code) {
121
+ if ($status_code > 0) {
122
+ $this->http_status = (integer) $status_code;
123
+ }
124
+ return $status_header;
125
+ },
126
+ PHP_INT_MAX,
127
+ 2
128
+ );
129
+ }
130
+
131
+ /**
132
+ * Hooks `NC_DEBUG_` info into the WordPress `shutdown` phase (if applicable).
133
+ *
134
+ * @since 150422 Rewrite.
135
+ */
136
+ public function maybeSetDebugInfoPostload()
137
+ {
138
+ if (!COMET_CACHE_DEBUGGING_ENABLE) {
139
+ return; // Nothing to do.
140
+ }
141
+ if (empty($this->postload['set_debug_info'])) {
142
+ return; // Nothing to do in this case.
143
+ }
144
+ if (is_admin()) {
145
+ return; // Not applicable.
146
+ }
147
+ if (strcasecmp(PHP_SAPI, 'cli') === 0) {
148
+ return; // Let's not run the risk here.
149
+ }
150
+ add_action('shutdown', [$this, 'maybeEchoNcDebugInfo'], PHP_INT_MAX - 10);
151
+ }
152
+
153
+ /**
154
+ * Grab details from WP and the Comet Cache plugin itself,
155
+ * after the main query is loaded (if at all possible).
156
+ *
157
+ * This is where we have a chance to grab any values we need from WordPress; or from the CC plugin.
158
+ * It is EXTREMEMLY important that we NOT attempt to grab any object references here.
159
+ * Anything acquired in this phase should be stored as a scalar value.
160
+ * See {@link outputBufferCallbackHandler()} for further details.
161
+ *
162
+ * @since 150422 Rewrite.
163
+ *
164
+ * @attaches-to `wp` hook.
165
+ */
166
+ public function wpMainQueryPostload()
167
+ {
168
+ if (empty($this->postload['wp_main_query'])) {
169
+ return; // Nothing to do in this case.
170
+ }
171
+ if ($this->is_wp_loaded_query || is_admin()) {
172
+ return; // Nothing to do.
173
+ }
174
+ if (!is_main_query()) {
175
+ return; // Not main query.
176
+ }
177
+ $this->is_wp_loaded_query = true;
178
+ $this->is_404 = is_404();
179
+ $this->is_user_logged_in = is_user_logged_in();
180
+ $this->content_url = rtrim(content_url(), '/');
181
+ $this->is_maintenance = $this->functionIsPossible('is_maintenance') && is_maintenance();
182
+
183
+ add_action(
184
+ 'template_redirect',
185
+ function () {
186
+ $this->is_a_wp_content_type = $this->is_404 || $this->is_maintenance
187
+ || is_front_page() // See <https://core.trac.wordpress.org/ticket/21602#comment:7>
188
+ || is_home() || is_singular() || is_archive() || is_post_type_archive() || is_tax() || is_search() || is_feed();
189
+ },
190
+ 11
191
+ );
192
+ }
193
+ }
src/includes/traits/Ac/ShutdownUtils.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Ac;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ShutdownUtils
7
+ {
8
+ /**
9
+ * Registers a shutdown flag.
10
+ *
11
+ * @since 140605 Improving output buffer.
12
+ *
13
+ * @note In `/wp-settings.php`, Comet Cache is loaded before WP registers its own shutdown function.
14
+ * Therefore, this flag is set before {@link shutdown_action_hook()} fires, and thus before {@link wp_ob_end_flush_all()}.
15
+ *
16
+ * @see http://www.php.net/manual/en/function.register-shutdown-function.php
17
+ */
18
+ public function registerShutdownFlag()
19
+ {
20
+ register_shutdown_function(
21
+ function () {
22
+ $GLOBALS[GLOBAL_NS.'_shutdown_flag'] = -1;
23
+ }
24
+ );
25
+ }
26
+ }
src/includes/traits/Plugin/ActionUtils.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ActionUtils
7
+ {
8
+ /**
9
+ * Plugin action handler.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `wp_loaded` hook.
14
+ */
15
+ public function actions()
16
+ {
17
+ if (!empty($_REQUEST[GLOBAL_NS])) {
18
+ new Classes\Actions();
19
+ }
20
+
21
+ }
22
+ }
src/includes/traits/Plugin/BbPressUtils.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait BbPressUtils
7
+ {
8
+ /**
9
+ * Is bbPress active?
10
+ *
11
+ * @since 150821 Improving bbPress support.
12
+ *
13
+ * @return bool `TRUE` if bbPress is active.
14
+ */
15
+ public function isBbPressActive()
16
+ {
17
+ return class_exists('bbPress');
18
+ }
19
+
20
+ /**
21
+ * bbPress post types.
22
+ *
23
+ * @since 150821 Improving bbPress support.
24
+ *
25
+ * @return array All bbPress post types.
26
+ */
27
+ public function bbPressPostTypes()
28
+ {
29
+ if (!$this->isBbPressActive()) {
30
+ return [];
31
+ }
32
+ if (!is_null($types = &$this->cacheKey('bbPressPostTypes'))) {
33
+ return $types; // Already did this.
34
+ }
35
+ $types = []; // Initialize.
36
+ $types[] = bbp_get_forum_post_type();
37
+ $types[] = bbp_get_topic_post_type();
38
+ $types[] = bbp_get_reply_post_type();
39
+
40
+ return $types;
41
+ }
42
+
43
+ /**
44
+ * bbPress post statuses.
45
+ *
46
+ * @since 150821 Improving bbPress support.
47
+ *
48
+ * @return array All bbPress post statuses.
49
+ */
50
+ public function bbPressStatuses()
51
+ {
52
+ if (!$this->isBbPressActive()) {
53
+ return [];
54
+ }
55
+ if (!is_null($statuses = &$this->cacheKey('bbPressStatuses'))) {
56
+ return $statuses; // Already did this.
57
+ }
58
+ $statuses = []; // Initialize.
59
+
60
+ foreach (get_post_stati([], 'objects') as $_key => $_status) {
61
+ if (isset($_status->label_count['domain']) && $_status->label_count['domain'] === 'bbpress') {
62
+ $statuses[] = $_status->name;
63
+ }
64
+ }
65
+ unset($_key, $_status); // Housekeeping.
66
+
67
+ return $statuses;
68
+ }
69
+ }
src/includes/traits/Plugin/CleanupUtils.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CleanupUtils
7
+ {
8
+ /**
9
+ * Runs cleanup routine via CRON job.
10
+ *
11
+ * @since 151002 While working on directory stats.
12
+ *
13
+ * @attaches-to `'_cron_'.__GLOBAL_NS__.'_cleanup'`
14
+ */
15
+ public function cleanupCache()
16
+ {
17
+ if (!$this->options['enable']) {
18
+ return; // Nothing to do.
19
+ }
20
+
21
+
22
+
23
+ $this->wurgeCache(); // Purge now.
24
+ }
25
+ }
src/includes/traits/Plugin/CondUtils.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CondUtils
7
+ {
8
+ /**
9
+ * Is pro preview?
10
+ *
11
+ * @since 150511 Rewrite.
12
+ *
13
+ * @return bool `TRUE` if it's a pro preview.
14
+ */
15
+ public function isProPreview()
16
+ {
17
+ return !empty($_REQUEST[GLOBAL_NS.'_pro_preview']);
18
+ }
19
+ }
src/includes/traits/Plugin/CronUtils.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CronUtils
7
+ {
8
+ /**
9
+ * Extends WP-Cron schedules.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `cron_schedules` filter.
14
+ *
15
+ * @param array $schedules An array of the current schedules.
16
+ *
17
+ * @return array Revised array of WP-Cron schedules.
18
+ */
19
+ public function extendCronSchedules($schedules)
20
+ {
21
+ $schedules['every15m'] = [
22
+ 'interval' => 900,
23
+ 'display' => __('Every 15 Minutes', 'comet-cache'),
24
+ ];
25
+ return $schedules;
26
+ }
27
+
28
+ /**
29
+ * Checks Cron setup, validates schedules, and reschedules events if necessary.
30
+ *
31
+ * @attaches-to `init` hook.
32
+ *
33
+ * @since 151220 Improving WP Cron setup and validation of schedules
34
+ */
35
+ public function checkCronSetup()
36
+ {
37
+ if ($this->options['crons_setup'] < 1439005906
38
+ || $this->options['crons_setup_on_namespace'] !== __NAMESPACE__
39
+ || $this->options['crons_setup_with_cache_cleanup_schedule'] !== $this->options['cache_cleanup_schedule']
40
+ || $this->options['crons_setup_on_wp_with_schedules'] !== sha1(serialize(wp_get_schedules()))
41
+ || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_cleanup')
42
+
43
+ ) {
44
+ wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
45
+ wp_schedule_event(time() + 60, $this->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup');
46
+
47
+
48
+
49
+ $this->updateOptions(
50
+ [
51
+ 'crons_setup' => time(),
52
+ 'crons_setup_on_namespace' => __NAMESPACE__,
53
+ 'crons_setup_with_cache_cleanup_schedule' => $this->options['cache_cleanup_schedule'],
54
+ 'crons_setup_on_wp_with_schedules' => sha1(serialize(wp_get_schedules())),
55
+ ]
56
+ );
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Resets `crons_setup` and clears WP-Cron schedules.
62
+ *
63
+ * @since 151220 Fixing bug with Auto-Cache Engine cron disappearing in some scenarios
64
+ *
65
+ * @note This MUST happen upon uninstall and deactivation due to buggy WP_Cron behavior. Events with a custom schedule will disappear when plugin is not active (see http://bit.ly/1lGdr78).
66
+ */
67
+ public function resetCronSetup()
68
+ {
69
+ if (is_multisite()) { // Main site CRON jobs.
70
+ switch_to_blog(get_current_site()->blog_id);
71
+
72
+ wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
73
+ restore_current_blog(); // Restore current blog.
74
+ } else { // Standard WP installation.
75
+
76
+ wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
77
+ }
78
+ $this->updateOptions(
79
+ [ // Reset so that crons are rescheduled upon next activation
80
+ 'crons_setup' => $this->default_options['crons_setup'],
81
+ 'crons_setup_on_namespace' => $this->default_options['crons_setup_on_namespace'],
82
+ 'crons_setup_with_cache_cleanup_schedule' => $this->default_options['crons_setup_with_cache_cleanup_schedule'],
83
+ 'crons_setup_on_wp_with_schedules' => $this->default_options['crons_setup_on_wp_with_schedules'],
84
+ ]
85
+ );
86
+ }
87
+ }
src/includes/traits/Plugin/DbUtils.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait DbUtils
7
+ {
8
+ /**
9
+ * WordPress database instance.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @return \wpdb Reference for IDEs.
14
+ */
15
+ public function wpdb()
16
+ {
17
+ return $GLOBALS['wpdb'];
18
+ }
19
+ }
src/includes/traits/Plugin/DirUtils.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait DirUtils
7
+ {
8
+ /**
9
+ * This constructs an absolute server directory path (no trailing slashes);
10
+ * which is always nested into {@link \WP_CONTENT_DIR} and the configured `base_dir` option value.
11
+ *
12
+ * @since 150422 Rewrite.
13
+ *
14
+ * @param string $rel_dir_file A sub-directory or file; relative location please.
15
+ *
16
+ * @throws \Exception If `base_dir` is empty when this method is called upon;
17
+ * i.e. if you attempt to call upon this method before {@link setup()} runs.
18
+ *
19
+ * @return string The full absolute server path to `$rel_dir_file`.
20
+ */
21
+ public function wpContentBaseDirTo($rel_dir_file)
22
+ {
23
+ $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B");
24
+
25
+ if (empty($this->options['base_dir'])) {
26
+ throw new \Exception(__('Missing `base_dir` option value.', 'comet-cache'));
27
+ }
28
+ $wp_content_base_dir_to = WP_CONTENT_DIR.'/'.$this->options['base_dir'];
29
+
30
+ if (isset($rel_dir_file[0])) {
31
+ $wp_content_base_dir_to .= '/'.$rel_dir_file;
32
+ }
33
+ return $wp_content_base_dir_to;
34
+ }
35
+
36
+ /**
37
+ * This constructs a relative/base directory path (no leading/trailing slashes).
38
+ * Always relative to {@link \WP_CONTENT_DIR}. Depends on the configured `base_dir` option value.
39
+ *
40
+ * @since 150422 Rewrite.
41
+ *
42
+ * @param string $rel_dir_file A sub-directory or file; relative location please.
43
+ *
44
+ * @throws \Exception If `base_dir` is empty when this method is called upon;
45
+ * i.e. if you attempt to call upon this method before {@link setup()} runs.
46
+ *
47
+ * @return string The relative/base directory path to `$rel_dir_file`.
48
+ */
49
+ public function basePathTo($rel_dir_file)
50
+ {
51
+ $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B");
52
+
53
+ if (empty($this->options['base_dir'])) {
54
+ throw new \Exception(__('Missing `base_dir` option value.', 'comet-cache'));
55
+ }
56
+ $base_path_to = $this->options['base_dir'];
57
+
58
+ if (isset($rel_dir_file[0])) {
59
+ $base_path_to .= '/'.$rel_dir_file;
60
+ }
61
+ return $base_path_to;
62
+ }
63
+
64
+ /**
65
+ * Get the absolute filesystem path to the root of the WordPress installation.
66
+ *
67
+ * Copied verbatim from get_home_path() in wp-admin/includes/file.php
68
+ *
69
+ * @since 151114 Adding `.htaccess` tweaks.
70
+ *
71
+ * @return string Full filesystem path to the root of the WordPress installation
72
+ */
73
+ public function wpHomePath()
74
+ {
75
+ $home = set_url_scheme(get_option('home'), 'http');
76
+ $siteurl = set_url_scheme(get_option('siteurl'), 'http');
77
+ if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
78
+ $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
79
+ $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
80
+ $home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
81
+ $home_path = trailingslashit($home_path);
82
+ } else {
83
+ $home_path = ABSPATH;
84
+ }
85
+ return str_replace('\\', '/', $home_path);
86
+ }
87
+ }
src/includes/traits/Plugin/HtaccessUtils.php ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait HtaccessUtils
7
+ {
8
+ /**
9
+ * Unique comment marker.
10
+ *
11
+ * @since 151220 Enhancing `.htaccess` tweaks.
12
+ *
13
+ * @return string Used in `.htaccess` parsing.
14
+ */
15
+ public $htaccess_marker = 'WmVuQ2FjaGU';
16
+
17
+ /**
18
+ * Plugin options that have associated htaccess rules.
19
+ *
20
+ * @since 160103 Improving `.htaccess` tweaks.
21
+ *
22
+ * @return array Plugin options that have associated htaccess rules
23
+ *
24
+ * @note We keep track of this to avoid the issue described here: http://git.io/vEFIH
25
+ */
26
+ public $options_with_htaccess_rules = ['cdn_enable'];
27
+
28
+ /**
29
+ * Add template blocks to `/.htaccess` file.
30
+ *
31
+ * @since 151114 Adding `.htaccess` tweaks.
32
+ *
33
+ * @return bool True if added successfully.
34
+ *
35
+ * @TODO Improve error reporting detail to better catch unexpected failures; see http://git.io/vEFLT
36
+ */
37
+ public function addWpHtaccess()
38
+ {
39
+ global $is_apache;
40
+
41
+ if (!$is_apache) {
42
+ return false; // Not running the Apache web server.
43
+ }
44
+ if (!$this->options['enable']) {
45
+ return true; // Nothing to do.
46
+ }
47
+ if (!$this->needHtaccessRules()) {
48
+ if ($this->findHtaccessMarker()) { // Do we need to clean up previously added rules?
49
+ $this->removeWpHtaccess(); // Fail silently since we don't need rules in place.
50
+ }
51
+ return true; // Nothing to do; no options enabled that require htaccess rules.
52
+ }
53
+ if (!$this->removeWpHtaccess()) {
54
+ return false; // Unable to remove.
55
+ }
56
+ if (!($htaccess = $this->readHtaccessFile())) {
57
+ return false; // Failure; could not read file or invalid UTF8 encountered, file may be corrupt.
58
+ }
59
+
60
+ $template_blocks = ''; // Initialize.
61
+ if (is_dir($templates_dir = dirname(dirname(__DIR__)).'/templates/htaccess')) {
62
+ foreach (scandir($templates_dir) as $_template_file) {
63
+ switch ($_template_file) {
64
+
65
+ }
66
+ }
67
+ unset($_template_file); // Housekeeping.
68
+ }
69
+
70
+ if (empty($template_blocks)) { // Do we need to add anything to htaccess?
71
+ $this->closeHtaccessFile($htaccess); // No need to write to htaccess file in this case.
72
+ return true; // Nothing to do, but no failures either.
73
+ }
74
+
75
+ $template_header = '# BEGIN '.NAME.' '.$this->htaccess_marker.' (the '.$this->htaccess_marker.' marker is required for '.NAME.'; do not remove)'."\n";
76
+ $template_footer = '# END '.NAME.' '.$this->htaccess_marker;
77
+ $htaccess['file_contents'] = $template_header.trim($template_blocks)."\n".$template_footer."\n\n".$htaccess['file_contents'];
78
+
79
+ if (!$this->writeHtaccessFile($htaccess, true)) {
80
+ return false; // Failure; could not write changes.
81
+ }
82
+
83
+ return true; // Added successfully.
84
+ }
85
+
86
+ /**
87
+ * Remove template blocks from `/.htaccess` file.
88
+ *
89
+ * @since 151114 Adding `.htaccess` tweaks.
90
+ *
91
+ * @return bool True if removed successfully.
92
+ *
93
+ * @TODO Improve error reporting detail to better catch unexpected failures; see http://git.io/vEFLT
94
+ */
95
+ public function removeWpHtaccess()
96
+ {
97
+ global $is_apache;
98
+
99
+ if (!$is_apache) {
100
+ return false; // Not running the Apache web server.
101
+ }
102
+ if (!($htaccess_file = $this->findHtaccessFile())) {
103
+ return true; // File does not exist.
104
+ }
105
+ if (!$this->findHtaccessMarker()) {
106
+ return true; // Template blocks are already gone.
107
+ }
108
+ if (!($htaccess = $this->readHtaccessFile())) {
109
+ return false; // Failure; could not read file, create file, or invalid UTF8 encountered, file may be corrupt.
110
+ }
111
+
112
+ $regex = '/#\s*BEGIN\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'.*?#\s*END\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'\s*/is';
113
+ $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
114
+
115
+ if (!$this->writeHtaccessFile($htaccess, false)) {
116
+ return false; // Failure; could not write changes.
117
+ }
118
+
119
+ return true; // Removed successfully.
120
+ }
121
+
122
+ /**
123
+ * Finds absolute server path to `/.htaccess` file.
124
+ *
125
+ * @since 151114 Adding `.htaccess` tweaks.
126
+ *
127
+ * @return string Absolute server path to `/.htaccess` file;
128
+ * else an empty string if unable to locate the file.
129
+ */
130
+ public function findHtaccessFile()
131
+ {
132
+ $file = ''; // Initialize.
133
+ $home_path = $this->wpHomePath();
134
+
135
+ if (is_file($htaccess_file = $home_path.'.htaccess')) {
136
+ $file = $htaccess_file;
137
+ }
138
+ return $file;
139
+ }
140
+
141
+ /**
142
+ * Determines if there are any plugin options enabled that require htaccess rules to be added.
143
+ *
144
+ * @since 160103 Improving `.htaccess` tweaks.
145
+ *
146
+ * @return bool True when an option is enabled that requires htaccess rules, false otherwise.
147
+ */
148
+ public function needHtaccessRules()
149
+ {
150
+ if (!is_array($this->options_with_htaccess_rules)) {
151
+ return false; // Nothing to do.
152
+ }
153
+ foreach ($this->options_with_htaccess_rules as $option) {
154
+ if ($this->options[$option]) {
155
+ return true; // Yes, there are options enabled that require htaccess rules.
156
+ }
157
+ }
158
+ return false; // No, there are no options enabled that require htaccess rules.
159
+ }
160
+
161
+ /**
162
+ * Utility method used to check if htaccess file contains $htaccess_marker.
163
+ *
164
+ * @since 151114 Adding `.htaccess` tweaks.
165
+ *
166
+ * @param string $htaccess_marker Unique comment marker used to identify rules added by this plugin.
167
+ *
168
+ * @return bool False on failure or when marker does not exist in htaccess, true otherwise.
169
+ */
170
+ public function findHtaccessMarker($htaccess_marker = '')
171
+ {
172
+ if (!($htaccess_file = $this->findHtaccessFile())) {
173
+ return false; // File does not exist.
174
+ }
175
+ if (!is_readable($htaccess_file)) {
176
+ return false; // Not possible.
177
+ }
178
+ if (($htaccess_file_contents = file_get_contents($htaccess_file)) === false) {
179
+ return false; // Failure; could not read file.
180
+ }
181
+ if (empty($htaccess_marker)) {
182
+ $htaccess_marker = $this->htaccess_marker;
183
+ }
184
+ if (stripos($htaccess_file_contents, $htaccess_marker) === false) {
185
+ return false; // Htaccess marker is missing
186
+ }
187
+
188
+ return true; // Htaccess has the marker
189
+ }
190
+
191
+ /**
192
+ * Gets contents of `/.htaccess` file with exclusive lock to read+write. If file doesn't exist, we attempt to create it.
193
+ *
194
+ * @since 151220 Improving `.htaccess` utils.
195
+ *
196
+ * @param string $htaccess_file Absolute path to the htaccess file. Optional.
197
+ * If not provided, we attempt to find it or create it if it doesn't exist.
198
+ *
199
+ * @return array|bool Returns an array with data necessary to call $this->writeHtaccessFile():
200
+ * `fp` a file pointer resource, `file_contents` a string. Returns `false` on failure.
201
+ *
202
+ * @note If a call to this method is not followed by a call to $this->writeHtaccessFile(),
203
+ * you must make sure that you unlock and close the `fp` resource yourself.
204
+ */
205
+ public function readHtaccessFile($htaccess_file = '')
206
+ {
207
+ if (empty($htaccess_file) && !($htaccess_file = $this->findHtaccessFile())) {
208
+ if (!is_writable($this->wpHomePath()) || file_put_contents($htaccess_file = $this->wpHomePath().'.htaccess', '') === false) {
209
+ return false; // Unable to find and/or create `.htaccess`.
210
+ } // If it doesn't exist, we create the `.htaccess` file here.
211
+ }
212
+ if (!is_readable($htaccess_file) || !is_writable($htaccess_file) || (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)) {
213
+ return false; // Not possible.
214
+ }
215
+ if (!($fp = fopen($htaccess_file, 'rb+')) || !flock($fp, LOCK_EX)) {
216
+ fclose($fp); // Just in case we opened it before failing to obtain a lock.
217
+ return false; // Failure; could not open file and obtain an exclusive lock.
218
+ }
219
+ if (($file_contents = fread($fp, filesize($htaccess_file))) && ($file_contents === wp_check_invalid_utf8($file_contents))) {
220
+ rewind($fp); // Rewind pointer to beginning of file.
221
+ return compact('fp', 'file_contents');
222
+ } else { // Failure; could not read file or invalid UTF8 encountered, file may be corrupt.
223
+ flock($fp, LOCK_UN);
224
+ fclose($fp);
225
+ return false;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Writes to `/.htaccess` file using provided file pointer.
231
+ *
232
+ * @since 151220 Improving `.htaccess` utils.
233
+ *
234
+ * @param array $htaccess Array containing `fp` file resource pointing to htaccess file and `file_contents` to write to file.
235
+ * @param bool $require_marker Whether or not to require the marker be present in contents before writing.
236
+ * @param string $htaccess_marker Unique comment marker used to identify rules added by this plugin.
237
+ *
238
+ * @return bool True on success, false on failure.
239
+ */
240
+ public function writeHtaccessFile(array $htaccess, $require_marker = true, $htaccess_marker = '')
241
+ {
242
+ if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
243
+ return false; // Not possible.
244
+ }
245
+ if (!is_resource($htaccess['fp'])) {
246
+ return false;
247
+ }
248
+ $htaccess_marker = $htaccess_marker ?: $this->htaccess_marker;
249
+
250
+ $_have_marker = stripos($htaccess['file_contents'], $htaccess_marker);
251
+
252
+ // Note: rewind() necessary here because we fread() above.
253
+ if (($require_marker && $_have_marker === false) || !rewind($htaccess['fp']) || !ftruncate($htaccess['fp'], 0) || !fwrite($htaccess['fp'], $htaccess['file_contents'])) {
254
+ flock($htaccess['fp'], LOCK_UN);
255
+ fclose($htaccess['fp']);
256
+ return false; // Failure; could not write changes.
257
+ }
258
+ fflush($htaccess['fp']);
259
+ flock($htaccess['fp'], LOCK_UN);
260
+ fclose($htaccess['fp']);
261
+
262
+ return true;
263
+ }
264
+
265
+ /**
266
+ * Utility method used to unlock and close htaccess file resource.
267
+ *
268
+ * @since 151114 Adding `.htaccess` tweaks.
269
+ *
270
+ * @param array $htaccess Array containing at least an `fp` file resource pointing to htaccess file.
271
+ *
272
+ * @return bool False on failure, true otherwise.
273
+ */
274
+ public function closeHtaccessFile(array $htaccess)
275
+ {
276
+ if (!is_resource($htaccess['fp'])) {
277
+ return false; // Failure; requires a valid file resource.
278
+ }
279
+ flock($htaccess['fp'], LOCK_UN);
280
+ fclose($htaccess['fp']);
281
+
282
+ return true;
283
+ }
284
+ }
src/includes/traits/Plugin/InstallUtils.php ADDED
@@ -0,0 +1,553 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait InstallUtils
7
+ {
8
+ /**
9
+ * Plugin activation hook.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to {@link \register_activation_hook()}
14
+ */
15
+ public function activate()
16
+ {
17
+ $this->setup(); // Ensure setup is complete.
18
+
19
+ if (defined('WP_CLI') && WP_CLI) {
20
+ $this->updateOptions(['enable' => '1']);
21
+ }
22
+ if (!$this->options['welcomed'] && !$this->options['enable']) {
23
+ $settings_url = add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), network_admin_url('/admin.php'));
24
+ $this->enqueueMainNotice(sprintf(__('<strong>%1$s</strong> successfully installed! :-) <strong>Please <a href="%2$s">enable caching and review options</a>.</strong>', 'comet-cache'), esc_html(NAME), esc_attr($settings_url)), ['push_to_top' => true]);
25
+ $this->updateOptions(['welcomed' => '1']);
26
+ }
27
+ if (!$this->options['enable']) {
28
+ return; // Nothing to do.
29
+ }
30
+ $this->addWpCacheToWpConfig();
31
+ $this->addWpHtaccess();
32
+ $this->addAdvancedCache();
33
+ $this->updateBlogPaths();
34
+ $this->autoClearCache();
35
+ }
36
+
37
+ /**
38
+ * Check current plugin version that is installed in WP.
39
+ *
40
+ * @since 150422 Rewrite.
41
+ *
42
+ * @attaches-to `admin_init` hook.
43
+ */
44
+ public function checkVersion()
45
+ {
46
+ $prev_version = $this->options['version'];
47
+ if (version_compare($prev_version, VERSION, '>=')) {
48
+ return; // Nothing to do; up-to-date.
49
+ }
50
+ $this->updateOptions(['version' => VERSION]);
51
+
52
+ new Classes\VsUpgrades($prev_version);
53
+
54
+ if ($this->options['enable']) {
55
+ $this->addWpCacheToWpConfig();
56
+ $this->addWpHtaccess();
57
+ $this->addAdvancedCache();
58
+ $this->updateBlogPaths();
59
+ }
60
+ $this->wipeCache(); // Fresh start now.
61
+
62
+ $this->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)', 'comet-cache'), esc_html(NAME)), ['push_to_top' => true]);
63
+ }
64
+
65
+ /**
66
+ * Plugin deactivation hook.
67
+ *
68
+ * @since 150422 Rewrite.
69
+ *
70
+ * @attaches-to {@link \register_deactivation_hook()}
71
+ */
72
+ public function deactivate()
73
+ {
74
+ $this->setup(); // Ensure setup is complete.
75
+
76
+ $this->removeWpCacheFromWpConfig();
77
+ $this->removeWpHtaccess();
78
+ $this->removeAdvancedCache();
79
+ $this->clearCache();
80
+ $this->resetCronSetup();
81
+ }
82
+
83
+ /**
84
+ * Plugin uninstall hook.
85
+ *
86
+ * @since 150422 Rewrite.
87
+ */
88
+ public function uninstall()
89
+ {
90
+ $this->setup(); // Ensure setup is complete.
91
+
92
+ if (!defined('WP_UNINSTALL_PLUGIN')) {
93
+ return; // Disallow.
94
+ }
95
+ if (empty($GLOBALS[GLOBAL_NS.'_uninstalling'])) {
96
+ return; // Not uninstalling.
97
+ }
98
+ if (!current_user_can($this->uninstall_cap)) {
99
+ return; // Extra layer of security.
100
+ }
101
+ $this->removeWpCacheFromWpConfig();
102
+ $this->removeWpHtaccess();
103
+ $this->removeAdvancedCache();
104
+ $this->wipeCache();
105
+ $this->resetCronSetup();
106
+
107
+ if (!$this->options['uninstall_on_deletion']) {
108
+ return; // Nothing to do here.
109
+ }
110
+ $this->deleteAdvancedCache();
111
+ $this->deleteBaseDir();
112
+
113
+ $wpdb = $this->wpdb(); // WordPress DB.
114
+ $like = '%'.$wpdb->esc_like(GLOBAL_NS).'%';
115
+
116
+ if (is_multisite()) { // Site options for a network installation.
117
+ $wpdb->query('DELETE FROM `'.esc_sql($wpdb->sitemeta).'` WHERE `meta_key` LIKE \''.esc_sql($like).'\'');
118
+
119
+ switch_to_blog(get_current_site()->blog_id); // In case it started as a standard WP installation.
120
+ $wpdb->query('DELETE FROM `'.esc_sql($wpdb->options).'` WHERE `option_name` LIKE \''.esc_sql($like).'\'');
121
+ restore_current_blog(); // Restore current blog.
122
+ //
123
+ } else { // Standard WP installation.
124
+ $wpdb->query('DELETE FROM `'.esc_sql($wpdb->options).'` WHERE `option_name` LIKE \''.esc_sql($like).'\'');
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Adds `define('WP_CACHE', TRUE);` to the `/wp-config.php` file.
130
+ *
131
+ * @since 150422 Rewrite.
132
+ *
133
+ * @return string The new contents of the updated `/wp-config.php` file;
134
+ * else an empty string if unable to add the `WP_CACHE` constant.
135
+ */
136
+ public function addWpCacheToWpConfig()
137
+ {
138
+ if (!$this->options['enable']) {
139
+ return ''; // Nothing to do.
140
+ }
141
+ if (!($wp_config_file = $this->findWpConfigFile())) {
142
+ return ''; // Unable to find `/wp-config.php`.
143
+ }
144
+ if (!is_readable($wp_config_file)) {
145
+ return ''; // Not possible.
146
+ }
147
+ if (!($wp_config_file_contents = file_get_contents($wp_config_file))) {
148
+ return ''; // Failure; could not read file.
149
+ }
150
+ if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
151
+ return ''; // Failure; file empty
152
+ }
153
+ if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[1-9][0-9\.]*|TRUE|([\'"])(?:[^0\'"]|[^\'"]{2,})\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace)) {
154
+ return $wp_config_file_contents; // It's already in there; no need to modify this file.
155
+ }
156
+ if (!($wp_config_file_contents = $this->removeWpCacheFromWpConfig())) {
157
+ return ''; // Unable to remove previous value.
158
+ }
159
+ if (!($wp_config_file_contents = preg_replace('/^\s*(\<\?php|\<\?)\s+/i', '${1}'."\n"."define('WP_CACHE', TRUE);"."\n", $wp_config_file_contents, 1))) {
160
+ return ''; // Failure; something went terribly wrong here.
161
+ }
162
+ if (strpos($wp_config_file_contents, "define('WP_CACHE', TRUE);") === false) {
163
+ return ''; // Failure; unable to add; unexpected PHP code.
164
+ }
165
+ if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
166
+ return ''; // We may NOT edit any files.
167
+ }
168
+ if (!is_writable($wp_config_file)) {
169
+ return ''; // Not possible.
170
+ }
171
+ if (!file_put_contents($wp_config_file, $wp_config_file_contents)) {
172
+ return ''; // Failure; could not write changes.
173
+ }
174
+ return $wp_config_file_contents;
175
+ }
176
+
177
+ /**
178
+ * Removes `define('WP_CACHE', TRUE);` from the `/wp-config.php` file.
179
+ *
180
+ * @since 150422 Rewrite.
181
+ *
182
+ * @return string The new contents of the updated `/wp-config.php` file;
183
+ * else an empty string if unable to remove the `WP_CACHE` constant.
184
+ */
185
+ public function removeWpCacheFromWpConfig()
186
+ {
187
+ if (!($wp_config_file = $this->findWpConfigFile())) {
188
+ return ''; // Unable to find `/wp-config.php`.
189
+ }
190
+ if (!is_readable($wp_config_file)) {
191
+ return ''; // Not possible.
192
+ }
193
+ if (!($wp_config_file_contents = file_get_contents($wp_config_file))) {
194
+ return ''; // Failure; could not read file.
195
+ }
196
+ if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
197
+ return ''; // Failure; file empty
198
+ }
199
+ if (!preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents_no_whitespace)) {
200
+ return $wp_config_file_contents; // Already gone.
201
+ }
202
+ if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:0|FALSE|NULL|([\'"])0?\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace) && !is_writable($wp_config_file)) {
203
+ return $wp_config_file_contents; // It's already disabled, and since we can't write to this file let's let this slide.
204
+ }
205
+ if (!($wp_config_file_contents = preg_replace('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[0-9\.]+|TRUE|FALSE|NULL|([\'"])[^\'"]*\\2)\s*\)\s*;/i', '', $wp_config_file_contents))) {
206
+ return ''; // Failure; something went terribly wrong here.
207
+ }
208
+ if (preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents)) {
209
+ return ''; // Failure; perhaps the `/wp-config.php` file contains syntax we cannot remove safely.
210
+ }
211
+ if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
212
+ return ''; // We may NOT edit any files.
213
+ }
214
+ if (!is_writable($wp_config_file)) {
215
+ return ''; // Not possible.
216
+ }
217
+ if (!file_put_contents($wp_config_file, $wp_config_file_contents)) {
218
+ return ''; // Failure; could not write changes.
219
+ }
220
+ return $wp_config_file_contents;
221
+ }
222
+
223
+ /**
224
+ * Checks to make sure the `advanced-cache.php` file still exists;
225
+ * and if it doesn't, the `advanced-cache.php` is regenerated automatically.
226
+ *
227
+ * @since 150422 Rewrite.
228
+ *
229
+ * @attaches-to `init` hook.
230
+ *
231
+ * @note This runs so that remote deployments which completely wipe out an
232
+ * existing set of website files (like the AWS Elastic Beanstalk does) will NOT cause Comet Cache
233
+ * to stop functioning due to the lack of an `advanced-cache.php` file, which is generated by Comet Cache.
234
+ *
235
+ * For instance, if you have a Git repo with all of your site files; when you push those files
236
+ * to your website to deploy them, you most likely do NOT have the `advanced-cache.php` file.
237
+ * Comet Cache creates this file on its own. Thus, if it's missing (and CC is active)
238
+ * we simply regenerate the file automatically to keep Comet Cache running.
239
+ */
240
+ public function checkAdvancedCache()
241
+ {
242
+ if (!$this->options['enable']) {
243
+ return; // Nothing to do.
244
+ }
245
+ if (!empty($_REQUEST[GLOBAL_NS])) {
246
+ return; // Skip on plugin actions.
247
+ }
248
+ $cache_dir = $this->cacheDir();
249
+ $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
250
+ $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
251
+
252
+ // Fixes zero-byte advanced-cache.php bug related to migrating from ZenCache
253
+ // See: <https://github.com/websharks/zencache/issues/432>
254
+
255
+ // Also fixes a missing `define('WP_CACHE', TRUE)` bug related to migrating from ZenCache
256
+ // See <https://github.com/websharks/zencache/issues/450>
257
+
258
+ if (!is_file($advanced_cache_check_file) || !is_file($advanced_cache_file) || filesize($advanced_cache_file) === 0) {
259
+ $this->addAdvancedCache();
260
+ $this->addWpCacheToWpConfig();
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Creates and adds the `advanced-cache.php` file.
266
+ *
267
+ * @since 150422 Rewrite.
268
+ *
269
+ * @return bool|null `TRUE` on success. `FALSE` or `NULL` on failure.
270
+ * A special `NULL` return value indicates success with a single failure
271
+ * that is specifically related to the `[SHORT_NAME]-advanced-cache` file.
272
+ */
273
+ public function addAdvancedCache()
274
+ {
275
+ if (!$this->removeAdvancedCache()) {
276
+ return false; // Still exists.
277
+ }
278
+ $cache_dir = $this->cacheDir();
279
+ $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
280
+ $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
281
+ $advanced_cache_template = dirname(dirname(__DIR__)).'/templates/advanced-cache.txt';
282
+
283
+ if (is_file($advanced_cache_file) && !is_writable($advanced_cache_file)) {
284
+ return false; // Not possible to create.
285
+ }
286
+ if (!is_file($advanced_cache_file) && !is_writable(dirname($advanced_cache_file))) {
287
+ return false; // Not possible to create.
288
+ }
289
+ if (!is_file($advanced_cache_template) || !is_readable($advanced_cache_template)) {
290
+ return false; // Template file is missing; or not readable.
291
+ }
292
+ if (!($advanced_cache_contents = file_get_contents($advanced_cache_template))) {
293
+ return false; // Template file is missing; or is not readable.
294
+ }
295
+ $possible_advanced_cache_constant_key_values = array_merge(
296
+ $this->options, // The following additional keys are dynamic.
297
+ [
298
+ 'cache_dir' => $this->basePathTo($this->cache_sub_dir),
299
+
300
+ ]
301
+ );
302
+ if ($this->applyWpFilters(GLOBAL_NS.'_exclude_uris_client_side_too', true)) {
303
+ $possible_advanced_cache_constant_key_values['exclude_client_side_uris'] .= "\n".$this->options['exclude_uris'];
304
+ }
305
+ foreach ($possible_advanced_cache_constant_key_values as $_option => $_value) {
306
+ $_value = (string) $_value; // Force string.
307
+
308
+ switch ($_option) {
309
+ case 'exclude_uris': // Converts to regex (caSe insensitive).
310
+ case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
311
+ case 'exclude_refs': // Converts to regex (caSe insensitive).
312
+ case 'exclude_agents': // Converts to regex (caSe insensitive).
313
+
314
+
315
+
316
+ $_value = "'".$this->escSq($this->lineDelimitedPatternsToRegex($_value))."'";
317
+
318
+ break; // Break switch handler.
319
+
320
+
321
+
322
+ default: // Default case handler.
323
+ $_value = "'".$this->escSq($_value)."'";
324
+ break; // Break switch handler.
325
+ }
326
+ $advanced_cache_contents = // Fill replacement codes.
327
+ str_ireplace(
328
+ [
329
+ "'%%".GLOBAL_NS.'_'.$_option."%%'",
330
+ "'%%".GLOBAL_NS.'_'.preg_replace('/^cache_/i', '', $_option)."%%'",
331
+ ],
332
+ $_value,
333
+ $advanced_cache_contents
334
+ );
335
+ }
336
+ unset($_option, $_value, $_values, $_response); // Housekeeping.
337
+
338
+ if (strpos(PLUGIN_FILE, WP_CONTENT_DIR) === 0) {
339
+ $plugin_file = "WP_CONTENT_DIR.'".$this->escSq(str_replace(WP_CONTENT_DIR, '', PLUGIN_FILE))."'";
340
+ } else {
341
+ $plugin_file = "'".$this->escSq(PLUGIN_FILE)."'"; // Full absolute path.
342
+ }
343
+ // Make it possible for the `advanced-cache.php` handler to find the plugin directory reliably.
344
+ $advanced_cache_contents = str_ireplace("'%%".GLOBAL_NS."_PLUGIN_FILE%%'", $plugin_file, $advanced_cache_contents);
345
+
346
+ // Ignore; this is created by Comet Cache; and we don't need to obey in this case.
347
+ #if(defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)
348
+ # return FALSE; // We may NOT edit any files.
349
+
350
+ if (!file_put_contents($advanced_cache_file, $advanced_cache_contents)) {
351
+ return false; // Failure; could not write file.
352
+ }
353
+ $cache_lock = $this->cacheLock(); // Lock cache.
354
+
355
+ if (!is_dir($cache_dir)) {
356
+ mkdir($cache_dir, 0775, true);
357
+ }
358
+ if (is_writable($cache_dir) && !is_file($cache_dir.'/.htaccess')) {
359
+ file_put_contents($cache_dir.'/.htaccess', $this->htaccess_deny);
360
+ }
361
+ if (!is_dir($cache_dir) || !is_writable($cache_dir) || !is_file($cache_dir.'/.htaccess') || !file_put_contents($advanced_cache_check_file, time())) {
362
+ $this->cacheUnlock($cache_lock); // Release.
363
+ return; // Special return value (NULL).
364
+ }
365
+ $this->cacheUnlock($cache_lock); // Release.
366
+
367
+ $this->clearAcDropinFromOpcacheByForce();
368
+
369
+ return true;
370
+ }
371
+
372
+ /**
373
+ * Removes the `advanced-cache.php` file.
374
+ *
375
+ * @since 150422 Rewrite.
376
+ *
377
+ * @return bool `TRUE` on success. `FALSE` on failure.
378
+ *
379
+ * @note The `advanced-cache.php` file is NOT actually deleted by this routine.
380
+ * Instead of deleting the file, we simply empty it out so that it's `0` bytes in size.
381
+ *
382
+ * The reason for this is to preserve any file permissions set by the site owner.
383
+ * If the site owner previously allowed this specific file to become writable, we don't want to
384
+ * lose that permission by deleting the file; forcing the site owner to do it all over again later.
385
+ *
386
+ * An example of where this is useful is when a site owner deactivates the CC plugin,
387
+ * but later they decide that CC really is the most awesome plugin in the world and they turn it back on.
388
+ */
389
+ public function removeAdvancedCache()
390
+ {
391
+ $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
392
+
393
+ if (!is_file($advanced_cache_file)) {
394
+ return true; // Already gone.
395
+ }
396
+ if (is_readable($advanced_cache_file) && filesize($advanced_cache_file) === 0) {
397
+ return true; // Already gone; i.e. it's empty already.
398
+ }
399
+ if (!is_writable($advanced_cache_file)) {
400
+ return false; // Not possible.
401
+ }
402
+ /* Empty the file only. This way permissions are NOT lost in cases where
403
+ a site owner makes this specific file writable for Comet Cache. */
404
+ if (file_put_contents($advanced_cache_file, '') !== 0) {
405
+ return false; // Failure.
406
+ }
407
+ $this->clearAcDropinFromOpcacheByForce();
408
+
409
+ return true;
410
+ }
411
+
412
+ /**
413
+ * Deletes the `advanced-cache.php` file.
414
+ *
415
+ * @since 150422 Rewrite.
416
+ *
417
+ * @return bool `TRUE` on success. `FALSE` on failure.
418
+ *
419
+ * @note The `advanced-cache.php` file is deleted by this routine.
420
+ */
421
+ public function deleteAdvancedCache()
422
+ {
423
+ $cache_dir = $this->cacheDir();
424
+ $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
425
+ $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
426
+
427
+ if (is_file($advanced_cache_file)) {
428
+ if (!is_writable($advanced_cache_file) || !unlink($advanced_cache_file)) {
429
+ return false; // Not possible; or outright failure.
430
+ }
431
+ }
432
+ if (is_file($advanced_cache_check_file)) {
433
+ if (!is_writable($advanced_cache_check_file) || !unlink($advanced_cache_check_file)) {
434
+ return false; // Not possible; or outright failure.
435
+ }
436
+ }
437
+ $this->clearAcDropinFromOpcacheByForce();
438
+
439
+ return true; // Deletion success.
440
+ }
441
+
442
+ /**
443
+ * Checks to make sure the `[SHORT_NAME]-blog-paths` file still exists;
444
+ * and if it doesn't, the `[SHORT_NAME]-blog-paths` file is regenerated automatically.
445
+ *
446
+ * @since 150422 Rewrite.
447
+ *
448
+ * @attaches-to `init` hook.
449
+ *
450
+ * @note This runs so that remote deployments which completely wipe out an
451
+ * existing set of website files (like the AWS Elastic Beanstalk does) will NOT cause Comet Cache
452
+ * to stop functioning due to the lack of a `[SHORT_NAME]-blog-paths` file, which is generated by Comet Cache.
453
+ *
454
+ * For instance, if you have a Git repo with all of your site files; when you push those files
455
+ * to your website to deploy them, you most likely do NOT have the `[SHORT_NAME]-blog-paths` file.
456
+ * Comet Cache creates this file on its own. Thus, if it's missing (and CC is active)
457
+ * we simply regenerate the file automatically to keep Comet Cache running.
458
+ */
459
+ public function checkBlogPaths()
460
+ {
461
+ if (!$this->options['enable']) {
462
+ return; // Nothing to do.
463
+ }
464
+ if (!is_multisite()) {
465
+ return; // N/A.
466
+ }
467
+ if (!empty($_REQUEST[GLOBAL_NS])) {
468
+ return; // Skip on plugin actions.
469
+ }
470
+ $cache_dir = $this->cacheDir();
471
+ $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
472
+
473
+ if (!is_file($blog_paths_file)) {
474
+ $this->updateBlogPaths();
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Creates and/or updates the `[SHORT_NAME]-blog-paths` file.
480
+ *
481
+ * @since 150422 Rewrite.
482
+ *
483
+ * @attaches-to `enable_live_network_counts` filter.
484
+ *
485
+ * @param mixed $enable_live_network_counts Optional, defaults to a `NULL` value.
486
+ *
487
+ * @return mixed The value of `$enable_live_network_counts` (passes through).
488
+ *
489
+ * @note While this routine is attached to a WP filter, we also call upon it directly at times.
490
+ */
491
+ public function updateBlogPaths($enable_live_network_counts = null)
492
+ {
493
+ $value = $enable_live_network_counts; // This hook actually rides on a filter.
494
+
495
+ if (!$this->options['enable']) {
496
+ return $value; // Nothing to do.
497
+ }
498
+ if (!is_multisite()) {
499
+ return $value; // N/A.
500
+ }
501
+ $cache_dir = $this->cacheDir();
502
+ $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
503
+
504
+ $cache_lock = $this->cacheLock();
505
+
506
+ if (!is_dir($cache_dir)) {
507
+ mkdir($cache_dir, 0775, true);
508
+ }
509
+ if (is_writable($cache_dir) && !is_file($cache_dir.'/.htaccess')) {
510
+ file_put_contents($cache_dir.'/.htaccess', $this->htaccess_deny);
511
+ }
512
+ if (is_dir($cache_dir) && is_writable($cache_dir)) {
513
+ $paths = // Collect child `[/base]/path/`s from the WordPress database.
514
+ $this->wpdb()->get_col('SELECT `path` FROM `'.esc_sql($this->wpdb()->blogs)."` WHERE `deleted` <= '0'");
515
+
516
+ $host_base_token = $this->hostBaseToken(); // Pull this once only.
517
+
518
+ foreach ($paths as $_key => &$_path) {
519
+ if ($_path && $_path !== '/' && $host_base_token && $host_base_token !== '/') {
520
+ // Note that each `path` in the DB looks like: `[/base]/path/` (i.e., it includes base).
521
+ $_path = '/'.ltrim(preg_replace('/^'.preg_quote($host_base_token, '/').'/', '', $_path), '/');
522
+ }
523
+ if (!$_path || $_path === '/') {
524
+ unset($paths[$_key]); // Exclude main site.
525
+ }
526
+ }
527
+ unset($_key, $_path); // Housekeeping.
528
+
529
+ file_put_contents($blog_paths_file, serialize($paths));
530
+ }
531
+ $this->cacheUnlock($cache_lock); // Release.
532
+
533
+ return $value; // Pass through untouched (always).
534
+ }
535
+
536
+ /**
537
+ * Deletes base directory.
538
+ *
539
+ * @since 151002 Improving multisite compat.
540
+ *
541
+ * @return int Total files removed by this routine (if any).
542
+ */
543
+ public function deleteBaseDir()
544
+ {
545
+ $counter = 0; // Initialize.
546
+
547
+ @set_time_limit(1800); // @TODO Display a warning.
548
+
549
+ $counter += $this->deleteAllFilesDirsIn($this->wpContentBaseDirTo(''), true);
550
+
551
+ return $counter;
552
+ }
553
+ }
src/includes/traits/Plugin/MenuPageUtils.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait MenuPageUtils
7
+ {
8
+ /**
9
+ * Adds CSS for administrative menu pages.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `admin_enqueue_scripts` hook.
14
+ */
15
+ public function enqueueAdminStyles()
16
+ {
17
+ if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
18
+ return; // NOT a plugin page in the administrative area.
19
+ }
20
+ $deps = []; // Plugin dependencies.
21
+
22
+ wp_enqueue_style(GLOBAL_NS, $this->url('/src/client-s/css/menu-pages.min.css'), $deps, VERSION, 'all');
23
+ }
24
+
25
+ /**
26
+ * Adds JS for administrative menu pages.
27
+ *
28
+ * @since 150422 Rewrite.
29
+ *
30
+ * @attaches-to `admin_enqueue_scripts` hook.
31
+ */
32
+ public function enqueueAdminScripts()
33
+ {
34
+ if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
35
+ return; // NOT a plugin page in the administrative area.
36
+ }
37
+ $deps = ['jquery', 'chartjs']; // Plugin dependencies.
38
+
39
+ wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), [], null, true);
40
+ wp_enqueue_script(GLOBAL_NS, $this->url('/src/client-s/js/menu-pages.min.js'), $deps, VERSION, true);
41
+ wp_localize_script(
42
+ GLOBAL_NS,
43
+ GLOBAL_NS.'_menu_page_vars',
44
+ [
45
+ '_wpnonce' => wp_create_nonce(),
46
+ 'isMultisite' => is_multisite(), // Network?
47
+ 'currentUserHasCap' => current_user_can($this->cap),
48
+ 'currentUserHasNetworkCap' => current_user_can($this->network_cap),
49
+ 'htmlCompressorEnabled' => (boolean) $this->options['htmlc_enable'],
50
+ 'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
51
+ 'emptyStatsCountsImageUrl' => $this->url('/src/client-s/images/stats-fc-empty.png'),
52
+ 'emptyStatsFilesImageUrl' => $this->url('/src/client-s/images/stats-fs-empty.png'),
53
+ 'i18n' => [
54
+ 'name' => NAME,
55
+ 'perSymbol' => __('%', 'comet-cache'),
56
+ 'file' => __('file', 'comet-cache'),
57
+ 'files' => __('files', 'comet-cache'),
58
+ 'pageCache' => __('Page Cache', 'comet-cache'),
59
+ 'htmlCompressor' => __('HTML Compressor', 'comet-cache'),
60
+ 'currentTotal' => __('Current Total', 'comet-cache'),
61
+ 'currentSite' => __('Current Site', 'comet-cache'),
62
+ 'xDayHigh' => __('%s Day High', 'comet-cache'),
63
+ ],
64
+ ]
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Creates network admin menu pages.
70
+ *
71
+ * @since 150422 Rewrite.
72
+ *
73
+ * @attaches-to `network_admin_menu` hook.
74
+ */
75
+ public function addNetworkMenuPages()
76
+ {
77
+ if (!is_multisite()) {
78
+ return; // Not applicable.
79
+ }
80
+ $icon = file_get_contents(dirname(dirname(dirname(__DIR__))).'/client-s/images/inline-icon.svg');
81
+ $icon = 'data:image/svg+xml;base64,'.base64_encode($this->colorSvgMenuIcon($icon));
82
+
83
+ add_menu_page(NAME.(IS_PRO ? ' Pro' : ''), NAME.(IS_PRO ? ' Pro' : ''), $this->network_cap, GLOBAL_NS, [$this, 'menuPageOptions'], $icon);
84
+ add_submenu_page(GLOBAL_NS, __('Plugin Options', 'comet-cache'), __('Plugin Options', 'comet-cache'), $this->network_cap, GLOBAL_NS, [$this, 'menuPageOptions']);
85
+
86
+
87
+
88
+
89
+ }
90
+
91
+ /**
92
+ * Creates admin menu pages.
93
+ *
94
+ * @since 150422 Rewrite.
95
+ *
96
+ * @attaches-to `admin_menu` hook.
97
+ */
98
+ public function addMenuPages()
99
+ {
100
+ if (is_multisite()) {
101
+ return; // Multisite networks MUST use network admin area.
102
+ }
103
+ $icon = file_get_contents(dirname(dirname(dirname(__DIR__))).'/client-s/images/inline-icon.svg');
104
+ $icon = 'data:image/svg+xml;base64,'.base64_encode($this->colorSvgMenuIcon($icon));
105
+
106
+ add_menu_page(NAME.(IS_PRO ? ' Pro' : ''), NAME.(IS_PRO ? ' Pro' : ''), $this->cap, GLOBAL_NS, [$this, 'menuPageOptions'], $icon);
107
+ add_submenu_page(GLOBAL_NS, __('Plugin Options', 'comet-cache'), __('Plugin Options', 'comet-cache'), $this->cap, GLOBAL_NS, [$this, 'menuPageOptions']);
108
+
109
+
110
+
111
+
112
+ }
113
+
114
+ /**
115
+ * Adds link(s) to Comet Cache row on the WP plugins page.
116
+ *
117
+ * @since 150422 Rewrite.
118
+ *
119
+ * @attaches-to `plugin_action_links_'.plugin_basename(PLUGIN_FILE)` filter.
120
+ *
121
+ * @param array $links An array of the existing links provided by WordPress.
122
+ *
123
+ * @return array Revised array of links.
124
+ */
125
+ public function addSettingsLink($links)
126
+ {
127
+ if (is_multisite() && !is_network_admin()) {
128
+ return $links;
129
+ }
130
+
131
+ $links[] = '<a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), self_admin_url('/admin.php'))).'">'.__('Settings', 'comet-cache').'</a>';
132
+ if (!IS_PRO) {
133
+ $links[] = '<br/><a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, GLOBAL_NS.'_pro_preview' => '1']), self_admin_url('/admin.php'))).'">'.__('Preview Pro Features', 'comet-cache').'</a>';
134
+ $links[] = '<a href="'.esc_attr('http://cometcache.com/prices/').'" target="_blank">'.__('Upgrade', 'comet-cache').'</a>';
135
+ }
136
+ return $links;
137
+ }
138
+
139
+ /**
140
+ * Fills menu page inline SVG icon color.
141
+ *
142
+ * @since 150422 Rewrite.
143
+ *
144
+ * @param string $svg Inline SVG icon markup.
145
+ *
146
+ * @return string Inline SVG icon markup.
147
+ */
148
+ public function colorSvgMenuIcon($svg)
149
+ {
150
+ if (!($color = get_user_option('admin_color'))) {
151
+ $color = 'fresh'; // Default color scheme.
152
+ }
153
+ if (empty($this->wp_admin_icon_colors[$color])) {
154
+ return $svg; // Not possible.
155
+ }
156
+ $icon_colors = $this->wp_admin_icon_colors[$color];
157
+ $use_icon_fill_color = $icon_colors['base']; // Default base.
158
+
159
+ $current_pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
160
+ $current_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
161
+
162
+ if (strpos($current_pagenow, GLOBAL_NS) === 0 || strpos($current_page, GLOBAL_NS) === 0) {
163
+ $use_icon_fill_color = $icon_colors['current'];
164
+ }
165
+ return str_replace(' fill="currentColor"', ' fill="'.esc_attr($use_icon_fill_color).'"', $svg);
166
+ }
167
+
168
+ /**
169
+ * Loads the admin menu page options.
170
+ *
171
+ * @since 150422 Rewrite.
172
+ */
173
+ public function menuPageOptions()
174
+ {
175
+ new Classes\MenuPage('options');
176
+ }
177
+
178
+
179
+
180
+
181
+
182
+ /**
183
+ * WordPress admin icon color schemes.
184
+ *
185
+ * @since 150422 Rewrite.
186
+ *
187
+ * @type array WP admin icon colors.
188
+ *
189
+ * @note These must be hard-coded, because they don't become available
190
+ * in core until `admin_init`; i.e., too late for `admin_menu`.
191
+ */
192
+ public $wp_admin_icon_colors = [
193
+ 'fresh' => ['base' => '#999999', 'focus' => '#2EA2CC', 'current' => '#FFFFFF'],
194
+ 'light' => ['base' => '#999999', 'focus' => '#CCCCCC', 'current' => '#CCCCCC'],
195
+ 'blue' => ['base' => '#E5F8FF', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
196
+ 'midnight' => ['base' => '#F1F2F3', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
197
+ 'sunrise' => ['base' => '#F3F1F1', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
198
+ 'ectoplasm' => ['base' => '#ECE6F6', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
199
+ 'ocean' => ['base' => '#F2FCFF', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
200
+ 'coffee' => ['base' => '#F3F2F1', 'focus' => '#FFFFFF', 'current' => '#FFFFFF'],
201
+ ];
202
+
203
+ /**
204
+ * On a specific menu page?
205
+ *
206
+ * @since 151002 Improving multisite compat.
207
+ *
208
+ * @param string $which Which page to check; may contain wildcards.
209
+ *
210
+ * @return bool True if is the menu page.
211
+ */
212
+ public function isMenuPage($which)
213
+ {
214
+ if (!($which = trim((string) $which))) {
215
+ return false; // Empty.
216
+ }
217
+ if (!is_admin()) {
218
+ return false;
219
+ }
220
+ $page = $pagenow = ''; // Initialize.
221
+
222
+ if (!empty($_REQUEST['page'])) {
223
+ $page = (string) $_REQUEST['page'];
224
+ }
225
+ if (!empty($GLOBALS['pagenow'])) {
226
+ $pagenow = (string) $GLOBALS['pagenow'];
227
+ }
228
+ if ($page && fnmatch($which, $page, FNM_CASEFOLD)) {
229
+ return true; // Wildcard match.
230
+ }
231
+ if ($pagenow && fnmatch($which, $pagenow, FNM_CASEFOLD)) {
232
+ return true; // Wildcard match.
233
+ }
234
+ return false; // Nope.
235
+ }
236
+ }
src/includes/traits/Plugin/NoticeUtils.php ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait NoticeUtils
7
+ {
8
+ /*
9
+ * Notice queue handlers.
10
+ */
11
+
12
+ /**
13
+ * Enqueue an administrative notice.
14
+ *
15
+ * @since 150422 Rewrite. Improved 151002.
16
+ *
17
+ * @param string $notice HTML markup containing the notice itself.
18
+ * @param array $args Any additional arguments supported by the notice API in this plugin.
19
+ * @param int $blog_id Optional. Defaults to the current blog ID. Use any value `< 0` to indicate the main site.
20
+ *
21
+ * @return string A unique key generated for this notice.
22
+ */
23
+ public function enqueueNotice($notice, array $args = [], $blog_id = 0)
24
+ {
25
+ $notice = trim((string) $notice);
26
+ $blog_id = (integer) $blog_id;
27
+
28
+ if (!$notice) {
29
+ return; // Nothing to do.
30
+ }
31
+ $notice = ['notice' => $notice];
32
+ $notice = $this->normalizeNotice($notice, $args);
33
+ $key = sha1(serialize($notice)); // Prevent dupes.
34
+
35
+ $notices = $this->getNotices($blog_id);
36
+
37
+ if ($notice['push_to_top']) {
38
+ $notices = [$key => $notice] + $notices;
39
+ } else {
40
+ $notices[$key] = $notice; // Default behavior.
41
+ }
42
+ $this->updateNotices($notices, $blog_id);
43
+
44
+ return $key; // For dismissals.
45
+ }
46
+
47
+ /**
48
+ * Dismiss an administrative notice.
49
+ *
50
+ * @since 151002 Improving multisite compat.
51
+ *
52
+ * @param string $key_to_dismiss A unique key which identifies a particular notice.
53
+ * Or, a persistent key which identifies one or more persistent notices.
54
+ * @param int $blog_id The blog ID from which to dismiss the notice.
55
+ *
56
+ * @return array All remaining notices.
57
+ */
58
+ public function dismissNotice($key_to_dismiss, $blog_id = 0)
59
+ {
60
+ $key_to_dismiss = trim((string) $key_to_dismiss);
61
+ $blog_id = (integer) $blog_id; // For multisite compat.
62
+ $notices = $enqueued_notices = $this->getNotices($blog_id);
63
+
64
+ if (!$key_to_dismiss) {
65
+ return $notices; // Nothing to do.
66
+ }
67
+ foreach ($notices as $_key => $_notice) {
68
+ if ($_key === $key_to_dismiss) {
69
+ unset($notices[$_key]); // A specific key.
70
+ } elseif ($_notice['persistent_key'] === $key_to_dismiss) {
71
+ unset($notices[$_key]); // All matching keys.
72
+ }
73
+ } // ↑ Dismisses all matching keys.
74
+ unset($_key, $_notice); // Housekeeping.
75
+
76
+ if ($notices !== $enqueued_notices) { // Something changed?
77
+ $this->updateNotices($notices, $blog_id); // Update.
78
+ }
79
+ return $notices; // All remaining notices.
80
+ }
81
+
82
+ /**
83
+ * Enqueue an administrative error notice.
84
+ *
85
+ * @since 150422 Rewrite. Improved 151002.
86
+ */
87
+ public function enqueueError($notice, array $args = [], $blog_id = 0)
88
+ {
89
+ return $this->enqueueNotice($notice, array_merge($args, ['class' => 'error']), $blog_id);
90
+ }
91
+
92
+ /**
93
+ * Enqueue an administrative notice (main site).
94
+ *
95
+ * @since 151002. Improving multisite compat.
96
+ */
97
+ public function enqueueMainNotice($notice, array $args = [])
98
+ {
99
+ return $this->enqueueNotice($notice, $args, -1);
100
+ }
101
+
102
+ /**
103
+ * Enqueue an administrative error notice (main site).
104
+ *
105
+ * @since 151002. Improving multisite compat.
106
+ */
107
+ public function enqueueMainError($notice, array $args = [])
108
+ {
109
+ return $this->enqueueNotice($notice, array_merge($args, ['class' => 'error']), -1);
110
+ }
111
+
112
+ /**
113
+ * Dismiss an administrative notice (main site).
114
+ *
115
+ * @since 151002 Improving multisite compat.
116
+ */
117
+ public function dismissMainNotice($key_to_dismiss)
118
+ {
119
+ return $this->dismissNotice($key_to_dismiss, -1);
120
+ }
121
+
122
+ /*
123
+ * Notice display handler.
124
+ */
125
+
126
+ /**
127
+ * Render admin notices.
128
+ *
129
+ * @since 150422 Rewrite. Improved 151002.
130
+ *
131
+ * @attaches-to `all_admin_notices` hook.
132
+ */
133
+ public function allAdminNotices()
134
+ {
135
+ $notices = $enqueued_notices = $this->getNotices();
136
+ $combined_notices = []; // Initialize
137
+
138
+ foreach ($notices as $_key => $_notice) {
139
+ # Always dismiss all non-persistent transients.
140
+
141
+ if ($_notice['is_transient'] && !$_notice['persistent_key']) {
142
+ unset($notices[$_key]); // Dismiss.
143
+ }
144
+ # Current user can see this notice?
145
+
146
+ if (!current_user_can($this->cap)) {
147
+ continue; // Current user unable to see.
148
+ }
149
+ if ($_notice['cap_required'] && !current_user_can($_notice['cap_required'])) {
150
+ continue; // Current user unable to see this notice.
151
+ }
152
+ # Current URI matches a limited scope/context for this notice?
153
+
154
+ if ($_notice['only_on_uris'] && !@preg_match($_notice['only_on_uris'], $_SERVER['REQUEST_URI'])) {
155
+ continue; // Not in the right context at the moment; i.e., does not regex.
156
+ }
157
+ # If persistent, allow a site owner to dismiss.
158
+
159
+ $_dismiss = ''; // Initialize
160
+ if ($_notice['persistent_key'] && $_notice['dismissable']) { // See above. The `dismissNotice()` action requires `$this->cap` always.
161
+ $_dismiss = add_query_arg(urlencode_deep([GLOBAL_NS => ['dismissNotice' => ['key' => $_key]], '_wpnonce' => wp_create_nonce()]));
162
+ $_dismiss = '<a href="'.esc_attr($_dismiss).'"><button type="button" class="notice-dismiss"><span class="screen-reader-text">'.__('Dismiss this notice.', 'comet-cache').'</span></button></a>';
163
+ }
164
+ # Display this notice, or save for displaying compacted later. If not persistent, we can dismiss it too.
165
+
166
+ if ($_notice['combinable'] && !$_notice['persistent_key']) {
167
+ $combined_notices[] = $_notice['notice']; // Save this for displaying as part of a single, combined notice.
168
+ } else {
169
+ echo '<div class="'.esc_attr($_notice['class']).'" style="clear:both; padding-right:38px; position: relative;"><p>'.$_notice['notice'].'</p>'.$_dismiss.'</div>';
170
+ }
171
+
172
+ if (!$_notice['persistent_key']) { // If not persistent, dismiss.
173
+ unset($notices[$_key]); // Dismiss; this notice has been displayed now.
174
+ }
175
+ }
176
+ unset($_key, $_notice, $_dismiss); // Housekeeping.
177
+
178
+ if (!empty($combined_notices)) { // Display a single notice with details hidden by default.
179
+ $_line_items = ''; // Initialize
180
+ foreach ($combined_notices as $_item) {
181
+ $_line_items .= '<p><span class="dashicons dashicons-yes"></span> '.$_item.'</p>'."\n";
182
+ }
183
+
184
+ $_show_details = __('Show details.', 'comet-cache');
185
+ $_hide_details = __('Hide details.', 'comet-cache');
186
+
187
+ $_combined = '<div class="updated notice is-dismissible" style="clear:both; padding-right:38px; position: relative;">';
188
+ $_combined .= '<p><img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />';
189
+ $_combined .= sprintf(__('<strong>%1$s</strong> detected changes and intelligently cleared the cache to keep your site up-to-date. <a href="#" id="'.SLUG_TD.'-toggle-notices" onclick="jQuery(\'#'.SLUG_TD.'-combined-notices\').toggle();if (jQuery(\'#comet-cache-combined-notices\').is(\':visible\')) { jQuery(this).text(\''.$_hide_details.'\'); } else { jQuery(this).text(\''.$_show_details.'\'); }">'.$_show_details.'</a>', 'comet-cache'), esc_html(NAME)).'</p>';
190
+ $_combined .= '<div id="'.SLUG_TD.'-combined-notices" style="display: none;">'.$_line_items.'</div>';
191
+ $_combined .= '<button type="button" class="notice-dismiss"><span class="screen-reader-text">'.__('Dismiss this notice.', 'comet-cache').'</span></button>';
192
+ $_combined .= '</div>';
193
+
194
+ echo $_combined;
195
+
196
+ unset($_item, $_line_item, $_combined); // Housekeeping.
197
+ }
198
+
199
+ # Update notices if something changed above.
200
+
201
+ if ($notices !== $enqueued_notices) { // Something changed?
202
+ $this->updateNotices($notices); // Update.
203
+ }
204
+ }
205
+
206
+ /*
207
+ * Notice getter/setter.
208
+ */
209
+
210
+ /**
211
+ * Get admin notices.
212
+ *
213
+ * @since 151002 Improving multisite compat.
214
+ *
215
+ * @param int $blog_id Optional. Defaults to the current blog ID.
216
+ * Use any value `< 0` to indicate the main site.
217
+ *
218
+ * @return array All notices.
219
+ */
220
+ public function getNotices($blog_id = 0)
221
+ {
222
+ if (is_multisite()) {
223
+ if (!($blog_id = (integer) $blog_id)) {
224
+ $blog_id = (integer) get_current_blog_id();
225
+ }
226
+ if ($blog_id < 0) { // Blog for main site.
227
+ $blog_id = (integer) get_current_site()->blog_id;
228
+ }
229
+ $blog_suffix = '_'.$blog_id; // Site option suffix.
230
+ $notices = get_site_option(GLOBAL_NS.$blog_suffix.'_notices');
231
+ } else {
232
+ $notices = get_site_option(GLOBAL_NS.'_notices');
233
+ }
234
+ if (!is_array($notices)) {
235
+ $notices = []; // Force array.
236
+ // Prevent multiple DB queries by adding this key.
237
+ $this->updateNotices($notices, $blog_id);
238
+ }
239
+ foreach ($notices as $_key => &$_notice) {
240
+ if (!is_string($_key) || !is_array($_notice) || empty($_notice['notice'])) {
241
+ unset($notices[$_key]); // Old notice.
242
+ continue; // Bypass; i.e., do not normalize.
243
+ }
244
+ $_notice = $this->normalizeNotice($_notice);
245
+ } // ↑ Typecast/normalized each of the array elements.
246
+ unset($_key, $_notice); // Housekeeping.
247
+
248
+ return $notices;
249
+ }
250
+
251
+ /**
252
+ * Update admin notices.
253
+ *
254
+ * @since 151002 Improving multisite compat.
255
+ *
256
+ * @param array $notices New array of notices.
257
+ * @param int $blog_id Optional. Defaults to the current blog ID.
258
+ * Use any value `< 0` to indicate the main site.
259
+ *
260
+ * @return array All notices.
261
+ */
262
+ public function updateNotices(array $notices, $blog_id = 0)
263
+ {
264
+ if (is_multisite()) {
265
+ if (!($blog_id = (integer) $blog_id)) {
266
+ $blog_id = (integer) get_current_blog_id();
267
+ }
268
+ if ($blog_id < 0) { // Blog for main site.
269
+ $blog_id = (integer) get_current_site()->blog_id;
270
+ }
271
+ $blog_suffix = '_'.$blog_id; // Site option suffix.
272
+ update_site_option(GLOBAL_NS.$blog_suffix.'_notices', $notices);
273
+ } else {
274
+ update_site_option(GLOBAL_NS.'_notices', $notices);
275
+ }
276
+ return $notices;
277
+ }
278
+
279
+ /*
280
+ * Notice property utilities.
281
+ */
282
+
283
+ /**
284
+ * Normalize notice elements.
285
+ *
286
+ * @since 151002 Improving multisite compat.
287
+ *
288
+ * @param array $notice Notice array elements.
289
+ * @param array $args Any additional array elements.
290
+ *
291
+ * @return array Normalized notice array elements.
292
+ */
293
+ public function normalizeNotice(array $notice, array $args = [])
294
+ {
295
+ $notice_defaults = [
296
+ 'notice' => '',
297
+ 'only_on_uris' => '',
298
+ 'persistent_key' => '',
299
+ 'combinable' => false,
300
+ 'dismissable' => true,
301
+ 'is_transient' => true,
302
+ 'push_to_top' => false,
303
+ 'class' => 'updated',
304
+ 'cap_required' => '', // `$this->cap` always.
305
+ // i.e., this cap is in addition to `$this->cap`.
306
+ ];
307
+ $notice = array_merge($notice_defaults, $notice, $args);
308
+ $notice = array_intersect_key($notice, $notice_defaults);
309
+
310
+ foreach ($notice as $_key => &$_value) {
311
+ switch ($_key) {
312
+ case 'notice':
313
+ case 'only_on_uris':
314
+ case 'persistent_key':
315
+ $_value = trim((string) $_value);
316
+ break; // Stop here.
317
+
318
+ case 'is_transient':
319
+ case 'push_to_top':
320
+ case 'combinable':
321
+ case 'dismissable':
322
+ $_value = (boolean) $_value;
323
+ break; // Stop here.
324
+
325
+ case 'class':
326
+ case 'cap_required':
327
+ $_value = trim((string) $_value);
328
+ break; // Stop here.
329
+ }
330
+ } // ↑ Typecast each of the array elements.
331
+ unset($_key, $_value); // A little housekeeping.
332
+
333
+ ksort($notice); // For more accurate comparison in other routines.
334
+
335
+ return $notice; // Normalized.
336
+ }
337
+ }
src/includes/traits/Plugin/OptionUtils.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait OptionUtils
7
+ {
8
+ /**
9
+ * Get plugin options.
10
+ *
11
+ * @since 151002 Improving multisite compat.
12
+ *
13
+ * @return array Plugin options.
14
+ */
15
+ public function getOptions()
16
+ {
17
+ if (!($options = $this->options)) { // Not defined yet?
18
+ if (!is_array($options = get_site_option(GLOBAL_NS.'_options'))) {
19
+ $options = []; // Force array.
20
+ }
21
+ if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) {
22
+ $options = $zencache_options; // Old ZenCache options.
23
+ $options['crons_setup'] = $this->default_options['crons_setup'];
24
+ $options['latest_lite_version'] = $this->default_options['latest_lite_version'];
25
+ $options['latest_pro_version'] = $this->default_options['latest_pro_version'];
26
+ }
27
+ }
28
+ $this->options = array_merge($this->default_options, $options);
29
+ $this->options = $this->applyWpFilters(GLOBAL_NS.'_options', $this->options);
30
+ $this->options = array_intersect_key($this->options, $this->default_options);
31
+
32
+ foreach ($this->options as $_key => &$_value) {
33
+ $_value = trim((string) $_value); // Force strings.
34
+ }
35
+ unset($_key, $_value); // Housekeeping.
36
+
37
+ $this->options['base_dir'] = trim($this->options['base_dir'], '\\/'." \t\n\r\0\x0B");
38
+ if (!$this->options['base_dir'] || strpos(basename($this->options['base_dir']), 'wp-') === 0) {
39
+ $this->options['base_dir'] = $this->default_options['base_dir'];
40
+ }
41
+ return $this->options; // Plugin options.
42
+ }
43
+
44
+ /**
45
+ * Update plugin options.
46
+ *
47
+ * @since 151002 Improving multisite compat.
48
+ *
49
+ * @param array $options One or more new options.
50
+ *
51
+ * @return array Plugin options after update.
52
+ */
53
+ public function updateOptions(array $options)
54
+ {
55
+ if (!IS_PRO) { // Do not save Pro option keys.
56
+ $options = array_diff_key($options, $this->pro_only_option_keys);
57
+ }
58
+ if (!empty($options['base_dir']) && $options['base_dir'] !== $this->options['base_dir']) {
59
+ $this->tryErasingAllFilesDirsIn($this->wpContentBaseDirTo(''));
60
+ }
61
+ $this->options = array_merge($this->default_options, $this->options, $options);
62
+ $this->options = array_intersect_key($this->options, $this->default_options);
63
+ update_site_option(GLOBAL_NS.'_options', $this->options);
64
+
65
+ return $this->getOptions();
66
+ }
67
+
68
+ /**
69
+ * Restore default plugin options.
70
+ *
71
+ * @since 151002 Improving multisite compat.
72
+ *
73
+ * @return array Plugin options after update.
74
+ */
75
+ public function restoreDefaultOptions()
76
+ {
77
+ delete_site_option(GLOBAL_NS.'_options'); // Force restore.
78
+ $this->options = $this->default_options; // In real-time.
79
+ return $this->getOptions();
80
+ }
81
+ }
src/includes/traits/Plugin/PostUtils.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait PostUtils
7
+ {
8
+ /**
9
+ * All post statuses.
10
+ *
11
+ * @since 150821 Improving bbPress support.
12
+ *
13
+ * @return array All post statuses.
14
+ */
15
+ public function postStatuses()
16
+ {
17
+ if (!is_null($statuses = &$this->cacheKey('postStatuses'))) {
18
+ return $statuses; // Already did this.
19
+ }
20
+ $statuses = get_post_stati();
21
+ $statuses = array_keys($statuses);
22
+
23
+ return $statuses;
24
+ }
25
+
26
+ /**
27
+ * All built-in post statuses.
28
+ *
29
+ * @since 150821 Improving bbPress support.
30
+ *
31
+ * @return array All built-in post statuses.
32
+ */
33
+ public function builtInPostStatuses()
34
+ {
35
+ if (!is_null($statuses = &$this->cacheKey('builtInPostStatuses'))) {
36
+ return $statuses; // Already did this.
37
+ }
38
+ $statuses = []; // Initialize.
39
+
40
+ foreach (get_post_stati([], 'objects') as $_key => $_status) {
41
+ if (!empty($_status->_builtin)) {
42
+ $statuses[] = $_status->name;
43
+ }
44
+ }
45
+ unset($_key, $_status); // Housekeeping.
46
+
47
+ return $statuses;
48
+ }
49
+ }
src/includes/traits/Plugin/UpdateUtils.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait UpdateUtils
7
+ {
8
+ /**
9
+ * Checks for a new lite release.
10
+ *
11
+ * @since 151220 Show version number in plugin options.
12
+ *
13
+ * @attaches-to `admin_init` hook.
14
+ */
15
+ public function maybeCheckLatestLiteVersion()
16
+ {
17
+ if (IS_PRO) {
18
+ return; // Not applicable.
19
+ }
20
+ if (!$this->options['lite_update_check']) {
21
+ return; // Nothing to do.
22
+ }
23
+ if (!current_user_can($this->update_cap)) {
24
+ return; // Nothing to do.
25
+ }
26
+ if (is_multisite() && !current_user_can($this->network_cap)) {
27
+ return; // Nothing to do.
28
+ }
29
+ if ($this->options['last_lite_update_check'] >= strtotime('-1 hour')) {
30
+ return; // No reason to keep checking on this.
31
+ }
32
+ $this->updateOptions(['last_lite_update_check' => time()]);
33
+
34
+ $product_api_url = 'https://'.urlencode(DOMAIN).'/';
35
+ $product_api_input_vars = ['product_api' => ['action' => 'latest_lite_version']];
36
+
37
+ $product_api_response = wp_remote_post($product_api_url, ['body' => $product_api_input_vars]);
38
+ $product_api_response = json_decode(wp_remote_retrieve_body($product_api_response));
39
+
40
+ if (is_object($product_api_response) && !empty($product_api_response->lite_version)) {
41
+ $this->updateOptions(['latest_lite_version' => $product_api_response->lite_version]);
42
+ }
43
+ // Disabling the notice for now. We only run this check to collect the latest version number.
44
+ #if ($this->options['latest_lite_version'] && version_compare(VERSION, $this->options['latest_lite_version'], '<')) {
45
+ # $this->dismissMainNotice('new-lite-version-available'); // Dismiss any existing notices like this.
46
+ # $lite_updater_page = network_admin_url('/plugins.php'); // In a network this points to the master plugins list.
47
+ # $this->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> a new version is now available. Please <a href="%2$s">upgrade to v%3$s</a>.', 'comet-cache'), esc_html(NAME), esc_attr($lite_updater_page), esc_html($this->options['latest_lite_version'])), array('persistent_key' => 'new-lite-version-available'));
48
+ #}
49
+ }
50
+
51
+
52
+ }
src/includes/traits/Plugin/UrlUtils.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait UrlUtils
7
+ {
8
+ /**
9
+ * URL to a Comet Cache plugin file.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $file Optional file path; relative to plugin directory.
14
+ * @param string $scheme Optional URL scheme; defaults to the current scheme.
15
+ *
16
+ * @return string URL to plugin directory; or to the specified `$file` if applicable.
17
+ */
18
+ public function url($file = '', $scheme = '')
19
+ {
20
+ $url = rtrim(plugin_dir_url(PLUGIN_FILE), '/');
21
+ $url .= (string) $file;
22
+
23
+ if ($scheme) {
24
+ $url = set_url_scheme($url, (string) $scheme);
25
+ }
26
+ return $url;
27
+ }
28
+
29
+ /**
30
+ * Retrieves the home URL for a given site preserving the home URL scheme.
31
+ *
32
+ * @since 160416 Improving Auto-Cache Engine Sitemap routines.
33
+ *
34
+ * @param int $blog_id (Optional) Blog ID. Default null (current blog).
35
+ *
36
+ * @return string $url Home URL link with Home URL scheme preserved.
37
+ */
38
+ public function getHomeUrlWithHomeScheme($blog_id = null)
39
+ {
40
+ if (empty($blog_id) || !is_multisite()) {
41
+ $url = get_option('home');
42
+ } else {
43
+ switch_to_blog($blog_id);
44
+ $url = get_option('home');
45
+ restore_current_blog();
46
+ }
47
+
48
+ $url = set_url_scheme($url, parse_url($url, PHP_URL_SCHEME));
49
+
50
+ return $url;
51
+ }
52
+ }
src/includes/traits/Plugin/UserUtils.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait UserUtils
7
+ {
8
+ /**
9
+ * Current user can clear the cache?
10
+ *
11
+ * @since 151002 Enhancing user permissions.
12
+ *
13
+ * @return bool Current user can clear the cache?
14
+ */
15
+ public function currentUserCanClearCache()
16
+ {
17
+ if (!is_null($can = &$this->cacheKey('currentUserCanClearCache'))) {
18
+ return $can; // Already cached this.
19
+ }
20
+ $is_multisite = is_multisite();
21
+
22
+ if (!$is_multisite && current_user_can($this->cap)) {
23
+ return $can = true; // Plugin admin.
24
+ }
25
+ if ($is_multisite && current_user_can($this->network_cap)) {
26
+ return $can = true; // Plugin admin.
27
+ }
28
+
29
+ return $can = false;
30
+ }
31
+
32
+ /**
33
+ * Alias for currentUserCanClearCache().
34
+ *
35
+ * @since 151002 Enhancing user permissions.
36
+ *
37
+ * @return bool Current user can clear the cache?
38
+ */
39
+ public function currentUserCanWipeCache()
40
+ {
41
+ return call_user_func_array([$this, 'currentUserCanClearCache'], func_get_args());
42
+ }
43
+
44
+ /**
45
+ * Current user can clear the opcache?
46
+ *
47
+ * @since 151114 Enhancing user permissions.
48
+ *
49
+ * @return bool Current user can clear the opcache?
50
+ */
51
+ public function currentUserCanClearOpCache()
52
+ {
53
+ if (!is_null($can = &$this->cacheKey('currentUserCanClearOpCache'))) {
54
+ return $can; // Already cached this.
55
+ }
56
+ $is_multisite = is_multisite();
57
+
58
+ if (!$is_multisite && current_user_can($this->cap)) {
59
+ return $can = true; // Plugin admin.
60
+ }
61
+ if ($is_multisite && current_user_can($this->network_cap)) {
62
+ return $can = true; // Plugin admin.
63
+ }
64
+ return $can = false;
65
+ }
66
+
67
+ /**
68
+ * Alias for currentUserCanClearOpCache().
69
+ *
70
+ * @since 151114 Enhancing user permissions.
71
+ *
72
+ * @return bool Current user can clear the opcache?
73
+ */
74
+ public function currentUserCanWipeOpCache()
75
+ {
76
+ return call_user_func_array([$this, 'currentUserCanClearOpCache'], func_get_args());
77
+ }
78
+
79
+ /**
80
+ * Current user can clear the CDN cache?
81
+ *
82
+ * @since 151114 Enhancing user permissions.
83
+ *
84
+ * @return bool Current user can clear the CDN cache?
85
+ */
86
+ public function currentUserCanClearCdnCache()
87
+ {
88
+ if (!is_null($can = &$this->cacheKey('currentUserCanClearCdnCache'))) {
89
+ return $can; // Already cached this.
90
+ }
91
+ $is_multisite = is_multisite();
92
+
93
+ if (!$is_multisite && current_user_can($this->cap)) {
94
+ return $can = true; // Plugin admin.
95
+ }
96
+ if ($is_multisite && current_user_can($this->network_cap)) {
97
+ return $can = true; // Plugin admin.
98
+ }
99
+ return $can = false;
100
+ }
101
+
102
+ /**
103
+ * Alias for currentUserCanClearCdnCache().
104
+ *
105
+ * @since 151114 Enhancing user permissions.
106
+ *
107
+ * @return bool Current user can clear the CDN cache?
108
+ */
109
+ public function currentUserCanWipeCdnCache()
110
+ {
111
+ return call_user_func_array([$this, 'currentUserCanClearCdnCache'], func_get_args());
112
+ }
113
+
114
+ /**
115
+ * Current user can clear expired transients?
116
+ *
117
+ * @since 151220 Enhancing user permissions.
118
+ *
119
+ * @return bool Current user can clear expired transients?
120
+ */
121
+ public function currentUserCanClearExpiredTransients()
122
+ {
123
+ if (!is_null($can = &$this->cacheKey('currentUserCanClearExpiredTransients'))) {
124
+ return $can; // Already cached this.
125
+ }
126
+ $is_multisite = is_multisite();
127
+
128
+ if (!$is_multisite && current_user_can($this->cap)) {
129
+ return $can = true; // Plugin admin.
130
+ }
131
+ if ($is_multisite && current_user_can($this->network_cap)) {
132
+ return $can = true; // Plugin admin.
133
+ }
134
+ return $can = false;
135
+ }
136
+
137
+ /**
138
+ * Alias for currentUserCanClearExpiredTransients().
139
+ *
140
+ * @since 151220 Enhancing user permissions.
141
+ *
142
+ * @return bool Current user can clear expired transients?
143
+ */
144
+ public function currentUserCanWipeExpiredTransients()
145
+ {
146
+ return call_user_func_array([$this, 'currentUserCanClearExpiredTransients'], func_get_args());
147
+ }
148
+
149
+ /**
150
+ * Current user can see stats?
151
+ *
152
+ * @since 151002 Enhancing user permissions.
153
+ *
154
+ * @return bool Current user can see stats?
155
+ */
156
+ public function currentUserCanSeeStats()
157
+ {
158
+ if (!is_null($can = &$this->cacheKey('currentUserCanSeeStats'))) {
159
+ return $can; // Already cached this.
160
+ }
161
+ $is_multisite = is_multisite();
162
+
163
+ if (!$is_multisite && current_user_can($this->cap)) {
164
+ return $can = true; // Plugin admin.
165
+ }
166
+ if ($is_multisite && current_user_can($this->network_cap)) {
167
+ return $can = true; // Plugin admin.
168
+ }
169
+
170
+ return $can = false;
171
+ }
172
+ }
src/includes/traits/Plugin/WcpAuthorUtils.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpAuthorUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for the author page(s).
10
+ *
11
+ * @attaches-to `post_updated` hook.
12
+ *
13
+ * @since 150422 Rewrite.
14
+ *
15
+ * @param int $post_id A WordPress post ID.
16
+ * @param \WP_Post $post_after WP_Post object following the update.
17
+ * @param \WP_Post $post_before WP_Post object before the update.
18
+ *
19
+ * @throws \Exception If a clear failure occurs.
20
+ *
21
+ * @return int Total files cleared by this routine (if any).
22
+ *
23
+ * @note If the author for the post is being changed, both the previous author
24
+ * and current author pages are cleared, if the post status is applicable.
25
+ */
26
+ public function autoClearAuthorPageCache($post_id, \WP_Post $post_after, \WP_Post $post_before)
27
+ {
28
+ $counter = 0; // Initialize.
29
+ $enqueued_notices = 0; // Initialize.
30
+ $authors = []; // Initialize.
31
+ $authors_to_clear = []; // Initialize.
32
+
33
+ if (!($post_id = (integer) $post_id)) {
34
+ return $counter; // Nothing to do.
35
+ }
36
+ if (!is_null($done = &$this->cacheKey('autoClearAuthorPageCache', [$post_id, $post_after->ID, $post_before->ID]))) {
37
+ return $counter; // Already did this.
38
+ }
39
+ $done = true; // Flag as having been done.
40
+
41
+ if (!$this->options['enable']) {
42
+ return $counter; // Nothing to do.
43
+ }
44
+ if (!$this->options['cache_clear_author_page_enable']) {
45
+ return $counter; // Nothing to do.
46
+ }
47
+ if (!is_dir($cache_dir = $this->cacheDir())) {
48
+ return $counter; // Nothing to do.
49
+ }
50
+ /*
51
+ * If we're changing the post author AND
52
+ * the previous post status was either 'published' or 'private'
53
+ * then clear the author page for both authors.
54
+ *
55
+ * Else if the old post status was 'published' or 'private' OR
56
+ * the new post status is 'published' or 'private'
57
+ * then clear the author page for the current author.
58
+ *
59
+ * Else return the counter; post status does not warrant clearing author page cache.
60
+ */
61
+ if ($post_after->post_author !== $post_before->post_author &&
62
+ ($post_before->post_status === 'publish' || $post_before->post_status === 'private')
63
+ ) {
64
+ $authors[] = (integer) $post_before->post_author;
65
+ $authors[] = (integer) $post_after->post_author;
66
+ } elseif (($post_before->post_status === 'publish' || $post_before->post_status === 'private') ||
67
+ ($post_after->post_status === 'publish' || $post_after->post_status === 'private')
68
+ ) {
69
+ $authors[] = (integer) $post_after->post_author;
70
+ }
71
+ if (!$authors) {
72
+ return $counter; // Nothing to do.
73
+ }
74
+ foreach ($authors as $_author_id) {
75
+ $authors_to_clear[$_author_id]['posts_url'] = get_author_posts_url($_author_id);
76
+ $authors_to_clear[$_author_id]['display_name'] = get_the_author_meta('display_name', $_author_id);
77
+ }
78
+ unset($_author_id); // Housekeeping.
79
+
80
+ foreach ($authors_to_clear as $_author) {
81
+ $_author_regex = $this->buildHostCachePathRegex($_author['posts_url']);
82
+ $_author_counter = $this->clearFilesFromHostCacheDir($_author_regex);
83
+ $counter += $_author_counter; // Add to overall counter.
84
+
85
+ if ($_author_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
86
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for Author Page: <code>%2$s</code>; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($_author_counter)), esc_html($_author['display_name'])), ['combinable' => true]);
87
+ ++$enqueued_notices; // Increment enqueued notices counter.
88
+ }
89
+ }
90
+ unset($_author, $_author_regex, $_author_counter); // Housekeeping.
91
+
92
+ $counter += $this->autoClearXmlFeedsCache('blog');
93
+ $counter += $this->autoClearXmlFeedsCache('post-authors', $post_id);
94
+
95
+ return $counter;
96
+ }
97
+ }
src/includes/traits/Plugin/WcpCommentUtils.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpCommentUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for a post associated with a particular comment.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `trackback_post` hook.
14
+ * @attaches-to `pingback_post` hook.
15
+ * @attaches-to `comment_post` hook.
16
+ *
17
+ * @param int $comment_id A WordPress comment ID.
18
+ *
19
+ * @return int Total files cleared by this routine (if any).
20
+ */
21
+ public function autoClearCommentPostCache($comment_id)
22
+ {
23
+ $counter = 0; // Initialize.
24
+
25
+ if (!($comment_id = (integer) $comment_id)) {
26
+ return $counter; // Nothing to do.
27
+ }
28
+ if (!is_null($done = &$this->cacheKey('autoClearCommentPostCache', $comment_id))) {
29
+ return $counter; // Already did this.
30
+ }
31
+ $done = true; // Flag as having been done.
32
+
33
+ if (!$this->options['enable']) {
34
+ return $counter; // Nothing to do.
35
+ }
36
+ if (!is_object($comment = get_comment($comment_id))) {
37
+ return $counter; // Nothing we can do.
38
+ }
39
+ if (empty($comment->comment_post_ID)) {
40
+ return $counter; // Nothing we can do.
41
+ }
42
+ if ($comment->comment_approved === 'spam' || $comment->comment_approved === '0') {
43
+ // Don't allow next `autoClearPostCache()` call to clear post cache.
44
+ $allow = &$this->cacheKey('autoClearPostCache_allow');
45
+ $allow = false; // Flag as false; i.e., disallow.
46
+ return $counter;
47
+ }
48
+ $counter += $this->autoClearXmlFeedsCache('blog-comments');
49
+ $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
50
+ $counter += $this->autoClearPostCache($comment->comment_post_ID);
51
+
52
+ return $counter;
53
+ }
54
+
55
+ /**
56
+ * Automatically clears cache files for a post associated with a particular comment.
57
+ *
58
+ * @since 150422 Rewrite.
59
+ *
60
+ * @attaches-to `transition_comment_status` hook.
61
+ *
62
+ * @param string $new_status New comment status.
63
+ * @param string $old_status Old comment status.
64
+ * @param \stdClass $comment Comment object.
65
+ *
66
+ * @throws \Exception If a clear failure occurs.
67
+ *
68
+ * @return int Total files cleared by this routine (if any).
69
+ *
70
+ * @note This is also called upon by other routines which listen for
71
+ * events that are indirectly associated with a comment ID.
72
+ */
73
+ public function autoClearCommentPostCacheTransition($new_status, $old_status, $comment)
74
+ {
75
+ $counter = 0; // Initialize.
76
+
77
+ if (!is_object($comment)) {
78
+ return $counter; // Nothing we can do.
79
+ }
80
+ if (empty($comment->comment_post_ID)) {
81
+ return $counter; // Nothing we can do.
82
+ }
83
+ if (!is_null($done = &$this->cacheKey('autoClearCommentPostCacheTransition', [$new_status, $old_status, $comment->comment_post_ID]))) {
84
+ return $counter; // Already did this.
85
+ }
86
+ $done = true; // Flag as having been done.
87
+
88
+ if (!$this->options['enable']) {
89
+ return $counter; // Nothing to do.
90
+ }
91
+ if (!($old_status === 'approved' || ($old_status === 'unapproved' && $new_status === 'approved'))) {
92
+ // If excluded here, don't allow next `autoClearPostCache()` call to clear post cache.
93
+ $allow = &$this->cacheKey('autoClearPostCache_allow');
94
+ $allow = false; // Flag as false; i.e., disallow.
95
+ return $counter;
96
+ }
97
+ $counter += $this->autoClearXmlFeedsCache('blog-comments');
98
+ $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
99
+ $counter += $this->autoClearPostCache($comment->comment_post_ID);
100
+
101
+ return $counter;
102
+ }
103
+ }
src/includes/traits/Plugin/WcpFeedUtils.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpFeedUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files related to XML feeds.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $type Type of feed(s) to auto-clear.
14
+ * @param int $post_id A Post ID (when applicable).
15
+ *
16
+ * @throws \Exception If a clear failure occurs.
17
+ *
18
+ * @return int Total files cleared by this routine (if any).
19
+ *
20
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently
21
+ * attached to any hooks. However, it is called upon by other routines attached to hooks.
22
+ */
23
+ public function autoClearXmlFeedsCache($type, $post_id = 0)
24
+ {
25
+ $counter = 0; // Initialize.
26
+
27
+ if (!($type = (string) $type)) {
28
+ return $counter; // Nothing we can do.
29
+ }
30
+ $post_id = (integer) $post_id; // Force integer.
31
+
32
+ if (!is_null($done = &$this->cacheKey('autoClearXmlFeedsCache', [$type, $post_id]))) {
33
+ return $counter; // Already did this.
34
+ }
35
+ $done = true; // Flag as having been done.
36
+
37
+ if (!$this->options['enable']) {
38
+ return $counter; // Nothing to do.
39
+ }
40
+ if (!$this->options['feeds_enable']) {
41
+ return $counter; // Nothing to do.
42
+ }
43
+ if (!$this->options['cache_clear_xml_feeds_enable']) {
44
+ return $counter; // Nothing to do.
45
+ }
46
+ if (!is_dir($cache_dir = $this->cacheDir())) {
47
+ return $counter; // Nothing to do.
48
+ }
49
+ $utils = new Classes\FeedUtils(); // Feed utilities.
50
+ $variations = $variation_regex_frags = []; // Initialize.
51
+
52
+ switch ($type) { // Handle clearing based on the `$type`.
53
+
54
+ case 'blog': // The blog feed; i.e. `/feed/` on most WP installs.
55
+ $variations = array_merge($variations, $utils->feedLinkVariations());
56
+ break; // Break switch handler.
57
+
58
+ case 'blog-comments': // The blog comments feed; i.e. `/comments/feed/` on most WP installs.
59
+ $variations = array_merge($variations, $utils->feedLinkVariations('comments_'));
60
+ break; // Break switch handler.
61
+
62
+ case 'post-comments': // Feeds related to comments that a post has.
63
+ if (!$post_id) {
64
+ break; // Break switch handler.
65
+ }
66
+ if (!($post = get_post($post_id))) {
67
+ break; // Break switch handler.
68
+ }
69
+ $variations = array_merge($variations, $utils->postCommentsFeedLinkVariations($post));
70
+ break; // Break switch handler.
71
+
72
+ case 'post-authors': // Feeds related to authors that a post has.
73
+ if (!$post_id) {
74
+ break; // Break switch handler.
75
+ }
76
+ if (!($post = get_post($post_id))) {
77
+ break; // Break switch handler.
78
+ }
79
+ $variations = array_merge($variations, $utils->postAuthorFeedLinkVariations($post));
80
+ break; // Break switch handler.
81
+
82
+ case 'post-terms': // Feeds related to terms that a post has.
83
+ if (!$post_id) {
84
+ break; // Break switch handler.
85
+ }
86
+ if (!($post = get_post($post_id))) {
87
+ break; // Break switch handler.
88
+ }
89
+ $variations = array_merge($variations, $utils->postTermFeedLinkVariations($post, true));
90
+ break; // Break switch handler.
91
+
92
+ case 'custom-post-type': // Feeds related to a custom post type archive view.
93
+ if (!$post_id) {
94
+ break; // Break switch handler.
95
+ }
96
+ if (!($post = get_post($post_id))) {
97
+ break; // Break switch handler.
98
+ }
99
+ $variations = array_merge($variations, $utils->postTypeArchiveFeedLinkVariations($post));
100
+ break; // Break switch handler.
101
+
102
+ // @TODO Possibly consider search-related feeds in the future.
103
+ // See: <http://codex.wordpress.org/WordPress_Feeds#Categories_and_Tags>
104
+ }
105
+ if (!($variation_regex_frags = $utils->convertVariationsToHostCachePathRegexFrags($variations))) {
106
+ return $counter; // Nothing to do here.
107
+ }
108
+ $in_sets_of = $this->applyWpFilters(GLOBAL_NS.'_autoClearXmlFeedsCache_in_sets_of', 10, get_defined_vars());
109
+ for ($_i = 0; $_i < count($variation_regex_frags); $_i = $_i + $in_sets_of) {
110
+ $_variation_regex_frags = array_slice($variation_regex_frags, $_i, $in_sets_of);
111
+ $_regex = '/^\/(?:'.implode('|', $_variation_regex_frags).')\./i';
112
+ $counter += $this->clearFilesFromHostCacheDir($_regex);
113
+ }
114
+ unset($_i, $_variation_regex_frags, $_regex); // Housekeeping.
115
+
116
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
117
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache, for XML feeds of type: <code>%2$s</code>; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter)), esc_html($type)), ['combinable' => true]);
118
+ }
119
+ return $counter;
120
+ }
121
+ }
src/includes/traits/Plugin/WcpHomeBlogUtils.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpHomeBlogUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for the home page.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @throws \Exception If a clear failure occurs.
14
+ *
15
+ * @return int Total files cleared by this routine (if any).
16
+ *
17
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently
18
+ * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
19
+ */
20
+ public function autoClearHomePageCache()
21
+ {
22
+ $counter = 0; // Initialize.
23
+
24
+ if (!is_null($done = &$this->cacheKey('autoClearHomePageCache'))) {
25
+ return $counter; // Already did this.
26
+ }
27
+ $done = true; // Flag as having been done.
28
+
29
+ if (!$this->options['enable']) {
30
+ return $counter; // Nothing to do.
31
+ }
32
+ if (!$this->options['cache_clear_home_page_enable']) {
33
+ return $counter; // Nothing to do.
34
+ }
35
+ if (!is_dir($cache_dir = $this->cacheDir())) {
36
+ return $counter; // Nothing to do.
37
+ }
38
+ $regex = $this->buildHostCachePathRegex(home_url('/'));
39
+ $counter += $this->clearFilesFromHostCacheDir($regex);
40
+
41
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
42
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Home Page"; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
43
+ }
44
+ $counter += $this->autoClearXmlFeedsCache('blog');
45
+
46
+ return $counter;
47
+ }
48
+
49
+ /**
50
+ * Automatically clears cache files for the posts page.
51
+ *
52
+ * @since 150422 Rewrite.
53
+ *
54
+ * @throws \Exception If a clear failure occurs.
55
+ *
56
+ * @return int Total files cleared by this routine (if any).
57
+ *
58
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently
59
+ * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
60
+ */
61
+ public function autoClearPostsPageCache()
62
+ {
63
+ $counter = 0; // Initialize.
64
+
65
+ if (!is_null($done = &$this->cacheKey('autoClearPostsPageCache'))) {
66
+ return $counter; // Already did this.
67
+ }
68
+ $done = true; // Flag as having been done.
69
+
70
+ if (!$this->options['enable']) {
71
+ return $counter; // Nothing to do.
72
+ }
73
+ if (!$this->options['cache_clear_posts_page_enable']) {
74
+ return $counter; // Nothing to do.
75
+ }
76
+ if (!is_dir($cache_dir = $this->cacheDir())) {
77
+ return $counter; // Nothing to do.
78
+ }
79
+ $show_on_front = get_option('show_on_front');
80
+ $page_for_posts = get_option('page_for_posts');
81
+
82
+ if (!in_array($show_on_front, ['posts', 'page'], true)) {
83
+ return $counter; // Nothing we can do in this case.
84
+ }
85
+ if ($show_on_front === 'page' && !$page_for_posts) {
86
+ return $counter; // Nothing we can do.
87
+ }
88
+ if ($show_on_front === 'posts') {
89
+ $posts_page = home_url('/');
90
+ } elseif ($show_on_front === 'page') {
91
+ $posts_page = get_permalink($page_for_posts);
92
+ }
93
+ if (empty($posts_page)) {
94
+ return $counter; // Nothing we can do.
95
+ }
96
+ $regex = $this->buildHostCachePathRegex($posts_page);
97
+ $counter += $this->clearFilesFromHostCacheDir($regex);
98
+
99
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
100
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Posts Page"; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
101
+ }
102
+ $counter += $this->autoClearXmlFeedsCache('blog');
103
+
104
+ return $counter;
105
+ }
106
+ }
src/includes/traits/Plugin/WcpJetpackUtils.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpJetpackUtils
7
+ {
8
+ /**
9
+ * Automatically clears all cache files for current blog when JetPack Custom CSS is saved.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `safecss_save_pre` hook.
14
+ *
15
+ * @param array $args Args passed in by hook.
16
+ */
17
+ public function autoClearCacheOnJetpackCustomCss($args)
18
+ {
19
+ $counter = 0; // Initialize.
20
+
21
+ if (!is_null($done = &$this->cacheKey('autoClearCacheOnJetpackCustomCss', $args))) {
22
+ return $counter; // Already did this.
23
+ }
24
+ $done = true; // Flag as having been done.
25
+
26
+ if (empty($args['is_preview']) && class_exists('\\Jetpack')) {
27
+ $counter += $this->autoClearCache();
28
+ }
29
+ }
30
+ }
src/includes/traits/Plugin/WcpOpcacheUtils.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpOpcacheUtils
7
+ {
8
+ /**
9
+ * Wipe (i.e., reset) OPCache.
10
+ *
11
+ * @since 151002 Adding OPCache support.
12
+ *
13
+ * @param bool $manually True if wiping is done manually.
14
+ * @param bool $maybe Defaults to a true value.
15
+ * @param array $files Optional; wipe only specific files?
16
+ *
17
+ * @return int Total keys wiped.
18
+ */
19
+ public function wipeOpcache($manually = false, $maybe = true, $files = [])
20
+ {
21
+ $counter = 0; // Initialize counter.
22
+
23
+ if ($maybe && !$this->options['cache_clear_opcache_enable']) {
24
+ return $counter; // Not enabled at this time.
25
+ }
26
+ if (!$this->functionIsPossible('opcache_reset')) {
27
+ return $counter; // Not possible.
28
+ }
29
+ if (!($status = $this->sysOpcacheStatus())) {
30
+ return $counter; // Not possible.
31
+ }
32
+ if (empty($status->opcache_enabled)) {
33
+ return $counter; // Not necessary.
34
+ }
35
+ if (empty($status->opcache_statistics->num_cached_keys)) {
36
+ return $counter; // Not possible.
37
+ }
38
+ if ($files) { // Specific files?
39
+ foreach ($files as $_file) {
40
+ $counter += (int) opcache_invalidate($_file, true);
41
+ } // unset($_file); // Housekeeping.
42
+ } elseif (opcache_reset()) { // True if a reset occurs.
43
+ $counter += $status->opcache_statistics->num_cached_keys;
44
+ }
45
+ return $counter;
46
+ }
47
+
48
+ /**
49
+ * Clear (i.e., reset) OPCache.
50
+ *
51
+ * @since 151002 Adding OPCache support.
52
+ *
53
+ * @param bool $manually True if clearing is done manually.
54
+ * @param bool $maybe Defaults to a true value.
55
+ *
56
+ * @return int Total keys cleared.
57
+ */
58
+ public function clearOpcache($manually = false, $maybe = true)
59
+ {
60
+ if (!is_multisite() || is_main_site() || current_user_can($this->network_cap)) {
61
+ return $this->wipeOpcache($manually, $maybe);
62
+ }
63
+ return 0; // Not applicable.
64
+ }
65
+
66
+ /**
67
+ * Clear AC class file from Opcache (by force).
68
+ *
69
+ * @since 151215 Adding OPCache support.
70
+ *
71
+ * @return int Total keys cleared.
72
+ */
73
+ public function clearAcDropinFromOpcacheByForce()
74
+ {
75
+ return $this->wipeOpcache(false, false, [WP_CONTENT_DIR.'/advanced-cache.php']);
76
+ }
77
+ }
src/includes/traits/Plugin/WcpPluginUtils.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpPluginUtils
7
+ {
8
+ /**
9
+ * Automatically wipes/clears on plugin activation/deactivation.
10
+ *
11
+ * @since 151220 Adding auto-wipe|clear on plugin activations/deactivations.
12
+ *
13
+ * @attaches-to `activated_plugin` hook.
14
+ * @attaches-to `deactivated_plugin` hook.
15
+ *
16
+ * @param string $plugin Plugin basename.
17
+ * @param bool True if activating|deactivating network-wide. Defaults to boolean `FALSE` in case parameter is not passed to hook.
18
+ *
19
+ * @return int Total files wiped|cleared by this routine (if any).
20
+ */
21
+ public function autoClearOnPluginActivationDeactivation($plugin, $network_wide = false)
22
+ {
23
+ if (!$this->applyWpFilters(GLOBAL_NS.'_auto_clear_on_plugin_activation_deactivation', true)) {
24
+ return 0; // Nothing to do here.
25
+ }
26
+ return $this->{($network_wide ? 'autoWipeCache' : 'autoClearCache')}();
27
+ }
28
+ }
src/includes/traits/Plugin/WcpPostTypeUtils.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpPostTypeUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for a custom post type archive view.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param int $post_id A WordPress post ID.
14
+ *
15
+ * @throws \Exception If a clear failure occurs.
16
+ *
17
+ * @return int Total files cleared by this routine (if any).
18
+ *
19
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently
20
+ * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
21
+ */
22
+ public function autoClearCustomPostTypeArchiveCache($post_id)
23
+ {
24
+ $counter = 0; // Initialize.
25
+
26
+ if (!($post_id = (integer) $post_id)) {
27
+ return $counter; // Nothing to do.
28
+ }
29
+ if (!is_null($done = &$this->cacheKey('autoClearCustomPostTypeArchiveCache', $post_id))) {
30
+ return $counter; // Already did this.
31
+ }
32
+ $done = true; // Flag as having been done.
33
+
34
+ if (!$this->options['enable']) {
35
+ return $counter; // Nothing to do.
36
+ }
37
+ if (!$this->options['cache_clear_custom_post_type_enable']) {
38
+ return $counter; // Nothing to do.
39
+ }
40
+ if (!is_dir($cache_dir = $this->cacheDir())) {
41
+ return $counter; // Nothing to do.
42
+ }
43
+ if (!($post_type = get_post_type($post_id))) {
44
+ return $counter; // Nothing to do.
45
+ }
46
+ if (!($all_custom_post_types = get_post_types(['_builtin' => false]))) {
47
+ return $counter; // No custom post types.
48
+ }
49
+ if (!in_array($post_type, array_keys($all_custom_post_types), true)) {
50
+ return $counter; // This is NOT a custom post type.
51
+ }
52
+ if (!($custom_post_type = get_post_type_object($post_type))) {
53
+ return $counter; // Unable to retrieve post type.
54
+ }
55
+ if (empty($custom_post_type->labels->name) || !($custom_post_type_name = $custom_post_type->labels->name)) {
56
+ $custom_post_type_name = __('Untitled', 'comet-cache');
57
+ }
58
+ if (!($custom_post_type_archive_link = get_post_type_archive_link($post_type))) {
59
+ return $counter; // Nothing to do; no link to work from in this case.
60
+ }
61
+ $regex = $this->buildHostCachePathRegex($custom_post_type_archive_link);
62
+ $counter += $this->clearFilesFromHostCacheDir($regex);
63
+
64
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
65
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for Custom Post Type: <code>%2$s</code>; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter)), esc_html($custom_post_type_name)), ['combinable' => true]);
66
+ }
67
+ $counter += $this->autoClearXmlFeedsCache('custom-post-type', $post_id);
68
+
69
+ return $counter;
70
+ }
71
+ }
src/includes/traits/Plugin/WcpPostUtils.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpPostUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for a particular post.
10
+ *
11
+ * @attaches-to `save_post` hook.
12
+ * @attaches-to `delete_post` hook.
13
+ * @attaches-to `clean_post_cache` hook.
14
+ *
15
+ * @since 150422 Rewrite.
16
+ *
17
+ * @param int $post_id A WordPress post ID.
18
+ * @param bool $force Defaults to a `FALSE` value.
19
+ * Pass as TRUE if clearing should be done for `draft`, `pending`,
20
+ * `future`, or `trash` post statuses.
21
+ *
22
+ * @throws \Exception If a clear failure occurs.
23
+ *
24
+ * @return int Total files cleared by this routine (if any).
25
+ *
26
+ * @note This is also called upon by other routines which listen for
27
+ * events that are indirectly associated with a post ID.
28
+ */
29
+ public function autoClearPostCache($post_id, $force = false)
30
+ {
31
+ $counter = 0; // Initialize.
32
+
33
+ if (!is_null($allow = &$this->cacheKey('autoClearPostCache_allow'))) {
34
+ if ($allow === false) { // Disallow?
35
+ $allow = true; // Reset flag.
36
+ return $counter;
37
+ }
38
+ }
39
+ if (!($post_id = (integer) $post_id)) {
40
+ return $counter; // Nothing to do.
41
+ }
42
+ if (!is_null($done = &$this->cacheKey('autoClearPostCache', [$post_id, $force]))) {
43
+ return $counter; // Already did this.
44
+ }
45
+ $done = true; // Flag as having been done.
46
+
47
+ if (!$this->options['enable']) {
48
+ return $counter; // Nothing to do.
49
+ }
50
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
51
+ return $counter; // Nothing to do.
52
+ }
53
+ if (!is_dir($cache_dir = $this->cacheDir())) {
54
+ return $counter; // Nothing to do.
55
+ }
56
+ if (!($post_type = get_post_type($post_id))) {
57
+ return $counter; // Nothing to do.
58
+ }
59
+ $post_statuses = $this->postStatuses();
60
+ $unpublished_post_statuses = array_diff($post_statuses, ['publish']);
61
+ $is_bbpress_post_type = in_array($post_type, $this->bbPressPostTypes(), true);
62
+
63
+ if (!empty($this->pre_post_update_post_permalink[$post_id])) {
64
+ $permalink = $this->pre_post_update_post_permalink[$post_id];
65
+ $this->pre_post_update_post_permalink[$post_id] = ''; // Reset; only used for post status transitions.
66
+ } elseif (!($permalink = get_permalink($post_id))) {
67
+ return $counter; // Nothing we can do.
68
+ }
69
+ if (!($post_status = get_post_status($post_id))) {
70
+ return $counter; // Nothing to do.
71
+ }
72
+ if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
73
+ && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
74
+ && strpos(wp_get_referer(), '/post-new.php') !== false
75
+ ) {
76
+ $post_status = 'publish'; // A new post being published now.
77
+ }
78
+ if (in_array($post_status, ['inherit', 'auto-draft'], true)) {
79
+ return $counter; // Nothing to do. Note: `inherit` = revision.
80
+ }
81
+ if (in_array($post_status, ['draft', 'pending', 'future', 'trash'], true) && !$force) {
82
+ return $counter; // Nothing to do; i.e., NOT forcing in this case.
83
+ }
84
+ if (($post_type_obj = get_post_type_object($post_type)) && !empty($post_type_obj->labels->singular_name)) {
85
+ $post_type_singular_name = $post_type_obj->labels->singular_name; // Singular name for the post type.
86
+ } else {
87
+ $post_type_singular_name = __('Post', 'comet-cache'); // Default value.
88
+ }
89
+ $regex = $this->buildHostCachePathRegex($permalink);
90
+ $counter += $this->clearFilesFromHostCacheDir($regex);
91
+
92
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
93
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for %2$s ID: <code>%3$s</code>; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter)), esc_html($post_type_singular_name), esc_html($post_id)), ['combinable' => true]);
94
+ }
95
+ $counter += $this->autoClearXmlFeedsCache('blog');
96
+ $counter += $this->autoClearXmlFeedsCache('post-terms', $post_id);
97
+ $counter += $this->autoClearXmlFeedsCache('post-authors', $post_id);
98
+
99
+ $counter += $this->autoClearXmlSitemapsCache();
100
+ $counter += $this->autoClearHomePageCache();
101
+ $counter += $this->autoClearPostsPageCache();
102
+ $counter += $this->autoClearPostTermsCache($post_id, $force);
103
+ $counter += $this->autoClearCustomPostTypeArchiveCache($post_id);
104
+
105
+
106
+ if ($post_type !== 'page' && ($parent_post_id = wp_get_post_parent_id($post_id))) {
107
+ // Recursion: i.e., nested post types like bbPress forums/topic/replies.
108
+ $counter += $this->autoClearPostCache($parent_post_id, $force);
109
+ }
110
+ return $counter;
111
+ }
112
+
113
+ // @codingStandardsIgnoreStart
114
+ /*
115
+ * Back compat. alias for autoClearPostCache()
116
+ */
117
+ public function auto_clear_post_cache()
118
+ { // @codingStandardsIgnoreEnd
119
+ return call_user_func_array([$this, 'autoClearPostCache'], func_get_args());
120
+ }
121
+
122
+ /**
123
+ * Handles post status transitioning.
124
+ *
125
+ * @attaches-to `pre_post_update` hook.
126
+ *
127
+ * @since 150422 Rewrite.
128
+ *
129
+ * @param int $post_id Post ID.
130
+ * @param array $data Array of unslashed post data.
131
+ *
132
+ * @throws \Exception If a clear failure occurs.
133
+ *
134
+ * @return int Total files cleared by this routine (if any).
135
+ *
136
+ * @note This is also called upon by other routines which listen for
137
+ * events that are indirectly associated with a post ID.
138
+ */
139
+ public function autoClearPostCacheTransition($post_id, $data)
140
+ {
141
+ $counter = 0; // Initialize.
142
+
143
+ $old_status = (string) get_post_status($post_id);
144
+ $new_status = (string) $data['post_status'];
145
+ /*
146
+ * When a post has a status of `pending` or `draft`, the `get_permalink()` function
147
+ * does not return a friendly permalink and therefore `autoClearPostCache()` will
148
+ * have no way of building a path to the cache file that should be cleared as part of
149
+ * this post status transition. To get around this, we temporarily store the permalink
150
+ * in $this->pre_post_update_post_permalink for `autoClearPostCache()` to use.
151
+ *
152
+ * See also: <https://github.com/websharks/zencache/issues/441>
153
+ */
154
+ if (in_array($new_status, ['pending', 'draft'], true)) {
155
+ $this->pre_post_update_post_permalink[$post_id] = get_permalink($post_id);
156
+ }
157
+ // Begin post status transition sub-routine now.
158
+
159
+ if (!is_null($done = &$this->cacheKey('autoClearPostCacheTransition', [$old_status, $new_status, $post_id]))) {
160
+ return $counter; // Already did this.
161
+ }
162
+ $done = true; // Flag as having been done.
163
+
164
+ if (!$this->options['enable']) {
165
+ return $counter; // Nothing to do.
166
+ }
167
+ if ($new_status === $old_status) {
168
+ return $counter; // Nothing to do.
169
+ }
170
+ if (!($post_type = get_post_type($post_id))) {
171
+ return $counter; // Nothing to do.
172
+ }
173
+ $post_statuses = $this->postStatuses();
174
+ $unpublished_post_statuses = array_diff($post_statuses, ['publish']);
175
+ $is_bbpress_post_type = in_array($post_type, $this->bbPressPostTypes(), true);
176
+
177
+ if ($is_bbpress_post_type) {
178
+ if (in_array($old_status, ['publish', 'private', 'closed', 'spam', 'hidden'], true)) {
179
+ if (in_array($new_status, $unpublished_post_statuses, true)) {
180
+ $counter += $this->autoClearPostCache($post_id, true);
181
+ }
182
+ }
183
+ } elseif (in_array($old_status, ['publish', 'private'], true)) {
184
+ if (in_array($new_status, $unpublished_post_statuses, true)) {
185
+ $counter += $this->autoClearPostCache($post_id, true);
186
+ }
187
+ }
188
+ return $counter;
189
+ }
190
+ }
src/includes/traits/Plugin/WcpSettingUtils.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpSettingUtils
7
+ {
8
+ /**
9
+ * Automatically clears all cache files for current blog under various conditions;
10
+ * used to check for conditions that don't have a hook that we can attach to.
11
+ *
12
+ * @since 150422 Rewrite.
13
+ *
14
+ * @attaches-to `admin_init` hook.
15
+ */
16
+ public function autoClearCacheOnSettingChanges()
17
+ {
18
+ $counter = 0; // Initialize.
19
+ $pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
20
+ $settings_updated = !empty($_REQUEST['settings-updated']);
21
+
22
+ if (!is_null($done = &$this->cacheKey('autoClearCacheOnSettingChanges', [$pagenow, $settings_updated]))) {
23
+ return $counter; // Already did this.
24
+ }
25
+ $done = true; // Flag as having been done.
26
+
27
+ if ($pagenow === 'options-general.php' && $settings_updated) {
28
+ $counter += $this->autoClearCache();
29
+ } elseif ($pagenow === 'options-reading.php' && $settings_updated) {
30
+ $counter += $this->autoClearCache();
31
+ } elseif ($pagenow === 'options-discussion.php' && $settings_updated) {
32
+ $counter += $this->autoClearCache();
33
+ } elseif ($pagenow === 'options-permalink.php' && $settings_updated) {
34
+ $counter += $this->autoClearCache();
35
+ }
36
+ }
37
+ }
src/includes/traits/Plugin/WcpSitemapUtils.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpSitemapUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files related to XML sitemaps.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @throws \Exception If a clear failure occurs.
14
+ *
15
+ * @return int Total files cleared by this routine (if any).
16
+ *
17
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently
18
+ * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
19
+ */
20
+ public function autoClearXmlSitemapsCache()
21
+ {
22
+ $counter = 0; // Initialize.
23
+
24
+ if (!is_null($done = &$this->cacheKey('autoClearXmlSitemapsCache'))) {
25
+ return $counter; // Already did this.
26
+ }
27
+ $done = true; // Flag as having been done.
28
+
29
+ if (!$this->options['enable']) {
30
+ return $counter; // Nothing to do.
31
+ }
32
+ if (!$this->options['cache_clear_xml_sitemaps_enable']) {
33
+ return $counter; // Nothing to do.
34
+ }
35
+ if (!$this->options['cache_clear_xml_sitemap_patterns']) {
36
+ return $counter; // Nothing to do.
37
+ }
38
+ if (!is_dir($cache_dir = $this->cacheDir())) {
39
+ return $counter; // Nothing to do.
40
+ }
41
+ if (!($regex_frags = $this->buildHostCachePathRegexFragsFromWcUris($this->options['cache_clear_xml_sitemap_patterns'], ''))) {
42
+ return $counter; // There are no patterns to look for.
43
+ }
44
+ $regex = $this->buildHostCachePathRegex('', '\/'.$regex_frags.'\.');
45
+ $counter += $this->clearFilesFromHostCacheDir($regex);
46
+
47
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
48
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for XML sitemaps; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
49
+ }
50
+ return $counter;
51
+ }
52
+ }
src/includes/traits/Plugin/WcpTermUtils.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpTermUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache files for terms associated with a post.
10
+ *
11
+ * @attaches-to `added_term_relationship` hook.
12
+ * @attaches-to `delete_term_relationships` hook.
13
+ *
14
+ * @since 150422 Rewrite.
15
+ *
16
+ * @param int $post_id A WordPress post ID.
17
+ * @param bool $force Defaults to a `FALSE` value.
18
+ * Pass as TRUE if clearing should be done for `draft`, `pending`,
19
+ * or `future` post statuses.
20
+ *
21
+ * @throws \Exception If a clear failure occurs.
22
+ *
23
+ * @return int Total files cleared by this routine (if any).
24
+ *
25
+ * @note In addition to the hooks this is attached to, it is also
26
+ * called upon by {@link autoClearPostCache()}.
27
+ */
28
+ public function autoClearPostTermsCache($post_id, $force = false)
29
+ {
30
+ $counter = 0; // Initialize.
31
+ $enqueued_notices = 0; // Initialize.
32
+
33
+ if (!($post_id = (integer) $post_id)) {
34
+ return $counter; // Nothing to do.
35
+ }
36
+ if (!is_null($done = &$this->cacheKey('autoClearPostTermsCache', [$post_id, $force]))) {
37
+ return $counter; // Already did this.
38
+ }
39
+ $done = true; // Flag as having been done.
40
+
41
+ if (!$this->options['enable']) {
42
+ return $counter; // Nothing to do.
43
+ }
44
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
45
+ return $counter; // Nothing to do.
46
+ }
47
+ if (!$this->options['cache_clear_term_category_enable'] && !$this->options['cache_clear_term_post_tag_enable'] && !$this->options['cache_clear_term_other_enable']) {
48
+ return $counter; // Nothing to do.
49
+ }
50
+ if (!is_dir($cache_dir = $this->cacheDir())) {
51
+ return $counter; // Nothing to do.
52
+ }
53
+ $post_status = get_post_status($post_id); // Cache this.
54
+
55
+ if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
56
+ && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
57
+ && strpos(wp_get_referer(), '/post-new.php') !== false
58
+ ) {
59
+ $post_status = 'publish'; // A new post being published now.
60
+ }
61
+ if (in_array($post_status, ['inherit', 'auto-draft'], true)) {
62
+ return $counter; // Nothing to do. Note: `inherit` = revision.
63
+ }
64
+ if (in_array($post_status, ['draft', 'pending', 'future'], true) && !$force) {
65
+ return $counter; // Nothing to do; i.e., NOT forcing in this case.
66
+ }
67
+ /*
68
+ * Build an array of available taxonomies for this post (as taxonomy objects).
69
+ */
70
+ $taxonomies = get_object_taxonomies(get_post($post_id), 'objects');
71
+
72
+ if (!is_array($taxonomies)) {
73
+ return $counter; // Nothing to do.
74
+ }
75
+ /*
76
+ * Build an array of terms associated with this post for each taxonomy.
77
+ * Also save taxonomy label information for Dashboard messaging later.
78
+ */
79
+ $terms = [];
80
+ $taxonomy_labels = [];
81
+
82
+ foreach ($taxonomies as $_taxonomy) {
83
+ if (// Check if this is a taxonomy/term that we should clear.
84
+ ($_taxonomy->name === 'category' && !$this->options['cache_clear_term_category_enable'])
85
+ || ($_taxonomy->name === 'post_tag' && !$this->options['cache_clear_term_post_tag_enable'])
86
+ || ($_taxonomy->name !== 'category' && $_taxonomy->name !== 'post_tag' && !$this->options['cache_clear_term_other_enable'])
87
+ ) {
88
+ continue; // Continue; nothing to do for this taxonomy.
89
+ }
90
+ if (is_array($_terms = wp_get_post_terms($post_id, $_taxonomy->name))) {
91
+ $terms = array_merge($terms, $_terms);
92
+ if (empty($_taxonomy->labels->singular_name) || $_taxonomy->labels->singular_name === '') {
93
+ $taxonomy_labels[$_taxonomy->name] = $_taxonomy->name;
94
+ } else {
95
+ $taxonomy_labels[$_taxonomy->name] = $_taxonomy->labels->singular_name;
96
+ }
97
+ }
98
+ }
99
+ unset($_taxonomy, $_terms);
100
+
101
+ if (empty($terms)) {
102
+ return $counter; // Nothing to do.
103
+ }
104
+ /*
105
+ * Build an array of terms with term names,
106
+ * permalinks, and associated taxonomy labels.
107
+ */
108
+ $terms_to_clear = [];
109
+ $_i = 0;
110
+
111
+ foreach ($terms as $_term) {
112
+ if (($_link = get_term_link($_term))) {
113
+ $terms_to_clear[$_i]['permalink'] = $_link;
114
+ $terms_to_clear[$_i]['term_name'] = $_term->name;
115
+ if (!empty($taxonomy_labels[$_term->taxonomy])) {
116
+ $terms_to_clear[$_i]['taxonomy_label'] = $taxonomy_labels[$_term->taxonomy];
117
+ } else {
118
+ $terms_to_clear[$_i]['taxonomy_label'] = $_term->taxonomy;
119
+ }
120
+ }
121
+ ++$_i; // Array index counter.
122
+ }
123
+ unset($_term, $_link, $_i);
124
+
125
+ if (empty($terms_to_clear)) {
126
+ return $counter; // Nothing to do.
127
+ }
128
+ foreach ($terms_to_clear as $_term) {
129
+ $_term_regex = $this->buildHostCachePathRegex($_term['permalink']);
130
+ $_term_counter = $this->clearFilesFromHostCacheDir($_term_regex);
131
+ $counter += $_term_counter; // Add to overall counter.
132
+
133
+ if ($_term_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
134
+ $this->enqueueNotice(sprintf(__('Found %1$s in the cache for %2$s: <code>%3$s</code>; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($_term_counter)), esc_html($_term['taxonomy_label']), esc_html($_term['term_name'])), ['combinable' => true]);
135
+ ++$enqueued_notices; // Increment enqueued notices counter.
136
+ }
137
+ }
138
+ unset($_term, $_term_regex, $_term_counter); // Housekeeping.
139
+
140
+ $counter += $this->autoClearXmlFeedsCache('post-terms', $post_id);
141
+
142
+ return $counter;
143
+ }
144
+ }
src/includes/traits/Plugin/WcpUpdaterUtils.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpUpdaterUtils
7
+ {
8
+ /**
9
+ * Automatically clears all cache files for current blog when WordPress core, or an active component, is upgraded.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @attaches-to `upgrader_process_complete` hook.
14
+ *
15
+ * @param \WP_Upgrader $upgrader_instance An instance of \WP_Upgrader.
16
+ * Or, any class that extends \WP_Upgrader.
17
+ * @param array $data Array of bulk item update data.
18
+ *
19
+ * This array may include one or more of the following keys:
20
+ *
21
+ * - `string` `$action` Type of action. Default 'update'.
22
+ * - `string` `$type` Type of update process; e.g. 'plugin', 'theme', 'core'.
23
+ * - `boolean` `$bulk` Whether the update process is a bulk update. Default true.
24
+ * - `array` `$packages` Array of plugin, theme, or core packages to update.
25
+ */
26
+ public function autoClearOnUpgraderProcessComplete(\WP_Upgrader $upgrader_instance, array $data)
27
+ {
28
+ $counter = 0; // Initialize.
29
+
30
+ switch (!empty($data['type']) ? $data['type'] : '') {
31
+ case 'plugin': // Plugin upgrade.
32
+
33
+ $multi_plugin_update = $single_plugin_update = false;
34
+ $upgrading_active_plugin = false; // Initialize.
35
+
36
+ if (!empty($data['bulk']) && !empty($data['plugins']) && is_array($data['plugins'])) {
37
+ $multi_plugin_update = true;
38
+ } elseif (!empty($data['plugin']) && is_string($data['plugin'])) {
39
+ $single_plugin_update = true;
40
+ }
41
+ if ($multi_plugin_update) {
42
+ foreach ($data['plugins'] as $_plugin) {
43
+ if ($_plugin && is_string($_plugin) && is_plugin_active($_plugin)) {
44
+ $upgrading_active_plugin = true;
45
+ break; // Got what we need here.
46
+ }
47
+ }
48
+ unset($_plugin); // Housekeeping.
49
+ } elseif ($single_plugin_update && is_plugin_active($data['plugin'])) {
50
+ $upgrading_active_plugin = true;
51
+ }
52
+ if ($upgrading_active_plugin) {
53
+ $counter += $this->autoClearCache();
54
+ }
55
+ break; // Break switch.
56
+
57
+ case 'theme': // Theme upgrade.
58
+
59
+ $current_active_theme = wp_get_theme();
60
+ $current_active_theme_parent = $current_active_theme->parent();
61
+ $multi_theme_update = $single_theme_update = false;
62
+ $upgrading_active_parent_theme = $upgrading_active_theme = false;
63
+
64
+ if (!empty($data['bulk']) && !empty($data['themes']) && is_array($data['themes'])) {
65
+ $multi_theme_update = true;
66
+ } elseif (!empty($data['theme']) && is_string($data['theme'])) {
67
+ $single_theme_update = true;
68
+ }
69
+ if ($multi_theme_update) {
70
+ foreach ($data['themes'] as $_theme) {
71
+ if (!$_theme || !is_string($_theme) || !($_theme_obj = wp_get_theme($_theme))) {
72
+ continue; // Unable to acquire theme object instance.
73
+ }
74
+ if ($current_active_theme_parent && $current_active_theme_parent->get_stylesheet() === $_theme_obj->get_stylesheet()) {
75
+ $upgrading_active_parent_theme = true;
76
+ break; // Got what we needed here.
77
+ } elseif ($current_active_theme->get_stylesheet() === $_theme_obj->get_stylesheet()) {
78
+ $upgrading_active_theme = true;
79
+ break; // Got what we needed here.
80
+ }
81
+ }
82
+ unset($_theme, $_theme_obj); // Housekeeping.
83
+ } elseif ($single_theme_update && ($_theme_obj = wp_get_theme($data['theme']))) {
84
+ if ($current_active_theme_parent && $current_active_theme_parent->get_stylesheet() === $_theme_obj->get_stylesheet()) {
85
+ $upgrading_active_parent_theme = true;
86
+ } elseif ($current_active_theme->get_stylesheet() === $_theme_obj->get_stylesheet()) {
87
+ $upgrading_active_theme = true;
88
+ }
89
+ }
90
+ unset($_theme_obj); // Housekeeping.
91
+
92
+ if ($upgrading_active_theme || $upgrading_active_parent_theme) {
93
+ $counter += $this->autoClearCache();
94
+ }
95
+ break; // Break switch.
96
+
97
+ case 'core': // Core upgrade.
98
+ default: // Or any other sort of upgrade.
99
+ $counter += $this->autoClearCache();
100
+ break; // Break switch.
101
+ }
102
+ }
103
+ }
src/includes/traits/Plugin/WcpUtils.php ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpUtils
7
+ {
8
+ /**
9
+ * Used for temporarily storing the permalink for posts transitioning from
10
+ * `publish` or `private` post status to `pending` or `draft` post status.
11
+ *
12
+ * @since 150422 Rewrite.
13
+ *
14
+ * @type array An associative array with the Post ID as the named key containing
15
+ * the post permalink before the post has been transitioned.
16
+ */
17
+ public $pre_post_update_post_permalink = [];
18
+
19
+ /**
20
+ * Wipes out all cache files.
21
+ *
22
+ * @since 150422 Rewrite.
23
+ *
24
+ * @param bool $manually TRUE if wiping is done manually.
25
+ *
26
+ * @throws \Exception If a wipe failure occurs.
27
+ *
28
+ * @return int Total files wiped by this routine.
29
+ */
30
+ public function wipeCache($manually = false)
31
+ {
32
+ $counter = 0; // Initialize.
33
+
34
+ if (!$manually && $this->disableAutoWipeCacheRoutines()) {
35
+ return $counter; // Nothing to do.
36
+ }
37
+ @set_time_limit(1800); // @TODO Display a warning.
38
+
39
+ if (is_dir($cache_dir = $this->cacheDir())) {
40
+ $regex = $this->assembleCachePathRegex('', '.+');
41
+ $counter += $this->wipeFilesFromCacheDir($regex);
42
+ }
43
+
44
+
45
+
46
+
47
+
48
+ return $counter;
49
+ }
50
+
51
+ // @codingStandardsIgnoreStart
52
+ /*
53
+ * Back compat. alias for autoClearUserCache()
54
+ */
55
+ public function wipe_cache()
56
+ { // @codingStandardsIgnoreEnd
57
+ return call_user_func_array([$this, 'wipeCache'], func_get_args());
58
+ }
59
+
60
+ /**
61
+ * Clears cache files (current blog).
62
+ *
63
+ * @since 150422 Rewrite.
64
+ *
65
+ * @param bool $manually TRUE if clearing is done manually.
66
+ *
67
+ * @throws \Exception If a clearing failure occurs.
68
+ *
69
+ * @return int Total files cleared by this routine.
70
+ */
71
+ public function clearCache($manually = false)
72
+ {
73
+ $counter = 0; // Initialize.
74
+
75
+ if (!$manually && $this->disableAutoClearCacheRoutines()) {
76
+ return $counter; // Nothing to do.
77
+ }
78
+ @set_time_limit(1800); // @TODO Display a warning.
79
+
80
+ if (is_dir($cache_dir = $this->cacheDir())) {
81
+ $regex = $this->buildHostCachePathRegex('', '.+');
82
+ $counter += $this->clearFilesFromHostCacheDir($regex);
83
+ }
84
+
85
+
86
+
87
+
88
+
89
+ return $counter;
90
+ }
91
+
92
+ // @codingStandardsIgnoreStart
93
+ /*
94
+ * Back compat. alias for clearCache()
95
+ */
96
+ public function clear_cache()
97
+ { // @codingStandardsIgnoreEnd
98
+ return call_user_func_array([$this, 'clearCache'], func_get_args());
99
+ }
100
+
101
+ /**
102
+ * Purges expired cache files (current blog).
103
+ *
104
+ * @since 150422 Rewrite.
105
+ *
106
+ * @param bool $manually TRUE if purging is done manually.
107
+ *
108
+ * @throws \Exception If a purge failure occurs.
109
+ *
110
+ * @return int Total files purged by this routine.
111
+ */
112
+ public function purgeCache($manually = false)
113
+ {
114
+ $counter = 0; // Initialize.
115
+
116
+ if (!$manually && $this->disableAutoPurgeCacheRoutines()) {
117
+ return $counter; // Nothing to do.
118
+ }
119
+ @set_time_limit(1800); // @TODO Display a warning.
120
+
121
+ if (is_dir($cache_dir = $this->cacheDir())) {
122
+ $regex = $this->buildHostCachePathRegex('', '.+');
123
+ $counter += $this->purgeFilesFromHostCacheDir($regex);
124
+ }
125
+
126
+ return $counter;
127
+ }
128
+
129
+ // @codingStandardsIgnoreStart
130
+ /*
131
+ * Back compat. alias for purgeCache()
132
+ */
133
+ public function purge_cache()
134
+ { // @codingStandardsIgnoreEnd
135
+ return call_user_func_array([$this, 'purgeCache'], func_get_args());
136
+ }
137
+
138
+ /**
139
+ * Wurges (purges) all expired cache files; like wipe, but expired files only.
140
+ *
141
+ * @since 151002 Look at entire cache directory.
142
+ *
143
+ * @param bool $manually TRUE if wurging is done manually.
144
+ *
145
+ * @throws \Exception If a wurge failure occurs.
146
+ *
147
+ * @return int Total files wurged by this routine.
148
+ */
149
+ public function wurgeCache($manually = false)
150
+ {
151
+ $counter = 0; // Initialize.
152
+
153
+ if (!$manually && $this->disableAutoPurgeCacheRoutines()) {
154
+ return $counter; // Nothing to do.
155
+ }
156
+ @set_time_limit(1800); // @TODO Display a warning.
157
+
158
+ if (is_dir($cache_dir = $this->cacheDir())) {
159
+ $regex = $this->assembleCachePathRegex('', '.+');
160
+ $counter += $this->wurgeFilesFromCacheDir($regex);
161
+ }
162
+
163
+ return $counter;
164
+ }
165
+
166
+ /**
167
+ * Automatically wipes out all cache files.
168
+ *
169
+ * @attaches-to Nothing at this time.
170
+ *
171
+ * @since 150422 Rewrite.
172
+ *
173
+ * @return int Total files wiped by this routine (if any).
174
+ *
175
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
176
+ * This is called upon whenever options are saved and/or restored though.
177
+ */
178
+ public function autoWipeCache()
179
+ {
180
+ $counter = 0; // Initialize.
181
+
182
+ if (!is_null($done = &$this->cacheKey('autoWipeCache'))) {
183
+ return $counter; // Already did this.
184
+ }
185
+ $done = true; // Flag as having been done.
186
+
187
+ if (!$this->options['enable']) {
188
+ return $counter; // Nothing to do.
189
+ }
190
+ if ($this->disableAutoWipeCacheRoutines()) {
191
+ return $counter; // Nothing to do.
192
+ }
193
+ $counter += $this->wipeCache();
194
+
195
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
196
+ $this->enqueueNotice(sprintf(__('Detected significant changes that require a full wipe of the cache. Found %1$s in the cache; auto-wiping.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
197
+ }
198
+ return $counter;
199
+ }
200
+
201
+ /**
202
+ * Automatically clears all cache files (current host).
203
+ *
204
+ * @attaches-to `switch_theme` hook.
205
+ *
206
+ * @attaches-to `wp_create_nav_menu` hook.
207
+ * @attaches-to `wp_update_nav_menu` hook.
208
+ * @attaches-to `wp_delete_nav_menu` hook.
209
+ *
210
+ * @attaches-to `create_term` hook.
211
+ * @attaches-to `edit_terms` hook.
212
+ * @attaches-to `delete_term` hook.
213
+ *
214
+ * @attaches-to `add_link` hook.
215
+ * @attaches-to `edit_link` hook.
216
+ * @attaches-to `delete_link` hook.
217
+ *
218
+ * @since 150422 Rewrite.
219
+ *
220
+ * @return int Total files cleared by this routine (if any).
221
+ *
222
+ * @note This is also called upon during plugin activation.
223
+ */
224
+ public function autoClearCache()
225
+ {
226
+ $counter = 0; // Initialize.
227
+
228
+ if (!is_null($done = &$this->cacheKey('autoClearCache'))) {
229
+ return $counter; // Already did this.
230
+ }
231
+ $done = true; // Flag as having been done.
232
+
233
+ if (!$this->options['enable']) {
234
+ return $counter; // Nothing to do.
235
+ }
236
+ if ($this->disableAutoClearCacheRoutines()) {
237
+ return $counter; // Nothing to do.
238
+ }
239
+ $counter += $this->clearCache();
240
+
241
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
242
+ $this->enqueueNotice(sprintf(__('Detected important site changes that affect the entire cache. Found %1$s in the cache for this site; auto-clearing.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
243
+ }
244
+ return $counter;
245
+ }
246
+
247
+ /**
248
+ * Automatically purges all cache files (current host).
249
+ *
250
+ * @attaches-to Nothing at this time.
251
+ *
252
+ * @since 151002 While working on directory stats.
253
+ *
254
+ * @return int Total files purged by this routine.
255
+ *
256
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
257
+ */
258
+ public function autoPurgeCache()
259
+ {
260
+ $counter = 0; // Initialize.
261
+
262
+ if (!is_null($done = &$this->cacheKey('autoPurgeCache'))) {
263
+ return $counter; // Already did this.
264
+ }
265
+ $done = true; // Flag as having been done.
266
+
267
+ if (!$this->options['enable']) {
268
+ return $counter; // Nothing to do.
269
+ }
270
+ if ($this->disableAutoPurgeCacheRoutines()) {
271
+ return $counter; // Nothing to do.
272
+ }
273
+ $counter += $this->purgeCache();
274
+
275
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
276
+ $this->enqueueNotice(sprintf(__('Detected important site changes. Found %1$s in the cache for this site that were expired; auto-purging.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
277
+ }
278
+ return $counter;
279
+ }
280
+
281
+ /**
282
+ * Automatically wurges all cache files.
283
+ *
284
+ * @attaches-to Nothing at this time.
285
+ *
286
+ * @since 151002 While working on directory stats.
287
+ *
288
+ * @return int Total files wurged by this routine.
289
+ *
290
+ * @note Unlike many of the other `auto_` methods, this one is NOT currently attached to any hooks.
291
+ */
292
+ public function autoWurgeCache()
293
+ {
294
+ $counter = 0; // Initialize.
295
+
296
+ if (!is_null($done = &$this->cacheKey('autoWurgeCache'))) {
297
+ return $counter; // Already did this.
298
+ }
299
+ $done = true; // Flag as having been done.
300
+
301
+ if (!$this->options['enable']) {
302
+ return $counter; // Nothing to do.
303
+ }
304
+ if ($this->disableAutoPurgeCacheRoutines()) {
305
+ return $counter; // Nothing to do.
306
+ }
307
+ $counter += $this->wurgeCache();
308
+
309
+ if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
310
+ $this->enqueueNotice(sprintf(__('Detected important site changes. Found %1$s in the cache that were expired; auto-purging.', 'comet-cache'), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
311
+ }
312
+ return $counter;
313
+ }
314
+
315
+ /**
316
+ * Allows a site owner to disable the automatic cache wiping routines.
317
+ *
318
+ * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_wipe_cache_routines` to return TRUE,
319
+ * in which case this method returns TRUE, otherwise it returns FALSE.
320
+ *
321
+ * @since 150422 Rewrite.
322
+ *
323
+ * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
324
+ */
325
+ public function disableAutoWipeCacheRoutines()
326
+ {
327
+ $is_disabled = (boolean) $this->applyWpFilters(GLOBAL_NS.'_disable_auto_wipe_cache_routines', false);
328
+
329
+ if ($is_disabled && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
330
+ $this->enqueueMainNotice(
331
+ '<img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
332
+ sprintf(__('<strong>%1$s:</strong> detected significant changes that would normally trigger cache wiping routines. However, cache wiping routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME))
333
+ );
334
+ }
335
+ return $is_disabled;
336
+ }
337
+
338
+ /**
339
+ * Allows a site owner to disable the automatic cache clearing routines.
340
+ *
341
+ * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_clear_cache_routines` to return TRUE,
342
+ * in which case this method returns TRUE, otherwise it returns FALSE.
343
+ *
344
+ * @since 150422 Rewrite.
345
+ *
346
+ * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
347
+ */
348
+ public function disableAutoClearCacheRoutines()
349
+ {
350
+ $is_disabled = (boolean) $this->applyWpFilters(GLOBAL_NS.'_disable_auto_clear_cache_routines', false);
351
+
352
+ if ($is_disabled && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
353
+ $this->enqueueMainNotice(
354
+ '<img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
355
+ sprintf(__('<strong>%1$s:</strong> detected important site changes that would normally trigger cache clearing routines. However, cache clearing routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME))
356
+ );
357
+ }
358
+ return $is_disabled;
359
+ }
360
+
361
+ /**
362
+ * Allows a site owner to disable the automatic cache purging routines.
363
+ *
364
+ * This is done by filtering `'.__GLOBAL_NS__.'_disable_auto_purge_cache_routines` to return TRUE,
365
+ * in which case this method returns TRUE, otherwise it returns FALSE.
366
+ *
367
+ * @since 151002 While working on directory stats.
368
+ *
369
+ * @return bool `TRUE` if disabled; and this also creates a dashboard notice in some cases.
370
+ */
371
+ public function disableAutoPurgeCacheRoutines()
372
+ {
373
+ $is_disabled = (boolean) $this->applyWpFilters(GLOBAL_NS.'_disable_auto_purge_cache_routines', false);
374
+
375
+ if ($is_disabled && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
376
+ $this->enqueueMainNotice(
377
+ '<img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />'.
378
+ sprintf(__('<strong>%1$s:</strong> detected important site changes that would normally trigger cache purging routines. However, cache purging routines have been disabled by a site administrator. [<a href="http://cometcache.com/r/kb-clear-and-wipe-cache-routines/" target="_blank">?</a>]', 'comet-cache'), esc_html(NAME))
379
+ );
380
+ }
381
+ return $is_disabled;
382
+ }
383
+ }
src/includes/traits/Plugin/WcpWooCommerceUtils.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Plugin;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait WcpWooCommerceUtils
7
+ {
8
+ /**
9
+ * Automatically clears cache file for a WooCommerce Product when its stock is changed.
10
+ *
11
+ * @since 151220 Improving WooCommerce Compatibility.
12
+ *
13
+ * @attaches-to `woocommerce_product_set_stock` hook.
14
+ *
15
+ * @param \WC_Product $product A WooCommerce WC_Product object
16
+ */
17
+ public function autoClearPostCacheOnWooCommerceSetStock($product)
18
+ {
19
+ $counter = 0; // Initialize.
20
+
21
+ if (!is_null($done = &$this->cacheKey('autoClearPostCacheOnWooCommerceSetStock'))) {
22
+ return $counter; // Already did this.
23
+ }
24
+ $done = true; // Flag as having been done.
25
+
26
+ if (class_exists('\\WooCommerce')) {
27
+ $counter += $this->autoClearPostCache($product->id);
28
+ }
29
+ }
30
+ }
src/includes/traits/Shared/BlogUtils.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait BlogUtils
7
+ {
8
+ /**
9
+ * Get blog details.
10
+ *
11
+ * @since 150821 Improving multisite compat.
12
+ *
13
+ * @param int $blog_id For which blog ID?
14
+ *
15
+ * @return \stdClass|null Blog details if possible.
16
+ *
17
+ * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
18
+ */
19
+ public function blogDetails($blog_id = 0)
20
+ {
21
+ if (!is_multisite() || $this->isAdvancedCache()) {
22
+ return null; // Not possible.
23
+ }
24
+ if (($blog_id = (integer) $blog_id) < 0) {
25
+ $blog_id = (integer) get_current_site()->blog_id;
26
+ }
27
+ if (!$blog_id) {
28
+ $blog_id = (integer) get_current_blog_id();
29
+ }
30
+ if (!$blog_id || $blog_id < 0) {
31
+ return null; // Not possible.
32
+ }
33
+ $details = get_blog_details($blog_id);
34
+
35
+ return is_object($details) ? $details : null;
36
+ }
37
+ }
src/includes/traits/Shared/CacheDirUtils.php ADDED
@@ -0,0 +1,651 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CacheDirUtils
7
+ {
8
+ /**
9
+ * Cache directory path.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $rel_path Relative path inside cache directory.
14
+ *
15
+ * @throws \Exception If unable to get cache directory.
16
+ *
17
+ * @return string Absolute path to cache directory.
18
+ */
19
+ public function cacheDir($rel_path = '')
20
+ {
21
+ $rel_path = (string) $rel_path;
22
+
23
+ if ($this->isAdvancedCache()) {
24
+ $cache_dir = defined('COMET_CACHE_DIR') ? COMET_CACHE_DIR : '';
25
+ } elseif (!empty($this->cache_sub_dir)) {
26
+ $cache_dir = $this->wpContentBaseDirTo($this->cache_sub_dir);
27
+ }
28
+ if (empty($cache_dir)) {
29
+ throw new \Exception(__('Unable to determine cache directory location.', 'comet-cache'));
30
+ }
31
+ return rtrim($cache_dir, '/').($rel_path ? '/'.ltrim($rel_path) : '');
32
+ }
33
+
34
+ /**
35
+ * Wipe files from the cache directory (for all hosts/blogs);
36
+ * i.e., those that match a specific regex pattern.
37
+ *
38
+ * @since 151002 While working on directory stats.
39
+ *
40
+ * @param string $regex A regex pattern; see {@link deleteFilesFromCacheDir()}.
41
+ *
42
+ * @return int Total files wiped by this routine.
43
+ */
44
+ public function wipeFilesFromCacheDir($regex)
45
+ {
46
+ return $this->deleteFilesFromCacheDir($regex);
47
+ }
48
+
49
+ /**
50
+ * Clear files from the cache directory (for the current host);
51
+ * i.e., those that match a specific regex pattern.
52
+ *
53
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
54
+ *
55
+ * @param string $regex A regex pattern; see {@link deleteFilesFromHostCacheDir()}.
56
+ *
57
+ * @return int Total files cleared by this routine (if any).
58
+ */
59
+ public function clearFilesFromHostCacheDir($regex)
60
+ {
61
+ return $this->deleteFilesFromHostCacheDir($regex);
62
+ }
63
+
64
+ /**
65
+ * Wurge (purge) files from the cache directory (for all hosts/blogs);
66
+ * i.e., those that match a specific regex pattern.
67
+ *
68
+ * @since 151002 While working on directory stats.
69
+ *
70
+ * @param string $regex A regex pattern; see {@link deleteFilesFromCacheDir()}.
71
+ *
72
+ * @return int Total files wurged by this routine.
73
+ */
74
+ public function wurgeFilesFromCacheDir($regex)
75
+ {
76
+ return $this->deleteFilesFromCacheDir($regex, true);
77
+ }
78
+
79
+ /**
80
+ * Purge files from the cache directory (for the current host);
81
+ * i.e., those that match a specific regex pattern.
82
+ *
83
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
84
+ *
85
+ * @param string $regex A regex pattern; see {@link deleteFilesFromHostCacheDir()}.
86
+ *
87
+ * @return int Total files purged by this routine (if any).
88
+ */
89
+ public function purgeFilesFromHostCacheDir($regex)
90
+ {
91
+ return $this->deleteFilesFromHostCacheDir($regex, true);
92
+ }
93
+
94
+ /**
95
+ * Delete files from the cache directory (for all hosts/blogs);
96
+ * i.e., those that match a specific regex pattern.
97
+ *
98
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
99
+ *
100
+ * @param string $regex A `/[regex pattern]/`; relative to the cache directory.
101
+ * e.g. `/^http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
102
+ *
103
+ * Or, this can also be a full/absolute regex pattern against an absolute path;
104
+ * provided that it always starts with `/^`; including the full absolute cache/host directory path.
105
+ * e.g. `/^\/cache\/dir\/http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
106
+ * @param bool $check_max_age Check max age? i.e., use purge behavior?
107
+ *
108
+ * @throws \Exception If unable to delete a file for any reason.
109
+ * @return int Total files deleted by this routine (if any).
110
+ *
111
+ *
112
+ * @TODO Optimize this for multisite networks w/ a LOT of child blogs.
113
+ * @TODO Optimize this for extremely large sites. A LOT of files here could slow things down.
114
+ * This class member is currently used in wiping and purging for a network. So there is the potential for a LOT of files in a single scan.
115
+ * See also: <https://codex.wordpress.org/Function_Reference/wp_is_large_network>
116
+ */
117
+ public function deleteFilesFromCacheDir($regex, $check_max_age = false)
118
+ {
119
+ $counter = 0; // Initialize.
120
+
121
+ if (!($regex = (string) $regex)) {
122
+ return $counter; // Nothing to do.
123
+ }
124
+ if (!is_dir($cache_dir = $this->cacheDir())) {
125
+ return $counter; // Nothing to do.
126
+ }
127
+ $cache_dir = $this->nDirSeps($cache_dir);
128
+
129
+ if ($check_max_age && $this->isAdvancedCache()) {
130
+ throw new \Exception(__('Invalid argument; isAdvancedCache!', 'comet-cache'));
131
+ }
132
+ if ($check_max_age && !($max_age = strtotime('-'.$this->options['cache_max_age']))) {
133
+ return $counter; // Invalid cache expiration time.
134
+ }
135
+ /* ------- Begin lock state... ----------- */
136
+
137
+ $cache_lock = $this->cacheLock(); // Lock cache writes.
138
+
139
+ clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
140
+
141
+ $cache_dir_tmp = $this->addTmpSuffix($cache_dir); // Temporary directory.
142
+
143
+ $cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
144
+ $cache_dir_tmp_regex = '\\/'.ltrim($cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
145
+ $cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($cache_dir.'/', '/'), '', $cache_dir_tmp_regex);
146
+
147
+ $cache_dir_tmp_regex = ltrim($cache_dir_tmp_regex, '^\\/');
148
+ if (strpos($cache_dir_tmp_regex, '(?:\/') === 0 || strpos($cache_dir_tmp_regex, '(\/') === 0) {
149
+ $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp, '/').$cache_dir_tmp_regex;
150
+ } else {
151
+ $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp.'/', '/').$cache_dir_tmp_regex;
152
+ }
153
+ # if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
154
+ // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
155
+
156
+ if (!rename($cache_dir, $cache_dir_tmp)) {
157
+ throw new \Exception(sprintf(__('Unable to delete files. Rename failure on directory: `%1$s`.', 'comet-cache'), $cache_dir));
158
+ }
159
+ foreach (($_dir_regex_iteration = $this->dirRegexIteration($cache_dir_tmp, $cache_dir_tmp_regex)) as $_resource) {
160
+ $_resource_type = $_resource->getType();
161
+ $_sub_path_name = $_resource->getSubpathname();
162
+ $_path_name = $_resource->getPathname();
163
+
164
+ if ($_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
165
+ continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
166
+ // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
167
+ }
168
+ switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
169
+
170
+ case 'link': // Symbolic links; i.e., 404 errors.
171
+
172
+ if ($check_max_age && !empty($max_age) && is_file($_resource->getLinkTarget())) {
173
+ if (($_lstat = lstat($_path_name)) && !empty($_lstat['mtime'])) {
174
+ if ($_lstat['mtime'] >= $max_age) {
175
+ break; // Break switch.
176
+ }
177
+ }
178
+ }
179
+ if (!unlink($_path_name)) {
180
+ $this->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
181
+ throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
182
+ }
183
+ ++$counter; // Increment counter for each link we delete.
184
+
185
+ break; // Break switch handler.
186
+
187
+ case 'file': // Regular files; i.e., not symlinks.
188
+
189
+ if ($check_max_age && !empty($max_age)) {
190
+ if ($_resource->getMTime() >= $max_age) {
191
+ break; // Break switch.
192
+ }
193
+ }
194
+ if (!unlink($_path_name)) {
195
+ $this->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
196
+ throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
197
+ }
198
+ ++$counter; // Increment counter for each file we delete.
199
+
200
+ break; // Break switch handler.
201
+
202
+ case 'dir': // A regular directory; i.e., not a symlink.
203
+
204
+ if ($regex !== '/^.+/i') {
205
+ break; // Not deleting everything.
206
+ }
207
+ if ($check_max_age && !empty($max_age)) {
208
+ break; // Not deleting everything.
209
+ }
210
+ if (!rmdir($_path_name)) {
211
+ $this->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
212
+ throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
213
+ }
214
+ # $counter++; // Increment counter for each directory we delete. ~ NO don't do that here.
215
+
216
+ break; // Break switch handler.
217
+
218
+ default: // Something else that is totally unexpected here.
219
+ $this->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
220
+ throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
221
+ }
222
+ }
223
+ unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name, $_lstat); // Housekeeping.
224
+
225
+ if (!rename($cache_dir_tmp, $cache_dir)) {
226
+ $this->tryErasingAllFilesDirsIn($cache_dir_tmp, true); // Cleanup if possible.
227
+ throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $cache_dir_tmp));
228
+ }
229
+ /* ------- End lock state... ------------- */
230
+
231
+ $this->cacheUnlock($cache_lock); // Release.
232
+
233
+ return $counter;
234
+ }
235
+
236
+ /**
237
+ * Delete files from the cache directory (for the current host);
238
+ * i.e., those that match a specific regex pattern.
239
+ *
240
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
241
+ *
242
+ * @param string $regex A `/[regex pattern]/`; relative to the host cache directory.
243
+ * e.g. `/^my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
244
+ *
245
+ * Or, this can also be a full/absolute regex pattern against an absolute path;
246
+ * provided that it always starts with `/^`; including the full absolute cache/host directory path.
247
+ * e.g. `/^\/cache\/dir\/http\/example\.com\/my\-slug(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])/`
248
+ * @param bool $check_max_age Check max age? i.e., use purge behavior?
249
+ * @param bool $___considering_domain_mapping For internal use only.
250
+ * @param bool $___consider_domain_mapping_host_token For internal use only.
251
+ * @param bool $___consider_domain_mapping_host_base_dir_tokens For internal use only.
252
+ *
253
+ * @throws \Exception If unable to delete a file for any reason.
254
+ * @return int Total files deleted by this routine (if any).
255
+ *
256
+ */
257
+ public function deleteFilesFromHostCacheDir(
258
+ $regex,
259
+ $check_max_age = false,
260
+ $___considering_domain_mapping = false,
261
+ $___consider_domain_mapping_host_token = null,
262
+ $___consider_domain_mapping_host_base_dir_tokens = null
263
+ ) {
264
+ $counter = 0; // Initialize.
265
+
266
+ if (!($regex = (string) $regex)) {
267
+ return $counter; // Nothing to do.
268
+ }
269
+ if (!is_dir($cache_dir = $this->cacheDir())) {
270
+ return $counter; // Nothing to do.
271
+ }
272
+ $cache_dir = $this->nDirSeps($cache_dir); // Normalize.
273
+ $host_token = $current_host_token = $this->hostToken();
274
+ $host_base_dir_tokens = $current_host_base_dir_tokens = $this->hostBaseDirTokens();
275
+
276
+ if ($___considering_domain_mapping && isset($___consider_domain_mapping_host_token, $___consider_domain_mapping_host_base_dir_tokens)) {
277
+ $host_token = (string) $___consider_domain_mapping_host_token;
278
+ $host_base_dir_tokens = (string) $___consider_domain_mapping_host_base_dir_tokens;
279
+ }
280
+ if (!$host_token) { // Must have a host in the sub-routine below.
281
+ throw new \Exception(__('Invalid argument; host token empty!', 'comet-cache'));
282
+ }
283
+ if ($check_max_age && $this->isAdvancedCache()) {
284
+ throw new \Exception(__('Invalid argument; isAdvancedCache!', 'comet-cache'));
285
+ }
286
+ if ($check_max_age && !($max_age = strtotime('-'.$this->options['cache_max_age']))) {
287
+ return $counter; // Invalid cache expiration time.
288
+ }
289
+ /* ------- Begin lock state... ----------- */
290
+
291
+ $cache_lock = $this->cacheLock(); // Lock cache writes.
292
+
293
+ clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
294
+
295
+ foreach (['http', 'https'] as $_host_scheme) {
296
+ $_host_url = $_host_scheme.'://'.$host_token.$host_base_dir_tokens;
297
+ $_host_cache_path_flags = $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT;
298
+ $_host_cache_path = $this->buildCachePath($_host_url, '', '', $_host_cache_path_flags);
299
+ $_host_cache_dir = $this->nDirSeps($cache_dir.'/'.$_host_cache_path); // Normalize.
300
+
301
+ if (!$_host_cache_dir || !is_dir($_host_cache_dir)) {
302
+ // On a multisite install this may have a cache sub-directory.
303
+ // e.g., `http/example-com[[-base]-child1][[/base]/child1]` instead of `http/example-com`.
304
+ continue; // Nothing to do.
305
+ }
306
+ $_host_cache_dir_tmp = $this->addTmpSuffix($_host_cache_dir); // Temporary directory.
307
+
308
+ $_host_cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
309
+ $_host_cache_dir_tmp_regex = '\\/'.ltrim($_host_cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
310
+ $_host_cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($_host_cache_path.'/', '/'), '', $_host_cache_dir_tmp_regex);
311
+ $_host_cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($_host_cache_dir.'/', '/'), '', $_host_cache_dir_tmp_regex);
312
+
313
+ $_host_cache_dir_tmp_regex = ltrim($_host_cache_dir_tmp_regex, '^\\/');
314
+ if (strpos($_host_cache_dir_tmp_regex, '(?:\/') === 0 || strpos($_host_cache_dir_tmp_regex, '(\/') === 0) {
315
+ $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp, '/').$_host_cache_dir_tmp_regex;
316
+ } else {
317
+ $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp.'/', '/').$_host_cache_dir_tmp_regex;
318
+ }
319
+ #if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($_host_cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
320
+ // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
321
+
322
+ if (!rename($_host_cache_dir, $_host_cache_dir_tmp)) {
323
+ throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $_host_cache_dir));
324
+ }
325
+ foreach (($_dir_regex_iteration = $this->dirRegexIteration($_host_cache_dir_tmp, $_host_cache_dir_tmp_regex)) as $_resource) {
326
+ $_resource_type = $_resource->getType();
327
+ $_sub_path_name = $_resource->getSubpathname();
328
+ $_path_name = $_resource->getPathname();
329
+
330
+ if ($_host_cache_dir === $cache_dir && $_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
331
+ continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
332
+ // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
333
+ }
334
+ switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
335
+
336
+ case 'link': // Symbolic links; i.e., 404 errors.
337
+
338
+ if ($check_max_age && !empty($max_age) && is_file($_resource->getLinkTarget())) {
339
+ if (($_lstat = lstat($_path_name)) && !empty($_lstat['mtime'])) {
340
+ if ($_lstat['mtime'] >= $max_age) {
341
+ break; // Break switch.
342
+ }
343
+ }
344
+ }
345
+ if (!unlink($_path_name)) {
346
+ $this->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
347
+ throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
348
+ }
349
+ ++$counter; // Increment counter for each link we delete.
350
+
351
+ break; // Break switch handler.
352
+
353
+ case 'file': // Regular files; i.e., not symlinks.
354
+
355
+ if ($check_max_age && !empty($max_age)) {
356
+ if ($_resource->getMTime() >= $max_age) {
357
+ break; // Break switch handler.
358
+ }
359
+ }
360
+ if (!unlink($_path_name)) {
361
+ $this->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
362
+ throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
363
+ }
364
+ ++$counter; // Increment counter for each file we delete.
365
+
366
+ break; // Break switch handler.
367
+
368
+ case 'dir': // A regular directory; i.e., not a symlink.
369
+
370
+ if ($regex !== '/^.+/i') {
371
+ break; // Not deleting everything.
372
+ }
373
+ if ($check_max_age && !empty($max_age)) {
374
+ break; // Not deleting everything.
375
+ }
376
+ if (!rmdir($_path_name)) {
377
+ $this->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
378
+ throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
379
+ }
380
+ # $counter++; // Increment counter for each directory we delete. ~ NO don't do that here.
381
+
382
+ break; // Break switch handler.
383
+
384
+ default: // Something else that is totally unexpected here.
385
+ $this->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
386
+ throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
387
+ }
388
+ }
389
+ unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name, $_lstat); // Housekeeping.
390
+
391
+ if (!rename($_host_cache_dir_tmp, $_host_cache_dir)) {
392
+ $this->tryErasingAllFilesDirsIn($_host_cache_dir_tmp, true); // Cleanup if possible.
393
+ throw new \Exception(sprintf(__('Unable to delete files. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $_host_cache_dir_tmp));
394
+ }
395
+ }
396
+ unset($_host_scheme, $_host_url, $_host_cache_path_flags, $_host_cache_path, $_host_cache_dir, $_host_cache_dir_tmp, $_host_cache_dir_tmp_regex);
397
+
398
+ /* ------- End lock state... ------------- */
399
+
400
+ $this->cacheUnlock($cache_lock); // Release.
401
+
402
+ /* ------- Include domain mapping variations also. ------- */
403
+
404
+ if (!$___considering_domain_mapping && is_multisite() && $this->canConsiderDomainMapping()) {
405
+ $domain_mapping_variations = []; // Initialize array of domain variations.
406
+
407
+ if (($_host_token_for_blog = $this->hostTokenForBlog())) {
408
+ $_host_base_dir_tokens_for_blog = $this->hostBaseDirTokensForBlog();
409
+ $domain_mapping_variations[] = ['host_token' => $_host_token_for_blog, 'host_base_dir_tokens' => $_host_base_dir_tokens_for_blog];
410
+ } // The original blog host; i.e., without domain mapping.
411
+ unset($_host_token_for_blog, $_host_base_dir_tokens_for_blog); // Housekeeping.
412
+
413
+ foreach ($this->domainMappingBlogDomains() as $_domain_mapping_blog_domain) {
414
+ if (($_domain_host_token_for_blog = $this->hostTokenForBlog(false, true, $_domain_mapping_blog_domain))) {
415
+ $_domain_host_base_dir_tokens_for_blog = $this->hostBaseDirTokensForBlog(false, true); // This is only a formality.
416
+ $domain_mapping_variations[] = ['host_token' => $_domain_host_token_for_blog, 'host_base_dir_tokens' => $_domain_host_base_dir_tokens_for_blog];
417
+ }
418
+ } // This includes all of the domain mappings configured for the current blog ID.
419
+ unset($_domain_mapping_blog_domain, $_domain_host_token_for_blog, $_domain_host_base_dir_tokens_for_blog); // Housekeeping.
420
+
421
+ foreach ($domain_mapping_variations as $_domain_mapping_variation) {
422
+ if ($_domain_mapping_variation['host_token'] === $current_host_token && $_domain_mapping_variation['host_base_dir_tokens'] === $current_host_base_dir_tokens) {
423
+ continue; // Exclude current tokens. They were already iterated above.
424
+ }
425
+ $counter += $this->deleteFilesFromHostCacheDir($regex, $check_max_age, true, $_domain_mapping_variation['host_token'], $_domain_mapping_variation['host_base_dir_tokens']);
426
+ }
427
+ unset($_domain_mapping_variation); // Housekeeping.
428
+ }
429
+ return $counter;
430
+ }
431
+
432
+ /**
433
+ * Delete all files/dirs from a directory (for all schemes/hosts);
434
+ * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
435
+ *
436
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
437
+ *
438
+ * @param string $dir The directory from which to delete files/dirs.
439
+ *
440
+ * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
441
+ * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
442
+ * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
443
+ * @param bool $delete_dir_too Delete parent? i.e., delete the `$dir` itself also?
444
+ *
445
+ * @throws \Exception If unable to delete a file/directory for any reason.
446
+ * @return int Total files/directories deleted by this routine (if any).
447
+ *
448
+ */
449
+ public function deleteAllFilesDirsIn($dir, $delete_dir_too = false)
450
+ {
451
+ $counter = 0; // Initialize.
452
+
453
+ if (!($dir = trim((string) $dir)) || !is_dir($dir)) {
454
+ return $counter; // Nothing to do.
455
+ }
456
+ $dir = $this->nDirSeps($dir);
457
+ $dir_temp = $this->addTmpSuffix($dir);
458
+ $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
459
+ $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
460
+
461
+ if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
462
+ return $counter; // Security flag; do nothing in this case.
463
+ }
464
+ if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
465
+ return $counter; // Security flag; do nothing in this case.
466
+ }
467
+ /* ------- Begin lock state... ----------- */
468
+
469
+ $cache_lock = $this->cacheLock(); // Lock cache writes.
470
+
471
+ clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
472
+
473
+ if (!rename($dir, $dir_temp)) {
474
+ throw new \Exception(sprintf(__('Unable to delete all files/dirs. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $dir));
475
+ }
476
+ foreach (($_dir_regex_iteration = $this->dirRegexIteration($dir_temp, '/.+/')) as $_resource) {
477
+ $_resource_type = $_resource->getType();
478
+ $_sub_path_name = $_resource->getSubpathname();
479
+ $_path_name = $_resource->getPathname();
480
+
481
+ switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
482
+
483
+ case 'link': // Symbolic links; i.e., 404 errors.
484
+
485
+ if (!unlink($_path_name)) {
486
+ $this->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
487
+ throw new \Exception(sprintf(__('Unable to delete symlink: `%1$s`.', 'comet-cache'), $_path_name));
488
+ }
489
+ ++$counter; // Increment counter for each link we delete.
490
+
491
+ break; // Break switch handler.
492
+
493
+ case 'file': // Regular files; i.e., not symlinks.
494
+
495
+ if (!unlink($_path_name)) {
496
+ $this->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
497
+ throw new \Exception(sprintf(__('Unable to delete file: `%1$s`.', 'comet-cache'), $_path_name));
498
+ }
499
+ ++$counter; // Increment counter for each file we delete.
500
+
501
+ break; // Break switch handler.
502
+
503
+ case 'dir': // A regular directory; i.e., not a symlink.
504
+
505
+ if (!rmdir($_path_name)) {
506
+ $this->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
507
+ throw new \Exception(sprintf(__('Unable to delete dir: `%1$s`.', 'comet-cache'), $_path_name));
508
+ }
509
+ # ++$counter; // Increment counter for each directory we delete. ~ NO don't do that here.
510
+
511
+ break; // Break switch handler.
512
+
513
+ default: // Something else that is totally unexpected here.
514
+ $this->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
515
+ throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
516
+ }
517
+ }
518
+ unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name); // Housekeeping.
519
+
520
+ if (!rename($dir_temp, $dir)) {
521
+ $this->tryErasingAllFilesDirsIn($dir_temp, true); // Cleanup if possible.
522
+ throw new \Exception(sprintf(__('Unable to delete all files/dirs. Rename failure on tmp directory: `%1$s`.', 'comet-cache'), $dir_temp));
523
+ }
524
+ if ($delete_dir_too) {
525
+ if (!rmdir($dir)) {
526
+ throw new \Exception(sprintf(__('Unable to delete directory: `%1$s`.', 'comet-cache'), $dir));
527
+ }
528
+ ++$counter; // Increment counter for each directory we delete.
529
+ }
530
+ /* ------- End lock state... ------------- */
531
+
532
+ $this->cacheUnlock($cache_lock); // Release.
533
+
534
+ return $counter;
535
+ }
536
+
537
+ /**
538
+ * Erase all files/dirs from a directory (for all schemes/hosts);
539
+ * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
540
+ *
541
+ * WARNING: This does NO LOCKING and NO ATOMIC deletions.
542
+ *
543
+ * @since 150821 Improving recovery under stress.
544
+ *
545
+ * @param string $dir The directory from which to erase files/dirs.
546
+ *
547
+ * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
548
+ * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
549
+ * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
550
+ * @param bool $erase_dir_too Erase parent? i.e., erase the `$dir` itself also?
551
+ *
552
+ * @throws \Exception If unable to erase a file/directory for any reason.
553
+ * @return int Total files/directories erased by this routine (if any).
554
+ *
555
+ */
556
+ public function eraseAllFilesDirsIn($dir, $erase_dir_too = false)
557
+ {
558
+ $counter = 0; // Initialize.
559
+
560
+ if (!($dir = trim((string) $dir)) || !is_dir($dir)) {
561
+ return $counter; // Nothing to do.
562
+ }
563
+ $dir = $this->nDirSeps($dir);
564
+ $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
565
+ $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
566
+
567
+ if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
568
+ return $counter; // Security flag; do nothing in this case.
569
+ }
570
+ if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
571
+ return $counter; // Security flag; do nothing in this case.
572
+ }
573
+ clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
574
+
575
+ foreach (($_dir_regex_iteration = $this->dirRegexIteration($dir, '/.+/')) as $_resource) {
576
+ $_resource_type = $_resource->getType();
577
+ $_sub_path_name = $_resource->getSubpathname();
578
+ $_path_name = $_resource->getPathname();
579
+
580
+ switch ($_resource_type) {// Based on type; i.e., `link`, `file`, `dir`.
581
+
582
+ case 'link': // Symbolic links; i.e., 404 errors.
583
+
584
+ if (!unlink($_path_name)) {
585
+ throw new \Exception(sprintf(__('Unable to erase symlink: `%1$s`.', 'comet-cache'), $_path_name));
586
+ }
587
+ ++$counter; // Increment counter for each link we erase.
588
+
589
+ break; // Break switch handler.
590
+
591
+ case 'file': // Regular files; i.e., not symlinks.
592
+
593
+ if (!unlink($_path_name)) {
594
+ throw new \Exception(sprintf(__('Unable to erase file: `%1$s`.', 'comet-cache'), $_path_name));
595
+ }
596
+ ++$counter; // Increment counter for each file we erase.
597
+
598
+ break; // Break switch handler.
599
+
600
+ case 'dir': // A regular directory; i.e., not a symlink.
601
+
602
+ if (!rmdir($_path_name)) {
603
+ throw new \Exception(sprintf(__('Unable to erase dir: `%1$s`.', 'comet-cache'), $_path_name));
604
+ }
605
+ # ++$counter; // Increment counter for each directory we erase. ~ NO don't do that here.
606
+
607
+ break; // Break switch handler.
608
+
609
+ default: // Something else that is totally unexpected here.
610
+ throw new \Exception(sprintf(__('Unexpected resource type: `%1$s`.', 'comet-cache'), $_resource_type));
611
+ }
612
+ }
613
+ unset($_dir_regex_iteration, $_resource, $_resource_type, $_sub_path_name, $_path_name); // Housekeeping.
614
+
615
+ if ($erase_dir_too) {
616
+ if (!rmdir($dir)) {
617
+ throw new \Exception(sprintf(__('Unable to erase directory: `%1$s`.', 'comet-cache'), $dir));
618
+ }
619
+ ++$counter; // Increment counter for each directory we erase.
620
+ }
621
+ return $counter;
622
+ }
623
+
624
+ /**
625
+ * Try to erase all files/dirs from a directory (for all schemes/hosts);
626
+ * including `[SHORT_NAME]-` prefixed files; or anything else for that matter.
627
+ *
628
+ * WARNING: This does NO LOCKING and NO ATOMIC deletions.
629
+ *
630
+ * @since 150821 Improving recovery under stress.
631
+ *
632
+ * @param string $dir The directory from which to erase files/dirs.
633
+ *
634
+ * SECURITY: This directory MUST be located inside the `/wp-content/` directory.
635
+ * Also, it MUST be a sub-directory of `/wp-content/`, NOT the directory itself.
636
+ * Also, it cannot be: `mu-plugins`, `themes`, or `plugins`.
637
+ * @param bool $erase_dir_too Erase parent? i.e., erase the `$dir` itself also?
638
+ *
639
+ * @return int Total files/directories erased by this routine (if any).
640
+ */
641
+ public function tryErasingAllFilesDirsIn($dir, $erase_dir_too = false)
642
+ {
643
+ $counter = 0; // Initialize counter.
644
+ try {
645
+ $counter += $this->eraseAllFilesDirsIn($dir, $erase_dir_too);
646
+ } catch (\Exception $exception) {
647
+ // Fail softly.
648
+ }
649
+ return $counter;
650
+ }
651
+ }
src/includes/traits/Shared/CacheLockUtils.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CacheLockUtils
7
+ {
8
+ /**
9
+ * Get an exclusive lock on the cache directory.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @throws \Exception If {@link \sem_get()} not available and there's
14
+ * no writable tmp directory for {@link \flock()} either.
15
+ * @throws \Exception If unable to obtain an exclusive lock by any available means.
16
+ * @return array Lock type & resource handle needed to unlock later or FALSE if disabled by filter.
17
+ *
18
+ *
19
+ * @note This call is blocking; i.e. it will not return a lock until a lock becomes possible.
20
+ * In short, this will block the caller until such time as write access becomes possible.
21
+ */
22
+ public function cacheLock()
23
+ {
24
+ if ($this->applyWpFilters(GLOBAL_NS.'\\share::disable_cache_locking', false)
25
+ || $this->applyWpFilters(GLOBAL_NS.'_disable_cache_locking', false)
26
+ ) {
27
+ return false; // Disabled cache locking.
28
+ }
29
+ if (!($wp_config_file = $this->findWpConfigFile())) {
30
+ throw new \Exception(__('Unable to find the wp-config.php file.', 'comet-cache'));
31
+ }
32
+ $lock_type = 'flock'; // Default lock type.
33
+ $lock_type = $this->applyWpFilters(GLOBAL_NS.'\\share::cache_lock_lock_type', $lock_type);
34
+ $lock_type = $this->applyWpFilters(GLOBAL_NS.'_cache_lock_type', $lock_type);
35
+
36
+ if (!in_array($lock_type, ['flock', 'sem'], true)) {
37
+ $lock_type = 'flock'; // Default lock type.
38
+ }
39
+ if ($lock_type === 'sem' && $this->functionIsPossible('sem_get')) {
40
+ if (($ipc_key = ftok($wp_config_file, 'w'))) {
41
+ if (($resource = sem_get($ipc_key, 1)) && sem_acquire($resource)) {
42
+ return ['type' => 'sem', 'resource' => $resource];
43
+ }
44
+ }
45
+ }
46
+ if (!($tmp_dir = $this->getTmpDir())) {
47
+ throw new \Exception(__('No writable tmp directory.', 'comet-cache'));
48
+ }
49
+ $inode_key = fileinode($wp_config_file);
50
+ $mutex = $tmp_dir.'/'.SLUG_TD.'-'.$inode_key.'.lock';
51
+
52
+ if (!($resource = fopen($mutex, 'wb')) || !flock($resource, LOCK_EX)) {
53
+ throw new \Exception(__('Unable to obtain an exclusive lock.', 'comet-cache'));
54
+ }
55
+
56
+ @chmod($mutex, 0666); // See https://git.io/v2WAt
57
+
58
+ return ['type' => 'flock', 'resource' => $resource];
59
+ }
60
+
61
+ /**
62
+ * Release an exclusive lock on the cache directory.
63
+ *
64
+ * @since 150422 Rewrite. Updated 151002 to remove the `array` typecast.
65
+ *
66
+ * @param array|mixed $lock Type & resource.
67
+ */
68
+ public function cacheUnlock($lock)
69
+ {
70
+ if (!is_array($lock)) {
71
+ return; // Not possible.
72
+ // Or, they disabled cache locking.
73
+ }
74
+ if (empty($lock['type']) || empty($lock['resource'])) {
75
+ return; // Not possible.
76
+ }
77
+ if (!is_resource($lock['resource'])) {
78
+ return; // Not possible.
79
+ }
80
+ if ($lock['type'] === 'sem') {
81
+ sem_release($lock['resource']);
82
+ } elseif ($lock['type'] === 'flock') {
83
+ flock($lock['resource'], LOCK_UN);
84
+ fclose($lock['resource']);
85
+ }
86
+ }
87
+ }
src/includes/traits/Shared/CachePathUtils.php ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait CachePathUtils
7
+ {
8
+ /**
9
+ * Cache-path suffix frag (regex).
10
+ *
11
+ * @since 151220 Enhancing translation support.
12
+ *
13
+ * @param string $regex_suffix_frag Existing regex suffix frag?
14
+ *
15
+ * @return string Cache-path suffix frag (regex).
16
+ */
17
+ public function cachePathRegexSuffixFrag($regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
18
+ {
19
+ if ($regex_suffix_frag === $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG) {
20
+ return $this->cachePathRegexDefaultSuffixFrag();
21
+ }
22
+ return (string) $regex_suffix_frag;
23
+ }
24
+
25
+ /**
26
+ * Default cache-path suffix frag (regex).
27
+ *
28
+ * @since 151220 Enhancing translation support.
29
+ *
30
+ * @return string Default cache-path suffix frag (regex).
31
+ *
32
+ * @TODO Use conditional to detect the AMP plugin (e.g., `isAmpInstalled()`) to avoid edge cases with the `|\/amp` regex here
33
+ */
34
+ public function cachePathRegexDefaultSuffixFrag()
35
+ {
36
+ if ($this->isPlugin() && !empty($GLOBALS['wp_rewrite'])) {
37
+ $pagination_base = $GLOBALS['wp_rewrite']->pagination_base;
38
+ $comments_pagination_base = $GLOBALS['wp_rewrite']->comments_pagination_base;
39
+ return '(?:\/index|\/amp)?(?:\.|\/(?:'.preg_quote($pagination_base, '/').'\/[0-9]+|'.preg_quote($comments_pagination_base, '/').'\-[0-9]+)[.\/])';
40
+ } else {
41
+ return '(?:\/index|\/amp)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])';
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Converts a URL into a `cache/path` based on input `$flags`.
47
+ *
48
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
49
+ *
50
+ * @param string $url The input URL to convert.
51
+ * @param string $with_user_token Optional user token (if applicable).
52
+ * @param string $with_version_salt Optional version salt (if applicable).
53
+ * @param int $flags Optional flags. A bitmask via `$this::CACHE_PATH_*` constants.
54
+ *
55
+ * @return string The resulting `cache/path` based on the input `$url` & `$flags`.
56
+ */
57
+ public function buildCachePath($url, $with_user_token = '', $with_version_salt = '', $flags = self::CACHE_PATH_DEFAULT)
58
+ {
59
+ # Force parameter types.
60
+
61
+ $url = trim((string) $url);
62
+ $with_user_token = trim((string) $with_user_token);
63
+ $with_version_salt = trim((string) $with_version_salt);
64
+
65
+ # Initialize variables.
66
+
67
+ $is_multisite = is_multisite();
68
+ $can_consider_domain_mapping = $is_multisite && $this->canConsiderDomainMapping();
69
+ $cache_path = ''; // Initialize cache path being built here.
70
+
71
+ # Deal w/ domain mapping considerations.
72
+
73
+ if ($flags & $this::CACHE_PATH_CONSIDER_DOMAIN_MAPPING && $is_multisite && $can_consider_domain_mapping) {
74
+ if ($flags & $this::CACHE_PATH_REVERSE_DOMAIN_MAPPING) {
75
+ $url = $this->domainMappingReverseUrlFilter($url);
76
+ } else {
77
+ $url = $this->domainMappingUrlFilter($url);
78
+ }
79
+ }
80
+ # Validate the URL we have now.
81
+
82
+ if (!$url || !($url_parts = $this->parseUrl($url))) {
83
+ return $cache_path = ''; // Not possible.
84
+ }
85
+ if (empty($url_parts['scheme']) || $url_parts['scheme'] === '//') {
86
+ return $cache_path = ''; // Not possible.
87
+ }
88
+ if (empty($url_parts['host'])) {
89
+ return $cache_path = ''; // Not possible.
90
+ }
91
+ # Initialize additional variables; based on the parsed URL.
92
+
93
+ $is_url_domain_mapped = $is_multisite && $can_consider_domain_mapping && $this->domainMappingBlogId($url);
94
+ $host_base_dir_tokens = $this->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
95
+
96
+ $is_a_multisite_base_dir = $is_multisite && $host_base_dir_tokens && $host_base_dir_tokens !== '/' // Check?
97
+ && stripos(!empty($url_parts['path']) ? rtrim($url_parts['path'], '/').'/' : '/', $host_base_dir_tokens) === 0;
98
+
99
+ $is_a_multisite_base_dir_root = $is_multisite && $is_a_multisite_base_dir // Save time by using the previous check here.
100
+ && strcasecmp(trim($host_base_dir_tokens, '/'), trim(!empty($url_parts['path']) ? $url_parts['path'] : '/', '/')) === 0;
101
+
102
+ # Build and return the cache path.
103
+
104
+ if (!($flags & $this::CACHE_PATH_NO_SCHEME)) {
105
+ $cache_path .= $url_parts['scheme'].'/';
106
+ }
107
+ if (!($flags & $this::CACHE_PATH_NO_HOST)) {
108
+ $cache_path .= $url_parts['host'].'/';
109
+
110
+ // Put multisite sub-roots into a host directory of their own.
111
+ // e.g., `example-com[[-base]-child1]` instead of `example-com`.
112
+ if ($is_a_multisite_base_dir && $host_base_dir_tokens && $host_base_dir_tokens !== '/') {
113
+ $host_base_dir_suffix = preg_replace('/[^a-z0-9.]/i', '-', rtrim($host_base_dir_tokens, '/'));
114
+ $cache_path = rtrim($cache_path, '/').$host_base_dir_suffix.'/';
115
+ }
116
+ }
117
+ if (!($flags & $this::CACHE_PATH_NO_PATH)) {
118
+ if (isset($url_parts['path'][201])) {
119
+ $_path_tmp = '/'; // Initialize tmp path.
120
+ foreach (explode('/', $url_parts['path']) as $_path_component) {
121
+ if (!isset($_path_component[0])) {
122
+ continue; // Empty.
123
+ }
124
+ if (isset($_path_component[201])) {
125
+ $_path_component = 'lpc-'.sha1($_path_component);
126
+ }
127
+ $_path_tmp .= $_path_component.'/';
128
+ }
129
+ $url_parts['path'] = $_path_tmp; // Shorter components.
130
+ unset($_path_component, $_path_tmp); // Housekeeping.
131
+
132
+ if (isset($url_parts['path'][2001])) {
133
+ $url_parts['path'] = '/lp-'.sha1($url_parts['path']).'/';
134
+ }
135
+ } // Now add the path and check for a possible root `index/` suffix.
136
+ if (!empty($url_parts['path']) && strlen($url_parts['path'] = trim($url_parts['path'], '\\/'." \t\n\r\0\x0B"))) {
137
+ $cache_path .= $url_parts['path'].'/'; // Add the path as it exists.
138
+
139
+ if (!($flags & $this::CACHE_PATH_NO_PATH_INDEX) && $is_multisite && $is_a_multisite_base_dir_root) {
140
+ // We should build an `index/` when this ends with a multisite [[/base]/child1] root.
141
+ // e.g., `http/example-com[[-base]-child1][[/base]/child1]` is a root directory.
142
+ $cache_path .= 'index/'; // Use an index suffix.
143
+ }
144
+ } elseif (!($flags & $this::CACHE_PATH_NO_PATH_INDEX)) {
145
+ $cache_path .= 'index/';
146
+ }
147
+ }
148
+ if ($this->isExtensionLoaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) {
149
+ $cache_path = mb_strtolower($cache_path, 'UTF-8');
150
+ }
151
+ $cache_path = str_replace('.', '-', strtolower($cache_path));
152
+
153
+ if (!($flags & $this::CACHE_PATH_NO_QUV)) {
154
+ if (!($flags & $this::CACHE_PATH_NO_QUERY)) {
155
+ if (isset($url_parts['query']) && $url_parts['query'] !== '') {
156
+ $cache_path = rtrim($cache_path, '/').'.q/'.md5($url_parts['query']).'/';
157
+ }
158
+ }
159
+ if (!($flags & $this::CACHE_PATH_NO_USER)) {
160
+ if ($with_user_token !== '') {
161
+ $cache_path = rtrim($cache_path, '/').'.u/'.str_replace(['/', '\\'], '-', $with_user_token).'/';
162
+ }
163
+ }
164
+ if (!($flags & $this::CACHE_PATH_NO_VSALT)) {
165
+ if ($with_version_salt !== '') {
166
+ $cache_path = rtrim($cache_path, '/').'.v/'.str_replace(['/', '\\'], '-', $with_version_salt).'/';
167
+ }
168
+ }
169
+ }
170
+ $cache_path = trim(preg_replace(['/\/+/', '/\.+/'], ['/', '.'], $cache_path), '/');
171
+
172
+ if ($flags & $this::CACHE_PATH_ALLOW_WD_REGEX) {
173
+ $cache_path = preg_replace('/[^a-z0-9\/.*\^$]/i', '-', $cache_path);
174
+ } elseif ($flags & $this::CACHE_PATH_ALLOW_WILDCARDS) {
175
+ $cache_path = preg_replace('/[^a-z0-9\/.*]/i', '-', $cache_path);
176
+ } else {
177
+ $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path);
178
+ }
179
+ if (!($flags & $this::CACHE_PATH_NO_EXT)) {
180
+ $cache_path .= '.html';
181
+ }
182
+ return $cache_path;
183
+ }
184
+
185
+ /**
186
+ * Regex pattern for a call to `deleteFilesFromCacheDir()`.
187
+ *
188
+ * @since 151114 Updated to support an arbitrary URL instead of a regex frag.
189
+ *
190
+ * @param string $url The input URL to convert. This CAN be left empty when necessary.
191
+ * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
192
+ * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
193
+ * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
194
+ * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
195
+ * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
196
+ * See also: {@link $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
197
+ *
198
+ * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
199
+ */
200
+ public function buildCachePathRegex($url, $regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
201
+ {
202
+ $url = trim((string) $url);
203
+ $regex_suffix_frag = $this->cachePathRegexSuffixFrag($regex_suffix_frag);
204
+ $cache_path_regex = ''; // Initialize regex.
205
+
206
+ if ($url) {
207
+ $flags = $this::CACHE_PATH_NO_SCHEME // Scheme added below.
208
+ | $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT;
209
+ $cache_path = $this->buildCachePath($url, '', '', $flags); // Without the scheme.
210
+ $cache_path_regex = isset($cache_path[0]) ? '\/https?\/'.preg_quote($cache_path, '/') : '';
211
+ }
212
+ return '/^'.$cache_path_regex.$regex_suffix_frag.'/i';
213
+ }
214
+
215
+ /**
216
+ * Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
217
+ *
218
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
219
+ *
220
+ * @param string $url The input URL to convert. This CAN be left empty when necessary.
221
+ * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
222
+ * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
223
+ * @param string $regex_suffix_frag Regex fragment to come after the relative cache/path regex frag.
224
+ * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
225
+ * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
226
+ * See also: {@link $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
227
+ *
228
+ * @return string Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
229
+ */
230
+ public function buildHostCachePathRegex($url, $regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
231
+ {
232
+ $url = trim((string) $url);
233
+ $regex_suffix_frag = $this->cachePathRegexSuffixFrag($regex_suffix_frag);
234
+ $abs_relative_cache_path_regex = ''; // Initialize regex.
235
+ $is_url_domain_mapped = false; // Initialize.
236
+
237
+ if ($url) {
238
+ if (is_multisite() && $this->canConsiderDomainMapping()) {
239
+ // Shortest possible URI; i.e., consider domain mapping.
240
+ $url = $this->domainMappingUrlFilter($url);
241
+ $is_url_domain_mapped = $url && $this->domainMappingBlogId($url);
242
+ }
243
+ if ($url && ($url_parts = $this->parseUrl($url)) && !empty($url_parts['host'])) {
244
+ $flags = $this::CACHE_PATH_NO_SCHEME | $this::CACHE_PATH_NO_HOST
245
+ | $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT;
246
+
247
+ $host_base_dir_tokens = $this->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
248
+ $host_url = rtrim('http://'.$url_parts['host'].$host_base_dir_tokens, '/');
249
+ $host_cache_path = $this->buildCachePath($host_url, '', '', $flags);
250
+
251
+ $cache_path = $this->buildCachePath($url, '', '', $flags);
252
+ $relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $cache_path);
253
+
254
+ $abs_relative_cache_path = isset($relative_cache_path[0]) ? '/'.$relative_cache_path : '';
255
+ $abs_relative_cache_path_regex = isset($abs_relative_cache_path[0]) ? preg_quote($abs_relative_cache_path, '/') : '';
256
+ }
257
+ }
258
+ return '/^'.$abs_relative_cache_path_regex.$regex_suffix_frag.'/i';
259
+ }
260
+
261
+ /**
262
+ * Regex pattern for a call to `deleteFilesFromCacheDir()`.
263
+ *
264
+ * @since 151114 Improving watered-down regex syntax.
265
+ *
266
+ * @param string $url The input URL to convert. This CAN be left empty when necessary.
267
+ * This may also contain watered-down regex; i.e., `*^$` characters are OK here.
268
+ * However, `^$` are discarded, as they are unnecessary in this context.
269
+ *
270
+ * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
271
+ * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
272
+ * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
273
+ * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
274
+ * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
275
+ * See also: {@link $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
276
+ *
277
+ * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
278
+ */
279
+ public function buildCachePathRegexFromWcUrl($url, $regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
280
+ {
281
+ $url = trim((string) $url, '^$');
282
+ $regex_suffix_frag = $this->cachePathRegexSuffixFrag($regex_suffix_frag);
283
+ $cache_path_regex = ''; // Initialize regex.
284
+
285
+ if ($url) { // After `^$` trimming above.
286
+ $flags = $this::CACHE_PATH_ALLOW_WILDCARDS | $this::CACHE_PATH_NO_SCHEME
287
+ | $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT;
288
+ $cache_path = $this->buildCachePath($url, '', '', $flags); // Without the scheme.
289
+ $cache_path_regex = isset($cache_path[0]) ? '\/https?\/'.$this->wdRegexToActualRegexFrag($cache_path) : '';
290
+ }
291
+ return '/^'.$cache_path_regex.$regex_suffix_frag.'/i';
292
+ }
293
+
294
+ /**
295
+ * Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
296
+ *
297
+ * @since 150422 Rewrite. Updated 151002 w/ multisite compat. improvements.
298
+ *
299
+ * @param string $uris A line-delimited list of URIs. These may contain `*^$` also.
300
+ * However, `^$` are discarded, as they are unnecessary in this context.
301
+ * @param string $regex_suffix_frag Regex fragment to come after each relative cache/path.
302
+ * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
303
+ * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
304
+ * See also: {@link $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
305
+ *
306
+ * @return string Regex pattern for a call to `deleteFilesFromHostCacheDir()`.
307
+ */
308
+ public function buildHostCachePathRegexFragsFromWcUris($uris, $regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
309
+ {
310
+ $uris = trim((string) $uris);
311
+ $regex_suffix_frag = $this->cachePathRegexSuffixFrag($regex_suffix_frag);
312
+
313
+ $flags = $this::CACHE_PATH_ALLOW_WILDCARDS | $this::CACHE_PATH_NO_SCHEME | $this::CACHE_PATH_NO_HOST
314
+ | $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT;
315
+
316
+ $host = 'doesnt-matter.foo.bar';
317
+ $host_url = rtrim('http://'.$host, '/');
318
+ $host_cache_path = $this->buildCachePath($host_url, '', '', $flags);
319
+ $uri_patterns = array_unique(preg_split('/['."\r\n".']+/', $uris, -1, PREG_SPLIT_NO_EMPTY));
320
+
321
+ foreach ($uri_patterns as $_key => &$_uri_pattern) {
322
+ if (($_uri_pattern = trim($_uri_pattern, '^$'))) {
323
+ $_cache_path = $this->buildCachePath($host_url.'/'.trim($_uri_pattern, '/'), '', '', $flags);
324
+ $_relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
325
+ $_uri_pattern = $this->wdRegexToActualRegexFrag($_relative_cache_path);
326
+ }
327
+ if (!$_uri_pattern) {
328
+ unset($uri_patterns[$_key]); // Remove it.
329
+ }
330
+ }
331
+ unset($_key, $_uri_pattern, $_cache_path, $_relative_cache_path); // Housekeeping.
332
+
333
+ return $uri_patterns ? '(?:'.implode('|', array_unique($uri_patterns)).')'.$regex_suffix_frag : '';
334
+ }
335
+
336
+ /**
337
+ * Regex pattern for a call to `deleteFilesFromCacheDir()`.
338
+ *
339
+ * @since 151114 Moving this low-level routine into a method of a different name.
340
+ *
341
+ * @param string $regex_frag A regex fragment. This CAN be left empty when necessary.
342
+ * If empty, the final regex pattern will be `/^'.$regex_suffix_frag.'/i`.
343
+ * If empty, it's a good idea to start `$regex_suffix_frag` with `.*?`.
344
+ * @param string $regex_suffix_frag Regex fragment to come after the `$regex_frag`.
345
+ * Defaults to: `(?:\/index)?(?:\.|\/(?:page\/[0-9]+|comment\-page\-[0-9]+)[.\/])`.
346
+ * Note: this should NOT have delimiters; i.e. do NOT start or end with `/`.
347
+ * See also: {@link $this::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG}.
348
+ *
349
+ * @return string Regex pattern for a call to `deleteFilesFromCacheDir()`.
350
+ */
351
+ public function assembleCachePathRegex($regex_frag, $regex_suffix_frag = self::CACHE_PATH_REGEX_DEFAULT_SUFFIX_FRAG)
352
+ {
353
+ $regex_frag = (string) $regex_frag;
354
+ $regex_suffix_frag = $this->cachePathRegexSuffixFrag($regex_suffix_frag);
355
+
356
+ return '/^'.$regex_frag.$regex_suffix_frag.'/i';
357
+ }
358
+ }
src/includes/traits/Shared/ConditionalUtils.php ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ConditionalUtils
7
+ {
8
+ /**
9
+ * PHP's language constructs.
10
+ *
11
+ * @type array PHP's language constructs.
12
+ * Keys are currently unimportant. Subject to change.
13
+ *
14
+ * @since 160222 First documented version.
15
+ */
16
+ public $php_constructs = [
17
+ 'die' => 'die',
18
+ 'echo' => 'echo',
19
+ 'empty' => 'empty',
20
+ 'exit' => 'exit',
21
+ 'eval' => 'eval',
22
+ 'include' => 'include',
23
+ 'include_once' => 'include_once',
24
+ 'isset' => 'isset',
25
+ 'list' => 'list',
26
+ 'require' => 'require',
27
+ 'require_once' => 'require_once',
28
+ 'return' => 'return',
29
+ 'print' => 'print',
30
+ 'unset' => 'unset',
31
+ '__halt_compiler' => '__halt_compiler',
32
+ ];
33
+
34
+ /**
35
+ * Is AdvancedCache class?
36
+ *
37
+ * @since 150821 Improving multisite compat.
38
+ *
39
+ * @return bool `TRUE` if this is the AdvancedCache class.
40
+ */
41
+ public function isAdvancedCache()
42
+ {
43
+ return $this instanceof Classes\AdvancedCache;
44
+ }
45
+
46
+ /**
47
+ * Is Plugin class?
48
+ *
49
+ * @since 150821 Improving multisite compat.
50
+ *
51
+ * @return bool `TRUE` if this is the Plugin class.
52
+ */
53
+ public function isPlugin()
54
+ {
55
+ return $this instanceof Classes\Plugin;
56
+ }
57
+
58
+ /**
59
+ * Is the current request method `POST`, `PUT` or `DELETE`?
60
+ *
61
+ * @since 150422 Rewrite.
62
+ *
63
+ * @return bool `TRUE` if current request method is `POST`, `PUT` or `DELETE`.
64
+ *
65
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
66
+ */
67
+ public function isPostPutDeleteRequest()
68
+ {
69
+ if (!is_null($is = &$this->staticKey('isPostPutDeleteRequest'))) {
70
+ return $is; // Already cached this.
71
+ }
72
+ if (!empty($_POST)) {
73
+ return $is = true;
74
+ }
75
+ if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
76
+ if (in_array(strtoupper($_SERVER['REQUEST_METHOD']), ['POST', 'PUT', 'DELETE'], true)) {
77
+ return $is = true;
78
+ }
79
+ }
80
+ return $is = false;
81
+ }
82
+
83
+ /**
84
+ * Does the current request include an uncacheable query string?
85
+ *
86
+ * @since 151002 Improving Nginx support.
87
+ *
88
+ * @return bool True if request includes an uncacheable query string.
89
+ *
90
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
91
+ */
92
+ public function requestContainsUncacheableQueryVars()
93
+ {
94
+ if (!is_null($is = &$this->staticKey('requestContainsUncacheableQueryVars'))) {
95
+ return $is; // Already cached this.
96
+ }
97
+ if (!empty($_GET) || !empty($_SERVER['QUERY_STRING'])) {
98
+ $_get_count = !empty($_GET) ? count($_GET) : 0;
99
+ $is_abc_only = $_get_count === 1 && isset($_GET[strtolower(SHORT_NAME).'ABC']);
100
+ $is_nginx_q_only = $_get_count === 1 && isset($_GET['q']) && $this->isNginx();
101
+ $is_ac_get_var_true = isset($_GET[strtolower(SHORT_NAME).'AC']) && filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN);
102
+
103
+ if (!$is_abc_only && !$is_nginx_q_only && !$is_ac_get_var_true) {
104
+ return $is = true;
105
+ }
106
+ }
107
+ return $is = false;
108
+ }
109
+
110
+ /**
111
+ * Is the current request method is uncacheable?
112
+ *
113
+ * @since 150422 Rewrite.
114
+ *
115
+ * @return bool `TRUE` if current request method is uncacheable.
116
+ *
117
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
118
+ */
119
+ public function isUncacheableRequestMethod()
120
+ {
121
+ if (!is_null($is = &$this->staticKey('isUncacheableRequestMethod'))) {
122
+ return $is; // Already cached this.
123
+ }
124
+ if (!empty($_POST)) {
125
+ return $is = true;
126
+ }
127
+ if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
128
+ if (!in_array(strtoupper($_SERVER['REQUEST_METHOD']), ['GET'], true)) {
129
+ return $is = true;
130
+ }
131
+ }
132
+ return $is = false;
133
+ }
134
+
135
+ /**
136
+ * Should the current user should be considered a logged-in user?
137
+ *
138
+ * @since 150422 Rewrite.
139
+ *
140
+ * @return bool `TRUE` if current user should be considered a logged-in user.
141
+ *
142
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
143
+ */
144
+ public function isLikeUserLoggedIn()
145
+ {
146
+ if (!is_null($is = &$this->staticKey('isLikeUserLoggedIn'))) {
147
+ return $is; // Already cached this.
148
+ }
149
+ if (defined('SID') && SID) {
150
+ return $is = true; // Session ID.
151
+ }
152
+ if (empty($_COOKIE)) {
153
+ return $is = false; // No cookies.
154
+ }
155
+ $regex_logged_in_cookies = '/^'; // Initialize.
156
+
157
+ if (defined('LOGGED_IN_COOKIE') && LOGGED_IN_COOKIE) {
158
+ $regex_logged_in_cookies .= preg_quote(LOGGED_IN_COOKIE, '/');
159
+ } else { // Use the default hard-coded cookie prefix.
160
+ $regex_logged_in_cookies .= 'wordpress_logged_in_';
161
+ }
162
+ $regex_logged_in_cookies .= '|comment_author_';
163
+ $regex_logged_in_cookies .= '|wp[_\-]postpass_';
164
+
165
+ $regex_logged_in_cookies .= '/'; // Close regex.
166
+
167
+ foreach ($_COOKIE as $_key => $_value) {
168
+ if ($_value && preg_match($regex_logged_in_cookies, $_key)) {
169
+ return $is = true; // Like a logged-in user.
170
+ }
171
+ }
172
+ unset($_key, $_value); // Housekeeping.
173
+
174
+ return $is = false;
175
+ }
176
+
177
+ /**
178
+ * Are we in a LOCALHOST environment?
179
+ *
180
+ * @since 150422 Rewrite.
181
+ *
182
+ * @return bool `TRUE` if we are in a LOCALHOST environment.
183
+ *
184
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
185
+ */
186
+ public function isLocalhost()
187
+ {
188
+ if (!is_null($is = &$this->staticKey('isLocalhost'))) {
189
+ return $is; // Already cached this.
190
+ }
191
+ if (defined('LOCALHOST')) {
192
+ return $is = (boolean) LOCALHOST;
193
+ }
194
+ if (preg_match('/\b(?:localhost|127\.0\.0\.1)\b/i', $this->hostToken())) {
195
+ return $is = true;
196
+ }
197
+ return $is = false;
198
+ }
199
+
200
+
201
+
202
+ /**
203
+ * Is the current request for a feed?
204
+ *
205
+ * @since 150422 Rewrite.
206
+ *
207
+ * @return bool `TRUE` if the current request is for a feed.
208
+ *
209
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
210
+ */
211
+ public function isFeed()
212
+ {
213
+ if (!is_null($is = &$this->staticKey('isFeed'))) {
214
+ return $is; // Already cached this.
215
+ }
216
+ if (isset($_REQUEST['feed'])) {
217
+ return $is = true;
218
+ }
219
+ if (!empty($_SERVER['REQUEST_URI']) && is_string($_SERVER['REQUEST_URI'])) {
220
+ if (preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) {
221
+ return $is = true;
222
+ }
223
+ }
224
+ return $is = false;
225
+ }
226
+
227
+ /**
228
+ * Is a document/string an HTML/XML doc; or no?
229
+ *
230
+ * @since 150422 Rewrite.
231
+ *
232
+ * @param string $doc Input string/document to check.
233
+ *
234
+ * @return bool True if `$doc` is an HTML/XML doc type.
235
+ */
236
+ public function isHtmlXmlDoc($doc)
237
+ {
238
+ $doc = trim((string) $doc);
239
+ $doc_hash = sha1($doc);
240
+
241
+ if (!is_null($is = &$this->staticKey('isHtmlXmlDoc', $doc_hash))) {
242
+ return $is; // Already cached this.
243
+ }
244
+ if (stripos($doc, '</html>') !== false) {
245
+ return $is = true;
246
+ }
247
+ if (stripos($doc, '<?xml') === 0) {
248
+ return $is = true;
249
+ }
250
+ return $is = false;
251
+ }
252
+
253
+ /**
254
+ * Does the current request have a cacheable content type?
255
+ *
256
+ * @since 150422 Rewrite.
257
+ *
258
+ * @return bool `TRUE` if the current request has a cacheable content type.
259
+ *
260
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
261
+ *
262
+ * @warning Do NOT call upon this method until the end of a script execution.
263
+ */
264
+ public function hasACacheableContentType()
265
+ {
266
+ if (!is_null($is = &$this->staticKey('hasACacheableContentType'))) {
267
+ return $is; // Already cached this.
268
+ }
269
+ foreach ($this->headersList() as $_key => $_header) {
270
+ if (stripos($_header, 'Content-Type:') === 0) {
271
+ $content_type = $_header; // Last one.
272
+ }
273
+ }
274
+ unset($_key, $_header); // Housekeeping.
275
+
276
+ if (isset($content_type[0]) && stripos($content_type, 'html') === false
277
+ && stripos($content_type, 'xml') === false && stripos($content_type, GLOBAL_NS) === false
278
+ ) {
279
+ return $is = false; // Do NOT cache data sent by scripts serving other MIME types.
280
+ }
281
+ return $is = true;
282
+ }
283
+
284
+ /**
285
+ * Does the current request have a cacheable HTTP status code?
286
+ *
287
+ * @since 150422 Rewrite.
288
+ *
289
+ * @return bool `TRUE` if the current request has a cacheable HTTP status code.
290
+ *
291
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
292
+ *
293
+ * @warning Do NOT call upon this method until the end of a script execution.
294
+ */
295
+ public function hasACacheableStatus()
296
+ {
297
+ if (!is_null($is = &$this->staticKey('hasACacheableStatus'))) {
298
+ return $is; // Already cached this.
299
+ }
300
+ if (($http_status = (string) $this->httpStatus()) && $http_status[0] !== '2' && $http_status !== '404') {
301
+ return $is = false; // A non-2xx & non-404 status code.
302
+ }
303
+ foreach ($this->headersList() as $_key => $_header) {
304
+ if (preg_match('/^(?:Retry\-After\:\s+(?P<retry>.+)|Status\:\s+(?P<status>[0-9]+)|HTTP\/[0-9]+(?:\.[0-9]+)?\s+(?P<http_status>[0-9]+))/i', $_header, $_m)) {
305
+ if (!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404')
306
+ || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404')
307
+ ) {
308
+ return $is = false; // Not a cacheable status.
309
+ }
310
+ }
311
+ }
312
+ unset($_key, $_header); // Housekeeping.
313
+
314
+ return $is = true;
315
+ }
316
+
317
+ /**
318
+ * Checks if a PHP extension is loaded up.
319
+ *
320
+ * @since 150422 Rewrite.
321
+ *
322
+ * @param string $extension A PHP extension slug (i.e. extension name).
323
+ *
324
+ * @return bool `TRUE` if the extension is loaded.
325
+ *
326
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
327
+ */
328
+ public function isExtensionLoaded($extension)
329
+ {
330
+ $extension = (string) $extension;
331
+
332
+ if (!is_null($is = &$this->staticKey('isExtensionLoaded', $extension))) {
333
+ return $is; // Already cached this.
334
+ }
335
+ return $is = (boolean) extension_loaded($extension);
336
+ }
337
+
338
+ /**
339
+ * Is a particular function possible in every way?
340
+ *
341
+ * @since 150422 Rewrite.
342
+ *
343
+ * @param string $function A PHP function (or user function) to check.
344
+ *
345
+ * @return string `TRUE` if the function is possible.
346
+ *
347
+ * @note This checks (among other things) if the function exists and that it's callable.
348
+ * It also checks the currently configured `disable_functions` and `suhosin.executor.func.blacklist`.
349
+ */
350
+ public function functionIsPossible($function)
351
+ {
352
+ $function = (string) $function;
353
+
354
+ if (!is_null($is = &$this->staticKey('functionIsPossible', $function))) {
355
+ return $is; // Already cached this.
356
+ }
357
+ if (is_null($disabled_functions = &$this->staticKey('functionIsPossible_disabled_functions'))) {
358
+ $disabled_functions = []; // Initialize disabled/blacklisted functions.
359
+
360
+ if (($disable_functions = trim(ini_get('disable_functions')))) {
361
+ $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($disable_functions), -1, PREG_SPLIT_NO_EMPTY));
362
+ }
363
+ if (($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) {
364
+ $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($blacklist_functions), -1, PREG_SPLIT_NO_EMPTY));
365
+ }
366
+ if (filter_var(ini_get('suhosin.executor.disable_eval'), FILTER_VALIDATE_BOOLEAN)) {
367
+ $disabled_functions = array_merge($disabled_functions, ['eval']);
368
+ }
369
+ }
370
+ if (!function_exists($function) || !is_callable($function)) {
371
+ if (!in_array($function, $this->php_constructs, true)) { // A language construct
372
+ return $is = false; // Not possible.
373
+ }
374
+ }
375
+ if ($disabled_functions && in_array(strtolower($function), $disabled_functions, true)) {
376
+ return $is = false; // Not possible.
377
+ }
378
+ return $is = true;
379
+ }
380
+ }
src/includes/traits/Shared/DomainMappingUtils.php ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait DomainMappingUtils
7
+ {
8
+ /**
9
+ * Can consider domain mapping?
10
+ *
11
+ * @since 150821 Improving multisite compat.
12
+ *
13
+ * @return bool `TRUE` if we can consider domain mapping.
14
+ *
15
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
16
+ */
17
+ public function canConsiderDomainMapping()
18
+ {
19
+ if (!is_null($can = &$this->staticKey('canConsiderDomainMapping'))) {
20
+ return $can; // Already cached this.
21
+ }
22
+ if (!$this->isAdvancedCache() && is_multisite() && $this->hostBaseToken() === '/'
23
+ && defined('SUNRISE_LOADED') && SUNRISE_LOADED && !empty($GLOBALS['dm_domain'])
24
+ ) {
25
+ return $can = true; // Can consider.
26
+ }
27
+ return $can = false; // Cannot consider.
28
+ }
29
+
30
+ /**
31
+ * Domain mapping?
32
+ *
33
+ * @since 150821 Improving multisite compat.
34
+ *
35
+ * @return int Domain mapping ID; else `0` (false).
36
+ *
37
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
38
+ */
39
+ public function isDomainMapping()
40
+ {
41
+ if (!is_null($is = &$this->staticKey('isDomainMapping'))) {
42
+ return $is; // Already cached this.
43
+ }
44
+ if (!$this->isAdvancedCache() && is_multisite() && $this->canConsiderDomainMapping()
45
+ && defined('DOMAIN_MAPPING') && DOMAIN_MAPPING && !empty($GLOBALS['domain_mapping_id'])
46
+ ) {
47
+ return $is = (integer) $GLOBALS['domain_mapping_id']; // Blog ID.
48
+ }
49
+ return $is = 0; // Not domain mapping.
50
+ }
51
+
52
+ /**
53
+ * Filters a URL in order to apply domain mapping.
54
+ *
55
+ * @since 150821 Improving multisite compat.
56
+ *
57
+ * @param string $url The input URL to filter.
58
+ *
59
+ * @return string The filtered URL; else the original URL.
60
+ *
61
+ * @note The return value of this function is NOT cached, but inner portions are.
62
+ */
63
+ public function domainMappingUrlFilter($url)
64
+ {
65
+ $original_url = (string) $url; // Preserve.
66
+ $url = trim((string) $url);
67
+
68
+ if (!is_multisite() || !$this->canConsiderDomainMapping()) {
69
+ return $original_url; // Not possible.
70
+ }
71
+ if (!$url || !($url_parts = $this->parseUrl($url))) {
72
+ return $original_url; // Not possible.
73
+ }
74
+ if (empty($url_parts['host'])) {
75
+ return $original_url; // Not possible.
76
+ }
77
+ $blog_domain = strtolower($url_parts['host']); // In the unfiltered URL.
78
+ $blog_path = $this->hostDirToken(false, false, !empty($url_parts['path']) ? $url_parts['path'] : '/');
79
+
80
+ if (!($blog_id = (integer) get_blog_id_from_url($blog_domain, $blog_path))) {
81
+ return $original_url; // Not possible.
82
+ }
83
+ if (!($domain = $this->domainMappingBlogDomain($blog_id)) || $domain === $blog_domain) {
84
+ return $original_url; // Not applicable.
85
+ }
86
+ $url_parts['host'] = $domain; // Filter the URL now.
87
+ if (!empty($url_parts['path']) && $url_parts['path'] !== '/') {
88
+ if (($host_base_dir_tokens = trim($this->hostBaseDirTokens(false, false, $url_parts['path']), '/'))) {
89
+ $url_parts['path'] = preg_replace('/^\/'.preg_quote($host_base_dir_tokens, '/').'(\/|$)/i', '${1}', $url_parts['path']);
90
+ }
91
+ }
92
+ return $url = $this->unParseUrl($url_parts);
93
+ }
94
+
95
+ /**
96
+ * Filters a URL in order to remove domain mapping.
97
+ *
98
+ * @since 150821 Improving multisite compat.
99
+ *
100
+ * @param string $url The input URL to filter.
101
+ *
102
+ * @return string The filtered URL; else the original URL.
103
+ *
104
+ * @note The return value of this function is NOT cached, but inner portions are.
105
+ */
106
+ public function domainMappingReverseUrlFilter($url)
107
+ {
108
+ $original_url = (string) $url; // Preserve.
109
+ $url = trim((string) $url);
110
+
111
+ if (!is_multisite() || !$this->canConsiderDomainMapping()) {
112
+ return $original_url; // Not possible.
113
+ }
114
+ if (!$url || !($url_parts = $this->parseUrl($url))) {
115
+ return $original_url; // Not possible.
116
+ }
117
+ if (empty($url_parts['host'])) {
118
+ return $original_url; // Not possible.
119
+ }
120
+ if (!($blog_id = $this->domainMappingBlogId('', $url_parts['host']))) {
121
+ return $original_url; // No a domain in the map.
122
+ }
123
+ if (!($blog_details = $this->blogDetails($blog_id))) {
124
+ return $original_url; // Not possible.
125
+ }
126
+ $url_parts['host'] = $blog_details->domain; // Filter the URL now.
127
+ if (($host_base_dir_tokens = trim($this->hostBaseDirTokens(false, false, $blog_details->path), '/'))) {
128
+ $url_parts['path'] = '/'.$host_base_dir_tokens.'/'.ltrim(@$url_parts['path'], '/');
129
+ }
130
+ return $url = $this->unParseUrl($url_parts);
131
+ }
132
+
133
+ /**
134
+ * Converts a host into a mapped blog ID.
135
+ *
136
+ * @since 150821 Improving multisite compat.
137
+ *
138
+ * @param string $url URL containing the domain to convert.
139
+ * @param string $domain The domain to convert. Override URL is provided.
140
+ *
141
+ * @return int The mapped blog ID; else `0` on failure.
142
+ *
143
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
144
+ */
145
+ public function domainMappingBlogId($url = '', $domain = '')
146
+ {
147
+ $domain = (string) $domain;
148
+ $url = $domain ? '' : (string) $url;
149
+
150
+ if (!is_multisite() || !$this->canConsiderDomainMapping()) {
151
+ return 0; // Not possible/applicable.
152
+ }
153
+ if ($url === 'network' || $domain === 'network') {
154
+ $domain = (string) get_current_site()->domain;
155
+ }
156
+ if (!$domain && $url && $url !== 'network') {
157
+ $domain = $this->parseUrl($url, PHP_URL_HOST);
158
+ }
159
+ if (!$url && !$domain && ($blog_details = $this->blogDetails())) {
160
+ $domain = $blog_details->domain;
161
+ }
162
+ $domain = strtolower(preg_replace('/^www\./i', '', $domain));
163
+
164
+ if (!$domain || strpos($domain, '.') === false) {
165
+ return 0; // Not possible.
166
+ }
167
+ if (!is_null($blog_id = &$this->staticKey('domainMappingBlogId', $domain))) {
168
+ return $blog_id; // Already cached this.
169
+ }
170
+ $wpdb = $this->wpdb(); // WordPress database class.
171
+ $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
172
+ $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
173
+
174
+ if (!$enforcing_primary_domain) {
175
+ $blog_id = (integer) $wpdb->get_var('SELECT `blog_id` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC, `active` DESC LIMIT 1');
176
+ } else {
177
+ $blog_id = (integer) $wpdb->get_var('SELECT `blog_id` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') AND `active` = \'1\' ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
178
+ }
179
+ $wpdb->suppress_errors($suppressing_errors); // Restore.
180
+
181
+ return $blog_id = (integer) $blog_id;
182
+ }
183
+
184
+ /**
185
+ * Converts a blog ID into a mapped domain.
186
+ *
187
+ * @since 150821 Improving multisite compat.
188
+ *
189
+ * @param int $blog_id The blog ID.
190
+ * @param bool $fallback Fallback on blog's domain?
191
+ *
192
+ * @return string The mapped domain, else an empty string.
193
+ *
194
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
195
+ */
196
+ public function domainMappingBlogDomain($blog_id = 0, $fallback = false)
197
+ {
198
+ if (!is_multisite() || !$this->canConsiderDomainMapping()) {
199
+ return ''; // Not possible/applicable.
200
+ }
201
+ if (($blog_id = (integer) $blog_id) < 0) {
202
+ $blog_id = (integer) get_current_site()->blog_id;
203
+ }
204
+ if (!$blog_id) {
205
+ $blog_id = (integer) get_current_blog_id();
206
+ }
207
+ if (!$blog_id || $blog_id < 0) {
208
+ return ''; // Not possible.
209
+ }
210
+ if (!is_null($domain = &$this->staticKey('domainMappingBlogDomain', $blog_id))) {
211
+ return $domain; // Already cached this.
212
+ }
213
+ $wpdb = $this->wpdb(); // WordPress database class.
214
+ $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
215
+ $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
216
+
217
+ if (!$enforcing_primary_domain) {
218
+ if ($this->isDomainMapping() === $blog_id) {
219
+ $domain = $this->hostToken();
220
+ $domain = preg_replace('/^www\./i', '', $domain);
221
+ $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
222
+ } elseif (($domains = $this->domainMappingBlogDomains($blog_id))) {
223
+ $domain = $domains[0]; // Use the first of all possible domains.
224
+ }
225
+ } else { // A single primary domain in this case; i.e., `active` = primary.
226
+ $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' AND `active` = \'1\' LIMIT 1');
227
+ }
228
+ if (!$domain && $fallback && ($blog_details = $this->blogDetails($blog_id))) {
229
+ $domain = $blog_details->domain; // Use original domain.
230
+ }
231
+ $wpdb->suppress_errors($suppressing_errors); // Restore.
232
+
233
+ return $domain = strtolower((string) $domain);
234
+ }
235
+
236
+ /**
237
+ * Converts a blog ID into mapped domains (plural).
238
+ *
239
+ * @since 150821 Improving multisite compat.
240
+ *
241
+ * @param int $blog_id The blog ID.
242
+ *
243
+ * @return array Mapped domains; else an empty array.
244
+ *
245
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
246
+ */
247
+ public function domainMappingBlogDomains($blog_id = 0)
248
+ {
249
+ if (!is_multisite() || !$this->canConsiderDomainMapping()) {
250
+ return []; // Not possible/applicable.
251
+ }
252
+ if (($blog_id = (integer) $blog_id) < 0) {
253
+ $blog_id = (integer) get_current_site()->blog_id;
254
+ }
255
+ if (!$blog_id) {
256
+ $blog_id = (integer) get_current_blog_id();
257
+ }
258
+ if (!$blog_id || $blog_id < 0) {
259
+ return []; // Not possible.
260
+ }
261
+ if (!is_null($domains = &$this->staticKey('domainMappingBlogDomains', $blog_id))) {
262
+ return $domains; // Already cached this.
263
+ }
264
+ $wpdb = $this->wpdb(); // WordPress database class.
265
+ $suppressing_errors = $wpdb->suppress_errors(); // In case table has not been created yet.
266
+ $enforcing_primary_domain = !get_site_option('dm_no_primary_domain'); // Enforcing primary domain?
267
+
268
+ if (!$enforcing_primary_domain) { // Not enforcing a primary domain, so let's pull all of the domains.
269
+ $domains = $wpdb->get_col('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' ORDER BY `active` DESC');
270
+ } else { // Primary domains in this case; i.e., `active` = primary.
271
+ $domains = $wpdb->get_col('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IS NOT NULL AND `domain` != \'\' AND `active` = \'1\'');
272
+ }
273
+ $wpdb->suppress_errors($suppressing_errors); // Restore.
274
+
275
+ return $domains = array_unique(array_map('strtolower', (array) $domains));
276
+ }
277
+ }
src/includes/traits/Shared/EscapeUtils.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait EscapeUtils
7
+ {
8
+ /**
9
+ * Escape single quotes.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $string Input string to escape.
14
+ * @param int $times Optional. Defaults to one escape char; e.g. `\'`.
15
+ * If you need to escape more than once, set this to something > `1`.
16
+ *
17
+ * @return string Escaped string; e.g. `Raam\'s the lead developer`.
18
+ */
19
+ public function escSq($string, $times = 1)
20
+ {
21
+ return str_replace("'", str_repeat('\\', abs($times))."'", (string) $string);
22
+ }
23
+ }
src/includes/traits/Shared/FsUtils.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait FsUtils
7
+ {
8
+ /**
9
+ * Normalizes directory/file separators.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $dir_file Directory/file path.
14
+ * @param bool $allow_trailing_slash Defaults to FALSE.
15
+ * If TRUE; and `$dir_file` contains a trailing slash; we'll leave it there.
16
+ *
17
+ * @return string Normalized directory/file path.
18
+ */
19
+ public function nDirSeps($dir_file, $allow_trailing_slash = false)
20
+ {
21
+ $dir_file = (string) $dir_file;
22
+
23
+ if (!isset($dir_file[0])) {
24
+ return ''; // Catch empty string.
25
+ }
26
+ if (strpos($dir_file, '://' !== false)) {
27
+ if (preg_match('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', $dir_file, $stream_wrapper)) {
28
+ $dir_file = preg_replace('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', '', $dir_file);
29
+ }
30
+ }
31
+ if (strpos($dir_file, ':' !== false)) {
32
+ if (preg_match('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', $dir_file)) {
33
+ $dir_file = preg_replace_callback('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', create_function('$m', 'return strtoupper($m[0]);'), $dir_file);
34
+ }
35
+ }
36
+ $dir_file = preg_replace('/\/+/', '/', str_replace([DIRECTORY_SEPARATOR, '\\', '/'], '/', $dir_file));
37
+ $dir_file = ($allow_trailing_slash) ? $dir_file : rtrim($dir_file, '/'); // Strip trailing slashes.
38
+
39
+ if (!empty($stream_wrapper[0])) {
40
+ $dir_file = strtolower($stream_wrapper[0]).$dir_file;
41
+ }
42
+ return $dir_file; // Normalized now.
43
+ }
44
+
45
+ /**
46
+ * Acquires system tmp directory path.
47
+ *
48
+ * @since 150422 Rewrite.
49
+ *
50
+ * @return string System tmp directory path; else an empty string.
51
+ */
52
+ public function getTmpDir()
53
+ {
54
+ if (!is_null($dir = &$this->staticKey('getTmpDir'))) {
55
+ return $dir; // Already cached this.
56
+ }
57
+ $possible_dirs = []; // Initialize.
58
+
59
+ if (defined('WP_TEMP_DIR')) {
60
+ $possible_dirs[] = (string) WP_TEMP_DIR;
61
+ }
62
+ if ($this->functionIsPossible('sys_get_temp_dir')) {
63
+ $possible_dirs[] = (string) sys_get_temp_dir();
64
+ }
65
+ $possible_dirs[] = (string) ini_get('upload_tmp_dir');
66
+
67
+ if (!empty($_SERVER['TEMP'])) {
68
+ $possible_dirs[] = (string) $_SERVER['TEMP'];
69
+ }
70
+ if (!empty($_SERVER['TMPDIR'])) {
71
+ $possible_dirs[] = (string) $_SERVER['TMPDIR'];
72
+ }
73
+ if (!empty($_SERVER['TMP'])) {
74
+ $possible_dirs[] = (string) $_SERVER['TMP'];
75
+ }
76
+ if (stripos(PHP_OS, 'win') === 0) {
77
+ $possible_dirs[] = 'C:/Temp';
78
+ }
79
+ if (stripos(PHP_OS, 'win') !== 0) {
80
+ $possible_dirs[] = '/tmp';
81
+ }
82
+ if (defined('WP_CONTENT_DIR')) {
83
+ $possible_dirs[] = (string) WP_CONTENT_DIR;
84
+ }
85
+ foreach ($possible_dirs as $_key => $_dir) {
86
+ if (($_dir = trim((string) $_dir)) && @is_dir($_dir) && @is_writable($_dir)) {
87
+ return $dir = $this->nDirSeps($_dir);
88
+ }
89
+ }
90
+ unset($_key, $_dir); // Housekeeping.
91
+
92
+ return $dir = '';
93
+ }
94
+
95
+ /**
96
+ * Finds absolute server path to `/wp-config.php` file.
97
+ *
98
+ * @since 150422 Rewrite.
99
+ *
100
+ * @return string Absolute server path to `/wp-config.php` file;
101
+ * else an empty string if unable to locate the file.
102
+ */
103
+ public function findWpConfigFile()
104
+ {
105
+ if (!is_null($file = &$this->staticKey('findWpConfigFile'))) {
106
+ return $file; // Already cached this.
107
+ }
108
+ $file = ''; // Initialize.
109
+
110
+ if (is_file($abspath_wp_config = ABSPATH.'wp-config.php')) {
111
+ $file = $abspath_wp_config;
112
+ } elseif (is_file($dirname_abspath_wp_config = dirname(ABSPATH).'/wp-config.php')) {
113
+ $file = $dirname_abspath_wp_config;
114
+ }
115
+ return $file;
116
+ }
117
+
118
+ /**
119
+ * Adds a tmp name suffix to a directory/file path.
120
+ *
121
+ * @since 150422 Rewrite.
122
+ *
123
+ * @param string $dir_file An input directory or file path.
124
+ *
125
+ * @return string The original `$dir_file` with a tmp name suffix.
126
+ */
127
+ public function addTmpSuffix($dir_file)
128
+ {
129
+ $dir_file = (string) $dir_file;
130
+ $dir_file = rtrim($dir_file, DIRECTORY_SEPARATOR.'\\/');
131
+
132
+ return $dir_file.'-'.str_replace('.', '', uniqid('', true)).'-tmp';
133
+ }
134
+
135
+ /**
136
+ * Recursive directory iterator based on a regex pattern.
137
+ *
138
+ * @since 150422 Rewrite.
139
+ *
140
+ * @param string $dir An absolute server directory path.
141
+ * @param string $regex A regex pattern; compares to each full file path.
142
+ *
143
+ * @return \RegexIterator Navigable with {@link \foreach()} where each item
144
+ * is a {@link \RecursiveDirectoryIterator}.
145
+ */
146
+ public function dirRegexIteration($dir, $regex = '')
147
+ {
148
+ $dir = (string) $dir;
149
+ $regex = (string) $regex;
150
+
151
+ $dir_iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS);
152
+ $iterator_iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST);
153
+
154
+ if ($regex && $regex !== '/.*/' && $regex !== '/.+/') { // Apply regex filter?
155
+ // @TODO Optimize calls to this method in order to avoid the regex iterator when not necessary.
156
+ return new \RegexIterator($iterator_iterator, $regex, \RegexIterator::MATCH, \RegexIterator::USE_KEY);
157
+ }
158
+ return $iterator_iterator; // Iterate everything.
159
+ }
160
+
161
+ /**
162
+ * Abbreviated byte notation for file sizes.
163
+ *
164
+ * @since 151002 Adding a few statistics.
165
+ *
166
+ * @param float $bytes File size in bytes. A (float) value.
167
+ * @param int $precision Number of decimals to use.
168
+ *
169
+ * @return string Byte notation.
170
+ */
171
+ public function bytesAbbr($bytes, $precision = 2)
172
+ {
173
+ $bytes = max(0.0, (float) $bytes);
174
+ $precision = max(0, (integer) $precision);
175
+ $units = ['bytes', 'kbs', 'MB', 'GB', 'TB'];
176
+
177
+ $power = floor(($bytes ? log($bytes) : 0) / log(1024));
178
+ $abbr_bytes = round($bytes / pow(1024, $power), $precision);
179
+ $abbr = $units[min($power, count($units) - 1)];
180
+
181
+ if ($abbr_bytes === (float) 1 && $abbr === 'bytes') {
182
+ $abbr = 'byte'; // Quick fix.
183
+ } elseif ($abbr_bytes === (float) 1 && $abbr === 'kbs') {
184
+ $abbr = 'kb'; // Quick fix.
185
+ }
186
+ return $abbr_bytes.' '.$abbr;
187
+ }
188
+
189
+ /**
190
+ * Converts an abbreviated byte notation into bytes.
191
+ *
192
+ * @since 151002 Adding a few statistics.
193
+ *
194
+ * @param string $string A string value in byte notation.
195
+ *
196
+ * @return float A float indicating the number of bytes.
197
+ */
198
+ public function abbrBytes($string)
199
+ {
200
+ $string = (string) $string;
201
+ $regex = '/^(?P<value>[0-9\.]+)\s*(?P<modifier>bytes|byte|kbs|kb|k|mb|m|gb|g|tb|t)$/i';
202
+
203
+ if (!preg_match($regex, $string, $_m)) {
204
+ return (float) 0;
205
+ }
206
+ $value = (float) $_m['value'];
207
+ $modifier = strtolower($_m['modifier']);
208
+ unset($_m); // Housekeeping.
209
+
210
+ switch ($modifier) {
211
+ case 't':
212
+ case 'tb':
213
+ $value *= 1024;
214
+ // Fall through.
215
+ case 'g':
216
+ case 'gb':
217
+ $value *= 1024;
218
+ // Fall through.
219
+ case 'm':
220
+ case 'mb':
221
+ $value *= 1024;
222
+ // Fall through.
223
+ case 'k':
224
+ case 'kb':
225
+ case 'kbs':
226
+ $value *= 1024;
227
+ }
228
+ return (float) $value;
229
+ }
230
+
231
+ /**
232
+ * Directory stats.
233
+ *
234
+ * @since 151002 Adding a few statistics.
235
+ *
236
+ * @param string $dir An absolute server directory path.
237
+ * @param string $regex A regex pattern; compares to each full file path.
238
+ * @param bool $include_paths Include array of all scanned file paths?
239
+ * @param bool $check_disk Also check disk statistics?
240
+ * @param bool $no_cache Do not read/write cache?
241
+ *
242
+ * @return array Directory stats.
243
+ */
244
+ public function getDirRegexStats($dir, $regex = '', $include_paths = false, $check_disk = true, $no_cache = false)
245
+ {
246
+ $dir = (string) $dir; // Force string.
247
+ $cache_keys = [$dir, $regex, $include_paths, $check_disk];
248
+ if (!$no_cache && !is_null($stats = &$this->staticKey('getDirRegexStats', $cache_keys))) {
249
+ return $stats; // Already cached this.
250
+ }
251
+ $stats = [
252
+ 'total_size' => 0,
253
+ 'total_resources' => 0,
254
+ 'total_links_files' => 0,
255
+
256
+ 'total_links' => 0,
257
+ 'link_subpaths' => [],
258
+
259
+ 'total_files' => 0,
260
+ 'file_subpaths' => [],
261
+
262
+ 'total_dirs' => 0,
263
+ 'dir_subpaths' => [],
264
+
265
+ 'disk_total_space' => 0,
266
+ 'disk_free_space' => 0,
267
+ ];
268
+ if (!$dir || !is_dir($dir)) {
269
+ return $stats; // Not possible.
270
+ }
271
+ $short_name_lc = strtolower(SHORT_NAME); // Once only.
272
+
273
+ foreach ($this->dirRegexIteration($dir, $regex) as $_resource) {
274
+ $_resource_sub_path = $_resource->getSubpathname();
275
+ $_resource_basename = basename($_resource_sub_path);
276
+
277
+ if ($_resource_basename === '.DS_Store') {
278
+ continue; // Ignore `.htaccess`.
279
+ }
280
+ if ($_resource_basename === '.htaccess') {
281
+ continue; // Ignore `.htaccess`.
282
+ }
283
+ if (stripos($_resource_sub_path, $short_name_lc.'-') === 0) {
284
+ continue; // Ignore [SHORT_NAME] files in base.
285
+ }
286
+ switch ($_resource->getType()) { // `link`, `file`, `dir`.
287
+ case 'link':
288
+ if ($include_paths) {
289
+ $stats['link_subpaths'][] = $_resource_sub_path;
290
+ }
291
+ ++$stats['total_resources'];
292
+ ++$stats['total_links_files'];
293
+ ++$stats['total_links'];
294
+
295
+ break; // Break switch.
296
+
297
+ case 'file':
298
+ if ($include_paths) {
299
+ $stats['file_subpaths'][] = $_resource_sub_path;
300
+ }
301
+ $stats['total_size'] += $_resource->getSize();
302
+ ++$stats['total_resources'];
303
+ ++$stats['total_links_files'];
304
+ ++$stats['total_files'];
305
+
306
+ break; // Break switch.
307
+
308
+ case 'dir':
309
+ if ($include_paths) {
310
+ $stats['dir_subpaths'][] = $_resource_sub_path;
311
+ }
312
+ ++$stats['total_resources'];
313
+ ++$stats['total_dirs'];
314
+
315
+ break; // Break switch.
316
+ }
317
+ }
318
+ unset($_resource, $_resource_sub_path, $_resource_basename); // Housekeeping.
319
+
320
+ if ($check_disk) { // Check disk also?
321
+ $stats['disk_total_space'] = disk_total_space($dir);
322
+ $stats['disk_free_space'] = disk_free_space($dir);
323
+ }
324
+ return $stats;
325
+ }
326
+
327
+ /**
328
+ * Apache `.htaccess` rules that deny public access to the contents of a directory.
329
+ *
330
+ * @since 150422 Rewrite.
331
+ *
332
+ * @type string `.htaccess` fules.
333
+ */
334
+ public $htaccess_deny = "<IfModule authz_core_module>\n\tRequire all denied\n</IfModule>\n<IfModule !authz_core_module>\n\tdeny from all\n</IfModule>";
335
+ }
src/includes/traits/Shared/HookUtils.php ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait HookUtils
7
+ {
8
+ /**
9
+ * Array of hooks.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @type array An array of hooks.
14
+ */
15
+ public $hooks = [];
16
+
17
+ /**
18
+ * Assigns an ID to each callable attached to a hook/filter.
19
+ *
20
+ * @since 150422 Rewrite.
21
+ *
22
+ * @param string|callable|mixed $function A string or a callable.
23
+ *
24
+ * @throws \Exception If the hook/function is invalid (i.e. it's not possible to generate an ID).
25
+ *
26
+ * @return string Hook ID for the given `$function`.
27
+ */
28
+ public function hookId($function)
29
+ {
30
+ if (is_string($function)) {
31
+ return $function;
32
+ }
33
+ if (is_object($function)) {
34
+ $function = [$function, ''];
35
+ } else {
36
+ $function = (array) $function;
37
+ }
38
+ if (isset($function[0], $function[1])) {
39
+ if (is_object($function[0])) {
40
+ return spl_object_hash($function[0]).$function[1];
41
+ } elseif (is_string($function[0])) {
42
+ return $function[0].'::'.$function[1];
43
+ }
44
+ }
45
+ throw new \Exception(__('Invalid hook.', 'comet-cache'));
46
+ }
47
+
48
+ /**
49
+ * Adds a new hook (works with both actions & filters).
50
+ *
51
+ * @since 150422 Rewrite.
52
+ *
53
+ * @param string $hook The name of a hook to attach to.
54
+ * @param string|callable|mixed $function A string or a callable.
55
+ * @param int $priority Hook priority; defaults to `10`.
56
+ * @param int $accepted_args Max number of args that should be passed to the `$function`.
57
+ *
58
+ * @return bool This always returns a `TRUE` value.
59
+ */
60
+ public function addHook($hook, $function, $priority = 10, $accepted_args = 1)
61
+ {
62
+ $hook = (string) $hook;
63
+ if (stripos($hook, 'zencache') === 0) {
64
+ $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
65
+ }
66
+ $priority = (integer) $priority;
67
+ $accepted_args = max(0, (integer) $accepted_args);
68
+ $hook_id = $this->hookId($function);
69
+
70
+ $this->hooks[$hook][$priority][$hook_id] = [
71
+ 'function' => $function,
72
+ 'accepted_args' => $accepted_args,
73
+ ];
74
+ return true; // Always returns true.
75
+ }
76
+
77
+ /**
78
+ * Adds a new action hook.
79
+ *
80
+ * @since 150422 Rewrite.
81
+ *
82
+ * @return bool This always returns a `TRUE` value.
83
+ */
84
+ public function addAction()
85
+ {
86
+ return call_user_func_array([$this, 'addHook'], func_get_args());
87
+ }
88
+
89
+ // @codingStandardsIgnoreStart
90
+ /*
91
+ * Back compat. alias for addAction()
92
+ */
93
+ public function add_action()
94
+ { // @codingStandardsIgnoreEnd
95
+ return call_user_func_array([$this, 'addAction'], func_get_args());
96
+ }
97
+
98
+ /**
99
+ * Adds a new filter.
100
+ *
101
+ * @since 150422 Rewrite.
102
+ *
103
+ * @return bool This always returns a `TRUE` value.
104
+ */
105
+ public function addFilter()
106
+ {
107
+ return call_user_func_array([$this, 'addHook'], func_get_args());
108
+ }
109
+
110
+ // @codingStandardsIgnoreStart
111
+ /*
112
+ * Back compat. alias for addFilter()
113
+ */
114
+ public function add_filter()
115
+ { // @codingStandardsIgnoreEnd
116
+ return call_user_func_array([$this, 'addFilter'], func_get_args());
117
+ }
118
+
119
+ /**
120
+ * Removes a hook (works with both actions & filters).
121
+ *
122
+ * @since 150422 Rewrite.
123
+ *
124
+ * @param string $hook The name of a hook to remove.
125
+ * @param string|callable|mixed $function A string or a callable.
126
+ * @param int $priority Hook priority; defaults to `10`.
127
+ *
128
+ * @return bool `TRUE` if removed; else `FALSE` if not removed for any reason.
129
+ */
130
+ public function removeHook($hook, $function, $priority = 10)
131
+ {
132
+ $hook = (string) $hook;
133
+ if (stripos($hook, 'zencache') === 0) {
134
+ $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
135
+ }
136
+ $priority = (integer) $priority;
137
+ $hook_id = $this->hookId($function);
138
+
139
+ if (!isset($this->hooks[$hook][$priority][$hook_id])) {
140
+ return false; // Nothing to remove.
141
+ }
142
+ unset($this->hooks[$hook][$priority][$hook_id]);
143
+
144
+ if (!$this->hooks[$hook][$priority]) {
145
+ unset($this->hooks[$hook][$priority]);
146
+ }
147
+ return true; // Existed before it was removed.
148
+ }
149
+
150
+ /**
151
+ * Removes an action.
152
+ *
153
+ * @since 150422 Rewrite.
154
+ *
155
+ * @return bool `TRUE` if removed; else `FALSE` if not removed for any reason.
156
+ */
157
+ public function removeAction()
158
+ {
159
+ return call_user_func_array([$this, 'removeHook'], func_get_args());
160
+ }
161
+
162
+ /**
163
+ * Removes a filter.
164
+ *
165
+ * @since 150422 Rewrite.
166
+ *
167
+ * @return bool `TRUE` if removed; else `FALSE` if not removed for any reason.
168
+ */
169
+ public function removeFilter()
170
+ {
171
+ return call_user_func_array([$this, 'removeHook'], func_get_args());
172
+ }
173
+
174
+ /**
175
+ * Runs any callables attached to an action.
176
+ *
177
+ * @since 150422 Rewrite.
178
+ *
179
+ * @param string $hook The name of an action hook.
180
+ */
181
+ public function doAction($hook)
182
+ {
183
+ $hook = (string) $hook;
184
+ if (empty($this->hooks[$hook])) {
185
+ return; // No hooks.
186
+ }
187
+ $hook_actions = $this->hooks[$hook];
188
+ $args = func_get_args();
189
+ ksort($hook_actions);
190
+
191
+ foreach ($hook_actions as $_hook_action) {
192
+ foreach ($_hook_action as $_action) {
193
+ if (!isset($_action['function'], $_action['accepted_args'])) {
194
+ continue; // Not a valid filter in this case.
195
+ }
196
+ call_user_func_array($_action['function'], array_slice($args, 1, $_action['accepted_args']));
197
+ }
198
+ }
199
+ unset($_hook_action, $_action); // Housekeeping.
200
+ }
201
+
202
+ /**
203
+ * Runs any callables attached to a filter.
204
+ *
205
+ * @since 150422 Rewrite.
206
+ *
207
+ * @param string $hook The name of a filter hook.
208
+ * @param mixed $value The value to filter.
209
+ *
210
+ * @return mixed The filtered `$value`.
211
+ */
212
+ public function applyFilters($hook, $value)
213
+ {
214
+ $hook = (string) $hook;
215
+ if (empty($this->hooks[$hook])) {
216
+ return $value; // No hooks.
217
+ }
218
+ $hook_filters = $this->hooks[$hook];
219
+ $args = func_get_args();
220
+ ksort($hook_filters);
221
+
222
+ foreach ($hook_filters as $_hook_filter) {
223
+ foreach ($_hook_filter as $_filter) {
224
+ if (!isset($_filter['function'], $_filter['accepted_args'])) {
225
+ continue; // Not a valid filter in this case.
226
+ }
227
+ $args[1] = $value; // Continously update the argument `$value`.
228
+ $value = call_user_func_array($_filter['function'], array_slice($args, 1, $_filter['accepted_args']));
229
+ }
230
+ }
231
+ unset($_hook_filter, $_filter); // Housekeeping.
232
+
233
+ return $value; // With applied filters.
234
+ }
235
+
236
+ /**
237
+ * Does an action w/ back compat. for ZenCache.
238
+ *
239
+ * @since 150422 Rewrite.
240
+ *
241
+ * @param string $hook The hook to apply.
242
+ */
243
+ public function doWpAction($hook)
244
+ {
245
+ $hook = (string) $hook;
246
+ $args = func_get_args();
247
+ call_user_func_array('do_action', $args);
248
+
249
+ if (stripos($hook, GLOBAL_NS) === 0) {
250
+ $zencache_filter = 'zencache'.substr($hook, strlen(GLOBAL_NS));
251
+ $zencache_args = $args; // Use a copy of the args.
252
+ $zencache_args[0] = $zencache_filter;
253
+ call_user_func_array('do_action', $zencache_args);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Applies filters w/ back compat. for ZenCache.
259
+ *
260
+ * @since 150422 Rewrite.
261
+ *
262
+ * @param string $hook The hook to apply.
263
+ *
264
+ * @return mixed The filtered value.
265
+ */
266
+ public function applyWpFilters($hook)
267
+ {
268
+ $hook = (string) $hook;
269
+ $args = func_get_args();
270
+ $value = call_user_func_array('apply_filters', $args);
271
+
272
+ if (stripos($hook, GLOBAL_NS) === 0) {
273
+ $zencache_hook = 'zencache'.substr($hook, strlen(GLOBAL_NS));
274
+ $zencache_args = $args; // Use a copy of the args.
275
+ $zencache_args[0] = $zencache_hook;
276
+ $zencache_args[1] = $value; // Filtered value.
277
+ $value = call_user_func_array('apply_filters', $zencache_args);
278
+ }
279
+ return $value; // Filtered value.
280
+ }
281
+ }
src/includes/traits/Shared/HttpUtils.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait HttpUtils
7
+ {
8
+ /**
9
+ * Current HTTP protocol.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @return string Current HTTP protocol.
14
+ */
15
+ public function httpProtocol()
16
+ {
17
+ if (!is_null($protocol = &$this->staticKey('httpProtocol'))) {
18
+ return $protocol; // Already cached this.
19
+ }
20
+ if (!empty($_SERVER['SERVER_PROTOCOL']) && is_string($_SERVER['SERVER_PROTOCOL'])) {
21
+ $protocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
22
+ }
23
+ if (!$protocol || stripos($protocol, 'HTTP/') !== 0) {
24
+ $protocol = 'HTTP/1.0'; // Default value.
25
+ }
26
+ return $protocol;
27
+ }
28
+
29
+ /**
30
+ * PHP {@link headers_list()} + HTTP status.
31
+ *
32
+ * @since 150422 Rewrite.
33
+ *
34
+ * @return array PHP {@link headers_list()} + HTTP status.
35
+ *
36
+ * @warning Do NOT call until end of script execution.
37
+ */
38
+ public function headersList()
39
+ {
40
+ if (!is_null($headers = &$this->staticKey('headersList'))) {
41
+ return $headers; // Already cached this.
42
+ }
43
+ $headers = headers_list(); // Lacks status.
44
+
45
+ if (($status = (string) $this->httpStatus())) {
46
+ array_unshift($headers, $this->httpProtocol().' '.$status);
47
+ }
48
+ return $headers;
49
+ }
50
+
51
+ /**
52
+ * PHP {@link headers_list()} + HTTP status.
53
+ *
54
+ * @since 150422 Rewrite.
55
+ *
56
+ * @return array PHP {@link headers_list()} + HTTP status.
57
+ *
58
+ * @warning Do NOT call until end of script execution.
59
+ */
60
+ public function cacheableHeadersList()
61
+ {
62
+ if (!is_null($headers = &$this->staticKey('cacheableHeadersList'))) {
63
+ return $headers; // Already cached this.
64
+ }
65
+ $headers = headers_list(); // Lacks status.
66
+
67
+ $cacheable_headers = [
68
+ 'Access-Control-Allow-Origin',
69
+ 'Accept-Ranges',
70
+ 'Age',
71
+ 'Allow',
72
+ 'Cache-Control',
73
+ 'Connection',
74
+ 'Content-Encoding',
75
+ 'Content-Language',
76
+ 'Content-Length',
77
+ 'Content-Location',
78
+ 'Content-MD5',
79
+ 'Content-Disposition',
80
+ 'Content-Range',
81
+ 'Content-Type',
82
+ 'Date',
83
+ 'ETag',
84
+ 'Expires',
85
+ 'Last-Modified',
86
+ 'Link',
87
+ 'Location',
88
+ 'P3P',
89
+ 'Pragma',
90
+ 'Proxy-Authenticate',
91
+ 'Refresh',
92
+ 'Retry-After',
93
+ 'Server',
94
+ 'Status',
95
+ 'Strict-Transport-Security',
96
+ 'Trailer',
97
+ 'Transfer-Encoding',
98
+ 'Upgrade',
99
+ 'Vary',
100
+ 'Via',
101
+ 'Warning',
102
+ 'WWW-Authenticate',
103
+ 'X-Frame-Options',
104
+ 'Public-Key-Pins',
105
+ 'X-XSS-Protection',
106
+ 'Content-Security-Policy',
107
+ 'X-Content-Security-Policy',
108
+ 'X-WebKit-CSP',
109
+ 'X-Content-Type-Options',
110
+ 'X-Powered-By',
111
+ 'X-UA-Compatible',
112
+ ];
113
+ $cacheable_headers = array_map('strtolower', $cacheable_headers);
114
+
115
+ foreach ($headers as $_key => $_header) {
116
+ $_header = strtolower((string) strstr($_header, ':', true));
117
+ if (!$_header || !in_array($_header, $cacheable_headers, true)) {
118
+ unset($headers[$_key]);
119
+ }
120
+ }
121
+ unset($_key, $_header); // Housekeeping.
122
+
123
+ if (($status = (string) $this->httpStatus())) {
124
+ array_unshift($headers, $this->httpProtocol().' '.$status);
125
+ }
126
+ return $headers;
127
+ }
128
+
129
+ /**
130
+ * HTTP status code.
131
+ *
132
+ * @since 150422 Rewrite.
133
+ *
134
+ * @return int HTTP status code.
135
+ *
136
+ * @warning Do NOT call until end of script execution.
137
+ *
138
+ * @note Automatically updates HTTP status-related flags.
139
+ */
140
+ public function httpStatus()
141
+ {
142
+ if (!is_null($status = &$this->staticKey('httpStatus'))) {
143
+ return $status; // Already cached this.
144
+ }
145
+ $status = 0; // Initialize.
146
+ $has_property_is_404 = property_exists($this, 'is_404');
147
+ $has_property_http_status = property_exists($this, 'http_status');
148
+
149
+ if ($has_property_is_404 && $this->is_404) {
150
+ $status = 404; // WordPress said so.
151
+ } elseif (($code = (integer) http_response_code())) {
152
+ $status = (integer) $code; // {@link \http_response_code()} available since PHP v5.4.
153
+ } elseif ($has_property_http_status && (integer) $this->http_status) {
154
+ $status = (integer) $this->http_status; // {@link \status_header()} filter.
155
+ }
156
+ if ($status && $has_property_http_status) {
157
+ $this->http_status = $status; // Prefer over {@link status_header()}.
158
+ }
159
+ if ($status === 404 && $has_property_is_404) {
160
+ $this->is_404 = true; // Prefer over {@link is_404()}.
161
+ }
162
+ return $status;
163
+ }
164
+
165
+ /**
166
+ * Sends no-cache headers.
167
+ *
168
+ * @since 151220 Enhancing no-cache headers.
169
+ */
170
+ public function sendNoCacheHeaders()
171
+ {
172
+ header_remove('Last-Modified');
173
+ header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
174
+ header('Cache-Control: no-cache, must-revalidate, max-age=0');
175
+ header('Pragma: no-cache');
176
+ }
177
+ }
src/includes/traits/Shared/I18nUtils.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait I18nUtils
7
+ {
8
+ /**
9
+ * `X file` or `X files`, translated w/ singlular/plural context.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param int $counter Total files; i.e. the counter.
14
+ *
15
+ * @return string The phrase `X file` or `X files`.
16
+ */
17
+ public function i18nFiles($counter)
18
+ {
19
+ $counter = (integer) $counter;
20
+ return sprintf(_n('%1$s file', '%1$s files', $counter, 'comet-cache'), $counter);
21
+ }
22
+
23
+ /**
24
+ * `X directory` or `X directories`, translated w/ singlular/plural context.
25
+ *
26
+ * @since 150422 Rewrite.
27
+ *
28
+ * @param int $counter Total directories; i.e. the counter.
29
+ *
30
+ * @return string The phrase `X directory` or `X directories`.
31
+ */
32
+ public function i18nDirs($counter)
33
+ {
34
+ $counter = (integer) $counter;
35
+ return sprintf(_n('%1$s directory', '%1$s directories', $counter, 'comet-cache'), $counter);
36
+ }
37
+
38
+ /**
39
+ * `X file/directory` or `X files/directories`, translated w/ singlular/plural context.
40
+ *
41
+ * @since 150422 Rewrite.
42
+ *
43
+ * @param int $counter Total files/directories; i.e. the counter.
44
+ *
45
+ * @return string The phrase `X file/directory` or `X files/directories`.
46
+ */
47
+ public function i18nFilesDirs($counter)
48
+ {
49
+ $counter = (integer) $counter;
50
+ return sprintf(_n('%1$s file/directory', '%1$s files/directories', $counter, 'comet-cache'), $counter);
51
+ }
52
+ }
src/includes/traits/Shared/IpAddrUtils.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait IpAddrUtils
7
+ {
8
+ /**
9
+ * Get the current visitor's real IP address.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @return string Real IP address, else `unknown` on failure.
14
+ *
15
+ * @note This supports both IPv4 and IPv6 addresses.
16
+ * @note See my tests against this here: http://3v4l.org/fVWUp
17
+ */
18
+ public function currentIp()
19
+ {
20
+ if (!is_null($ip = &$this->staticKey('currentIp'))) {
21
+ return $ip; // Already cached this.
22
+ }
23
+ $sources = [
24
+ 'HTTP_CF_CONNECTING_IP',
25
+ 'HTTP_CLIENT_IP',
26
+ 'HTTP_X_FORWARDED_FOR',
27
+ 'HTTP_X_FORWARDED',
28
+ 'HTTP_X_CLUSTER_CLIENT_IP',
29
+ 'HTTP_FORWARDED_FOR',
30
+ 'HTTP_FORWARDED',
31
+ 'HTTP_VIA',
32
+ 'REMOTE_ADDR',
33
+ ];
34
+ $sources = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_sources', $sources);
35
+ $sources = $this->applyFilters(GLOBAL_NS.'_current_ip_sources', $sources);
36
+
37
+ $prioritize_remote_addr = false; // Off by default; can be filtered however.
38
+ $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_prioritize_remote_addr', $prioritize_remote_addr);
39
+ $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'_current_ip_prioritize_remote_addr', $prioritize_remote_addr);
40
+
41
+ if (!empty($_SERVER['REMOTE_ADDR']) && $prioritize_remote_addr) {
42
+ if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER['REMOTE_ADDR']))) {
43
+ return $ip = $_valid_public_ip;
44
+ }
45
+ unset($_valid_public_ip); // Housekeeping.
46
+ }
47
+ foreach ($sources as $_key => $_source) {
48
+ if (!empty($_SERVER[$_source])) {
49
+ if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER[$_source]))) {
50
+ return $ip = $_valid_public_ip;
51
+ }
52
+ }
53
+ unset($_key, $_source, $_valid_public_ip); // Housekeeping.
54
+ }
55
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
56
+ return $ip = strtolower((string) $_SERVER['REMOTE_ADDR']);
57
+ }
58
+ return $ip = 'unknown'; // Not possible.
59
+ }
60
+
61
+ /**
62
+ * Gets a valid/public IP address.
63
+ *
64
+ * @since 150422 Rewrite.
65
+ *
66
+ * @param string $list_of_possible_ips A single IP, or a comma-delimited list of IPs.
67
+ *
68
+ * @return string A valid/public IP address (if one is found), else an empty string.
69
+ *
70
+ * @note This supports both IPv4 and IPv6 addresses.
71
+ * @note See my tests against this here: http://3v4l.org/fVWUp
72
+ */
73
+ public function validPublicIp($list_of_possible_ips)
74
+ {
75
+ if (!$list_of_possible_ips || !is_string($list_of_possible_ips)) {
76
+ return ''; // Empty or invalid data.
77
+ }
78
+ if (!($list_of_possible_ips = trim($list_of_possible_ips))) {
79
+ return ''; // Not possible; i.e., empty string.
80
+ }
81
+ foreach (preg_split('/[\s;,]+/', $list_of_possible_ips, -1, PREG_SPLIT_NO_EMPTY) as $_key => $_possible_ip) {
82
+ if (($_valid_public_ip = filter_var(strtolower($_possible_ip), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))) {
83
+ return $_valid_public_ip; // A valid public IPv4 or IPv6 address.
84
+ }
85
+ }
86
+ unset($_key, $_possible_ip, $_valid_public_ip); // Housekeeping.
87
+
88
+ return ''; // Default return value.
89
+ }
90
+ }
src/includes/traits/Shared/PatternUtils.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait PatternUtils
7
+ {
8
+ /**
9
+ * Convert line-delimited patterns to a regex.
10
+ *
11
+ * @since 151114 Enhancing exclusion pattern support.
12
+ *
13
+ * @param string $patterns Line-delimited list of patterns.
14
+ *
15
+ * @return string A `/(?:list|of|regex)/i` patterns.
16
+ */
17
+ public function lineDelimitedPatternsToRegex($patterns)
18
+ {
19
+ $regex = ''; // Initialize list of regex patterns.
20
+ $patterns = (string) $patterns;
21
+
22
+ if (($patterns = preg_split('/['."\r\n".']+/', $patterns, -1, PREG_SPLIT_NO_EMPTY))) {
23
+ $regex = '/(?:'.implode('|', array_map([$this, 'wdRegexToActualRegexFrag'], $patterns)).')/i';
24
+ }
25
+ return $regex;
26
+ }
27
+
28
+ /**
29
+ * Convert watered-down regex to actual regex.
30
+ *
31
+ * @since 151114 Enhancing exclusion pattern support.
32
+ *
33
+ * @param string $string Input watered-down regex to convert.
34
+ *
35
+ * @return string Actual regex pattern after conversion.
36
+ */
37
+ public function wdRegexToActualRegexFrag($string)
38
+ {
39
+ return preg_replace(
40
+ [
41
+ '/\\\\\^/',
42
+ '/\\\\\*\\\\\*/',
43
+ '/\\\\\*/',
44
+ '/\\\\\$/',
45
+ ],
46
+ [
47
+ '^', // Beginning of line.
48
+ '.*?', // Zero or more chars.
49
+ '[^\/]*?', // Zero or more chars != /.
50
+ '$', // End of line.
51
+ ],
52
+ preg_quote((string) $string, '/')
53
+ );
54
+ }
55
+ }
src/includes/traits/Shared/ReplaceUtils.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ReplaceUtils
7
+ {
8
+ /**
9
+ * String replace ONE time.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param string $needle A string to search/replace.
14
+ * @param string $replace What to replace `$needle` with.
15
+ * @param string $haystack The string/haystack to search in.
16
+ * @param bool $caSe_insensitive Defaults to a `FALSE` value.
17
+ * Pass this as `TRUE` to a caSe-insensitive search/replace.
18
+ *
19
+ * @return string The `$haystack`, with `$needle` replaced with `$replace` ONE time only.
20
+ */
21
+ public function strReplaceOnce($needle, $replace, $haystack, $caSe_insensitive = false)
22
+ {
23
+ $needle = (string) $needle;
24
+ $replace = (string) $replace;
25
+ $haystack = (string) $haystack;
26
+ $caSe_strpos = $caSe_insensitive ? 'stripos' : 'strpos';
27
+
28
+ if (($needle_strpos = $caSe_strpos($haystack, $needle)) === false) {
29
+ return $haystack; // Nothing to replace.
30
+ }
31
+ return (string) substr_replace($haystack, $replace, $needle_strpos, strlen($needle));
32
+ }
33
+
34
+ /**
35
+ * String replace ONE time (caSe-insensitive).
36
+ *
37
+ * @since 150422 Rewrite.
38
+ *
39
+ * @param string $needle A string to search/replace.
40
+ * @param string $replace What to replace `$needle` with.
41
+ * @param string $haystack The string/haystack to search in.
42
+ *
43
+ * @return string The `$haystack`, with `$needle` replaced with `$replace` ONE time only.
44
+ */
45
+ public function strIreplaceOnce($needle, $replace, $haystack)
46
+ {
47
+ return $this->strReplaceOnce($needle, $replace, $haystack, true);
48
+ }
49
+ }
src/includes/traits/Shared/ServerUtils.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ServerUtils
7
+ {
8
+ /**
9
+ * Is running on Apache?
10
+ *
11
+ * @since 151002 This is Apache?
12
+ *
13
+ * @return bool True if running Apache.
14
+ */
15
+ public function isApache()
16
+ {
17
+ if (!is_null($is = &$this->staticKey('isApache'))) {
18
+ return $is; // Already cached this.
19
+ }
20
+ if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
21
+ if (stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
22
+ return $is = true;
23
+ }
24
+ if (stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
25
+ return $is = true;
26
+ }
27
+ }
28
+ return $is = false;
29
+ }
30
+
31
+ /**
32
+ * Is running on Nginx?
33
+ *
34
+ * @since 151002 This is Nginx?
35
+ *
36
+ * @return bool True if running Nginx.
37
+ */
38
+ public function isNginx()
39
+ {
40
+ if (!is_null($is = &$this->staticKey('isNginx'))) {
41
+ return $is; // Already cached this.
42
+ }
43
+ if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
44
+ if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
45
+ return $is = true;
46
+ }
47
+ }
48
+ return $is = false;
49
+ }
50
+
51
+ /**
52
+ * Is running on Windows IIS?
53
+ *
54
+ * @since 151002 This is Windows IIS?
55
+ *
56
+ * @return bool True if running Windows IIS.
57
+ */
58
+ public function isIis()
59
+ {
60
+ if (!is_null($is = &$this->staticKey('isIis'))) {
61
+ return $is; // Already cached this.
62
+ }
63
+ if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
64
+ if (stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) {
65
+ return $is = true;
66
+ }
67
+ if (stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) {
68
+ return $is = true;
69
+ }
70
+ }
71
+ return $is = false;
72
+ }
73
+ }
src/includes/traits/Shared/StringUtils.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait StringUtils
7
+ {
8
+ /**
9
+ * Clips string(s) to X chars deeply.
10
+ *
11
+ * @since 151114 Adding string utils.
12
+ *
13
+ * @param mixed $value Any input value.
14
+ * @param int $max_length Defaults to a value of `80`.
15
+ * @param bool $force_ellipsis Defaults to a value of `FALSE`.
16
+ *
17
+ * @return string|array|object Clipped value.
18
+ */
19
+ public function clip($value, $max_length = 80, $force_ellipsis = false)
20
+ {
21
+ if (is_array($value) || is_object($value)) {
22
+ foreach ($value as $_key => &$_value) {
23
+ $_value = $this->clip($_value, $max_length, $force_ellipsis);
24
+ }
25
+ unset($_key, $_value); // Housekeeping.
26
+
27
+ return $value;
28
+ }
29
+ if (!($string = (string) $value)) {
30
+ return $string; // Empty.
31
+ }
32
+ $max_length = max(4, $max_length);
33
+
34
+ $string = strip_tags($string);
35
+ $string = preg_replace('/\s+/', ' ', strip_tags($string));
36
+ $string = trim($string); // Trim it up now.
37
+
38
+ if (strlen($string) > $max_length) {
39
+ $string = (string) substr($string, 0, $max_length - 3).'...';
40
+ } elseif ($force_ellipsis && strlen($string) + 3 > $max_length) {
41
+ $string = (string) substr($string, 0, $max_length - 3).'...';
42
+ } else {
43
+ $string .= $force_ellipsis ? '...' : '';
44
+ }
45
+ return $string;
46
+ }
47
+
48
+ /**
49
+ * Mid-clips string(s) to X chars deeply.
50
+ *
51
+ * @since 151114 Adding string utils.
52
+ *
53
+ * @param mixed $value Any input value.
54
+ * @param int $max_length Defaults to a value of `80`.
55
+ *
56
+ * @return string|array|object Mid-clipped value.
57
+ */
58
+ public function midClip($value, $max_length = 80)
59
+ {
60
+ if (is_array($value) || is_object($value)) {
61
+ foreach ($value as $_key => &$_value) {
62
+ $_value = $this->midClip($_value, $max_length);
63
+ }
64
+ unset($_key, $_value); // Housekeeping.
65
+
66
+ return $value;
67
+ }
68
+ if (!($string = (string) $value)) {
69
+ return $string; // Empty.
70
+ }
71
+ $max_length = max(4, $max_length);
72
+
73
+ $string = strip_tags($string);
74
+ $string = preg_replace('/\s+/', ' ', strip_tags($string));
75
+ $string = trim($string); // Trim it up now.
76
+
77
+ if (strlen($string) <= $max_length) {
78
+ return $string; // Nothing to do.
79
+ }
80
+ $full_string = $string;
81
+ $half_max_length = floor($max_length / 2);
82
+
83
+ $first_clip = $half_max_length - 3;
84
+ $string = $first_clip >= 1 // Something?
85
+ ? substr($full_string, 0, $first_clip).'...'
86
+ : '...'; // Ellipsis only.
87
+
88
+ $second_clip = strlen($full_string) - ($max_length - strlen($string));
89
+ $string .= $second_clip >= 0 && $second_clip >= $first_clip
90
+ ? substr($full_string, $second_clip) : '';
91
+
92
+ return $string;
93
+ }
94
+ }
src/includes/traits/Shared/SysUtils.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait SysUtils
7
+ {
8
+ /**
9
+ * System load averages.
10
+ *
11
+ * @since 151002 Adding cache directory statistics.
12
+ *
13
+ * @return array System load averages.
14
+ */
15
+ public function sysLoadAverages()
16
+ {
17
+ if (!is_null($averages = &$this->cacheKey('sysLoadAverages'))) {
18
+ return $averages; // Already cached these.
19
+ }
20
+ if (!$this->functionIsPossible('sys_getloadavg')) {
21
+ return $averages = [];
22
+ }
23
+ if (!is_array($averages = sys_getloadavg()) || !$averages) {
24
+ return $averages = [];
25
+ }
26
+ $averages = array_map('floatval', $averages);
27
+ $averages = array_slice($averages, 0, 3);
28
+ // i.e., 1m, 5m, 15m; see: <http://jas.xyz/1gWyJLt>
29
+
30
+ return $averages;
31
+ }
32
+
33
+ /**
34
+ * System memory info.
35
+ *
36
+ * @since 151002 Adding cache directory statistics.
37
+ *
38
+ * @return \stdClass|bool System memory info.
39
+ */
40
+ public function sysMemoryStatus()
41
+ {
42
+ if (!is_null($status = &$this->cacheKey('sysMemoryStatus'))) {
43
+ return $status; // Already cached this.
44
+ }
45
+ if (!$this->functionIsPossible('shell_exec')) {
46
+ return $status = false;
47
+ }
48
+ if (!($free = trim((string) @shell_exec('free')))) {
49
+ return $status = false;
50
+ }
51
+ if (!($free_lines = explode("\n", $free))) {
52
+ return $status = false;
53
+ }
54
+ if (empty($free_lines[1])) {
55
+ return $status = false;
56
+ }
57
+ if (!($memory = explode(' ', $free_lines[1]))) {
58
+ return $status = false;
59
+ }
60
+ if (!($memory = array_merge(array_filter($memory)))) {
61
+ return $status = false;
62
+ }
63
+ if (!isset($memory[1], $memory[2])) {
64
+ return $status = false;
65
+ }
66
+ if (($total = (integer) $memory[1]) <= 0) {
67
+ return $status = false;
68
+ }
69
+ $used = (integer) $memory[2];
70
+ $percent = $used / $total * 100;
71
+ $percentage = sprintf(__('%s%%', 'comet-cache'), number_format($percent, 2, '.', ''));
72
+ $status = (object) compact('total', 'used', 'percent', 'percentage');
73
+
74
+ return $status;
75
+ }
76
+
77
+ /**
78
+ * System opcache status/details.
79
+ *
80
+ * @since 151002 Adding cache directory statistics.
81
+ *
82
+ * @return \stdClass|bool System opcache status/details.
83
+ */
84
+ public function sysOpcacheStatus()
85
+ {
86
+ if (!is_null($status = &$this->cacheKey('sysOpcacheStatus'))) {
87
+ return $status; // Already cached this.
88
+ }
89
+ if (!$this->functionIsPossible('opcache_get_status')) {
90
+ return $status = false;
91
+ }
92
+ if (!is_array($status = opcache_get_status(false)) || !$status) {
93
+ return $status = false;
94
+ }
95
+ if (empty($status['opcache_enabled'])) {
96
+ return $status = false;
97
+ }
98
+ return json_decode(json_encode($status));
99
+ }
100
+ }
src/includes/traits/Shared/TokenUtils.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait TokenUtils
7
+ {
8
+
9
+
10
+ /**
11
+ * Current host.
12
+ *
13
+ * @since 150422 Rewrite.
14
+ *
15
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
16
+ * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
17
+ * @param bool $consider_domain_mapping Consider?
18
+ * @param string $consider_domain_mapping_domain A specific domain?
19
+ *
20
+ * @return string Current host.
21
+ *
22
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
23
+ */
24
+ public function hostToken($dashify = false, $consider_domain_mapping = false, $consider_domain_mapping_domain = '')
25
+ {
26
+ if (!is_null($token = &$this->staticKey('hostToken', [$dashify, $consider_domain_mapping, $consider_domain_mapping_domain]))) {
27
+ return $token; // Already cached this.
28
+ }
29
+ $token = ''; // Initialize token value.
30
+
31
+ if (!is_multisite() || $this->isAdvancedCache()) {
32
+ $token = (string) $_SERVER['HTTP_HOST'];
33
+ } elseif ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
34
+ if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
35
+ $token = $consider_domain_mapping_domain;
36
+ } elseif ($this->isDomainMapping()) {
37
+ $token = (string) $_SERVER['HTTP_HOST'];
38
+ } else { // For the current blog ID.
39
+ $token = $this->domainMappingUrlFilter($this->currentUrl());
40
+ $token = $this->parseUrl($token, PHP_URL_HOST);
41
+ }
42
+ }
43
+ if (!$token) { // Use default?
44
+ $token = (string) $_SERVER['HTTP_HOST'];
45
+ }
46
+ if ($token) { // Have token?
47
+ $token = strtolower($token);
48
+ if ($dashify) { // Dashify it?
49
+ $token = preg_replace('/[^a-z0-9]/i', '-', $token);
50
+ $token = trim($token, '-');
51
+ }
52
+ }
53
+ return $token;
54
+ }
55
+
56
+ /**
57
+ * Host for a specific blog.
58
+ *
59
+ * @since 150821 Improving multisite compat.
60
+ *
61
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
62
+ * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
63
+ * @param bool $consider_domain_mapping Consider?
64
+ * @param string $consider_domain_mapping_domain A specific domain?
65
+ * @param bool $fallback Fallback on blog's domain when mapping?
66
+ * @param int $blog_id For which blog ID?
67
+ *
68
+ * @return string Host for a specific blog.
69
+ *
70
+ * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
71
+ */
72
+ public function hostTokenForBlog($dashify = false, $consider_domain_mapping = false, $consider_domain_mapping_domain = '', $fallback = false, $blog_id = 0)
73
+ {
74
+ if (!is_multisite() || $this->isAdvancedCache()) {
75
+ return $this->hostToken($dashify, $consider_domain_mapping, $consider_domain_mapping_domain);
76
+ }
77
+ $token = ''; // Initialize token value.
78
+
79
+ if ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
80
+ if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
81
+ $token = $consider_domain_mapping_domain; // Force this value.
82
+ } else {
83
+ $token = $this->domainMappingBlogDomain($blog_id, $fallback);
84
+ }
85
+ } elseif (($blog_details = $this->blogDetails($blog_id))) {
86
+ $token = $blog_details->domain; // Unmapped domain.
87
+ }
88
+ if ($token) { // Have token?
89
+ $token = strtolower($token);
90
+ if ($dashify) { // Dashify it?
91
+ $token = preg_replace('/[^a-z0-9]/i', '-', $token);
92
+ $token = trim($token, '-');
93
+ }
94
+ }
95
+ return $token;
96
+ }
97
+
98
+ /**
99
+ * Current site's base directory.
100
+ *
101
+ * @since 150422 Rewrite.
102
+ *
103
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
104
+ * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`.
105
+ * @param bool $consider_domain_mapping Consider?
106
+ *
107
+ * @return string Current site's base directory.
108
+ *
109
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
110
+ */
111
+ public function hostBaseToken($dashify = false, $consider_domain_mapping = false)
112
+ {
113
+ if (!is_null($token = &$this->staticKey('hostBaseToken', [$dashify, $consider_domain_mapping]))) {
114
+ return $token; // Already cached this.
115
+ }
116
+ $token = '/'; // Assume NOT multisite; or own domain.
117
+
118
+ if (!is_multisite()) {
119
+ return $token; // Not applicable.
120
+ }
121
+ if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
122
+ return $token; // Not applicable.
123
+ }
124
+ if ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
125
+ return $token; // Not applicable.
126
+ }
127
+ if (defined('PATH_CURRENT_SITE')) {
128
+ $token = (string) PATH_CURRENT_SITE;
129
+ }
130
+ $token = trim($token, '\\/'." \t\n\r\0\x0B");
131
+ $token = isset($token[0]) ? '/'.$token.'/' : '/';
132
+
133
+ if ($token !== '/' && $dashify) {
134
+ $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
135
+ $token = trim($token, '-');
136
+ }
137
+ return $token;
138
+ }
139
+
140
+ /**
141
+ * Current blog's sub-directory.
142
+ *
143
+ * @since 150422 Rewrite.
144
+ *
145
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
146
+ * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`.
147
+ * @param bool $consider_domain_mapping Consider?
148
+ * @param string $path Defaults to the current URI path.
149
+ *
150
+ * @return string Current blog's sub-directory.
151
+ *
152
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
153
+ */
154
+ public function hostDirToken($dashify = false, $consider_domain_mapping = false, $path = null)
155
+ {
156
+ if (!isset($path)) { // Use current/default path?
157
+ $path = (string) $this->parseUrl($_SERVER['REQUEST_URI'], PHP_URL_PATH);
158
+ }
159
+ $path = '/'.ltrim((string) $path, '/'); // Force leading slash.
160
+
161
+ if (!is_null($token = &$this->staticKey('hostDirToken', [$dashify, $consider_domain_mapping, $path]))) {
162
+ return $token; // Already cached this.
163
+ }
164
+ $token = '/'; // Assume NOT multisite; or own domain.
165
+
166
+ if (!is_multisite()) {
167
+ return $token; // Not applicable.
168
+ }
169
+ if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
170
+ return $token; // Not applicable.
171
+ }
172
+ if ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
173
+ return $token; // Not applicable.
174
+ }
175
+ if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
176
+ $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
177
+ } else {
178
+ $path_minus_base = $path; // Default value.
179
+ }
180
+ list($token) = explode('/', trim($path_minus_base, '/'));
181
+ $token = trim($token, '\\/'." \t\n\r\0\x0B");
182
+ $token = isset($token[0]) ? '/'.$token.'/' : '/';
183
+
184
+ if ($token !== '/') { // Perhaps NOT the main site?
185
+ $blog_paths_file = $this->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
186
+ if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
187
+ $token = '/'; // NOT a real/valid child blog path.
188
+ }
189
+ }
190
+ if ($token !== '/' && $dashify) {
191
+ $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
192
+ $token = trim($token, '-');
193
+ }
194
+ return $token;
195
+ }
196
+
197
+ /**
198
+ * A blog's sub-directory.
199
+ *
200
+ * @since 150821 Improving multisite compat.
201
+ *
202
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
203
+ * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9]`.
204
+ * @param bool $consider_domain_mapping Consider?
205
+ * @param int $blog_id For which blog ID?
206
+ *
207
+ * @return string A blog's sub-directory.
208
+ *
209
+ * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
210
+ */
211
+ public function hostDirTokenForBlog($dashify = false, $consider_domain_mapping = false, $blog_id = 0)
212
+ {
213
+ if (!is_multisite() || $this->isAdvancedCache()) {
214
+ return $this->hostDirToken($dashify, $consider_domain_mapping);
215
+ }
216
+ $token = '/'; // Initialize token value.
217
+
218
+ if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) {
219
+ return $token; // Not applicable.
220
+ }
221
+ if ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
222
+ return $token; // Not applicable.
223
+ }
224
+ if (($blog_details = $this->blogDetails($blog_id))) {
225
+ $path = $blog_details->path; // e.g., `[/base]/path/` (includes base).
226
+ if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
227
+ $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
228
+ } else {
229
+ $path_minus_base = $path; // Default value.
230
+ }
231
+ list($token) = explode('/', trim($path_minus_base, '/'));
232
+ }
233
+ $token = trim($token, '\\/'." \t\n\r\0\x0B");
234
+ $token = isset($token[0]) ? '/'.$token.'/' : '/';
235
+
236
+ if ($token !== '/') { // Perhaps NOT the main site?
237
+ $blog_paths_file = $this->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
238
+ if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
239
+ $token = '/'; // NOT a real/valid child blog path.
240
+ }
241
+ }
242
+ if ($token !== '/' && $dashify) {
243
+ $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
244
+ $token = trim($token, '-');
245
+ }
246
+ return $token;
247
+ }
248
+
249
+ /**
250
+ * Current site's base directory & current blog's sub-directory.
251
+ *
252
+ * @since 150422 Rewrite.
253
+ *
254
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
255
+ * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`.
256
+ * @param bool $consider_domain_mapping Consider?
257
+ * @param string $path Defaults to the current URI path.
258
+ *
259
+ * @return string Current site's base directory & current blog's sub-directory.
260
+ *
261
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
262
+ */
263
+ public function hostBaseDirTokens($dashify = false, $consider_domain_mapping = false, $path = null)
264
+ {
265
+ if (!is_null($tokens = &$this->staticKey('hostBaseDirTokens', [$dashify, $consider_domain_mapping, $path]))) {
266
+ return $tokens; // Already cached this.
267
+ }
268
+ $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
269
+ $tokens .= $this->hostDirToken($dashify, $consider_domain_mapping, $path);
270
+
271
+ return $tokens = preg_replace('/\/+/', '/', $tokens);
272
+ }
273
+
274
+ /**
275
+ * A site's base directory & a blog's sub-directory.
276
+ *
277
+ * @since 150821 Improving multisite compat.
278
+ *
279
+ * @param bool $dashify Optional, defaults to a `FALSE` value.
280
+ * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`.
281
+ * @param bool $consider_domain_mapping Consider?
282
+ * @param int $blog_id For which blog ID?
283
+ *
284
+ * @return string A site's base directory & a blog's sub-directory.
285
+ *
286
+ * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
287
+ */
288
+ public function hostBaseDirTokensForBlog($dashify = false, $consider_domain_mapping = false, $blog_id = 0)
289
+ {
290
+ $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
291
+ $tokens .= $this->hostDirTokenForBlog($dashify, $consider_domain_mapping, $blog_id);
292
+
293
+ return $tokens = preg_replace('/\/+/', '/', $tokens);
294
+ }
295
+
296
+
297
+ }
src/includes/traits/Shared/TrimUtils.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait TrimUtils
7
+ {
8
+ /**
9
+ * Trims strings deeply.
10
+ *
11
+ * @since 150422 Rewrite.
12
+ *
13
+ * @param mixed $values Any value can be converted into a trimmed string.
14
+ * Actually, objects can't, but this recurses into objects.
15
+ * @param string $chars Specific chars to trim.
16
+ * Defaults to PHP's trim: " \r\n\t\0\x0B". Use an empty string to bypass.
17
+ * @param string $extra_chars Additional chars to trim.
18
+ *
19
+ * @return string|array|object Trimmed string, array, object.
20
+ */
21
+ public function trimDeep($values, $chars = '', $extra_chars = '')
22
+ {
23
+ if (is_array($values) || is_object($values)) {
24
+ foreach ($values as $_key => &$_values) {
25
+ $_values = $this->trimDeep($_values, $chars, $extra_chars);
26
+ }
27
+ unset($_key, $_values); // Housekeeping.
28
+
29
+ return $values;
30
+ }
31
+ $string = (string) $values;
32
+ $chars = (string) $chars;
33
+ $extra_chars = (string) $extra_chars;
34
+
35
+ $chars = isset($chars[0]) ? $chars : " \r\n\t\0\x0B";
36
+ $chars = $chars.$extra_chars; // Concatenate.
37
+
38
+ return trim($string, $chars);
39
+ }
40
+ }
src/includes/traits/Shared/UrlUtils.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait UrlUtils
7
+ {
8
+ /**
9
+ * Parses a URL.
10
+ *
11
+ * @since 150821 Improving multisite compat.
12
+ *
13
+ * @param string $url_uri_qsl Input URL, URI, or query string w/ a leading `?`.
14
+ * @param int $component Optional component to retrieve.
15
+ *
16
+ * @return array|string|int|null Array, else `string|int|null` component value.
17
+ */
18
+ public function parseUrl($url_uri_qsl, $component = -1)
19
+ {
20
+ $url_uri_qsl = (string) $url_uri_qsl;
21
+ $component = (integer) $component;
22
+ ${'//'} = strpos($url_uri_qsl, '//') === 0;
23
+
24
+ if ($url_uri_qsl && strpos($url_uri_qsl, '&amp;') !== false) {
25
+ $url_uri_qsl = str_replace('&amp;', '&', $url_uri_qsl);
26
+ }
27
+ if ($component > -1) {
28
+ if (${'//'} && $component === PHP_URL_SCHEME) {
29
+ return $part = '//';
30
+ }
31
+ return $part = parse_url($url_uri_qsl, $component);
32
+ } else {
33
+ if (!is_array($parts = parse_url($url_uri_qsl))) {
34
+ return $parts = [];
35
+ }
36
+ if (${'//'}) {
37
+ $parts['scheme'] = '//';
38
+ }
39
+ return $parts;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Unparses a URL.
45
+ *
46
+ * @since 150821 Improving multisite compat.
47
+ *
48
+ * @param array $parts Input URL parts.
49
+ *
50
+ * @return string Unparsed URL in string format.
51
+ */
52
+ public function unParseUrl(array $parts)
53
+ {
54
+ $scheme = '';
55
+ $host = '';
56
+ $port = '';
57
+ $user = '';
58
+ $pass = '';
59
+ $path = '';
60
+ $query = '';
61
+ $fragment = '';
62
+
63
+ if (!empty($parts['scheme'])) {
64
+ if ($parts['scheme'] === '//') {
65
+ $scheme = $parts['scheme'];
66
+ } else {
67
+ $scheme = $parts['scheme'].'://';
68
+ }
69
+ }
70
+ if (!empty($parts['host'])) {
71
+ $host = $parts['host'];
72
+ }
73
+ if (!empty($parts['port'])) {
74
+ $port = ':'.$parts['port'];
75
+ }
76
+ if (!empty($parts['user'])) {
77
+ $user = $parts['user'];
78
+ }
79
+ if (!empty($parts['pass'])) {
80
+ $pass = $parts['pass'];
81
+ }
82
+ if ($user || $pass) {
83
+ $pass .= '@';
84
+ }
85
+ if (!empty($parts['path'])) {
86
+ $path = '/'.ltrim($parts['path'], '/');
87
+ }
88
+ if (!empty($parts['query'])) {
89
+ $query = '?'.$parts['query'];
90
+ }
91
+ if (!empty($parts['fragment'])) {
92
+ $fragment = '#'.$parts['fragment'];
93
+ }
94
+ return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
95
+ }
96
+
97
+ /**
98
+ * Is the current request over SSL?
99
+ *
100
+ * @since 150422 Rewrite.
101
+ *
102
+ * @return bool `TRUE` if the current request is over SSL.
103
+ *
104
+ * @note The return value of this function is cached to reduce overhead on repeat calls.
105
+ */
106
+ public function isSsl()
107
+ {
108
+ if (!is_null($is = &$this->staticKey('isSsl'))) {
109
+ return $is; // Already cached this.
110
+ }
111
+ if (!empty($_SERVER['SERVER_PORT'])) {
112
+ if ((integer) $_SERVER['SERVER_PORT'] === 443) {
113
+ return $is = true;
114
+ }
115
+ }
116
+ if (!empty($_SERVER['HTTPS'])) {
117
+ if (filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN)) {
118
+ return $is = true;
119
+ }
120
+ }
121
+ if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
122
+ if (strcasecmp((string) $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) {
123
+ return $is = true;
124
+ }
125
+ }
126
+ return $is = false;
127
+ }
128
+
129
+ /**
130
+ * Current URL.
131
+ *
132
+ * @since 150821 Improving multisite compat.
133
+ *
134
+ * @return string Current URL.
135
+ */
136
+ public function currentUrl()
137
+ {
138
+ return ($this->isSsl() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
139
+ }
140
+ }
src/includes/translations/comet-cache.pot DELETED
@@ -1,1927 +0,0 @@
1
- # Copyright (C) 2016 Comet Cache
2
- # This file is distributed under the same license as the Comet Cache package.
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: Comet Cache 160227\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/comet-cache\n"
7
- "POT-Creation-Date: 2016-02-27 20:13:18+00:00\n"
8
- "MIME-Version: 1.0\n"
9
- "Content-Type: text/plain; charset=UTF-8\n"
10
- "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
12
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
- "Language-Team: LANGUAGE <LL@li.org>\n"
14
-
15
- #: plugin.php:17
16
- msgid "<strong>NOTICE: Comet Cache Minimum PHP Version</strong></h3>"
17
- msgstr ""
18
-
19
- #: plugin.php:18
20
- msgid "<strong>As of December 1st, 2015 Comet Cache requires PHP 5.4 or higher.</strong> Your server is currently running PHP v%1$s. You will need to upgrade to PHP 5.4 or higher to run this version of Comet Cache."
21
- msgstr ""
22
-
23
- #: plugin.php:19
24
- msgid "Learn more about this change here: <a href=\"http://cometcache.com/r/new-minimum-php-version-php-5-4/\" target=\"_blank\">New Minimum PHP Version: PHP 5.4</a>"
25
- msgstr ""
26
-
27
- #: plugin.php:21
28
- msgid "Your server is also running the <strong>outdated PHP APC extension</strong>. Please see: <a href=\"http://cometcache.com/r/php-apc-extension-no-longer-supported/\" target=\"_blank\">PHP APC Extension No Longer Supported</a>"
29
- msgstr ""
30
-
31
- #: plugin.php:39
32
- msgid "<strong>NOTICE: Comet Cache + PHP APC Extension</strong></h3>"
33
- msgstr ""
34
-
35
- #: plugin.php:40
36
- msgid "<strong>As of December 1st, 2015 Comet Cache no longer runs with the outdated PHP APC extension.</strong> It appears that you're currently running PHP v%1$s with APC enabled. You will need to follow one of the actions below to run this version of Comet Cache."
37
- msgstr ""
38
-
39
- #: plugin.php:41
40
- msgid "<h4 style=\"margin:0 0 .5em 0; font-size:1.25em;\"><span class=\"dashicons dashicons-lightbulb\"></span> Options Available (Action Required):</h4>"
41
- msgstr ""
42
-
43
- #: plugin.php:43
44
- msgid "Please add <code>ini_set('apc.cache_by_default', false);</code> to the top of your <code>/wp-config.php</code> file. That will get rid of this message and allow Comet Cache to run without issue."
45
- msgstr ""
46
-
47
- #: plugin.php:44
48
- msgid "Or, contact your web hosting provider and ask about upgrading to PHP v5.5+; which includes the new <a href=\"http://cometcache.com/r/php-opcache-extension/\" target=\"_blank\">OPcache extension for PHP</a>. The new OPcache extension replaces APC in modern versions of PHP."
49
- msgstr ""
50
-
51
- #: plugin.php:46
52
- msgid "To learn more about this change, please see the announcement: <a href=\"http://cometcache.com/r/php-apc-extension-no-longer-supported/\" target=\"_blank\">PHP APC Extension No Longer Supported</a>"
53
- msgstr ""
54
-
55
- #: plugin.php:66
56
- msgid "<strong>NOTICE: Comet Cache Will Require the PHP <code>mbstring</code> Extension</strong></h3>"
57
- msgstr ""
58
-
59
- #: plugin.php:67
60
- msgid "<strong>After March 1st, 2016 Comet Cache will require PHP Multibyte String support.</strong> It appears that your site is currently running PHP v%1$s <strong>without</strong> the <code>mbstring</code> extension enabled. You will need to contact your web hosting company and have them enable the PHP <code>mbstring</code> extension if you want to run the next version of Comet Cache."
61
- msgstr ""
62
-
63
- #: plugin.php:68
64
- msgid "The <code>mbstring</code> extension provides Multibyte String support to PHP and is required to properly handle UTF-8 characters, which many sites now use. Without Multibyte String support, Comet Cache will be unstable. For that reason we are requiring the <code>mbstring</code> extension to improve reliablity when caching and to prevent your site from experiencing unforeseen issues in the future."
65
- msgstr ""
66
-
67
- #: src/includes/classes/AbsBase.php:116
68
- msgid "Undefined overload property: `%1$s`."
69
- msgstr ""
70
-
71
- #: src/includes/classes/AbsBase.php:134
72
- msgid "Refused to set overload property: `%1$s`."
73
- msgstr ""
74
-
75
- #: src/includes/classes/AbsBase.php:151
76
- msgid "Refused to unset overload property: `%1$s`."
77
- msgstr ""
78
-
79
- #: src/includes/classes/AbsBaseAp.php:57
80
- msgid "Undefined method/closure: `%1$s`."
81
- msgstr ""
82
-
83
- #: src/includes/classes/Conflicts.php:89
84
- msgid "Pro"
85
- msgstr ""
86
-
87
- #: src/includes/classes/Conflicts.php:90
88
- msgid "Lite"
89
- msgstr ""
90
-
91
- #: src/includes/classes/Conflicts.php:95
92
- msgid "<strong>%1$s</strong> is NOT running. A conflicting plugin, <strong>%2$s</strong>, is currently active. Please deactivate the %2$s plugin to clear this message."
93
- msgstr ""
94
-
95
- #: src/includes/classes/MenuPageOptions.php:30
96
- msgid "Wipe Cache (Start Fresh); clears the cache for all sites in this network at once!"
97
- msgstr ""
98
-
99
- #: src/includes/classes/MenuPageOptions.php:32
100
- msgid "Wipe"
101
- msgstr ""
102
-
103
- #: src/includes/classes/MenuPageOptions.php:34
104
- msgid "Clear Cache (Start Fresh)"
105
- msgstr ""
106
-
107
- #: src/includes/classes/MenuPageOptions.php:34
108
- msgid "; affects the current site only."
109
- msgstr ""
110
-
111
- #: src/includes/classes/MenuPageOptions.php:36
112
- msgid "Clear"
113
- msgstr ""
114
-
115
- #: src/includes/classes/MenuPageOptions.php:39
116
- msgid "Restore default plugin options? You will lose all of your current settings! Are you absolutely sure about this?"
117
- msgstr ""
118
-
119
- #: src/includes/classes/MenuPageOptions.php:41
120
- msgid "Restore"
121
- msgstr ""
122
-
123
- #: src/includes/classes/MenuPageOptions.php:43
124
- msgid "All Panels"
125
- msgstr ""
126
-
127
- #: src/includes/classes/MenuPageOptions.php:50
128
- msgid "Pro Updater"
129
- msgstr ""
130
-
131
- #: src/includes/classes/MenuPageOptions.php:51
132
- #: src/includes/classes/MenuPageOptions.php:73
133
- msgid "Newsletter"
134
- msgstr ""
135
-
136
- #: src/includes/classes/MenuPageOptions.php:52
137
- #: src/includes/classes/MenuPageOptions.php:74
138
- msgid "Beta Testers"
139
- msgstr ""
140
-
141
- #: src/includes/classes/MenuPageOptions.php:55
142
- #: src/includes/closures/Plugin/MenuPageUtils.php:120
143
- msgid "Preview Pro Features"
144
- msgstr ""
145
-
146
- #: src/includes/classes/MenuPageOptions.php:56
147
- msgid "Pro Upgrade"
148
- msgstr ""
149
-
150
- #: src/includes/classes/MenuPageOptions.php:62
151
- msgid "Support"
152
- msgstr ""
153
-
154
- #: src/includes/classes/MenuPageOptions.php:65
155
- msgid "Community Forum"
156
- msgstr ""
157
-
158
- #: src/includes/classes/MenuPageOptions.php:67
159
- msgid "Knowledge Base"
160
- msgstr ""
161
-
162
- #: src/includes/classes/MenuPageOptions.php:68
163
- msgid "Blog"
164
- msgstr ""
165
-
166
- #: src/includes/classes/MenuPageOptions.php:80
167
- msgid "%1$s&trade; Pro v%2$s"
168
- msgstr ""
169
-
170
- #: src/includes/classes/MenuPageOptions.php:83
171
- #: src/includes/classes/MenuPageOptions.php:93
172
- msgid "update available"
173
- msgstr ""
174
-
175
- #: src/includes/classes/MenuPageOptions.php:85
176
- #: src/includes/classes/MenuPageOptions.php:95
177
- msgid "changelog"
178
- msgstr ""
179
-
180
- #: src/includes/classes/MenuPageOptions.php:90
181
- msgid "%1$s&trade; v%2$s"
182
- msgstr ""
183
-
184
- #: src/includes/classes/MenuPageOptions.php:99
185
- #: src/includes/closures/Plugin/MenuPageUtils.php:73
186
- #: src/includes/closures/Plugin/MenuPageUtils.php:95
187
- msgid "Plugin Options"
188
- msgstr ""
189
-
190
- #: src/includes/classes/MenuPageOptions.php:113
191
- msgid "Options updated successfully."
192
- msgstr ""
193
-
194
- #: src/includes/classes/MenuPageOptions.php:118
195
- msgid "Default options successfully restored."
196
- msgstr ""
197
-
198
- #: src/includes/classes/MenuPageOptions.php:123
199
- msgid "Cache wiped across all sites; recreation will occur automatically over time."
200
- msgstr ""
201
-
202
- #: src/includes/classes/MenuPageOptions.php:129
203
- msgid "Cache cleared for main site; recreation will occur automatically over time."
204
- msgstr ""
205
-
206
- #: src/includes/classes/MenuPageOptions.php:131
207
- msgid "Cache cleared for this site; recreation will occur automatically over time."
208
- msgstr ""
209
-
210
- #: src/includes/classes/MenuPageOptions.php:137
211
- #: src/includes/classes/MenuPageOptions.php:142
212
- msgid "Failed to update your <code>/.htaccess</code> file automatically. Most likely a permissions error. Please make sure it has permissions <code>644</code> or higher (perhaps <code>666</code>). Once you've done this, please try saving the %1$s options again."
213
- msgstr ""
214
-
215
- #: src/includes/classes/MenuPageOptions.php:147
216
- msgid "It appears that your server is running NGINX and does not support <code>.htaccess</code> rules. Please <a href=\"http://cometcache.com/r/kb-article-recommended-nginx-server-configuration/\" target=\"_new\">update your server configuration manually</a>. If you've already updated your NGINX configuration, you can safely <a href=\"http://cometcache.com/r/kb-article-how-do-i-disable-the-nginx-htaccess-notice/\" target=\"_new\">ignore this message</a>."
217
- msgstr ""
218
-
219
- #: src/includes/classes/MenuPageOptions.php:152
220
- msgid "Failed to update your <code>/wp-config.php</code> file automatically. Please add the following line to your <code>/wp-config.php</code> file (right after the opening <code>&lt;?php</code> tag; on it's own line). <pre class=\"code\"><code>&lt;?php<br />define('WP_CACHE', TRUE);</code></pre>"
221
- msgstr ""
222
-
223
- #: src/includes/classes/MenuPageOptions.php:157
224
- msgid "Failed to update your <code>/wp-config.php</code> file automatically. Please remove the following line from your <code>/wp-config.php</code> file, or set <code>WP_CACHE</code> to a <code>FALSE</code> value. <pre class=\"code\"><code>define('WP_CACHE', TRUE);</code></pre>"
225
- msgstr ""
226
-
227
- #: src/includes/classes/MenuPageOptions.php:163
228
- msgid "Failed to update your <code>/wp-content/advanced-cache.php</code> file. Cannot write stat file: <code>%1$s/%2$s-advanced-cache</code>. Please be sure this directory exists (and that it's writable): <code>%1$s</code>. Please use directory permissions <code>755</code> or higher (perhaps <code>777</code>). Once you've done this, please try again."
229
- msgstr ""
230
-
231
- #: src/includes/classes/MenuPageOptions.php:165
232
- msgid "Failed to update your <code>/wp-content/advanced-cache.php</code> file. Most likely a permissions error. Please create an empty file here: <code>/wp-content/advanced-cache.php</code> (just an empty PHP file, with nothing in it); give it permissions <code>644</code> or higher (perhaps <code>666</code>). Once you've done this, please try again."
233
- msgstr ""
234
-
235
- #: src/includes/classes/MenuPageOptions.php:171
236
- msgid "Failed to remove your <code>/wp-content/advanced-cache.php</code> file. Most likely a permissions error. Please delete (or empty the contents of) this file: <code>/wp-content/advanced-cache.php</code>."
237
- msgstr ""
238
-
239
- #: src/includes/classes/MenuPageOptions.php:176
240
- msgid "close"
241
- msgstr ""
242
-
243
- #: src/includes/classes/MenuPageOptions.php:177
244
- msgid "<strong>Pro Features (Preview)</strong> ~ New option panels below. Please explore before <a href=\"http://cometcache.com/prices/\" target=\"_blank\">upgrading <i class=\"si si-heart-o\"></i></a>.<br /><small>NOTE: the free version of %1$s (this lite version) is more-than-adequate for most sites. Please upgrade only if you desire advanced features or would like to support the developer.</small>"
245
- msgstr ""
246
-
247
- #: src/includes/classes/MenuPageOptions.php:182
248
- msgid "%1$s is currently disabled; please review options below."
249
- msgstr ""
250
-
251
- #: src/includes/classes/MenuPageOptions.php:192
252
- msgid "Basic Configuration (Required)"
253
- msgstr ""
254
-
255
- #: src/includes/classes/MenuPageOptions.php:193
256
- msgid "Review these basic options and %1$s&trade; will be ready-to-go!"
257
- msgstr ""
258
-
259
- #: src/includes/classes/MenuPageOptions.php:201
260
- msgid "Enable/Disable"
261
- msgstr ""
262
-
263
- #: src/includes/classes/MenuPageOptions.php:206
264
- msgid "%1$s&trade; = SPEED<em>!!</em>"
265
- msgstr ""
266
-
267
- #: src/includes/classes/MenuPageOptions.php:207
268
- msgid "Yes, enable %1$s&trade;"
269
- msgstr ""
270
-
271
- #: src/includes/classes/MenuPageOptions.php:207
272
- msgid "No, disable."
273
- msgstr ""
274
-
275
- #: src/includes/classes/MenuPageOptions.php:208
276
- msgid "<strong>HUGE Time-Saver:</strong> Approx. 95%% of all WordPress sites running %1$s, simply enable it here; and that's it :-) <strong>No further configuration is necessary (really).</strong> All of the other options (down below) are already tuned for the BEST performance on a typical WordPress installation. Simply enable %1$s here and click \"Save All Changes\". If you get any warnings please follow the instructions given. Otherwise, you're good <i class=\"si si-smile-o\"></i>. This plugin is designed to run just fine like it is. Take it for a spin right away; you can always fine-tune things later if you deem necessary."
277
- msgstr ""
278
-
279
- #: src/includes/classes/MenuPageOptions.php:211
280
- msgid "How Can I Tell %1$s is Working?"
281
- msgstr ""
282
-
283
- #: src/includes/classes/MenuPageOptions.php:212
284
- msgid "First of all, please make sure that you've enabled %1$s here; then scroll down to the bottom of this page and click \"Save All Changes\". All of the other options (below) are already pre-configured for typical usage. Feel free to skip them all for now. You can go back through all of these later and fine-tune things the way you like them."
285
- msgstr ""
286
-
287
- #: src/includes/classes/MenuPageOptions.php:213
288
- msgid "Once %1$s has been enabled, <strong>you'll need to log out (and/or clear browser cookies)</strong>. By default, cache files are NOT served to visitors who are logged-in, and that includes you too ;-) Cache files are NOT served to recent comment authors either. If you've commented (or replied to a comment lately); please clear your browser cookies before testing."
289
- msgstr ""
290
-
291
- #: src/includes/classes/MenuPageOptions.php:214
292
- msgid "<strong>To verify that %1$s is working</strong>, navigate your site like a normal visitor would. Right-click on any page (choose View Source), then scroll to the very bottom of the document. At the bottom, you'll find comments that show %1$s stats and information. You should also notice that page-to-page navigation is <i class=\"si si-flash\"></i> <strong>lightning fast</strong> now that %1$s is running; and it gets faster over time!"
293
- msgstr ""
294
-
295
- #: src/includes/classes/MenuPageOptions.php:216
296
- msgid "Yes, enable notes in the source code so I can see it's working (recommended)."
297
- msgstr ""
298
-
299
- #: src/includes/classes/MenuPageOptions.php:217
300
- msgid "Yes, enable notes in the source code AND show debugging details (not recommended for production)."
301
- msgstr ""
302
-
303
- #: src/includes/classes/MenuPageOptions.php:218
304
- msgid "No, I don't want my source code to contain any of these notes."
305
- msgstr ""
306
-
307
- #: src/includes/classes/MenuPageOptions.php:229
308
- msgid "Plugin Deletion Safeguards"
309
- msgstr ""
310
-
311
- #: src/includes/classes/MenuPageOptions.php:234
312
- msgid "Uninstall on Plugin Deletion; or Safeguard Options?"
313
- msgstr ""
314
-
315
- #: src/includes/classes/MenuPageOptions.php:235
316
- msgid "<strong>Tip:</strong> By default, if you delete %1$s using the plugins menu in WordPress, nothing is lost. However, if you want to completely uninstall %1$s you should set this to <code>Yes</code> and <strong>THEN</strong> deactivate &amp; delete %1$s from the plugins menu in WordPress. This way %1$s will erase your options for the plugin, erase directories/files created by the plugin, remove the <code>advanced-cache.php</code> file, terminate CRON jobs, etc. It erases itself from existence completely."
317
- msgstr ""
318
-
319
- #: src/includes/classes/MenuPageOptions.php:237
320
- msgid "Safeguard my options and the cache (recommended)."
321
- msgstr ""
322
-
323
- #: src/includes/classes/MenuPageOptions.php:238
324
- msgid "Yes, uninstall (completely erase) %1$s on plugin deletion."
325
- msgstr ""
326
-
327
- #: src/includes/classes/MenuPageOptions.php:247
328
- msgid "Advanced Configuration (All Optional)"
329
- msgstr ""
330
-
331
- #: src/includes/classes/MenuPageOptions.php:248
332
- msgid "Recommended for advanced site owners only; already pre-configured for most WP installs."
333
- msgstr ""
334
-
335
- #: src/includes/classes/MenuPageOptions.php:257
336
- msgid "Manual Cache Clearing"
337
- msgstr ""
338
-
339
- #: src/includes/classes/MenuPageOptions.php:261
340
- msgid "Clearing the Cache Manually"
341
- msgstr ""
342
-
343
- #: src/includes/classes/MenuPageOptions.php:263
344
- msgid "Once %1$s is enabled, you will find this new option in your WordPress Admin Bar (screenshot on right). Clicking this button will clear the cache and you can start fresh at anytime (e.g., you can do this manually; and as often as you wish)."
345
- msgstr ""
346
-
347
- #: src/includes/classes/MenuPageOptions.php:264
348
- msgid "Depending on the structure of your site, there could be many reasons to clear the cache. However, the most common reasons are related to Post/Page edits or deletions, Category/Tag edits or deletions, and Theme changes. %1$s handles most scenarios all by itself. However, many site owners like to clear the cache manually; for a variety of reasons (just to force a refresh)."
349
- msgstr ""
350
-
351
- #: src/includes/classes/MenuPageOptions.php:266
352
- msgid "Yes, enable &quot;Clear Cache&quot; button in admin bar"
353
- msgstr ""
354
-
355
- #: src/includes/classes/MenuPageOptions.php:267
356
- msgid "No, I don't intend to clear the cache manually."
357
- msgstr ""
358
-
359
- #: src/includes/classes/MenuPageOptions.php:270
360
- msgid "w/ dropdown options."
361
- msgstr ""
362
-
363
- #: src/includes/classes/MenuPageOptions.php:271
364
- msgid "w/ dropdown options in split menu."
365
- msgstr ""
366
-
367
- #: src/includes/classes/MenuPageOptions.php:272
368
- msgid "w/o dropdown options."
369
- msgstr ""
370
-
371
- #: src/includes/classes/MenuPageOptions.php:277
372
- msgid "Also allow Child Sites in a Network to clear the cache from their Admin Bar?"
373
- msgstr ""
374
-
375
- #: src/includes/classes/MenuPageOptions.php:278
376
- msgid "In a Multisite Network, each child site can clear its own cache. If you want child sites to see the \"Clear Cache\" button in their WordPress Admin Bar, you can specify a comma-delimited list of <a href=\"http://cometcache.com/r/wp-roles-caps/\" target=\"_blank\">Roles and/or Capabilities</a> that are allowed. For example, if I want Administrators to be capable of clearing the cache from their Admin Bar, I could enter <code>administrator</code> here. If I also want to allow Editors, I can use a comma-delimited list: <code>administrator,editor</code>. Or, I could use a single Capability of: <code>edit_others_posts</code>; which covers both Administrators &amp; Editors at the same time."
377
- msgstr ""
378
-
379
- #: src/includes/classes/MenuPageOptions.php:280
380
- #: src/includes/classes/MenuPageOptions.php:471
381
- msgid "<strong>Note:</strong> As a security measure, in addition to the Role(s) and/or Capabilities that you list here, each child site owner must also have the ability to <code>%1$s</code>."
382
- msgstr ""
383
-
384
- #: src/includes/classes/MenuPageOptions.php:285
385
- msgid "Also allow others to clear the cache from their Admin Bar?"
386
- msgstr ""
387
-
388
- #: src/includes/classes/MenuPageOptions.php:286
389
- msgid "If you want others to see the \"Clear Cache\" button in their WordPress Admin Bar, you can specify a comma-delimited list of <a href=\"http://cometcache.com/r/wp-roles-caps/\" target=\"_blank\">Roles and/or Capabilities</a> that are allowed. For example, if I want Editors to be capable of clearing the cache from their Admin Bar, I could enter <code>editor</code> here. If I also want to allow Authors, I can use a comma-delimited list: <code>editor,author</code>. Or, I could use a single Capability of: <code>publish_posts</code>; which covers both Editors &amp; Authors at the same time."
390
- msgstr ""
391
-
392
- #: src/includes/classes/MenuPageOptions.php:288
393
- #: src/includes/classes/MenuPageOptions.php:479
394
- msgid "<strong>Note:</strong> As a security measure, in addition to the Role(s) and/or Capabilities that you list here, each user must also have the ability to <code>%1$s</code>."
395
- msgstr ""
396
-
397
- #: src/includes/classes/MenuPageOptions.php:294
398
- msgid "Clear the <a href=\"http://cometcache.com/r/php-opcache/\" target=\"_blank\">PHP OPcache</a> Too?"
399
- msgstr ""
400
-
401
- #: src/includes/classes/MenuPageOptions.php:295
402
- msgid "If you clear the cache manually, do you want %1$s to clear the PHP OPcache too? This is not necessary, but if you want a truly clean start, this will clear all PHP files in the server's opcode cache also. Note: If you don't already know what the PHP OPcache is, it is suggested that you leave this disabled. It really is not necessary. This is just an added feature for advanced users."
403
- msgstr ""
404
-
405
- #: src/includes/classes/MenuPageOptions.php:297
406
- msgid "No, I don't use the PHP OPcache extension; or, I don't want the opcode cache cleared."
407
- msgstr ""
408
-
409
- #: src/includes/classes/MenuPageOptions.php:298
410
- msgid "Yes, if the PHP OPcache extension is enabled, also clear the entire PHP opcode cache."
411
- msgstr ""
412
-
413
- #: src/includes/classes/MenuPageOptions.php:303
414
- msgid "Clear the <a href=\"http://websharks-inc.com/product/s2clean/\" target=\"_blank\">s2Clean</a> Cache Too?"
415
- msgstr ""
416
-
417
- #: src/includes/classes/MenuPageOptions.php:304
418
- msgid "If the s2Clean theme is installed, and you clear the cache manually, %1$s can clear the s2Clean Markdown cache too (if you've enabled Markdown processing with s2Clean)."
419
- msgstr ""
420
-
421
- #: src/includes/classes/MenuPageOptions.php:306
422
- msgid "Yes, if the s2Clean theme is installed, also clear s2Clean-related caches."
423
- msgstr ""
424
-
425
- #: src/includes/classes/MenuPageOptions.php:307
426
- msgid "No, I don't use s2Clean; or, I don't want s2Clean-related caches cleared."
427
- msgstr ""
428
-
429
- #: src/includes/classes/MenuPageOptions.php:311
430
- msgid "Evaluate Custom PHP Code when Clearing the Cache?"
431
- msgstr ""
432
-
433
- #: src/includes/classes/MenuPageOptions.php:312
434
- msgid "If you have any custom routines you'd like to process when the cache is cleared manually, please enter PHP code here. If your PHP code outputs a message, it will be displayed along with any other notes from %1$s itself. This feature is intended for developers, and it may come in handy if you need to clear any system caches not already covered by %1$s configuration options."
435
- msgstr ""
436
-
437
- #: src/includes/classes/MenuPageOptions.php:314
438
- msgid "<strong>Example:</strong> <code>&lt;?php apc_clear_cache(); echo '&lt;p&gt;Also cleared APC cache.&lt;/p&gt;'; ?&gt;</code>"
439
- msgstr ""
440
-
441
- #: src/includes/classes/MenuPageOptions.php:317
442
- msgid "Clear the CDN Cache Too?"
443
- msgstr ""
444
-
445
- #: src/includes/classes/MenuPageOptions.php:318
446
- msgid "If you clear the cache manually, do you want %1$s to automatically bump the CDN invalidation counter too? i.e., automatically increment the <code>?%2$s=[counter]</code> in all static CDN URLs?"
447
- msgstr ""
448
-
449
- #: src/includes/classes/MenuPageOptions.php:320
450
- msgid "No, I don't use Static CDN Filters; or, I don't want the CDN cache cleared."
451
- msgstr ""
452
-
453
- #: src/includes/classes/MenuPageOptions.php:321
454
- msgid "Yes, if Static CDN Filters are enabled, also clear the CDN cache."
455
- msgstr ""
456
-
457
- #: src/includes/classes/MenuPageOptions.php:332
458
- msgid "Automatic Cache Clearing"
459
- msgstr ""
460
-
461
- #: src/includes/classes/MenuPageOptions.php:337
462
- msgid "Clearing the Cache Automatically"
463
- msgstr ""
464
-
465
- #: src/includes/classes/MenuPageOptions.php:339
466
- msgid "This is built into the %1$s plugin; i.e., this functionality is \"always on\". If you edit a Post/Page (or delete one), %1$s will automatically clear the cache file(s) associated with that content. This way a new updated version of the cache will be created automatically the next time this content is accessed. Simple updates like this occur each time you make changes in the Dashboard, and %1$s will notify you of these as they occur. %1$s monitors changes to Posts (of any kind, including Pages), Categories, Tags, Links, Themes (even Users), and more."
467
- msgstr ""
468
-
469
- #: src/includes/classes/MenuPageOptions.php:343
470
- msgid "Yes, enable %1$s notifications in the Dashboard when changes are detected &amp; one or more cache files are cleared automatically."
471
- msgstr ""
472
-
473
- #: src/includes/classes/MenuPageOptions.php:344
474
- msgid "No, I don't want to know (don't really care) what %1$s is doing behind-the-scene."
475
- msgstr ""
476
-
477
- #: src/includes/classes/MenuPageOptions.php:349
478
- msgid "Primary Page Options"
479
- msgstr ""
480
-
481
- #: src/includes/classes/MenuPageOptions.php:351
482
- msgid "Auto-Clear Designated \"Home Page\" Too?"
483
- msgstr ""
484
-
485
- #: src/includes/classes/MenuPageOptions.php:352
486
- msgid "On many sites, the Home Page (aka: the Front Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the \"Home Page\"?"
487
- msgstr ""
488
-
489
- #: src/includes/classes/MenuPageOptions.php:354
490
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the \"Home Page\"."
491
- msgstr ""
492
-
493
- #: src/includes/classes/MenuPageOptions.php:355
494
- msgid "No, my Home Page does not provide a list of Posts/Pages; e.g., this is not necessary."
495
- msgstr ""
496
-
497
- #: src/includes/classes/MenuPageOptions.php:357
498
- msgid "Auto-Clear Designated \"Posts Page\" Too?"
499
- msgstr ""
500
-
501
- #: src/includes/classes/MenuPageOptions.php:358
502
- msgid "On many sites, the Posts Page (aka: the Blog Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the \"Posts Page\"?"
503
- msgstr ""
504
-
505
- #: src/includes/classes/MenuPageOptions.php:360
506
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the \"Posts Page\"."
507
- msgstr ""
508
-
509
- #: src/includes/classes/MenuPageOptions.php:361
510
- msgid "No, I don't use a separate Posts Page; e.g., my Home Page IS my Posts Page."
511
- msgstr ""
512
-
513
- #: src/includes/classes/MenuPageOptions.php:365
514
- msgid "Author, Archive, and Tag/Term Options"
515
- msgstr ""
516
-
517
- #: src/includes/classes/MenuPageOptions.php:367
518
- msgid "Auto-Clear \"Author Page\" Too?"
519
- msgstr ""
520
-
521
- #: src/includes/classes/MenuPageOptions.php:368
522
- msgid "On many sites, each author has a related \"Author Page\" that offers an archive view of all posts associated with that author. Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the related \"Author Page\"?"
523
- msgstr ""
524
-
525
- #: src/includes/classes/MenuPageOptions.php:370
526
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the \"Author Page\"."
527
- msgstr ""
528
-
529
- #: src/includes/classes/MenuPageOptions.php:371
530
- msgid "No, my site doesn't use multiple authors and/or I don't have any \"Author Page\" archive views."
531
- msgstr ""
532
-
533
- #: src/includes/classes/MenuPageOptions.php:374
534
- msgid "Auto-Clear \"Category Archives\" Too?"
535
- msgstr ""
536
-
537
- #: src/includes/classes/MenuPageOptions.php:375
538
- msgid "On many sites, each post is associated with at least one Category. Each category then has an archive view that contains all the posts within that category. Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the associated Category archive views?"
539
- msgstr ""
540
-
541
- #: src/includes/classes/MenuPageOptions.php:377
542
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the associated Category archive views."
543
- msgstr ""
544
-
545
- #: src/includes/classes/MenuPageOptions.php:378
546
- msgid "No, my site doesn't use Categories and/or I don't have any Category archive views."
547
- msgstr ""
548
-
549
- #: src/includes/classes/MenuPageOptions.php:381
550
- msgid "Auto-Clear \"Tag Archives\" Too?"
551
- msgstr ""
552
-
553
- #: src/includes/classes/MenuPageOptions.php:382
554
- msgid "On many sites, each post may be associated with at least one Tag. Each tag then has an archive view that contains all the posts assigned that tag. Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the associated Tag archive views?"
555
- msgstr ""
556
-
557
- #: src/includes/classes/MenuPageOptions.php:384
558
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the associated Tag archive views."
559
- msgstr ""
560
-
561
- #: src/includes/classes/MenuPageOptions.php:385
562
- msgid "No, my site doesn't use Tags and/or I don't have any Tag archive views."
563
- msgstr ""
564
-
565
- #: src/includes/classes/MenuPageOptions.php:388
566
- msgid "Auto-Clear \"Custom Term Archives\" Too?"
567
- msgstr ""
568
-
569
- #: src/includes/classes/MenuPageOptions.php:389
570
- msgid "Most sites do not use any custom Terms so it should be safe to leave this disabled. However, if your site uses custom Terms and they have their own Term archive views, you may want to clear those when the associated post is cleared. Therefore, if a single Post/Page is changed in some way; and %1$s clears/resets the cache for a single Post/Page, would you like %1$s to also clear any existing cache files for the associated Tag archive views?"
571
- msgstr ""
572
-
573
- #: src/includes/classes/MenuPageOptions.php:391
574
- msgid "Yes, if any single Post/Page is cleared/reset; also clear any associated custom Term archive views."
575
- msgstr ""
576
-
577
- #: src/includes/classes/MenuPageOptions.php:392
578
- msgid "No, my site doesn't use any custom Terms and/or I don't have any custom Term archive views."
579
- msgstr ""
580
-
581
- #: src/includes/classes/MenuPageOptions.php:395
582
- msgid "Auto-Clear \"Custom Post Type Archives\" Too?"
583
- msgstr ""
584
-
585
- #: src/includes/classes/MenuPageOptions.php:396
586
- msgid "Most sites do not use any Custom Post Types so it should be safe to disable this option. However, if your site uses Custom Post Types and they have their own Custom Post Type archive views, you may want to clear those when any associated post is cleared. Therefore, if a single Post with a Custom Post Type is changed in some way; and %1$s clears/resets the cache for that post, would you like %1$s to also clear any existing cache files for the associated Custom Post Type archive views?"
587
- msgstr ""
588
-
589
- #: src/includes/classes/MenuPageOptions.php:398
590
- msgid "Yes, if any single Post with a Custom Post Type is cleared/reset; also clear any associated Custom Post Type archive views."
591
- msgstr ""
592
-
593
- #: src/includes/classes/MenuPageOptions.php:399
594
- msgid "No, my site doesn't use any Custom Post Types and/or I don't have any Custom Post Type archive views."
595
- msgstr ""
596
-
597
- #: src/includes/classes/MenuPageOptions.php:403
598
- msgid "Feed-Related Options"
599
- msgstr ""
600
-
601
- #: src/includes/classes/MenuPageOptions.php:405
602
- msgid "Auto-Clear \"RSS/RDF/ATOM Feeds\" Too?"
603
- msgstr ""
604
-
605
- #: src/includes/classes/MenuPageOptions.php:406
606
- msgid "If you enable Feed Caching (below), this can be quite handy. If enabled, when you update a Post/Page, approve a Comment, or make other changes where %1$s can detect that certain types of Feeds should be cleared to keep your site up-to-date, then %1$s will do this for you automatically. For instance, the blog's master feed, the blog's master comments feed, feeds associated with comments on a Post/Page, term-related feeds (including mixed term-related feeds), author-related feeds, etc. Under various circumstances (i.e., as you work in the Dashboard) these can be cleared automatically to keep your site up-to-date."
607
- msgstr ""
608
-
609
- #: src/includes/classes/MenuPageOptions.php:408
610
- msgid "Yes, automatically clear RSS/RDF/ATOM Feeds from the cache when certain changes occur."
611
- msgstr ""
612
-
613
- #: src/includes/classes/MenuPageOptions.php:409
614
- msgid "No, I don't have Feed Caching enabled, or I prefer not to automatically clear Feeds."
615
- msgstr ""
616
-
617
- #: src/includes/classes/MenuPageOptions.php:413
618
- msgid "Sitemap-Related Options"
619
- msgstr ""
620
-
621
- #: src/includes/classes/MenuPageOptions.php:415
622
- msgid "Auto-Clear \"XML Sitemaps\" Too?"
623
- msgstr ""
624
-
625
- #: src/includes/classes/MenuPageOptions.php:416
626
- msgid "If you're generating XML Sitemaps with a plugin like <a href=\"http://wordpress.org/plugins/google-sitemap-generator/\" target=\"_blank\">Google XML Sitemaps</a>, you can tell %1$s to automatically clear the cache of any XML Sitemaps whenever it clears a Post/Page. Note: This does NOT clear the XML Sitemap itself of course, only the cache. The point being, to clear the cache and allow changes to a Post/Page to be reflected by a fresh copy of your XML Sitemap; sooner rather than later."
627
- msgstr ""
628
-
629
- #: src/includes/classes/MenuPageOptions.php:418
630
- msgid "Yes, if any single Post/Page is cleared/reset; also clear the cache for any XML Sitemaps."
631
- msgstr ""
632
-
633
- #: src/includes/classes/MenuPageOptions.php:419
634
- msgid "No, my site doesn't use any XML Sitemaps and/or I prefer NOT to clear the cache for XML Sitemaps."
635
- msgstr ""
636
-
637
- #: src/includes/classes/MenuPageOptions.php:422
638
- msgid "<strong style=\"font-size:110%;\">XML Sitemap Patterns...</strong> A default value of <code>/sitemap**.xml</code> covers all XML Sitemaps for most installations. However, you may customize this further if you deem necessary. <strong>Please list one pattern per line.</strong> These XML Sitemap Pattern searches are performed against the <a href=\"https://gist.github.com/jaswsinc/338b6eb03a36c048c26f\" target=\"_blank\">REQUEST_URI</a>. A wildcard <code>**</code> character can also be used when necessary; e.g., <code>/sitemap**.xml</code> (where <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes). Other special characters include: <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href=\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
639
- msgstr ""
640
-
641
- #: src/includes/classes/MenuPageOptions.php:425
642
- msgid "In a Multisite Network, each child blog (whether it be a sub-domain, a sub-directory, or a mapped domain); will automatically change the leading <code>http://[sub.]domain/[sub-directory]</code> used in pattern matching. In short, there is no need to add sub-domains or sub-directories for each child blog in these patterns. Please include only the <a href=\"https://gist.github.com/jaswsinc/338b6eb03a36c048c26f\" target=\"_blank\">REQUEST_URI</a> (i.e., the path) which leads to the XML Sitemap on all child blogs in the network."
643
- msgstr ""
644
-
645
- #: src/includes/classes/MenuPageOptions.php:431
646
- msgid "Misc. Auto-Clear Options"
647
- msgstr ""
648
-
649
- #: src/includes/classes/MenuPageOptions.php:432
650
- msgid "Auto-Clear a List of Custom URLs Too?"
651
- msgstr ""
652
-
653
- #: src/includes/classes/MenuPageOptions.php:433
654
- msgid "When you update a Post/Page, approve a Comment, or make other changes where %1$s can detect that a Post/Page cache should be cleared to keep your site up-to-date; then %1$s will also clear a list of custom URLs that you list here. <strong>Please list one URL per line.</strong> A wildcard <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
655
- msgstr ""
656
-
657
- #: src/includes/classes/MenuPageOptions.php:446
658
- msgid "Cache-Related Statistics"
659
- msgstr ""
660
-
661
- #: src/includes/classes/MenuPageOptions.php:451
662
- msgid "Enable Cache-Related Stats &amp; Charts?"
663
- msgstr ""
664
-
665
- #: src/includes/classes/MenuPageOptions.php:452
666
- msgid "%1$s can collect and display cache-related statistics (including charts). Stats are displayed in the WordPress Admin Bar, and also in your Dashboard under: <strong>%1$s → Stats/Charts</strong>. Cache-related stats provide you with a quick look at what's happening behind-the-scenes. Your site grows faster and faster as the cache grows larger in size."
667
- msgstr ""
668
-
669
- #: src/includes/classes/MenuPageOptions.php:454
670
- msgid "Yes, enable stats collection &amp; the menu page in WordPress for viewing stats."
671
- msgstr ""
672
-
673
- #: src/includes/classes/MenuPageOptions.php:455
674
- msgid "No, I have a VERY large site and I want to avoid any unnecessary directory scans."
675
- msgstr ""
676
-
677
- #: src/includes/classes/MenuPageOptions.php:457
678
- msgid "<strong>Note:</strong> %1$s does a great job of collecting stats, in ways that don't cause a performance issue. In addition, as your cache grows larger than several hundred files in total size, statistics are collected less often and at longer intervals. All of that being said, if you run a VERY large site (e.g., more than 20K posts), you might want to disable stats collection in favor of blazing fast speeds not impeded by any directory scans needed to collect stats."
679
- msgstr ""
680
-
681
- #: src/includes/classes/MenuPageOptions.php:461
682
- msgid "Show Stats in the WordPress Admin Bar?"
683
- msgstr ""
684
-
685
- #: src/includes/classes/MenuPageOptions.php:463
686
- msgid "Yes, enable stats in the WordPress admin bar."
687
- msgstr ""
688
-
689
- #: src/includes/classes/MenuPageOptions.php:464
690
- msgid "No, I'll review stats from the menu page in WordPress if I need to."
691
- msgstr ""
692
-
693
- #: src/includes/classes/MenuPageOptions.php:468
694
- msgid "Allow Child Sites in a Network to See Stats in Admin Bar?"
695
- msgstr ""
696
-
697
- #: src/includes/classes/MenuPageOptions.php:469
698
- msgid "In a Multisite Network, each child site has stats of its own. If you want child sites to see cache-related stats in their WordPress Admin Bar, you can specify a comma-delimited list of <a href=\"http://cometcache.com/r/wp-roles-caps/\" target=\"_blank\">Roles and/or Capabilities</a> that are allowed to see stats. For example, if I want the Administrator to see stats in their Admin Bar, I could enter <code>administrator</code> here. If I also want to show stats to Editors, I can use a comma-delimited list: <code>administrator,editor</code>. Or, I could use a single Capability of: <code>edit_others_posts</code>; which covers both Administrators &amp; Editors at the same time."
699
- msgstr ""
700
-
701
- #: src/includes/classes/MenuPageOptions.php:476
702
- msgid "Allow Others to See Stats in Admin Bar?"
703
- msgstr ""
704
-
705
- #: src/includes/classes/MenuPageOptions.php:477
706
- msgid "If you want others to see cache-related stats in their WordPress Admin Bar, you can specify a comma-delimited list of <a href=\"http://cometcache.com/r/wp-roles-caps/\" target=\"_blank\">Roles and/or Capabilities</a> that are allowed to see stats. For example, if I want Editors to see stats in their Admin Bar, I could enter <code>editor</code> here. If I also want to show stats to Authors, I can use a comma-delimited list: <code>editor,author</code>. Or, I could use a single Capability of: <code>publish_posts</code>; which covers both Editors &amp; Authors at the same time."
707
- msgstr ""
708
-
709
- #: src/includes/classes/MenuPageOptions.php:493
710
- msgid "Cache Directory"
711
- msgstr ""
712
-
713
- #: src/includes/classes/MenuPageOptions.php:497
714
- msgid "Base Cache Directory (Must be Writable; i.e., <a href=\"http://cometcache.com/r/wp-file-permissions/\" target=\"_blank\">Permissions</a> <code>755</code> or Higher)"
715
- msgstr ""
716
-
717
- #: src/includes/classes/MenuPageOptions.php:498
718
- msgid "This is where %1$s will store the cached version of your site. If you're not sure how to deal with directory permissions, don't worry too much about this. If there is a problem, %1$s will let you know about it. By default, this directory is created by %1$s and the permissions are setup automatically. In most cases there is nothing more you need to do."
719
- msgstr ""
720
-
721
- #: src/includes/classes/MenuPageOptions.php:509
722
- msgid "Cache Expiration Time"
723
- msgstr ""
724
-
725
- #: src/includes/classes/MenuPageOptions.php:514
726
- msgid "Automatic Expiration Time (Max Age)"
727
- msgstr ""
728
-
729
- #: src/includes/classes/MenuPageOptions.php:515
730
- msgid "If you don't update your site much, you could set this to <code>6 months</code> and optimize everything even further. The longer the Cache Expiration Time is, the greater your performance gain. Alternatively, the shorter the Expiration Time, the fresher everything will remain on your site. A default value of <code>7 days</code> (recommended); is a good conservative middle-ground."
731
- msgstr ""
732
-
733
- #: src/includes/classes/MenuPageOptions.php:516
734
- msgid "Keep in mind that your Expiration Time is only one part of the big picture. %1$s will also clear the cache automatically as changes are made to the site (i.e., you edit a post, someone comments on a post, you change your theme, you add a new navigation menu item, etc., etc.). Thus, your Expiration Time is really just a fallback; e.g., the maximum amount of time that a cache file could ever possibly live."
735
- msgstr ""
736
-
737
- #: src/includes/classes/MenuPageOptions.php:517
738
- msgid "All of that being said, you could set this to just <code>60 seconds</code> and you would still see huge differences in speed and performance. If you're just starting out with %1$s (perhaps a bit nervous about old cache files being served to your visitors); you could set this to something like <code>30 minutes</code> and experiment with it while you build confidence in %1$s. It's not necessary to do so, but many site owners have reported this makes them feel like they're more-in-control when the cache has a short expiration time. All-in-all, it's a matter of preference <i class=\"si si-smile-o\"></i>."
739
- msgstr ""
740
-
741
- #: src/includes/classes/MenuPageOptions.php:519
742
- msgid "<strong>Tip:</strong> the value that you specify here MUST be compatible with PHP's <a href=\"http://php.net/manual/en/function.strtotime.php\" target=\"_blank\" style=\"text-decoration:none;\"><code>strtotime()</code></a> function. Examples: <code>30 seconds</code>, <code>2 hours</code>, <code>7 days</code>, <code>6 months</code>, <code>1 year</code>."
743
- msgstr ""
744
-
745
- #: src/includes/classes/MenuPageOptions.php:520
746
- msgid "<strong>Note:</strong> %1$s will never serve a cache file that is older than what you specify here (even if one exists in your cache directory; stale cache files are never used). In addition, a WP Cron job will automatically cleanup your cache directory (once per hour); purging expired cache files periodically. This prevents a HUGE cache from building up over time, creating a potential storage issue."
747
- msgstr ""
748
-
749
- #: src/includes/classes/MenuPageOptions.php:524
750
- msgid "Cache Cleanup Schedule"
751
- msgstr ""
752
-
753
- #: src/includes/classes/MenuPageOptions.php:525
754
- msgid "If you have an extremely large site and you lower the default Cache Expiration Time of <code>7 days</code>, expired cache files can build up more quickly. By default, %1$s cleans up expired cache files via <a href=\"http://cometcache.com/r/wp_cron-functions/\" target=\"_blank\">WP Cron</a> at an <code>hourly</code> interval, but you can tell %1$s to use a custom Cache Cleanup Schedule below to run the cleanup process more or less frequently, depending on your specific needs."
755
- msgstr ""
756
-
757
- #: src/includes/classes/MenuPageOptions.php:537
758
- msgid "Disable Cache Expiration If Server Load Average is High?"
759
- msgstr ""
760
-
761
- #: src/includes/classes/MenuPageOptions.php:538
762
- msgid "If you have high traffic at certain times of the day, %1$s can be told to check the current load average via <a href=\"http://cometcache.com/r/system-load-average-via-php/\" target=\"_blank\"><code>sys_getloadavg()</code></a>. If your server's load average has been high in the last 15 minutes or so, cache expiration is disabled automatically to help reduce stress on the server; i.e., to avoid generating a new version of the cache while the server is very busy."
763
- msgstr ""
764
-
765
- #: src/includes/classes/MenuPageOptions.php:539
766
- msgid "To enable this functionality you should first determine what a high load average is for your server. If you log into your machine via SSH you can run the <code>top</code> command to get a feel for what a high load average looks like. Once you know the number, you can enter it in the field below; e.g., <code>1.05</code> might be a high load average for a server with one CPU. See also: <a href=\"http://cometcache.com/r/understanding-load-average/\" target=\"_blank\">Understanding Load Average</a>"
767
- msgstr ""
768
-
769
- #: src/includes/classes/MenuPageOptions.php:542
770
- msgid "<strong>Note:</strong> It appears that your server is running Windows. The <code>sys_getloadavg()</code> function has not been implemented in PHP for Windows servers yet."
771
- msgstr ""
772
-
773
- #: src/includes/classes/MenuPageOptions.php:544
774
- msgid "<strong>Note:</strong> <code>sys_getloadavg()</code> has been disabled by your web hosting company or is not available on your server."
775
- msgstr ""
776
-
777
- #: src/includes/classes/MenuPageOptions.php:557
778
- msgid "Client-Side Cache"
779
- msgstr ""
780
-
781
- #: src/includes/classes/MenuPageOptions.php:562
782
- msgid "Allow Double-Caching In The Client-Side Browser?"
783
- msgstr ""
784
-
785
- #: src/includes/classes/MenuPageOptions.php:563
786
- msgid "Recommended setting: <code>No</code> (for membership sites, very important). Otherwise, <code>Yes</code> would be better (if users do NOT log in/out of your site)."
787
- msgstr ""
788
-
789
- #: src/includes/classes/MenuPageOptions.php:564
790
- msgid "%1$s handles content delivery through its ability to communicate with a browser using PHP. If you allow a browser to (cache) the caching system itself, you are momentarily losing some control; and this can have a negative impact on users that see more than one version of your site; e.g., one version while logged-in, and another while NOT logged-in. For instance, a user may log out of your site, but upon logging out they report seeing pages on the site which indicate they are STILL logged in (even though they're not — that's bad). This can happen if you allow a client-side cache, because their browser may cache web pages they visited while logged into your site which persist even after logging out. Sending no-cache headers will work to prevent this issue."
791
- msgstr ""
792
-
793
- #: src/includes/classes/MenuPageOptions.php:565
794
- msgid "All of that being said, if all you care about is blazing fast speed and users don't log in/out of your site (only you do); you can safely set this to <code>Yes</code> (recommended in this case). Allowing a client-side browser cache will improve speed and reduce outgoing bandwidth when this option is feasible."
795
- msgstr ""
796
-
797
- #: src/includes/classes/MenuPageOptions.php:567
798
- msgid "No, prevent a client-side browser cache (safest option)."
799
- msgstr ""
800
-
801
- #: src/includes/classes/MenuPageOptions.php:568
802
- msgid "Yes, I will allow a client-side browser cache of pages on the site."
803
- msgstr ""
804
-
805
- #: src/includes/classes/MenuPageOptions.php:570
806
- msgid "<strong>Tip:</strong> Setting this to <code>No</code> is highly recommended when running a membership plugin like <a href=\"http://wordpress.org/plugins/s2member/\" target=\"_blank\">s2Member</a> (as one example). In fact, many plugins like s2Member will send <a href=\"http://codex.wordpress.org/Function_Reference/nocache_headers\" target=\"_blank\">nocache_headers()</a> on their own, so your configuration here will likely be overwritten when you run such plugins (which is better anyway). In short, if you run a membership plugin, you should NOT allow a client-side browser cache."
807
- msgstr ""
808
-
809
- #: src/includes/classes/MenuPageOptions.php:571
810
- msgid "<strong>Tip:</strong> Setting this to <code>No</code> will NOT impact static content; e.g., CSS, JS, images, or other media. This setting pertains only to dynamic PHP scripts which produce content generated by WordPress."
811
- msgstr ""
812
-
813
- #: src/includes/classes/MenuPageOptions.php:572
814
- msgid "<strong>Advanced Tip:</strong> if you have this set to <code>No</code>, but you DO want to allow a few special URLs to be cached by the browser; you can add this parameter to your URL <code>?%2$sABC=1</code>. This tells %1$s that it's OK for the browser to cache that particular URL. In other words, the <code>%2$sABC=1</code> parameter tells %1$s NOT to send no-cache headers to the browser."
815
- msgstr ""
816
-
817
- #: src/includes/classes/MenuPageOptions.php:573
818
- msgid "Exclusion Patterns for Client-Side Caching"
819
- msgstr ""
820
-
821
- #: src/includes/classes/MenuPageOptions.php:574
822
- msgid "When you enable Client-Side Caching above, you may want to prevent certain pages on your site from being cached by a client-side browser. This is where you will enter those if you need to (one per line). Searches are performed against the <a href=\"https://gist.github.com/jaswsinc/338b6eb03a36c048c26f\" target=\"_blank\" style=\"text-decoration:none;\"><code>REQUEST_URI</code></a>; i.e., <code>/path/?query</code> (caSe insensitive). So, don't put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
823
- msgstr ""
824
-
825
- #: src/includes/classes/MenuPageOptions.php:576
826
- #: src/includes/classes/MenuPageOptions.php:700
827
- #: src/includes/classes/MenuPageOptions.php:861
828
- msgid "<strong>Tip:</strong> let's use this example URL: <code>http://www.example.com/post/example-post-123</code>. To exclude this URL, you would put this line into the field above: <code>/post/example-post-123</code>. Or, you could also just put in a small fragment, like: <code>example</code> or <code>example-*-123</code> and that would exclude any URI containing that word fragment."
829
- msgstr ""
830
-
831
- #: src/includes/classes/MenuPageOptions.php:577
832
- #: src/includes/classes/MenuPageOptions.php:701
833
- #: src/includes/classes/MenuPageOptions.php:719
834
- #: src/includes/classes/MenuPageOptions.php:737
835
- #: src/includes/classes/MenuPageOptions.php:853
836
- #: src/includes/classes/MenuPageOptions.php:857
837
- #: src/includes/classes/MenuPageOptions.php:862
838
- #: src/includes/classes/MenuPageOptions.php:986
839
- msgid "<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line."
840
- msgstr ""
841
-
842
- #: src/includes/classes/MenuPageOptions.php:588
843
- msgid "Logged-In Users"
844
- msgstr ""
845
-
846
- #: src/includes/classes/MenuPageOptions.php:593
847
- msgid "Caching Enabled for Logged-In Users &amp; Comment Authors?"
848
- msgstr ""
849
-
850
- #: src/includes/classes/MenuPageOptions.php:594
851
- msgid "This should almost ALWAYS be set to <code>No</code>. Most sites will NOT want to cache content generated while a user is logged-in. Doing so could result in a cache of dynamic content generated specifically for a particular user, where the content being cached may contain details that pertain only to the user that was logged-in when the cache was generated. Imagine visiting a website that says you're logged-in as Billy Bob (but you're not Billy Bob; NOT good). In short, do NOT turn this on unless you know what you're doing."
852
- msgstr ""
853
-
854
- #: src/includes/classes/MenuPageOptions.php:596
855
- msgid "<strong>Exception (Membership Sites):</strong> If you run a site with many users and the majority of your traffic comes from users who ARE logged-in, please choose: <code>Yes (maintain separate cache)</code>. %1$s will operate normally; but when a user is logged-in, the cache is user-specific. %1$s will intelligently refresh the cache when/if a user submits a form on your site with the GET or POST method. Or, if you make changes to their account (or another plugin makes changes to their account); including user <a href=\"http://codex.wordpress.org/Function_Reference/update_user_option\" target=\"_blank\">option</a>|<a href=\"http://codex.wordpress.org/Function_Reference/update_user_meta\" target=\"_blank\">meta</a> additions, updates &amp; deletions too. However, please note that enabling this feature (e.g., user-specific cache entries); will eat up MUCH more disk space. That being said, the benefits of this feature for most sites will outweigh the disk overhead (e.g., it's NOT an issue in most cases). Unless you are short on disk space (or you have MANY thousands of users), the disk overhead is neglible."
856
- msgstr ""
857
-
858
- #: src/includes/classes/MenuPageOptions.php:598
859
- msgid "No, do NOT cache; or serve a cache file when a user is logged-in (safest option)."
860
- msgstr ""
861
-
862
- #: src/includes/classes/MenuPageOptions.php:599
863
- msgid "Yes, and maintain a separate cache for each user (recommended for membership sites)."
864
- msgstr ""
865
-
866
- #: src/includes/classes/MenuPageOptions.php:602
867
- msgid "Yes, but DON'T maintain a separate cache for each user (I know what I'm doing)."
868
- msgstr ""
869
-
870
- #: src/includes/classes/MenuPageOptions.php:606
871
- msgid "<strong>Warning:</strong> Whenever you enable caching for logged-in users (without a separate cache for each user), the WordPress Admin Bar <em>must</em> be disabled to prevent one user from seeing another user's details in the Admin Bar. <strong>Given your current configuration, %1$s will automatically hide the WordPress Admin Bar on the front-end of your site.</strong>"
872
- msgstr ""
873
-
874
- #: src/includes/classes/MenuPageOptions.php:608
875
- msgid "<strong>Note:</strong> For most sites, the majority of their traffic (if not all of their traffic) comes from visitors who are not logged in, so disabling the cache for logged-in users is NOT ordinarily a performance issue. When a user IS logged-in, disabling the cache is considered ideal, because a logged-in user has a session open with your site; and the content they view should remain very dynamic in this scenario."
876
- msgstr ""
877
-
878
- #: src/includes/classes/MenuPageOptions.php:609
879
- msgid "<strong>Note:</strong> This setting includes some users who AREN'T actually logged into the system, but who HAVE authored comments recently. %1$s includes comment authors as part of it's logged-in user check. This way comment authors will be able to see updates to the comment thread immediately; and, so that any dynamically-generated messages displayed by your theme will work as intended. In short, %1$s thinks of a comment author as a logged-in user, even though technically they are not. ~ Users who gain access to password-protected Posts/Pages are also included."
880
- msgstr ""
881
-
882
- #: src/includes/classes/MenuPageOptions.php:611
883
- msgid "Static CDN Filters Enabled for Logged-In Users &amp; Comment Authors?"
884
- msgstr ""
885
-
886
- #: src/includes/classes/MenuPageOptions.php:612
887
- msgid "While this defaults to a value of <code>No</code>, it should almost always be set to <code>Yes</code>. This value defaults to <code>No</code> only because Logged-In User caching (see above) defaults to <code>No</code> and setting this value to <code>Yes</code> by default can cause confusion for some users. Once you understand that Static CDN Filters can be applied safely for all visitors (logged-in or not logged-in), please choose <code>Yes</code> in the dropdown below. If you are not using Static CDN Filters, the value below is ignored."
888
- msgstr ""
889
-
890
- #: src/includes/classes/MenuPageOptions.php:614
891
- msgid "No, disable Static CDN Filters when a user is logged-in."
892
- msgstr ""
893
-
894
- #: src/includes/classes/MenuPageOptions.php:615
895
- msgid "Yes, enable Static CDN Filters for logged-in users (recommended) ."
896
- msgstr ""
897
-
898
- #: src/includes/classes/MenuPageOptions.php:617
899
- msgid "<strong>Note:</strong> Static CDN Filters serve <em>static</em> resources. Static resources, are, simply put, static. Thus, it is not a problem to cache these resources for any visitor (logged-in or not logged-in). To avoid confusion, this defaults to a value of <code>No</code>, and we ask that you set it to <code>Yes</code> on your own so that you'll know to expect this behavior; i.e., that static resources will always be served from the CDN (logged-in or not logged-in) even though Logged-In User caching may be disabled above."
900
- msgstr ""
901
-
902
- #: src/includes/classes/MenuPageOptions.php:627
903
- msgid "GET Requests"
904
- msgstr ""
905
-
906
- #: src/includes/classes/MenuPageOptions.php:632
907
- msgid "Caching Enabled for GET (Query String) Requests?"
908
- msgstr ""
909
-
910
- #: src/includes/classes/MenuPageOptions.php:633
911
- msgid "This should almost ALWAYS be set to <code>No</code>. UNLESS, you're using unfriendly Permalinks. In other words, if all of your URLs contain a query string (e.g., <code>/?key=value</code>); you're using unfriendly Permalinks. Ideally, you would refrain from doing this; and instead, update your Permalink options immediately; which also optimizes your site for search engines. That being said, if you really want to use unfriendly Permalinks, and ONLY if you're using unfriendly Permalinks, you should set this to <code>Yes</code>; and don't worry too much, the sky won't fall on your head :-)"
912
- msgstr ""
913
-
914
- #: src/includes/classes/MenuPageOptions.php:635
915
- msgid "No, do NOT cache (or serve a cache file) when a query string is present."
916
- msgstr ""
917
-
918
- #: src/includes/classes/MenuPageOptions.php:636
919
- msgid "Yes, I would like to cache URLs that contain a query string."
920
- msgstr ""
921
-
922
- #: src/includes/classes/MenuPageOptions.php:638
923
- msgid "<strong>Note:</strong> POST requests (i.e., forms with <code>method=&quot;post&quot;</code>) are always excluded from the cache, which is the way it should be. Any <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html\" target=\"_blank\">POST/PUT/DELETE</a> request should NEVER (ever) be cached. CLI (and self-serve) requests are also excluded from the cache (always). A CLI request is one that comes from the command line; commonly used by CRON jobs and other automated routines. A self-serve request is an HTTP connection established from your site -› to your site. For instance, a WP Cron job, or any other HTTP request that is spawned not by a user, but by the server itself."
924
- msgstr ""
925
-
926
- #: src/includes/classes/MenuPageOptions.php:639
927
- msgid "<strong>Advanced Tip:</strong> If you are NOT caching GET requests (recommended), but you DO want to allow some special URLs that include query string parameters to be cached; you can add this special parameter to any URL <code>?%2$sAC=1</code>. This tells %1$s that it's OK to cache that particular URL, even though it contains query string arguments. If you ARE caching GET requests and you want to force %1$s to NOT cache a specific request, you can add this special parameter to any URL <code>?%2$sAC=0</code>."
928
- msgstr ""
929
-
930
- #: src/includes/classes/MenuPageOptions.php:649
931
- msgid "404 Requests"
932
- msgstr ""
933
-
934
- #: src/includes/classes/MenuPageOptions.php:654
935
- msgid "Caching Enabled for 404 Requests?"
936
- msgstr ""
937
-
938
- #: src/includes/classes/MenuPageOptions.php:655
939
- msgid "When this is set to <code>No</code>, %1$s will ignore all 404 requests and no cache file will be served. While this is fine for most site owners, caching the 404 page on a high-traffic site may further reduce server load. When this is set to <code>Yes</code>, %1$s will cache the 404 page (see <a href=\"https://codex.wordpress.org/Creating_an_Error_404_Page\" target=\"_blank\">Creating an Error 404 Page</a>) and then serve that single cache file to all future 404 requests."
940
- msgstr ""
941
-
942
- #: src/includes/classes/MenuPageOptions.php:657
943
- msgid "No, do NOT cache (or serve a cache file) for 404 requests."
944
- msgstr ""
945
-
946
- #: src/includes/classes/MenuPageOptions.php:658
947
- msgid "Yes, I would like to cache the 404 page and serve the cached file for 404 requests."
948
- msgstr ""
949
-
950
- #: src/includes/classes/MenuPageOptions.php:660
951
- msgid "<strong>How does %1$s cache 404 requests?</strong> %1$s will create a special cache file (<code>----404----.html</code>, see Advanced Tip below) for the first 404 request and then <a href=\"http://www.php.net/manual/en/function.symlink.php\" target=\"_blank\">symlink</a> future 404 requests to this special cache file. That way you don't end up with lots of 404 cache files that all contain the same thing (the contents of the 404 page). Instead, you'll have one 404 cache file and then several symlinks (i.e., references) to that 404 cache file."
952
- msgstr ""
953
-
954
- #: src/includes/classes/MenuPageOptions.php:661
955
- msgid "<strong>Advanced Tip:</strong> The default 404 cache filename (<code>----404----.html</code>) is designed to minimize the chance of a collision with a cache file for a real page with the same name. However, if you want to override this default and define your own 404 cache filename, you can do so by adding <code>define('COMET_CACHE_404_CACHE_FILENAME', 'your-404-cache-filename');</code> to your <code>wp-config.php</code> file (note that the <code>.html</code> extension should be excluded when defining a new filename)."
956
- msgstr ""
957
-
958
- #: src/includes/classes/MenuPageOptions.php:671
959
- msgid "RSS, RDF, and Atom Feeds"
960
- msgstr ""
961
-
962
- #: src/includes/classes/MenuPageOptions.php:676
963
- msgid "Caching Enabled for RSS, RDF, Atom Feeds?"
964
- msgstr ""
965
-
966
- #: src/includes/classes/MenuPageOptions.php:677
967
- msgid "This should almost ALWAYS be set to <code>No</code>. UNLESS, you're sure that you want to cache your feeds. If you use a web feed management provider like Google® Feedburner and you set this option to <code>Yes</code>, you may experience delays in the detection of new posts. <strong>NOTE:</strong> If you do enable this, it is highly recommended that you also enable automatic Feed Clearing too. Please see the section above: \"Automatic Cache Clearing\". Find the sub-section titled: \"Auto-Clear RSS/RDF/ATOM Feeds\"."
968
- msgstr ""
969
-
970
- #: src/includes/classes/MenuPageOptions.php:679
971
- msgid "No, do NOT cache (or serve a cache file) when displaying a feed."
972
- msgstr ""
973
-
974
- #: src/includes/classes/MenuPageOptions.php:680
975
- msgid "Yes, I would like to cache feed URLs."
976
- msgstr ""
977
-
978
- #: src/includes/classes/MenuPageOptions.php:682
979
- msgid "<strong>Note:</strong> This option affects all feeds served by WordPress, including the site feed, the site comment feed, post-specific comment feeds, author feeds, search feeds, and category and tag feeds. See also: <a href=\"http://codex.wordpress.org/WordPress_Feeds\" target=\"_blank\">WordPress Feeds</a>."
980
- msgstr ""
981
-
982
- #: src/includes/classes/MenuPageOptions.php:692
983
- msgid "URI Exclusion Patterns"
984
- msgstr ""
985
-
986
- #: src/includes/classes/MenuPageOptions.php:696
987
- msgid "Don't Cache These Special URI Exclusion Patterns?"
988
- msgstr ""
989
-
990
- #: src/includes/classes/MenuPageOptions.php:697
991
- msgid "Sometimes there are certain cases where a particular file, or a particular group of files, should never be cached. This is where you will enter those if you need to (one per line). Searches are performed against the <a href=\"https://gist.github.com/jaswsinc/338b6eb03a36c048c26f\" target=\"_blank\" style=\"text-decoration:none;\"><code>REQUEST_URI</code></a>; i.e., <code>/path/?query</code> (caSe insensitive). So, don't put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
992
- msgstr ""
993
-
994
- #: src/includes/classes/MenuPageOptions.php:711
995
- msgid "HTTP Referrer Exclusion Patterns"
996
- msgstr ""
997
-
998
- #: src/includes/classes/MenuPageOptions.php:715
999
- msgid "Don't Cache These Special HTTP Referrer Exclusion Patterns?"
1000
- msgstr ""
1001
-
1002
- #: src/includes/classes/MenuPageOptions.php:716
1003
- msgid "Sometimes there are special cases where a particular referring URL (or referring domain) that sends you traffic; or even a particular group of referring URLs or domains that send you traffic; should result in a page being loaded on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the <a href=\"http://www.php.net//manual/en/reserved.variables.server.php\" target=\"_blank\" style=\"text-decoration:none;\"><code>HTTP_REFERER</code></a> (caSe insensitive). A wildcard <code>*</code> character can also be used when necessary; e.g., <code>*.domain.com</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
1004
- msgstr ""
1005
-
1006
- #: src/includes/classes/MenuPageOptions.php:718
1007
- msgid "<strong>Tip:</strong> let's use this example URL: <code>http://www.referring-domain.com/search/?q=search+terms</code>. To exclude this referring URL, you could put this line into the field above: <code>www.referring-domain.com</code>. Or, you could also just put in a small fragment, like: <code>/search/</code> or <code>q=*</code>; and that would exclude any referrer containing that word fragment."
1008
- msgstr ""
1009
-
1010
- #: src/includes/classes/MenuPageOptions.php:729
1011
- msgid "User-Agent Exclusion Patterns"
1012
- msgstr ""
1013
-
1014
- #: src/includes/classes/MenuPageOptions.php:733
1015
- msgid "Don't Cache These Special User-Agent Exclusion Patterns?"
1016
- msgstr ""
1017
-
1018
- #: src/includes/classes/MenuPageOptions.php:734
1019
- msgid "Sometimes there are special cases when a particular user-agent (e.g., a specific browser or a specific type of device); should be shown a page on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the <a href=\"http://www.php.net//manual/en/reserved.variables.server.php\" target=\"_blank\" style=\"text-decoration:none;\"><code>HTTP_USER_AGENT</code></a> (caSe insensitive). A wildcard <code>*</code> character can also be used when necessary; e.g., <code>Android *; Chrome/* Mobile</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
1020
- msgstr ""
1021
-
1022
- #: src/includes/classes/MenuPageOptions.php:736
1023
- msgid "<strong>Tip:</strong> if you wanted to exclude iPhones put this line into the field above: <code>iPhone;*AppleWebKit</code>. Or, you could also just put in a small fragment, like: <code>iphone</code>; and that would exclude any user-agent containing that word fragment. Note, this is just an example. With a default installation of %1$s, there is no compelling reason to exclude iOS devices (or any mobile device for that matter)."
1024
- msgstr ""
1025
-
1026
- #: src/includes/classes/MenuPageOptions.php:748
1027
- msgid "Auto-Cache Engine"
1028
- msgstr ""
1029
-
1030
- #: src/includes/classes/MenuPageOptions.php:753
1031
- msgid "Enable the Auto-Cache Engine?"
1032
- msgstr ""
1033
-
1034
- #: src/includes/classes/MenuPageOptions.php:754
1035
- msgid "After using %1$s for awhile (or any other page caching plugin, for that matter); it becomes obvious that at some point (based on your configured Expiration Time) %1$s has to refresh itself. It does this by ditching its cached version of a page, reloading the database-driven content, and then recreating the cache with the latest data. This is a never ending regeneration cycle that is based entirely on your configured Expiration Time."
1036
- msgstr ""
1037
-
1038
- #: src/includes/classes/MenuPageOptions.php:755
1039
- msgid "Understanding this, you can see that 99% of your visitors are going to receive a lightning fast response from your server. However, there will always be around 1% of your visitors that land on a page for the very first time (before it's been cached), or land on a page that needs to have its cache regenerated, because the existing cache has become outdated. We refer to this as a <em>First-Come Slow-Load Issue</em>. Not a huge problem, but if you're optimizing your site for every ounce of speed possible, the Auto-Cache Engine can help with this. The Auto-Cache Engine has been designed to combat this issue by taking on the responsibility of being that first visitor to a page that has not yet been cached, or has an expired cache. The Auto-Cache Engine is powered, in part, by <a href=\"http://codex.wordpress.org/Category:WP-Cron_Functions\" target=\"_blank\">WP-Cron</a> (already built into WordPress). The Auto-Cache Engine runs at 15-minute intervals via WP-Cron. It also uses the <a href=\"http://core.trac.wordpress.org/browser/trunk/wp-includes/http.php\" target=\"_blank\">WP_Http</a> class, which is also built into WordPress already."
1040
- msgstr ""
1041
-
1042
- #: src/includes/classes/MenuPageOptions.php:756
1043
- msgid "The Auto-Cache Engine obtains its list of URLs to auto-cache, from two different sources. It can read an <a href=\"http://wordpress.org/extend/plugins/google-sitemap-generator/\" target=\"_blank\">XML Sitemap</a> and/or a list of specific URLs that you supply. If you supply both sources, it will use both sources collectively. The Auto-Cache Engine takes ALL of your other configuration options into consideration too, including your Expiration Time, as well as any cache exclusion rules."
1044
- msgstr ""
1045
-
1046
- #: src/includes/classes/MenuPageOptions.php:758
1047
- msgid "No, leave the Auto-Cache Engine disabled please."
1048
- msgstr ""
1049
-
1050
- #: src/includes/classes/MenuPageOptions.php:759
1051
- msgid "Yes, I want the Auto-Cache Engine to keep pages cached automatically."
1052
- msgstr ""
1053
-
1054
- #: src/includes/classes/MenuPageOptions.php:765
1055
- msgid "XML Sitemap URL (or an XML Sitemap Index)"
1056
- msgstr ""
1057
-
1058
- #: src/includes/classes/MenuPageOptions.php:769
1059
- msgid "All URLs in this network are in the sitemap for the main site."
1060
- msgstr ""
1061
-
1062
- #: src/includes/classes/MenuPageOptions.php:770
1063
- msgid "Using the path I've given, look for blog-specific sitemaps in each child blog also."
1064
- msgstr ""
1065
-
1066
- #: src/includes/classes/MenuPageOptions.php:772
1067
- msgid "<strong>↑</strong> If enabled here, each child blog can be auto-cached too. %1$s will dynamically change the leading <code>%2$s</code> as necessary; for each child blog in the network. %1$s supports both sub-directory &amp; sub-domain networks, including domain mapping plugins. For more information about how the Auto-Cache Engine caches child blogs, see <a href=\"http://cometcache.com/r/kb-article-how-does-the-auto-cache-engine-cache-child-blogs-in-a-multisite-network/\" target=\"_blank\">this article</a>."
1068
- msgstr ""
1069
-
1070
- #: src/includes/classes/MenuPageOptions.php:776
1071
- msgid "And/Or; a List of URLs to Auto-Cache (One Per Line)"
1072
- msgstr ""
1073
-
1074
- #: src/includes/classes/MenuPageOptions.php:778
1075
- msgid "<strong>Note:</strong> Wildcards are NOT supported here. If you are going to supply a list of URLs above, each line must contain one full URL for the Auto-Cache Engine to auto-cache. If you have many URLs, we recommend using an <a href=\"https://en.wikipedia.org/wiki/Sitemaps\" target=\"_blank\">XML Sitemap</a>."
1076
- msgstr ""
1077
-
1078
- #: src/includes/classes/MenuPageOptions.php:782
1079
- msgid "Auto-Cache Delay Timer (in Milliseconds)"
1080
- msgstr ""
1081
-
1082
- #: src/includes/classes/MenuPageOptions.php:783
1083
- msgid "As the Auto-Cache Engine runs through each URL, you can tell it to wait X number of milliseconds between each connection that it makes. It is strongly suggested that you DO have some small delay here. Otherwise, you run the risk of hammering your own web server with multiple repeated connections whenever the Auto-Cache Engine is running. This is especially true on very large sites; where there is the potential for hundreds of repeated connections as the Auto-Cache Engine goes through a long list of URLs. Adding a delay between each connection will prevent the Auto-Cache Engine from placing a heavy load on the processor that powers your web server. A value of <code>500</code> milliseconds is suggested here (half a second). If you experience problems, you can bump this up a little at a time, in increments of <code>500</code> milliseconds; until you find a happy place for your server. <em>Please note that <code>1000</code> milliseconds = <code>1</code> full second.</em>"
1084
- msgstr ""
1085
-
1086
- #: src/includes/classes/MenuPageOptions.php:788
1087
- msgid "Auto-Cache User-Agent String"
1088
- msgstr ""
1089
-
1090
- #: src/includes/classes/MenuPageOptions.php:790
1091
- msgid "This is how the Auto-Cache Engine identifies itself when connecting to URLs. See <a href=\"http://en.wikipedia.org/wiki/User_agent\" target=\"_blank\">User Agent</a> in the Wikipedia."
1092
- msgstr ""
1093
-
1094
- #: src/includes/classes/MenuPageOptions.php:802
1095
- msgid "HTML Compression"
1096
- msgstr ""
1097
-
1098
- #: src/includes/classes/MenuPageOptions.php:807
1099
- msgid "Enable WebSharks™ HTML Compression?"
1100
- msgstr ""
1101
-
1102
- #: src/includes/classes/MenuPageOptions.php:809
1103
- msgid "No, do NOT compress HTML/CSS/JS code at runtime."
1104
- msgstr ""
1105
-
1106
- #: src/includes/classes/MenuPageOptions.php:810
1107
- msgid "Yes, I want to compress HTML/CSS/JS for blazing fast speeds."
1108
- msgstr ""
1109
-
1110
- #: src/includes/classes/MenuPageOptions.php:812
1111
- msgid "<strong>Note:</strong> This is experimental. Please <a href=\"https://github.com/websharks/comet-cache/issues\" target=\"_blank\">report issues here</a>."
1112
- msgstr ""
1113
-
1114
- #: src/includes/classes/MenuPageOptions.php:815
1115
- msgid "HTML Compression Options"
1116
- msgstr ""
1117
-
1118
- #: src/includes/classes/MenuPageOptions.php:816
1119
- msgid "You can <a href=\"https://github.com/websharks/html-compressor\" target=\"_blank\">learn more about all of these options here</a>."
1120
- msgstr ""
1121
-
1122
- #: src/includes/classes/MenuPageOptions.php:818
1123
- msgid "Yes, combine CSS from &lt;head&gt; and &lt;body&gt; into fewer files."
1124
- msgstr ""
1125
-
1126
- #: src/includes/classes/MenuPageOptions.php:819
1127
- msgid "No, do not combine CSS from &lt;head&gt; and &lt;body&gt; into fewer files."
1128
- msgstr ""
1129
-
1130
- #: src/includes/classes/MenuPageOptions.php:822
1131
- msgid "Yes, compress the code in any unified CSS files."
1132
- msgstr ""
1133
-
1134
- #: src/includes/classes/MenuPageOptions.php:823
1135
- msgid "No, do not compress the code in any unified CSS files."
1136
- msgstr ""
1137
-
1138
- #: src/includes/classes/MenuPageOptions.php:826
1139
- msgid "Yes, combine JS from &lt;head&gt; into fewer files."
1140
- msgstr ""
1141
-
1142
- #: src/includes/classes/MenuPageOptions.php:827
1143
- msgid "No, do not combine JS from &lt;head&gt; into fewer files."
1144
- msgstr ""
1145
-
1146
- #: src/includes/classes/MenuPageOptions.php:830
1147
- msgid "Yes, combine JS footer scripts into fewer files."
1148
- msgstr ""
1149
-
1150
- #: src/includes/classes/MenuPageOptions.php:831
1151
- msgid "No, do not combine JS footer scripts into fewer files."
1152
- msgstr ""
1153
-
1154
- #: src/includes/classes/MenuPageOptions.php:834
1155
- msgid "Yes, combine CSS/JS from remote resources too."
1156
- msgstr ""
1157
-
1158
- #: src/includes/classes/MenuPageOptions.php:835
1159
- msgid "No, do not combine CSS/JS from remote resources."
1160
- msgstr ""
1161
-
1162
- #: src/includes/classes/MenuPageOptions.php:838
1163
- msgid "Yes, compress the code in any unified JS files."
1164
- msgstr ""
1165
-
1166
- #: src/includes/classes/MenuPageOptions.php:839
1167
- msgid "No, do not compress the code in any unified JS files."
1168
- msgstr ""
1169
-
1170
- #: src/includes/classes/MenuPageOptions.php:842
1171
- msgid "Yes, compress inline JavaScript snippets."
1172
- msgstr ""
1173
-
1174
- #: src/includes/classes/MenuPageOptions.php:843
1175
- msgid "No, do not compress inline JavaScript snippets."
1176
- msgstr ""
1177
-
1178
- #: src/includes/classes/MenuPageOptions.php:846
1179
- msgid "Yes, compress (remove extra whitespace) in the final HTML code too."
1180
- msgstr ""
1181
-
1182
- #: src/includes/classes/MenuPageOptions.php:847
1183
- msgid "No, do not compress the final HTML code."
1184
- msgstr ""
1185
-
1186
- #: src/includes/classes/MenuPageOptions.php:850
1187
- msgid "CSS Exclusion Patterns?"
1188
- msgstr ""
1189
-
1190
- #: src/includes/classes/MenuPageOptions.php:851
1191
- msgid "Sometimes there are special cases when a particular CSS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <code>&lt;link href=&quot;&quot;&gt;</code> value, and also against the contents of any inline <code>&lt;style&gt;</code> tags (caSe insensitive). A wildcard <code>*</code> character can also be used when necessary; e.g., <code>xy*-framework</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
1192
- msgstr ""
1193
-
1194
- #: src/includes/classes/MenuPageOptions.php:854
1195
- msgid "JavaScript Exclusion Patterns?"
1196
- msgstr ""
1197
-
1198
- #: src/includes/classes/MenuPageOptions.php:855
1199
- msgid "Sometimes there are special cases when a particular JS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <code>&lt;script src=&quot;&quot;&gt;</code> value, and also against the contents of any inline <code>&lt;script&gt;</code> tags (caSe insensitive). A wildcard <code>*</code> character can also be used when necessary; e.g., <code>xy*-framework</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
1200
- msgstr ""
1201
-
1202
- #: src/includes/classes/MenuPageOptions.php:858
1203
- msgid "URI Exclusions for HTML Compressor?"
1204
- msgstr ""
1205
-
1206
- #: src/includes/classes/MenuPageOptions.php:859
1207
- msgid "When you enable HTML Compression above, you may want to prevent certain pages on your site from being cached by the HTML Compressor. This is where you will enter those if you need to (one per line). Searches are performed against the <a href=\"https://gist.github.com/jaswsinc/338b6eb03a36c048c26f\" target=\"_blank\" style=\"text-decoration:none;\"><code>REQUEST_URI</code></a>; i.e., <code>/path/?query</code> (caSe insensitive). So, don't put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href =\"http://cometcache.com/r/watered-down-regex-syntax/\" target=\"_blank\">this KB article</a>."
1208
- msgstr ""
1209
-
1210
- #: src/includes/classes/MenuPageOptions.php:864
1211
- msgid "HTML Compression Cache Expiration"
1212
- msgstr ""
1213
-
1214
- #: src/includes/classes/MenuPageOptions.php:866
1215
- msgid "<strong>Tip:</strong> the value that you specify here MUST be compatible with PHP's <a href=\"http://php.net/manual/en/function.strtotime.php\" target=\"_blank\" style=\"text-decoration:none;\"><code>strtotime()</code></a> function. Examples: <code>2 hours</code>, <code>7 days</code>, <code>6 months</code>, <code>1 year</code>."
1216
- msgstr ""
1217
-
1218
- #: src/includes/classes/MenuPageOptions.php:867
1219
- msgid "<strong>Note:</strong> This does NOT impact the overall cache expiration time that you configure with %1$s. It only impacts the sub-routines provided by the HTML Compressor. In fact, this expiration time is mostly irrelevant. The HTML Compressor uses an internal checksum, and it also checks <code>filemtime()</code> before using an existing cache file. The HTML Compressor class also handles the automatic cleanup of your cache directories to keep it from growing too large over time. Therefore, unless you have VERY little disk space there is no reason to set this to a lower value (even if your site changes dynamically quite often). If anything, you might like to increase this value which could help to further reduce server load. You can <a href=\"https://github.com/websharks/HTML-Compressor\" target=\"_blank\">learn more here</a>. We recommend setting this value to at least double that of your overall %1$s expiration time."
1220
- msgstr ""
1221
-
1222
- #: src/includes/classes/MenuPageOptions.php:869
1223
- msgid "Enable HTML Compression for Logged-In Users?"
1224
- msgstr ""
1225
-
1226
- #: src/includes/classes/MenuPageOptions.php:870
1227
- msgid "Disabled by default. This setting is only applicable when caching for Logged-In Users is enabled. This should remain disabled for logged-in users because the user-specific cache has a much shorter Time To Live (TTL) which means their cache is likely to expire more quickly than a normal visitor. Rebuilding the HTML Compressor cache is time-consuming and doing it too frequently will actually slow things down for them. For example, if you're logged into the site as a user and you submit a form, that triggers a clearing of the cache for that user, including the HTML Compressor cache (when Logged-In User caching is enabled). Lots of little actions you take can result in a clearing of the cache. This shorter TTL is not ideal when running the HTML Compressor because it does a deep analysis of the page content and the associated resources in order to intelligently compress things. For logged-in users, it is better to skip that extra work and just cache the HTML source as-is, avoiding that extra overhead. In short, do NOT turn this on unless you know what you're doing."
1228
- msgstr ""
1229
-
1230
- #: src/includes/classes/MenuPageOptions.php:872
1231
- msgid "No, disable HTML Compression for logged-in users (recommended)."
1232
- msgstr ""
1233
-
1234
- #: src/includes/classes/MenuPageOptions.php:873
1235
- msgid "Yes, enable HTML Compression for logged-in users."
1236
- msgstr ""
1237
-
1238
- #: src/includes/classes/MenuPageOptions.php:885
1239
- msgid "GZIP Compression"
1240
- msgstr ""
1241
-
1242
- #: src/includes/classes/MenuPageOptions.php:890
1243
- msgid "<a href=\"https://developers.google.com/speed/articles/gzip\" target=\"_blank\">GZIP Compression</a> (Optional; Highly Recommended)"
1244
- msgstr ""
1245
-
1246
- #: src/includes/classes/MenuPageOptions.php:891
1247
- msgid "You don't have to use an <code>.htaccess</code> file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an <code>.htaccess</code> file to accomplish that part."
1248
- msgstr ""
1249
-
1250
- #: src/includes/classes/MenuPageOptions.php:892
1251
- msgid "%1$s fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your <code>php.ini</code> file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!"
1252
- msgstr ""
1253
-
1254
- #: src/includes/classes/MenuPageOptions.php:893
1255
- msgid "If you want to enable GZIP, create an <code>.htaccess</code> file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an <code>.htaccess</code> file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: <a href=\"https://developers.google.com/speed/articles/gzip\" target=\"_blank\"><i class=\"si si-youtube-play\"></i> video about GZIP Compression</a>."
1256
- msgstr ""
1257
-
1258
- #: src/includes/classes/MenuPageOptions.php:907
1259
- msgid "Static CDN Filters"
1260
- msgstr ""
1261
-
1262
- #: src/includes/classes/MenuPageOptions.php:911
1263
- msgid "Clear CDN Cache (Bump CDN Invalidation Counter)"
1264
- msgstr ""
1265
-
1266
- #: src/includes/classes/MenuPageOptions.php:911
1267
- msgid "Clear CDN Cache"
1268
- msgstr ""
1269
-
1270
- #: src/includes/classes/MenuPageOptions.php:912
1271
- msgid "Enable Static CDN Filters (e.g., MaxCDN/CloudFront)?"
1272
- msgstr ""
1273
-
1274
- #: src/includes/classes/MenuPageOptions.php:913
1275
- msgid "This feature allows you to serve some and/or ALL static files on your site from a CDN of your choosing. This is made possible through content/URL filters exposed by WordPress and implemented by %1$s. All it requires is that you setup a CDN host name sourced by your WordPress installation domain. You enter that CDN host name below and %1$s will do the rest! Super easy, and it doesn't require any DNS changes either. :-) Please <a href=\"http://cometcache.com/r/static-cdn-filters-general-instructions/\" target=\"_blank\">click here</a> for a general set of instructions."
1276
- msgstr ""
1277
-
1278
- #: src/includes/classes/MenuPageOptions.php:914
1279
- msgid "<strong>What's a CDN?</strong> It's a Content Delivery Network (i.e., a network of optimized servers) designed to cache static resources served from your site (e.g., JS/CSS/images and other static files) onto it's own servers, which are located strategically in various geographic areas around the world. Integrating a CDN for static files can dramatically improve the speed and performance of your site, lower the burden on your own server, and reduce latency associated with visitors attempting to access your site from geographic areas of the world that might be very far away from the primary location of your own web servers."
1280
- msgstr ""
1281
-
1282
- #: src/includes/classes/MenuPageOptions.php:917
1283
- msgid "It appears that your server is running NGINX and does not support <code>.htaccess</code> rules. Please <a href=\"http://cometcache.com/r/kb-article-recommended-nginx-server-configuration/\" target=\"_new\">update your server configuration manually</a>. Note that updating your NGINX server configuration <em>before</em> enabling Static CDN Filters is recommended to prevent any <a href=\"http://cometcache.com/r/kb-article-what-are-cross-origin-request-blocked-cors-errors/\" target=\"_new\">CORS errors</a> with your CDN. If you've already updated your NGINX configuration, you can safely <a href=\"http://cometcache.com/r/kb-article-how-do-i-disable-the-nginx-htaccess-notice/\" target=\"_new\">ignore this message</a>."
1284
- msgstr ""
1285
-
1286
- #: src/includes/classes/MenuPageOptions.php:921
1287
- msgid "No, I do NOT want CDN filters applied at runtime."
1288
- msgstr ""
1289
-
1290
- #: src/includes/classes/MenuPageOptions.php:922
1291
- msgid "Yes, I want CDN filters applied w/ my configuration below."
1292
- msgstr ""
1293
-
1294
- #: src/includes/classes/MenuPageOptions.php:929
1295
- msgid "CDN Host Name (Required)"
1296
- msgstr ""
1297
-
1298
- #: src/includes/classes/MenuPageOptions.php:935
1299
- msgid "This field is really all that's necessary to get Static CDN Filters working! However, it does requires a little bit of work on your part. You need to setup and configure a CDN before you can fill in this field. Once you configure a CDN, you'll receive a host name (provided by your CDN), which you'll enter here; e.g., <code>js9dgjsl4llqpp.cloudfront.net</code>. We recommend <a href=\"http://cometcache.com/r/maxcdn/\" target=\"_blank\">MaxCDN</a>, <a href=\"http://cometcache.com/r/amazon-cloudfront/\" target=\"_blank\">Amazon CloudFront</a>, <a href=\"http://cometcache.com/r/keycdn/\" target=\"_blank\">KeyCDN</a>, and/or <a href=\"http://cometcache.com/r/cdn77/\" target=\"_blank\">CDN77</a> but this should work with many of the most popular CDNs. Please read <a href=\"http://cometcache.com/r/static-cdn-filters-general-instructions/\" target=\"_blank\">this article</a> for a general set of instructions. We also have a <a href=\"http://cometcache.com/r/static-cdn-filters-maxcdn/\" target=\"_blank\">MaxCDN tutorial</a>, <a href=\"http://cometcache.com/r/static-cdn-filters-cloudfront/\" target=\"_blank\">CloudFront tutorial</a>, <a href=\"http://cometcache.com/r/static-cdn-filters-keycdn/\" target=\"_blank\">KeyCDN tutorial</a>, and a <a href=\"http://cometcache.com/r/static-cdn-filters-cdn77/\" target=\"_blank\">CDN77 tutorial</a> to walk you through the process."
1300
- msgstr ""
1301
-
1302
- #: src/includes/classes/MenuPageOptions.php:940
1303
- msgid "Multiple CDN Host Names for Domain Sharding and Multisite Networks (Optional)"
1304
- msgstr ""
1305
-
1306
- #: src/includes/classes/MenuPageOptions.php:941
1307
- msgid "%1$s also supports multiple CDN Host Names for any given domain. Using multiple CDN Host Names (instead of just one, as seen above) is referred to as <strong><a href=\"http://cometcache.com/r/domain-sharding/\" target=\"_blank\">Domain Sharding</a></strong> (<a href=\"http://cometcache.com/r/domain-sharding/\" target=\"_blank\">click here to learn more</a>). If you configure multiple CDN Host Names (i.e., if you implement Domain Sharding), %1$s will use the first one that you list for static resources loaded in the HTML <code>&lt;head&gt;</code> section, the last one for static resources loaded in the footer, and it will choose one at random for all other static resource locations. Configuring multiple CDN Host Names can improve speed! This is a way for advanced site owners to work around concurrency limits in popular browsers; i.e., making it possible for browsers to download many more resources simultaneously, resulting in a faster overall completion time. In short, this tells the browser that your website will not be overloaded by concurrent requests, because static resources are in fact being served by a content-delivery network (i.e., multiple CDN host names). If you use this functionality for Domain Sharding, we suggest that you setup one CDN Distribution (aka: Pull Zone), and then create multiple CNAME records pointing to that distribution. You can enter each of your CNAMES in the field below, as instructed."
1308
- msgstr ""
1309
-
1310
- #: src/includes/classes/MenuPageOptions.php:942
1311
- msgid "<strong>On WordPress Multisite Network installations</strong>, this field also allows you to configure different CDN Host Names for each domain (or sub-domain) that you run from a single installation of WordPress. For more information about configuring Static CDN Filters on a WordPress Multisite Network, see this tutorial: <a href=\"http://cometcache.com/r/static-cdn-filters-for-wordpress-multisite-networks/\" target=\"_blank\">Static CDN Filters for WordPress Multisite Networks</a>."
1312
- msgstr ""
1313
-
1314
- #: src/includes/classes/MenuPageOptions.php:944
1315
- msgid "<strong>↑ Syntax:</strong> This is a line-delimited list of domain mappings. Each line should start with your WordPress domain name (e.g., <code>%1$s</code>), followed by an <code>=</code> sign, followed by a comma-delimited list of CDN Host Names associated with the domain in that line. If you're running a Multisite Network installation of WordPress, you might have multiple configuration lines. Otherwise, you should only need one line to configure multiple CDN Host Names for a standard WordPress installation."
1316
- msgstr ""
1317
-
1318
- #: src/includes/classes/MenuPageOptions.php:948
1319
- msgid "CDN Supports HTTPS Connections?"
1320
- msgstr ""
1321
-
1322
- #: src/includes/classes/MenuPageOptions.php:950
1323
- msgid "No, I don't serve content over https://; or I haven't configured my CDN w/ an SSL certificate."
1324
- msgstr ""
1325
-
1326
- #: src/includes/classes/MenuPageOptions.php:951
1327
- msgid "Yes, I've configured my CDN w/ an SSL certificate; I need https:// enabled."
1328
- msgstr ""
1329
-
1330
- #: src/includes/classes/MenuPageOptions.php:958
1331
- msgid "Additional Options (For Advanced Users)"
1332
- msgstr ""
1333
-
1334
- #: src/includes/classes/MenuPageOptions.php:963
1335
- msgid "Everything else below is 100% completely optional; i.e., not required to enjoy the benefits of Static CDN Filters."
1336
- msgstr ""
1337
-
1338
- #: src/includes/classes/MenuPageOptions.php:967
1339
- msgid "Whitelisted File Extensions (Optional; Comma-Delimited)"
1340
- msgstr ""
1341
-
1342
- #: src/includes/classes/MenuPageOptions.php:969
1343
- msgid "If you leave this empty a default set of extensions are taken from WordPress itself. The default set of whitelisted file extensions includes everything supported by the WordPress media library."
1344
- msgstr ""
1345
-
1346
- #: src/includes/classes/MenuPageOptions.php:971
1347
- msgid "Blacklisted File Extensions (Optional; Comma-Delimited)"
1348
- msgstr ""
1349
-
1350
- #: src/includes/classes/MenuPageOptions.php:973
1351
- msgid "With or without a whitelist, you can force exclusions by explicitly blacklisting certain file extensions of your choosing. Please note, the <code>php</code> extension will never be considered a static resource; i.e., it is automatically blacklisted at all times."
1352
- msgstr ""
1353
-
1354
- #: src/includes/classes/MenuPageOptions.php:977
1355
- msgid "Whitelisted URI Inclusion Patterns (Optional; One Per Line)"
1356
- msgstr ""
1357
-
1358
- #: src/includes/classes/MenuPageOptions.php:979
1359
- msgid "<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one inclusion pattern per line."
1360
- msgstr ""
1361
-
1362
- #: src/includes/classes/MenuPageOptions.php:980
1363
- msgid "If provided, only local URIs matching one of the patterns you list here will be served from your CDN Host Name. URI patterns are caSe-insensitive. A wildcard <code>*</code> will match zero or more characters in any of your patterns. A caret <code>^</code> symbol will match zero or more characters that are NOT the <code>/</code> character. For instance, <code>*/wp-content/*</code> here would indicate that you only want to filter URLs that lead to files located inside the <code>wp-content</code> directory. Adding an additional line with <code>*/wp-includes/*</code> would filter URLs in the <code>wp-includes</code> directory also. <strong>If you leave this empty</strong>, ALL files matching a static file extension will be served from your CDN; i.e., the default behavior."
1364
- msgstr ""
1365
-
1366
- #: src/includes/classes/MenuPageOptions.php:981
1367
- msgid "Please note that URI patterns are tested against a file's path (i.e., a file's URI, and NOT its full URL). A URI always starts with a leading <code>/</code>. To clarify, a URI is the portion of the URL which comes after the host name. For instance, given the following URL: <code>http://example.com/path/to/style.css?ver=3</code>, the URI you are matching against would be: <code>/path/to/style.css?ver=3</code>. To whitelist this URI, you could use a line that contains something like this: <code>/path/to/*.css*</code>"
1368
- msgstr ""
1369
-
1370
- #: src/includes/classes/MenuPageOptions.php:983
1371
- msgid "Blacklisted URI Exclusion Patterns (Optional; One Per Line)"
1372
- msgstr ""
1373
-
1374
- #: src/includes/classes/MenuPageOptions.php:985
1375
- msgid "With or without a whitelist, you can force exclusions by explicitly blacklisting certain URI patterns. URI patterns are caSe-insensitive. A wildcard <code>*</code> will match zero or more characters in any of your patterns. A caret <code>^</code> symbol will match zero or more characters that are NOT the <code>/</code> character. For instance, <code>*/wp-content/*/dynamic.pdf*</code> would exclude a file with the name <code>dynamic.pdf</code> located anywhere inside a sub-directory of <code>wp-content</code>."
1376
- msgstr ""
1377
-
1378
- #: src/includes/classes/MenuPageOptions.php:990
1379
- msgid "Query String Invalidation Variable Name"
1380
- msgstr ""
1381
-
1382
- #: src/includes/classes/MenuPageOptions.php:992
1383
- msgid "Each filtered URL (which then leads to your CDN) will include this query string variable as an easy way to invalidate the CDN cache at any time. Invalidating the CDN cache is simply a matter of changing the global invalidation counter (i.e., the value assigned to this query string variable). %1$s manages invalidations automatically; i.e., %1$s will automatically bump an internal counter each time you upgrade a WordPress component (e.g., a plugin, theme, or WP itself). Or, if you ask %1$s to invalidate the CDN cache (e.g., a manual clearing of the CDN cache); the internal counter is bumped then too. In short, %1$s handles cache invalidations for you reliably. This option simply allows you to customize the query string variable name which makes cache invalidations possible. <strong>Please note, the default value is adequate for most sites. You can change this if you like, but it's not necessary.</strong>"
1384
- msgstr ""
1385
-
1386
- #: src/includes/classes/MenuPageOptions.php:993
1387
- msgid "<strong>Tip:</strong> You can also tell %1$s to automatically bump the CDN Invalidation Counter whenever you clear the cache manually. See: <strong>%1$s → Manual Cache Clearing → Clear the CDN Cache Too?</strong>"
1388
- msgstr ""
1389
-
1390
- #: src/includes/classes/MenuPageOptions.php:994
1391
- msgid "<strong>Note:</strong> If you empty this field, it will effectively disable the %1$s invalidation system for Static CDN Filters; i.e., the query string variable will NOT be included if you do not supply a variable name."
1392
- msgstr ""
1393
-
1394
- #: src/includes/classes/MenuPageOptions.php:1007
1395
- msgid "Dynamic Version Salt"
1396
- msgstr ""
1397
-
1398
- #: src/includes/classes/MenuPageOptions.php:1012
1399
- msgid "<i class=\"si si-flask\"></i> <span style=\"display:inline-block; padding:5px; border-radius:3px; background:#FFFFFF; color:#354913;\"><span style=\"font-weight:bold; font-size:80%;\">GEEK ALERT</span></span> This is for VERY advanced users only..."
1400
- msgstr ""
1401
-
1402
- #: src/includes/classes/MenuPageOptions.php:1013
1403
- msgid "<em>Note: Understanding the %1$s <a href=\"http://cometcache.com/r/kb-branched-cache-structure/\" target=\"_blank\">Branched Cache Structure</a> is a prerequisite to understanding how Dynamic Version Salts are added to the mix.</em>"
1404
- msgstr ""
1405
-
1406
- #: src/includes/classes/MenuPageOptions.php:1014
1407
- msgid "A Version Salt gives you the ability to dynamically create multiple variations of the cache, and those dynamic variations will be served on subsequent visits; e.g., if a visitor has a specific cookie (of a certain value) they will see pages which were cached with that version (i.e., w/ that Version Salt: the value of the cookie). A Version Salt can really be anything."
1408
- msgstr ""
1409
-
1410
- #: src/includes/classes/MenuPageOptions.php:1015
1411
- msgid "A Version Salt can be a single variable like <code>$_COOKIE['my_cookie']</code>, or it can be a combination of multiple variables, like <code>$_COOKIE['my_cookie'].$_COOKIE['my_other_cookie']</code>. (When using multiple variables, please separate them with a dot, as shown in the example.)"
1412
- msgstr ""
1413
-
1414
- #: src/includes/classes/MenuPageOptions.php:1016
1415
- msgid "Experts could even use PHP ternary expressions that evaluate into something. For example: <code>((preg_match('/iPhone/i', $_SERVER['HTTP_USER_AGENT'])) ? 'iPhones' : '')</code>. This would force a separate version of the cache to be created for iPhones (e.g., <code>/cache/PROTOCOL/HOST/REQUEST-URI.v/iPhones.html</code>)."
1416
- msgstr ""
1417
-
1418
- #: src/includes/classes/MenuPageOptions.php:1017
1419
- msgid "For more documentation, please see <a href=\"http://cometcache.com/r/kb-dynamic-version-salts/\" target=\"_blank\">Dynamic Version Salts</a>."
1420
- msgstr ""
1421
-
1422
- #: src/includes/classes/MenuPageOptions.php:1019
1423
- msgid "Create a Dynamic Version Salt For %1$s? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"font-size:90%%; opacity:0.5;\">150%% OPTIONAL</span>"
1424
- msgstr ""
1425
-
1426
- #: src/includes/classes/MenuPageOptions.php:1021
1427
- msgid "<a href=\"http://php.net/manual/en/language.variables.superglobals.php\" target=\"_blank\">Super Globals</a> work here; <a href=\"http://codex.wordpress.org/Editing_wp-config.php#table_prefix\" target=\"_blank\"><code>$GLOBALS['table_prefix']</code></a> is a popular one.<br />Or, perhaps a PHP Constant defined in <code>/wp-config.php</code>; such as <code>WPLANG</code> or <code>DB_HOST</code>."
1428
- msgstr ""
1429
-
1430
- #: src/includes/classes/MenuPageOptions.php:1022
1431
- msgid "<strong>Important:</strong> your Version Salt is scanned for PHP syntax errors via <a href=\"http://phpcodechecker.com/\" target=\"_blank\"><code>phpCodeChecker.com</code></a>. If errors are found, you'll receive a notice in the Dashboard."
1432
- msgstr ""
1433
-
1434
- #: src/includes/classes/MenuPageOptions.php:1023
1435
- msgid "If you've enabled a separate cache for each user (optional) that's perfectly OK. A Version Salt works with user caching too."
1436
- msgstr ""
1437
-
1438
- #: src/includes/classes/MenuPageOptions.php:1033
1439
- msgid "Theme/Plugin Developers"
1440
- msgstr ""
1441
-
1442
- #: src/includes/classes/MenuPageOptions.php:1038
1443
- msgid "Developing a Theme or Plugin for WordPress?"
1444
- msgstr ""
1445
-
1446
- #: src/includes/classes/MenuPageOptions.php:1039
1447
- msgid "<strong>Tip:</strong> %1$s can be disabled temporarily. If you're a theme/plugin developer, you can set a flag within your PHP code to disable the cache engine at runtime. Perhaps on a specific page, or in a specific scenario. In your PHP script, set: <code>$_SERVER['COMET_CACHE_ALLOWED'] = FALSE;</code> or <code>define('COMET_CACHE_ALLOWED', FALSE)</code>. %1$s is also compatible with: <code>define('DONOTCACHEPAGE', TRUE)</code>. It does't matter where or when you define one of these, because %1$s is the last thing to run before script execution ends."
1448
- msgstr ""
1449
-
1450
- #: src/includes/classes/MenuPageOptions.php:1041
1451
- msgid "Writing \"Advanced Cache\" Plugins Specifically for %1$s"
1452
- msgstr ""
1453
-
1454
- #: src/includes/classes/MenuPageOptions.php:1042
1455
- msgid "Theme/plugin developers can take advantage of the %1$s plugin architecture by creating PHP files inside this special directory: <code>/wp-content/ac-plugins/</code>. There is an <a href=\"http://cometcache.com/r/ac-plugin-example/\" target=\"_blank\">example plugin file @ GitHub</a> (please review it carefully and ask questions). If you develop a plugin for %1$s, please share it with the community by publishing it in the plugins respository at WordPress.org."
1456
- msgstr ""
1457
-
1458
- #: src/includes/classes/MenuPageOptions.php:1043
1459
- msgid "<strong>Why does %1$s have it's own plugin architecture?</strong> WordPress loads the <code>advanced-cache.php</code> drop-in file (for caching purposes) very early-on; before any other plugins or a theme. For this reason, %1$s implements it's own watered-down version of functions like <code>add_action()</code>, <code>do_action()</code>, <code>add_filter()</code>, <code>apply_filters()</code>."
1460
- msgstr ""
1461
-
1462
- #: src/includes/classes/MenuPageOptions.php:1054
1463
- msgid "Import/Export Options"
1464
- msgstr ""
1465
-
1466
- #: src/includes/classes/MenuPageOptions.php:1059
1467
- msgid "Import Options from Another %1$s Installation?"
1468
- msgstr ""
1469
-
1470
- #: src/includes/classes/MenuPageOptions.php:1060
1471
- msgid "Upload your <code>%1$s-options.json</code> file and click \"Save All Changes\" below. The options provided by your import file will override any that exist currently."
1472
- msgstr ""
1473
-
1474
- #: src/includes/classes/MenuPageOptions.php:1063
1475
- msgid "Export Existing Options from this %1$s Installation?"
1476
- msgstr ""
1477
-
1478
- #: src/includes/classes/MenuPageOptions.php:1066
1479
- msgid "%1$s-options.json"
1480
- msgstr ""
1481
-
1482
- #: src/includes/classes/MenuPageOptions.php:1067
1483
- msgid "Download your existing options and import them all into another %1$s installation; saves time on future installs."
1484
- msgstr ""
1485
-
1486
- #: src/includes/classes/MenuPageOptions.php:1075
1487
- msgid "Save All Changes"
1488
- msgstr ""
1489
-
1490
- #: src/includes/classes/VsUpgrades.php:201
1491
- msgid "<strong>Woohoo! %1$s activated.</strong> :-)"
1492
- msgstr ""
1493
-
1494
- #: src/includes/closures/Ac/NcDebugUtils.php:75
1495
- msgid "because `PHP_SAPI` reports that you are currently running from the command line."
1496
- msgstr ""
1497
-
1498
- #: src/includes/closures/Ac/NcDebugUtils.php:79
1499
- msgid "because `$_SERVER['HTTP_HOST']` is missing from your server configuration."
1500
- msgstr ""
1501
-
1502
- #: src/includes/closures/Ac/NcDebugUtils.php:83
1503
- msgid "because `$_SERVER['REQUEST_URI']` is missing from your server configuration."
1504
- msgstr ""
1505
-
1506
- #: src/includes/closures/Ac/NcDebugUtils.php:88
1507
- msgid "because the s2Member plugin set the PHP constant `COMET_CACHE_ALLOWED` to a boolean-ish `FALSE` value at runtime. The s2Member plugin is serving content that must remain dynamic on this particular page, and therefore this page was intentionally not cached for a very good reason."
1508
- msgstr ""
1509
-
1510
- #: src/includes/closures/Ac/NcDebugUtils.php:90
1511
- msgid "because the PHP constant `COMET_CACHE_ALLOWED` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it's usually for a very good reason."
1512
- msgstr ""
1513
-
1514
- #: src/includes/closures/Ac/NcDebugUtils.php:95
1515
- msgid "because the environment variable `$_SERVER['COMET_CACHE_ALLOWED']` has been set to a boolean-ish `FALSE` value at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it's usually for a very good reason."
1516
- msgstr ""
1517
-
1518
- #: src/includes/closures/Ac/NcDebugUtils.php:99
1519
- msgid "because the PHP constant `DONOTCACHEPAGE` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it's usually for a very good reason."
1520
- msgstr ""
1521
-
1522
- #: src/includes/closures/Ac/NcDebugUtils.php:103
1523
- msgid "because the environment variable `$_SERVER['DONOTCACHEPAGE']` has been set at runtime. Perhaps by WordPress itself, or by one of your themes/plugins. This usually means that you have a theme/plugin intentionally disabling the cache on this page; and it's usually for a very good reason."
1524
- msgstr ""
1525
-
1526
- #: src/includes/closures/Ac/NcDebugUtils.php:107
1527
- msgid "because `$_GET['%1$sAC']` is set to a boolean-ish FALSE value."
1528
- msgstr ""
1529
-
1530
- #: src/includes/closures/Ac/NcDebugUtils.php:111
1531
- msgid "because `$_SERVER['REQUEST_METHOD']` is `POST`, `PUT`, `DELETE`, `HEAD`, `OPTIONS`, `TRACE` or `CONNECT`. These request methods should never (ever) be cached in any way."
1532
- msgstr ""
1533
-
1534
- #: src/includes/closures/Ac/NcDebugUtils.php:115
1535
- msgid "because `[current IP address]` === `$_SERVER['SERVER_ADDR']`; i.e. a self-serve request. DEVELOPER TIP: if you are testing on a localhost installation, please add `define('LOCALHOST', TRUE);` to your `/wp-config.php` file while you run tests :-) Remove it (or set it to a `FALSE` value) once you go live on the web."
1536
- msgstr ""
1537
-
1538
- #: src/includes/closures/Ac/NcDebugUtils.php:119
1539
- msgid "because `$_SERVER['REQUEST_URI']` indicates this is a `/feed`; and the configuration of this site says not to cache XML-based feeds."
1540
- msgstr ""
1541
-
1542
- #: src/includes/closures/Ac/NcDebugUtils.php:123
1543
- msgid "because `$_SERVER['REQUEST_URI']` indicates this is a `wp-` or `xmlrpc` file; i.e. a WordPress systematic file. WordPress systematics are never (ever) cached in any way."
1544
- msgstr ""
1545
-
1546
- #: src/includes/closures/Ac/NcDebugUtils.php:127
1547
- msgid "because `$_SERVER['REQUEST_URI']` or the `is_admin()` function indicates this is an administrative area of the site."
1548
- msgstr ""
1549
-
1550
- #: src/includes/closures/Ac/NcDebugUtils.php:131
1551
- msgid "because `$_SERVER['REQUEST_URI']` indicates this is a Multisite Network; and this was a request for `/files/*`, not a page."
1552
- msgstr ""
1553
-
1554
- #: src/includes/closures/Ac/NcDebugUtils.php:136
1555
- msgid "because the current user visiting this page (usually YOU), appears to be logged-in. The current configuration says NOT to cache pages for logged-in visitors. This message may also appear if you have an active PHP session on this site, or if you've left (or replied to) a comment recently. If this message continues, please clear your cookies and try again."
1556
- msgstr ""
1557
-
1558
- #: src/includes/closures/Ac/NcDebugUtils.php:140
1559
- msgid "because the current page contains `_wpnonce` or `akismet_comment_nonce`. While your current configuration states that pages SHOULD be cache for logged-in visitors, `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details."
1560
- msgstr ""
1561
-
1562
- #: src/includes/closures/Ac/NcDebugUtils.php:144
1563
- msgid "because the current page contains `_wpnonce` or `akismet_comment_nonce`. Note that `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details."
1564
- msgstr ""
1565
-
1566
- #: src/includes/closures/Ac/NcDebugUtils.php:148
1567
- msgid "because the current user appeared to be logged into the site (in one way or another); but %1$s was unable to formulate a User Token for them. Please report this as a possible bug."
1568
- msgstr ""
1569
-
1570
- #: src/includes/closures/Ac/NcDebugUtils.php:152
1571
- msgid "because `$_GET` contains query string data. The current configuration says NOT to cache GET requests with a query string."
1572
- msgstr ""
1573
-
1574
- #: src/includes/closures/Ac/NcDebugUtils.php:156
1575
- msgid "because `$_REQUEST` indicates this is simply a preview of something to come."
1576
- msgstr ""
1577
-
1578
- #: src/includes/closures/Ac/NcDebugUtils.php:160
1579
- msgid "because `$_SERVER['REQUEST_URI']` matches a configured URI Exclusion Pattern on this installation."
1580
- msgstr ""
1581
-
1582
- #: src/includes/closures/Ac/NcDebugUtils.php:164
1583
- msgid "because `$_SERVER['HTTP_USER_AGENT']` matches a configured User-Agent Exclusion Pattern on this installation."
1584
- msgstr ""
1585
-
1586
- #: src/includes/closures/Ac/NcDebugUtils.php:168
1587
- msgid "because `$_SERVER['HTTP_REFERER']` and/or `$_GET['_wp_http_referer']` matches a configured HTTP Referrer Exclusion Pattern on this installation."
1588
- msgstr ""
1589
-
1590
- #: src/includes/closures/Ac/NcDebugUtils.php:172
1591
- msgid "because the WordPress `is_404()` Conditional Tag says the current page is a 404 error. The current configuration says NOT to cache 404 errors."
1592
- msgstr ""
1593
-
1594
- #: src/includes/closures/Ac/NcDebugUtils.php:176
1595
- msgid "because a plugin running on this installation says this page is in Maintenance Mode; i.e. is not available publicly at this time."
1596
- msgstr ""
1597
-
1598
- #: src/includes/closures/Ac/NcDebugUtils.php:180
1599
- msgid "because %1$s is unable to cache already-compressed output. Please use `mod_deflate` w/ Apache; or use `zlib.output_compression` in your `php.ini` file. %1$s is NOT compatible with `ob_gzhandler()` and others like this."
1600
- msgstr ""
1601
-
1602
- #: src/includes/closures/Ac/NcDebugUtils.php:184
1603
- msgid "because the contents of this document contain `<body id=\"error-page\">`, which indicates this is an auto-generated WordPress error message."
1604
- msgstr ""
1605
-
1606
- #: src/includes/closures/Ac/NcDebugUtils.php:188
1607
- msgid "because a `Content-Type:` header was set via PHP at runtime. The header contains a MIME type which is NOT a variation of HTML or XML. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins."
1608
- msgstr ""
1609
-
1610
- #: src/includes/closures/Ac/NcDebugUtils.php:192
1611
- msgid "because a `Status:` header (or an `HTTP/` header) was set via PHP at runtime. The header contains a non-`2xx` status code. This indicates the current page was not loaded successfully. This header might have been set by your hosting company, by WordPress itself; or by one of your themes/plugins."
1612
- msgstr ""
1613
-
1614
- #: src/includes/closures/Ac/NcDebugUtils.php:196
1615
- msgid "because the WordPress `is_404()` Conditional Tag says the current page is a 404 error; and this is the first time it's happened on this page. Your current configuration says that 404 errors SHOULD be cached, so %1$s built a cached symlink which points future requests for this location to your already-cached 404 error document. If you reload this page (assuming you don't clear the cache before you do so); you should get a cached version of your 404 error document. This message occurs ONCE for each new/unique 404 error request."
1616
- msgstr ""
1617
-
1618
- #: src/includes/closures/Ac/NcDebugUtils.php:200
1619
- msgid "because %1$s detected an early output buffer termination. This may happen when a theme/plugin ends, cleans, or flushes all output buffers before reaching the PHP shutdown phase. It's not always a bad thing. Sometimes it is necessary for a theme/plugin to do this. However, in this scenario it is NOT possible to cache the output; since %1$s is effectively disabled at runtime when this occurs."
1620
- msgstr ""
1621
-
1622
- #: src/includes/closures/Ac/NcDebugUtils.php:204
1623
- msgid "due to an unexpected behavior in the application. Please report this as a bug!"
1624
- msgstr ""
1625
-
1626
- #: src/includes/closures/Ac/NcDebugUtils.php:208
1627
- msgid "%1$s is NOT caching this page, %2$s"
1628
- msgstr ""
1629
-
1630
- #. translators: This string is actually NOT translatable because the `__()`
1631
- #. function is not available at this point in the processing.
1632
- #: src/includes/closures/Ac/ObUtils.php:210
1633
- msgid "%1$s fully functional :-) Cache file served for (%2$s) in %3$s seconds, on: %4$s."
1634
- msgstr ""
1635
-
1636
- #: src/includes/closures/Ac/ObUtils.php:238
1637
- msgid "Unexpected OB phase: `%1$s`."
1638
- msgstr ""
1639
-
1640
- #: src/includes/closures/Ac/ObUtils.php:318
1641
- msgid "Cache directory not writable. %1$s needs this directory please: `%2$s`. Set permissions to `755` or higher; `777` might be needed in some cases."
1642
- msgstr ""
1643
-
1644
- #: src/includes/closures/Ac/ObUtils.php:324
1645
- #: src/includes/closures/Ac/ObUtils.php:342
1646
- msgid "Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`."
1647
- msgstr ""
1648
-
1649
- #: src/includes/closures/Ac/ObUtils.php:335
1650
- msgid "%1$s file path: %2$s"
1651
- msgstr ""
1652
-
1653
- #: src/includes/closures/Ac/ObUtils.php:336
1654
- msgid "%1$s file built for (%2$s%3$s) in %4$s seconds, on: %5$s."
1655
- msgstr ""
1656
-
1657
- #: src/includes/closures/Ac/ObUtils.php:336
1658
- msgid "user token: %1$s"
1659
- msgstr ""
1660
-
1661
- #: src/includes/closures/Ac/ObUtils.php:337
1662
- msgid "This %1$s file will auto-expire (and be rebuilt) on: %2$s (based on your configured expiration time)."
1663
- msgstr ""
1664
-
1665
- #: src/includes/closures/Ac/ObUtils.php:352
1666
- msgid "%1$s: failed to write cache file for: `%2$s`; possible permissions issue (or race condition), please check your cache directory: `%3$s`."
1667
- msgstr ""
1668
-
1669
- #: src/includes/closures/Plugin/CronUtils.php:18
1670
- msgid "Every 15 Minutes"
1671
- msgstr ""
1672
-
1673
- #: src/includes/closures/Plugin/DirUtils.php:21
1674
- #: src/includes/closures/Plugin/DirUtils.php:48
1675
- msgid "Missing `base_dir` option value."
1676
- msgstr ""
1677
-
1678
- #: src/includes/closures/Plugin/InstallUtils.php:16
1679
- msgid "<strong>%1$s</strong> successfully installed! :-) <strong>Please <a href=\"%2$s\">enable caching and review options</a>.</strong>"
1680
- msgstr ""
1681
-
1682
- #: src/includes/closures/Plugin/InstallUtils.php:55
1683
- msgid "<strong>%1$s:</strong> detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)"
1684
- msgstr ""
1685
-
1686
- #: src/includes/closures/Plugin/MenuPageUtils.php:46
1687
- msgid "%"
1688
- msgstr ""
1689
-
1690
- #: src/includes/closures/Plugin/MenuPageUtils.php:47
1691
- msgid "file"
1692
- msgstr ""
1693
-
1694
- #: src/includes/closures/Plugin/MenuPageUtils.php:48
1695
- msgid "files"
1696
- msgstr ""
1697
-
1698
- #: src/includes/closures/Plugin/MenuPageUtils.php:49
1699
- msgid "Page Cache"
1700
- msgstr ""
1701
-
1702
- #: src/includes/closures/Plugin/MenuPageUtils.php:50
1703
- msgid "HTML Compressor"
1704
- msgstr ""
1705
-
1706
- #: src/includes/closures/Plugin/MenuPageUtils.php:51
1707
- msgid "Current Total"
1708
- msgstr ""
1709
-
1710
- #: src/includes/closures/Plugin/MenuPageUtils.php:52
1711
- msgid "Current Site"
1712
- msgstr ""
1713
-
1714
- #: src/includes/closures/Plugin/MenuPageUtils.php:53
1715
- msgid "%s Day High"
1716
- msgstr ""
1717
-
1718
- #: src/includes/closures/Plugin/MenuPageUtils.php:118
1719
- msgid "Settings"
1720
- msgstr ""
1721
-
1722
- #: src/includes/closures/Plugin/MenuPageUtils.php:121
1723
- msgid "Upgrade"
1724
- msgstr ""
1725
-
1726
- #: src/includes/closures/Plugin/NoticeUtils.php:151
1727
- msgid "dismiss &times;"
1728
- msgstr ""
1729
-
1730
- #: src/includes/closures/Plugin/WcpAuthorUtils.php:82
1731
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for Author Page: <code>%3$s</code>; auto-clearing."
1732
- msgstr ""
1733
-
1734
- #: src/includes/closures/Plugin/WcpFeedUtils.php:113
1735
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache, for XML feeds of type: <code>%3$s</code>; auto-clearing."
1736
- msgstr ""
1737
-
1738
- #: src/includes/closures/Plugin/WcpHomeBlogUtils.php:38
1739
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for the designated \"Home Page\"; auto-clearing."
1740
- msgstr ""
1741
-
1742
- #: src/includes/closures/Plugin/WcpHomeBlogUtils.php:96
1743
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for the designated \"Posts Page\"; auto-clearing."
1744
- msgstr ""
1745
-
1746
- #: src/includes/closures/Plugin/WcpPostTypeUtils.php:51
1747
- msgid "Untitled"
1748
- msgstr ""
1749
-
1750
- #: src/includes/closures/Plugin/WcpPostTypeUtils.php:61
1751
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for Custom Post Type: <code>%3$s</code>; auto-clearing."
1752
- msgstr ""
1753
-
1754
- #: src/includes/closures/Plugin/WcpPostUtils.php:82
1755
- msgid "Post"
1756
- msgstr ""
1757
-
1758
- #: src/includes/closures/Plugin/WcpPostUtils.php:89
1759
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for %3$s ID: <code>%4$s</code>; auto-clearing."
1760
- msgstr ""
1761
-
1762
- #: src/includes/closures/Plugin/WcpSitemapUtils.php:44
1763
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for XML sitemaps; auto-clearing."
1764
- msgstr ""
1765
-
1766
- #: src/includes/closures/Plugin/WcpTermUtils.php:130
1767
- msgid "<strong>%1$s:</strong> detected changes. Found %2$s in the cache for %3$s: <code>%4$s</code>; auto-clearing."
1768
- msgstr ""
1769
-
1770
- #: src/includes/closures/Plugin/WcpUtils.php:164
1771
- msgid "<strong>%1$s:</strong> detected significant changes. Found %2$s in the cache; auto-wiping."
1772
- msgstr ""
1773
-
1774
- #: src/includes/closures/Plugin/WcpUtils.php:210
1775
- msgid "<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache for this site; auto-clearing."
1776
- msgstr ""
1777
-
1778
- #: src/includes/closures/Plugin/WcpUtils.php:244
1779
- msgid "<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache for this site that were expired; auto-purging."
1780
- msgstr ""
1781
-
1782
- #: src/includes/closures/Plugin/WcpUtils.php:278
1783
- msgid "<strong>%1$s:</strong> detected important site changes. Found %2$s in the cache that were expired; auto-purging."
1784
- msgstr ""
1785
-
1786
- #: src/includes/closures/Plugin/WcpUtils.php:298
1787
- msgid "<strong>%1$s:</strong> detected significant changes that would normally trigger cache wiping routines. However, cache wiping routines have been disabled by a site administrator. [<a href=\"http://cometcache.com/r/kb-clear-and-wipe-cache-routines/\" target=\"_blank\">?</a>]"
1788
- msgstr ""
1789
-
1790
- #: src/includes/closures/Plugin/WcpUtils.php:318
1791
- msgid "<strong>%1$s:</strong> detected important site changes that would normally trigger cache clearing routines. However, cache clearing routines have been disabled by a site administrator. [<a href=\"http://cometcache.com/r/kb-clear-and-wipe-cache-routines/\" target=\"_blank\">?</a>]"
1792
- msgstr ""
1793
-
1794
- #: src/includes/closures/Plugin/WcpUtils.php:338
1795
- msgid "<strong>%1$s:</strong> detected important site changes that would normally trigger cache purging routines. However, cache purging routines have been disabled by a site administrator. [<a href=\"http://cometcache.com/r/kb-clear-and-wipe-cache-routines/\" target=\"_blank\">?</a>]"
1796
- msgstr ""
1797
-
1798
- #: src/includes/closures/Shared/CacheDirUtils.php:24
1799
- msgid "Unable to determine cache directory location."
1800
- msgstr ""
1801
-
1802
- #: src/includes/closures/Shared/CacheDirUtils.php:121
1803
- #: src/includes/closures/Shared/CacheDirUtils.php:277
1804
- msgid "Invalid argument; isAdvancedCache!"
1805
- msgstr ""
1806
-
1807
- #: src/includes/closures/Shared/CacheDirUtils.php:148
1808
- msgid "Unable to delete files. Rename failure on directory: `%1$s`."
1809
- msgstr ""
1810
-
1811
- #: src/includes/closures/Shared/CacheDirUtils.php:172
1812
- #: src/includes/closures/Shared/CacheDirUtils.php:340
1813
- #: src/includes/closures/Shared/CacheDirUtils.php:480
1814
- msgid "Unable to delete symlink: `%1$s`."
1815
- msgstr ""
1816
-
1817
- #: src/includes/closures/Shared/CacheDirUtils.php:187
1818
- #: src/includes/closures/Shared/CacheDirUtils.php:355
1819
- #: src/includes/closures/Shared/CacheDirUtils.php:490
1820
- msgid "Unable to delete file: `%1$s`."
1821
- msgstr ""
1822
-
1823
- #: src/includes/closures/Shared/CacheDirUtils.php:203
1824
- #: src/includes/closures/Shared/CacheDirUtils.php:371
1825
- #: src/includes/closures/Shared/CacheDirUtils.php:500
1826
- msgid "Unable to delete dir: `%1$s`."
1827
- msgstr ""
1828
-
1829
- #: src/includes/closures/Shared/CacheDirUtils.php:211
1830
- #: src/includes/closures/Shared/CacheDirUtils.php:379
1831
- #: src/includes/closures/Shared/CacheDirUtils.php:508
1832
- #: src/includes/closures/Shared/CacheDirUtils.php:603
1833
- msgid "Unexpected resource type: `%1$s`."
1834
- msgstr ""
1835
-
1836
- #: src/includes/closures/Shared/CacheDirUtils.php:218
1837
- #: src/includes/closures/Shared/CacheDirUtils.php:316
1838
- #: src/includes/closures/Shared/CacheDirUtils.php:386
1839
- msgid "Unable to delete files. Rename failure on tmp directory: `%1$s`."
1840
- msgstr ""
1841
-
1842
- #: src/includes/closures/Shared/CacheDirUtils.php:274
1843
- msgid "Invalid argument; host token empty!"
1844
- msgstr ""
1845
-
1846
- #: src/includes/closures/Shared/CacheDirUtils.php:467
1847
- #: src/includes/closures/Shared/CacheDirUtils.php:515
1848
- msgid "Unable to delete all files/dirs. Rename failure on tmp directory: `%1$s`."
1849
- msgstr ""
1850
-
1851
- #: src/includes/closures/Shared/CacheDirUtils.php:519
1852
- msgid "Unable to delete directory: `%1$s`."
1853
- msgstr ""
1854
-
1855
- #: src/includes/closures/Shared/CacheDirUtils.php:578
1856
- msgid "Unable to erase symlink: `%1$s`."
1857
- msgstr ""
1858
-
1859
- #: src/includes/closures/Shared/CacheDirUtils.php:587
1860
- msgid "Unable to erase file: `%1$s`."
1861
- msgstr ""
1862
-
1863
- #: src/includes/closures/Shared/CacheDirUtils.php:596
1864
- msgid "Unable to erase dir: `%1$s`."
1865
- msgstr ""
1866
-
1867
- #: src/includes/closures/Shared/CacheDirUtils.php:610
1868
- msgid "Unable to erase directory: `%1$s`."
1869
- msgstr ""
1870
-
1871
- #: src/includes/closures/Shared/CacheLockUtils.php:25
1872
- msgid "Unable to find the wp-config.php file."
1873
- msgstr ""
1874
-
1875
- #: src/includes/closures/Shared/CacheLockUtils.php:42
1876
- msgid "No writable tmp directory."
1877
- msgstr ""
1878
-
1879
- #: src/includes/closures/Shared/CacheLockUtils.php:48
1880
- msgid "Unable to obtain an exclusive lock."
1881
- msgstr ""
1882
-
1883
- #: src/includes/closures/Shared/HookUtils.php:40
1884
- msgid "Invalid hook."
1885
- msgstr ""
1886
-
1887
- #: src/includes/closures/Shared/I18nUtils.php:15
1888
- msgid "%1$s file"
1889
- msgid_plural "%1$s files"
1890
- msgstr[0] ""
1891
- msgstr[1] ""
1892
-
1893
- #: src/includes/closures/Shared/I18nUtils.php:29
1894
- msgid "%1$s directory"
1895
- msgid_plural "%1$s directories"
1896
- msgstr[0] ""
1897
- msgstr[1] ""
1898
-
1899
- #: src/includes/closures/Shared/I18nUtils.php:43
1900
- msgid "%1$s file/directory"
1901
- msgid_plural "%1$s files/directories"
1902
- msgstr[0] ""
1903
- msgstr[1] ""
1904
-
1905
- #: src/includes/closures/Shared/SysUtils.php:65
1906
- msgid "%s%%"
1907
- msgstr ""
1908
-
1909
- #. Plugin Name of the plugin/theme
1910
- msgid "Comet Cache"
1911
- msgstr ""
1912
-
1913
- #. Plugin URI of the plugin/theme
1914
- msgid "http://cometcache.com/"
1915
- msgstr ""
1916
-
1917
- #. Description of the plugin/theme
1918
- msgid "Comet Cache is an advanced WordPress caching plugin inspired by simplicity."
1919
- msgstr ""
1920
-
1921
- #. Author of the plugin/theme
1922
- msgid "WebSharks, Inc."
1923
- msgstr ""
1924
-
1925
- #. Author URI of the plugin/theme
1926
- msgid "http://websharks-inc.com/"
1927
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/includes/uninstall.php CHANGED
@@ -6,14 +6,16 @@
6
  */
7
  namespace WebSharks\CometCache;
8
 
 
 
9
  if (!defined('WPINC')) {
10
  exit('Do NOT access this file directly: '.basename(__FILE__));
11
  }
12
- require_once dirname(__FILE__).'/stub.php';
13
 
14
  $GLOBALS[GLOBAL_NS.'_uninstalling'] = true; // Needs to be set before calling Conflicts class
15
 
16
- if (!Conflicts::check()) {
17
- $GLOBALS[GLOBAL_NS] = new Plugin(false);
18
  $GLOBALS[GLOBAL_NS]->uninstall();
19
  }
6
  */
7
  namespace WebSharks\CometCache;
8
 
9
+ use WebSharks\CometCache\Classes;
10
+
11
  if (!defined('WPINC')) {
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
14
+ require_once __DIR__.'/stub.php';
15
 
16
  $GLOBALS[GLOBAL_NS.'_uninstalling'] = true; // Needs to be set before calling Conflicts class
17
 
18
+ if (!Classes\Conflicts::check()) {
19
+ $GLOBALS[GLOBAL_NS] = new Classes\Plugin(false);
20
  $GLOBALS[GLOBAL_NS]->uninstall();
21
  }
src/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2::getLoader();
src/vendor/composer/ClassLoader.php CHANGED
@@ -13,9 +13,7 @@
13
  namespace Composer\Autoload;
14
 
15
  /**
16
- * ClassLoader implements a PSR-0 class loader
17
- *
18
- * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19
  *
20
  * $loader = new \Composer\Autoload\ClassLoader();
21
  *
@@ -39,6 +37,8 @@ namespace Composer\Autoload;
39
  *
40
  * @author Fabien Potencier <fabien@symfony.com>
41
  * @author Jordi Boggiano <j.boggiano@seld.be>
 
 
42
  */
43
  class ClassLoader
44
  {
@@ -147,7 +147,7 @@ class ClassLoader
147
  * appending or prepending to the ones previously set for this namespace.
148
  *
149
  * @param string $prefix The prefix/namespace, with trailing '\\'
150
- * @param array|string $paths The PSR-0 base directories
151
  * @param bool $prepend Whether to prepend the directories
152
  *
153
  * @throws \InvalidArgumentException
13
  namespace Composer\Autoload;
14
 
15
  /**
16
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 
 
17
  *
18
  * $loader = new \Composer\Autoload\ClassLoader();
19
  *
37
  *
38
  * @author Fabien Potencier <fabien@symfony.com>
39
  * @author Jordi Boggiano <j.boggiano@seld.be>
40
+ * @see http://www.php-fig.org/psr/psr-0/
41
+ * @see http://www.php-fig.org/psr/psr-4/
42
  */
43
  class ClassLoader
44
  {
147
  * appending or prepending to the ones previously set for this namespace.
148
  *
149
  * @param string $prefix The prefix/namespace, with trailing '\\'
150
+ * @param array|string $paths The PSR-4 base directories
151
  * @param bool $prepend Whether to prepend the directories
152
  *
153
  * @throws \InvalidArgumentException
src/vendor/composer/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
 
2
- Copyright (c) 2015 Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
1
 
2
+ Copyright (c) 2016 Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
src/vendor/composer/autoload_psr4.php CHANGED
@@ -9,5 +9,7 @@ return array(
9
  'WebSharks\\JsMinifier\\' => array($vendorDir . '/websharks/js-minifier/src/includes/classes'),
10
  'WebSharks\\HtmlCompressor\\' => array($vendorDir . '/websharks/html-compressor/src/includes/classes'),
11
  'WebSharks\\CssMinifier\\' => array($vendorDir . '/websharks/css-minifier/src/includes/classes'),
12
- 'WebSharks\\CometCache\\' => array($baseDir . '/src/includes/classes'),
 
 
13
  );
9
  'WebSharks\\JsMinifier\\' => array($vendorDir . '/websharks/js-minifier/src/includes/classes'),
10
  'WebSharks\\HtmlCompressor\\' => array($vendorDir . '/websharks/html-compressor/src/includes/classes'),
11
  'WebSharks\\CssMinifier\\' => array($vendorDir . '/websharks/css-minifier/src/includes/classes'),
12
+ 'WebSharks\\CometCache\\Traits\\' => array($baseDir . '/src/includes/traits'),
13
+ 'WebSharks\\CometCache\\Interfaces\\' => array($baseDir . '/src/includes/interfaces'),
14
+ 'WebSharks\\CometCache\\Classes\\' => array($baseDir . '/src/includes/classes'),
15
  );
src/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -43,8 +43,3 @@ class ComposerAutoloaderInit33853609dfb2ae52d36861a4ab25a03b
43
  return $loader;
44
  }
45
  }
46
-
47
- function composerRequire33853609dfb2ae52d36861a4ab25a03b($file)
48
- {
49
- require $file;
50
- }
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
43
  return $loader;
44
  }
45
  }
 
 
 
 
 
src/vendor/composer/installed.json CHANGED
@@ -1,25 +1,31 @@
1
  [
2
  {
3
- "name": "websharks/wp-php-rv",
4
- "version": "150511",
5
- "version_normalized": "150511",
6
  "source": {
7
  "type": "git",
8
- "url": "https://github.com/websharks/wp-php-rv.git",
9
- "reference": "ed0a58f3647e59c740560235da1e61904dca8d84"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/websharks/wp-php-rv/zipball/ed0a58f3647e59c740560235da1e61904dca8d84",
14
- "reference": "ed0a58f3647e59c740560235da1e61904dca8d84",
15
  "shasum": ""
16
  },
17
  "require": {
18
- "php": ">=5.2"
 
19
  },
20
- "time": "2015-05-10 10:30:04",
21
  "type": "library",
22
  "installation-source": "dist",
 
 
 
 
 
23
  "notification-url": "https://packagist.org/downloads/",
24
  "license": [
25
  "GPL-3.0+"
@@ -41,12 +47,13 @@
41
  "role": "developer"
42
  }
43
  ],
44
- "description": "Stub for WordPress themes/plugins that require PHP vX.x+.",
45
- "homepage": "https://github.com/websharks/wp-php-rv",
46
  "keywords": [
47
- "php",
48
- "websharks",
49
- "wordpress"
 
50
  ]
51
  },
52
  {
@@ -106,30 +113,34 @@
106
  ]
107
  },
108
  {
109
- "name": "websharks/js-minifier",
110
- "version": "dev-master",
111
- "version_normalized": "9999999-dev",
112
  "source": {
113
  "type": "git",
114
- "url": "https://github.com/websharks/js-minifier.git",
115
- "reference": "3c1e99af6df9df8f691642fbb769a10e49bfba23"
116
  },
117
  "dist": {
118
  "type": "zip",
119
- "url": "https://api.github.com/repos/websharks/js-minifier/zipball/3c1e99af6df9df8f691642fbb769a10e49bfba23",
120
- "reference": "3c1e99af6df9df8f691642fbb769a10e49bfba23",
121
  "shasum": ""
122
  },
123
  "require": {
 
124
  "ext-mbstring": "*",
125
- "php": ">=5.3"
 
 
 
126
  },
127
- "time": "2015-05-11 20:53:04",
128
  "type": "library",
129
  "installation-source": "dist",
130
  "autoload": {
131
  "psr-4": {
132
- "WebSharks\\JsMinifier\\": "src/includes/classes"
133
  }
134
  },
135
  "notification-url": "https://packagist.org/downloads/",
@@ -153,45 +164,37 @@
153
  "role": "developer"
154
  }
155
  ],
156
- "description": "Compresses JavaScript code.",
157
- "homepage": "https://github.com/websharks/js-minifier",
158
  "keywords": [
159
- "JS",
160
  "compressor",
161
- "javascript",
162
  "websharks"
163
  ]
164
  },
165
  {
166
- "name": "websharks/html-compressor",
167
- "version": "160118",
168
- "version_normalized": "160118",
169
  "source": {
170
  "type": "git",
171
- "url": "https://github.com/websharks/html-compressor.git",
172
- "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2"
173
  },
174
  "dist": {
175
  "type": "zip",
176
- "url": "https://api.github.com/repos/websharks/html-compressor/zipball/bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
177
- "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
178
  "shasum": ""
179
  },
180
- "require": {
181
- "ext-curl": "*",
182
- "ext-mbstring": "*",
183
- "ext-openssl": "*",
184
- "php": ">=5.3",
185
- "websharks/css-minifier": "dev-master",
186
- "websharks/js-minifier": "dev-master"
187
  },
188
- "time": "2016-01-18 03:17:20",
189
  "type": "library",
190
  "installation-source": "dist",
191
  "autoload": {
192
- "psr-4": {
193
- "WebSharks\\HtmlCompressor\\": "src/includes/classes"
194
- }
195
  },
196
  "notification-url": "https://packagist.org/downloads/",
197
  "license": [
@@ -214,38 +217,35 @@
214
  "role": "developer"
215
  }
216
  ],
217
- "description": "Combines & compresses CSS/JS/HTML code.",
218
- "homepage": "https://github.com/websharks/html-compressor",
219
  "keywords": [
220
- "compressor",
221
- "html",
222
- "websharks"
223
  ]
224
  },
225
  {
226
- "name": "websharks/sharkicons",
227
- "version": "160221",
228
- "version_normalized": "160221",
229
  "source": {
230
  "type": "git",
231
- "url": "https://github.com/websharks/sharkicons.git",
232
- "reference": "2e6d6663c050f343fe944b424dea1759aa67cd05"
233
  },
234
  "dist": {
235
  "type": "zip",
236
- "url": "https://api.github.com/repos/websharks/sharkicons/zipball/2e6d6663c050f343fe944b424dea1759aa67cd05",
237
- "reference": "2e6d6663c050f343fe944b424dea1759aa67cd05",
238
  "shasum": ""
239
  },
240
- "require-dev": {
241
- "package/bourbon": "4.2.3"
242
  },
243
- "time": "2016-02-21 15:16:12",
244
  "type": "library",
245
  "installation-source": "dist",
246
- "autoload": {
247
- "psr-4": []
248
- },
249
  "notification-url": "https://packagist.org/downloads/",
250
  "license": [
251
  "GPL-3.0+"
@@ -267,8 +267,8 @@
267
  "role": "developer"
268
  }
269
  ],
270
- "description": "Font containing WebSharks logos/icons.",
271
- "homepage": "https://github.com/websharks/sharkicons",
272
  "keywords": [
273
  "php",
274
  "websharks",
@@ -295,15 +295,15 @@
295
  "source": {
296
  "type": "git",
297
  "url": "https://github.com/websharks/wp-i18n-tools.git",
298
- "reference": "47a2af9f88cfaf0ad33a81c2c882cd70bfed95b6"
299
  },
300
  "dist": {
301
  "type": "zip",
302
- "url": "https://api.github.com/repos/websharks/wp-i18n-tools/zipball/47a2af9f88cfaf0ad33a81c2c882cd70bfed95b6",
303
- "reference": "47a2af9f88cfaf0ad33a81c2c882cd70bfed95b6",
304
  "shasum": ""
305
  },
306
- "time": "2015-05-11 14:42:39",
307
  "type": "library",
308
  "installation-source": "dist",
309
  "notification-url": "https://packagist.org/downloads/",
1
  [
2
  {
3
+ "name": "websharks/js-minifier",
4
+ "version": "dev-master",
5
+ "version_normalized": "9999999-dev",
6
  "source": {
7
  "type": "git",
8
+ "url": "https://github.com/websharks/js-minifier.git",
9
+ "reference": "3c1e99af6df9df8f691642fbb769a10e49bfba23"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/websharks/js-minifier/zipball/3c1e99af6df9df8f691642fbb769a10e49bfba23",
14
+ "reference": "3c1e99af6df9df8f691642fbb769a10e49bfba23",
15
  "shasum": ""
16
  },
17
  "require": {
18
+ "ext-mbstring": "*",
19
+ "php": ">=5.3"
20
  },
21
+ "time": "2015-05-11 20:53:04",
22
  "type": "library",
23
  "installation-source": "dist",
24
+ "autoload": {
25
+ "psr-4": {
26
+ "WebSharks\\JsMinifier\\": "src/includes/classes"
27
+ }
28
+ },
29
  "notification-url": "https://packagist.org/downloads/",
30
  "license": [
31
  "GPL-3.0+"
47
  "role": "developer"
48
  }
49
  ],
50
+ "description": "Compresses JavaScript code.",
51
+ "homepage": "https://github.com/websharks/js-minifier",
52
  "keywords": [
53
+ "JS",
54
+ "compressor",
55
+ "javascript",
56
+ "websharks"
57
  ]
58
  },
59
  {
113
  ]
114
  },
115
  {
116
+ "name": "websharks/html-compressor",
117
+ "version": "160118",
118
+ "version_normalized": "160118",
119
  "source": {
120
  "type": "git",
121
+ "url": "https://github.com/websharks/html-compressor.git",
122
+ "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2"
123
  },
124
  "dist": {
125
  "type": "zip",
126
+ "url": "https://api.github.com/repos/websharks/html-compressor/zipball/bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
127
+ "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
128
  "shasum": ""
129
  },
130
  "require": {
131
+ "ext-curl": "*",
132
  "ext-mbstring": "*",
133
+ "ext-openssl": "*",
134
+ "php": ">=5.3",
135
+ "websharks/css-minifier": "dev-master",
136
+ "websharks/js-minifier": "dev-master"
137
  },
138
+ "time": "2016-01-18 03:17:20",
139
  "type": "library",
140
  "installation-source": "dist",
141
  "autoload": {
142
  "psr-4": {
143
+ "WebSharks\\HtmlCompressor\\": "src/includes/classes"
144
  }
145
  },
146
  "notification-url": "https://packagist.org/downloads/",
164
  "role": "developer"
165
  }
166
  ],
167
+ "description": "Combines & compresses CSS/JS/HTML code.",
168
+ "homepage": "https://github.com/websharks/html-compressor",
169
  "keywords": [
 
170
  "compressor",
171
+ "html",
172
  "websharks"
173
  ]
174
  },
175
  {
176
+ "name": "websharks/sharkicons",
177
+ "version": "160221",
178
+ "version_normalized": "160221",
179
  "source": {
180
  "type": "git",
181
+ "url": "https://github.com/websharks/sharkicons.git",
182
+ "reference": "2e6d6663c050f343fe944b424dea1759aa67cd05"
183
  },
184
  "dist": {
185
  "type": "zip",
186
+ "url": "https://api.github.com/repos/websharks/sharkicons/zipball/2e6d6663c050f343fe944b424dea1759aa67cd05",
187
+ "reference": "2e6d6663c050f343fe944b424dea1759aa67cd05",
188
  "shasum": ""
189
  },
190
+ "require-dev": {
191
+ "package/bourbon": "4.2.3"
 
 
 
 
 
192
  },
193
+ "time": "2016-02-21 15:16:12",
194
  "type": "library",
195
  "installation-source": "dist",
196
  "autoload": {
197
+ "psr-4": []
 
 
198
  },
199
  "notification-url": "https://packagist.org/downloads/",
200
  "license": [
217
  "role": "developer"
218
  }
219
  ],
220
+ "description": "Font containing WebSharks logos/icons.",
221
+ "homepage": "https://github.com/websharks/sharkicons",
222
  "keywords": [
223
+ "php",
224
+ "websharks",
225
+ "wordpress"
226
  ]
227
  },
228
  {
229
+ "name": "websharks/wp-php-rv",
230
+ "version": "150511",
231
+ "version_normalized": "150511",
232
  "source": {
233
  "type": "git",
234
+ "url": "https://github.com/websharks/wp-php-rv.git",
235
+ "reference": "ed0a58f3647e59c740560235da1e61904dca8d84"
236
  },
237
  "dist": {
238
  "type": "zip",
239
+ "url": "https://api.github.com/repos/websharks/wp-php-rv/zipball/ed0a58f3647e59c740560235da1e61904dca8d84",
240
+ "reference": "ed0a58f3647e59c740560235da1e61904dca8d84",
241
  "shasum": ""
242
  },
243
+ "require": {
244
+ "php": ">=5.2"
245
  },
246
+ "time": "2015-05-10 10:30:04",
247
  "type": "library",
248
  "installation-source": "dist",
 
 
 
249
  "notification-url": "https://packagist.org/downloads/",
250
  "license": [
251
  "GPL-3.0+"
267
  "role": "developer"
268
  }
269
  ],
270
+ "description": "Stub for WordPress themes/plugins that require PHP vX.x+.",
271
+ "homepage": "https://github.com/websharks/wp-php-rv",
272
  "keywords": [
273
  "php",
274
  "websharks",
295
  "source": {
296
  "type": "git",
297
  "url": "https://github.com/websharks/wp-i18n-tools.git",
298
+ "reference": "0275dc189293aee71e80a8bde43c4087f81ce9bb"
299
  },
300
  "dist": {
301
  "type": "zip",
302
+ "url": "https://api.github.com/repos/websharks/wp-i18n-tools/zipball/0275dc189293aee71e80a8bde43c4087f81ce9bb",
303
+ "reference": "0275dc189293aee71e80a8bde43c4087f81ce9bb",
304
  "shasum": ""
305
  },
306
+ "time": "2016-04-16 08:29:33",
307
  "type": "library",
308
  "installation-source": "dist",
309
  "notification-url": "https://packagist.org/downloads/",
src/vendor/websharks/sharkicons/src/long-classes.min.css CHANGED
@@ -1,3 +1,2 @@
1
  @font-face{font-family:sharkicons;src:url("fonts/sharkicons.eot?v160221");src:url("fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("fonts/sharkicons.ttf?v160221") format("truetype"),url("fonts/sharkicons.woff?v160221") format("woff"),url("fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.sharkicon::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.sharkicon-broom::before{content:""}.sharkicon-comment-mail-one::before{content:""}.sharkicon-comment-mail::before{content:""}.sharkicon-s2member::before{content:""}.sharkicon-websharks::before{content:""}.sharkicon-wp-kb-articles::before{content:""}.sharkicon-zencache-logo::before{content:""}.sharkicon-zencache::before{content:""}.sharkicon-wp-sharks::before{content:""}.sharkicon-wp-sharks-fin::before{content:""}.sharkicon-comet-cache::before{content:""}.sharkicon-comet-cache-logo::before{content:""}.sharkicon-comet-cache-comet::before{content:""}.sharkicon-feat-watch::before{content:""}.sharkicon-feat-server::before{content:""}.sharkicon-feat-layers::before{content:""}.sharkicon-feat-box::before{content:""}.sharkicon-feat-ellipsis::before{content:""}.sharkicon-typi-group::before{content:""}.sharkicon-enty-bookmark::before{content:""}.sharkicon-enty-bookmarks::before{content:""}.sharkicon-enty-open-book::before{content:""}.sharkicon-enty-archive::before{content:""}.sharkicon-enty-area-graph::before{content:""}.sharkicon-enty-bucket::before{content:""}.sharkicon-enty-colors::before{content:""}.sharkicon-enty-copy::before{content:""}.sharkicon-enty-drive::before{content:""}.sharkicon-enty-feather::before{content:""}.sharkicon-enty-gauge::before{content:""}.sharkicon-enty-hand::before{content:""}.sharkicon-enty-lab-flask::before{content:""}.sharkicon-enty-mask::before{content:""}.sharkicon-enty-medal::before{content:""}.sharkicon-enty-exclamation::before{content:""}.sharkicon-enty-palette::before{content:""}.sharkicon-enty-ruler::before{content:""}.sharkicon-enty-shop::before{content:""}.sharkicon-enty-basket::before{content:""}.sharkicon-enty-cart::before{content:""}.sharkicon-enty-traffic-cone::before{content:""}.sharkicon-enty-tree::before{content:""}.sharkicon-enty-trophy::before{content:""}.sharkicon-enty-v-card::before{content:""}.sharkicon-enty-google-hangouts::before{content:""}.sharkicon-eleg-line-graph::before{content:""}.sharkicon-eleg-male::before{content:""}.sharkicon-eleg-female::before{content:""}.sharkicon-eleg-atom::before{content:""}.sharkicon-broc-cart::before{content:""}.sharkicon-broc-crap::before{content:""}.sharkicon-broc-atom::before{content:""}.sharkicon-icom-headphones::before{content:""}.sharkicon-icom-barcode::before{content:""}.sharkicon-icom-user::before{content:""}.sharkicon-icom-users::before{content:""}.sharkicon-icom-user-plus::before{content:""}.sharkicon-icom-user-minus::before{content:""}.sharkicon-icom-user-check::before{content:""}.sharkicon-icom-user-tie::before{content:""}.sharkicon-icom-key::before{content:""}.sharkicon-icom-key2::before{content:""}.sharkicon-icom-happy::before{content:""}.sharkicon-icom-happy2::before{content:""}.sharkicon-icom-smile::before{content:""}.sharkicon-icom-smile2::before{content:""}.sharkicon-icom-tongue::before{content:""}.sharkicon-icom-tongue2::before{content:""}.sharkicon-icom-sad::before{content:""}.sharkicon-icom-sad2::before{content:""}.sharkicon-icom-wink::before{content:""}.sharkicon-icom-wink2::before{content:""}.sharkicon-icom-grin::before{content:""}.sharkicon-icom-grin2::before{content:""}.sharkicon-icom-cool::before{content:""}.sharkicon-icom-cool2::before{content:""}.sharkicon-icom-angry::before{content:""}.sharkicon-icom-angry2::before{content:""}.sharkicon-icom-evil::before{content:""}.sharkicon-icom-evil2::before{content:""}.sharkicon-icom-shocked::before{content:""}.sharkicon-icom-shocked2::before{content:""}.sharkicon-icom-baffled::before{content:""}.sharkicon-icom-baffled2::before{content:""}.sharkicon-icom-confused::before{content:""}.sharkicon-icom-confused2::before{content:""}.sharkicon-icom-neutral::before{content:""}.sharkicon-icom-neutral2::before{content:""}.sharkicon-icom-hipster::before{content:""}.sharkicon-icom-hipster2::before{content:""}.sharkicon-icom-wondering::before{content:""}.sharkicon-icom-wondering2::before{content:""}.sharkicon-icom-sleepy::before{content:""}.sharkicon-icom-sleepy2::before{content:""}.sharkicon-icom-frustrated::before{content:""}.sharkicon-icom-frustrated2::before{content:""}.sharkicon-icom-crying::before{content:""}.sharkicon-icom-crying2::before{content:""}.sharkicon-icom-spell-check::before{content:""}.sharkicon-icom-command-key::before{content:""}.sharkicon-icom-shift-key::before{content:""}.sharkicon-icom-control-key::before{content:""}.sharkicon-icom-option-key::before{content:""}.sharkicon-icom-wordpress::before{content:""}.sharkicon-icom-wordpress-square::before{content:""}.sharkicon-icom-yahoo::before{content:""}.sharkicon-icom-linux::before{content:""}.sharkicon-icom-finder::before{content:""}.sharkicon-icom-android::before{content:""}.sharkicon-icom-reddit::before{content:""}.sharkicon-icom-paypal::before{content:""}.sharkicon-icom-git::before{content:""}.sharkicon-octi-alignment-align::before{content:""}.sharkicon-octi-alignment-aligned-to::before{content:""}.sharkicon-octi-alignment-unalign::before{content:""}.sharkicon-octi-bookmark::before{content:""}.sharkicon-octi-broadcast::before{content:""}.sharkicon-octi-browser::before{content:""}.sharkicon-octi-checklist::before{content:""}.sharkicon-octi-circuit-board::before{content:""}.sharkicon-octi-clippy::before{content:""}.sharkicon-octi-cloud-download::before{content:""}.sharkicon-octi-cloud-upload::before{content:""}.sharkicon-octi-comment::before{content:""}.sharkicon-octi-comments::before{content:""}.sharkicon-octi-tach::before{content:""}.sharkicon-octi-device-camera::before{content:""}.sharkicon-octi-device-camera-video::before{content:""}.sharkicon-octi-device-desktop::before{content:""}.sharkicon-octi-diff::before{content:""}.sharkicon-octi-file-binary::before{content:""}.sharkicon-octi-file-media::before{content:""}.sharkicon-octi-file-submodule::before{content:""}.sharkicon-octi-file-symlink-directory::before{content:""}.sharkicon-octi-file-symlink-file::before{content:""}.sharkicon-octi-fold::before{content:""}.sharkicon-octi-git-branch::before{content:""}.sharkicon-octi-git-commit::before{content:""}.sharkicon-octi-git-compare::before{content:""}.sharkicon-octi-git-merge::before{content:""}.sharkicon-octi-git-pull-request::before{content:""}.sharkicon-octi-graph::before{content:""}.sharkicon-octi-home::before{content:""}.sharkicon-octi-horizontal-rule::before{content:""}.sharkicon-octi-key::before{content:""}.sharkicon-octi-light-bulb::before{content:""}.sharkicon-octi-link-external::before{content:""}.sharkicon-octi-lock::before{content:""}.sharkicon-octi-markdown::before{content:""}.sharkicon-octi-microscope::before{content:""}.sharkicon-octi-mirror::before{content:""}.sharkicon-octi-move-down::before{content:""}.sharkicon-octi-move-left::before{content:""}.sharkicon-octi-move-right::before{content:""}.sharkicon-octi-move-up::before{content:""}.sharkicon-octi-mute::before{content:""}.sharkicon-octi-organization::before{content:""}.sharkicon-octi-package::before{content:""}.sharkicon-octi-paintcan::before{content:""}.sharkicon-octi-person::before{content:""}.sharkicon-octi-plug::before{content:""}.sharkicon-octi-podium::before{content:""}.sharkicon-octi-pulse::before{content:""}.sharkicon-octi-puzzle::before{content:""}.sharkicon-octi-repo::before{content:""}.sharkicon-octi-repo-clone::before{content:""}.sharkicon-octi-repo-force-push::before{content:""}.sharkicon-octi-repo-forked::before{content:""}.sharkicon-octi-repo-pull::before{content:""}.sharkicon-octi-repo-push::before{content:""}.sharkicon-octi-rocket::before{content:""}.sharkicon-octi-ruby::before{content:""}.sharkicon-octi-screen-full::before{content:""}.sharkicon-octi-screen-normal::before{content:""}.sharkicon-octi-sign-in::before{content:""}.sharkicon-octi-sign-out::before{content:""}.sharkicon-octi-split::before{content:""}.sharkicon-octi-squirrel::before{content:""}.sharkicon-octi-steps::before{content:""}.sharkicon-octi-tag::before{content:""}.sharkicon-octi-telescope::before{content:""}.sharkicon-octi-terminal::before{content:""}.sharkicon-octi-unfold::before{content:""}.sharkicon-octi-versions::before{content:""}.sharkicon-glass::before{content:""}.sharkicon-music::before{content:""}.sharkicon-search::before{content:""}.sharkicon-envelope-o::before{content:""}.sharkicon-heart::before{content:""}.sharkicon-star::before{content:""}.sharkicon-star-o::before{content:""}.sharkicon-user::before{content:""}.sharkicon-film::before{content:""}.sharkicon-th-large::before{content:""}.sharkicon-th::before{content:""}.sharkicon-th-list::before{content:""}.sharkicon-check::before{content:""}.sharkicon-close::before{content:""}.sharkicon-search-plus::before{content:""}.sharkicon-search-minus::before{content:""}.sharkicon-power-off::before{content:""}.sharkicon-signal::before{content:""}.sharkicon-cog::before{content:""}.sharkicon-trash-o::before{content:""}.sharkicon-home::before{content:""}.sharkicon-file-o::before{content:""}.sharkicon-clock-o::before{content:""}.sharkicon-road::before{content:""}.sharkicon-download::before{content:""}.sharkicon-arrow-circle-o-down::before{content:""}.sharkicon-arrow-circle-o-up::before{content:""}.sharkicon-inbox::before{content:""}.sharkicon-play-circle-o::before{content:""}.sharkicon-repeat::before{content:""}.sharkicon-refresh::before{content:""}.sharkicon-list-alt::before{content:""}.sharkicon-lock::before{content:""}.sharkicon-flag::before{content:""}.sharkicon-headphones::before{content:""}.sharkicon-volume-off::before{content:""}.sharkicon-volume-down::before{content:""}.sharkicon-volume-up::before{content:""}.sharkicon-qrcode::before{content:""}.sharkicon-barcode::before{content:""}.sharkicon-tag::before{content:""}.sharkicon-tags::before{content:""}.sharkicon-book::before{content:""}.sharkicon-bookmark::before{content:""}.sharkicon-print::before{content:""}.sharkicon-camera::before{content:""}.sharkicon-font::before{content:""}.sharkicon-bold::before{content:""}.sharkicon-italic::before{content:""}.sharkicon-text-height::before{content:""}.sharkicon-text-width::before{content:""}.sharkicon-align-left::before{content:""}.sharkicon-align-center::before{content:""}.sharkicon-align-right::before{content:""}.sharkicon-align-justify::before{content:""}.sharkicon-list::before{content:""}.sharkicon-dedent::before{content:""}.sharkicon-indent::before{content:""}.sharkicon-video-camera::before{content:""}.sharkicon-image::before{content:""}.sharkicon-pencil::before{content:""}.sharkicon-map-marker::before{content:""}.sharkicon-adjust::before{content:""}.sharkicon-tint::before{content:""}.sharkicon-edit::before{content:""}.sharkicon-share-square-o::before{content:""}.sharkicon-check-square-o::before{content:""}.sharkicon-arrows::before{content:""}.sharkicon-step-backward::before{content:""}.sharkicon-fast-backward::before{content:""}.sharkicon-backward::before{content:""}.sharkicon-play::before{content:""}.sharkicon-pause::before{content:""}.sharkicon-stop::before{content:""}.sharkicon-forward::before{content:""}.sharkicon-fast-forward::before{content:""}.sharkicon-step-forward::before{content:""}.sharkicon-eject::before{content:""}.sharkicon-chevron-left::before{content:""}.sharkicon-chevron-right::before{content:""}.sharkicon-plus-circle::before{content:""}.sharkicon-minus-circle::before{content:""}.sharkicon-times-circle::before{content:""}.sharkicon-check-circle::before{content:""}.sharkicon-question-circle::before{content:""}.sharkicon-info-circle::before{content:""}.sharkicon-crosshairs::before{content:""}.sharkicon-times-circle-o::before{content:""}.sharkicon-check-circle-o::before{content:""}.sharkicon-ban::before{content:""}.sharkicon-arrow-left::before{content:""}.sharkicon-arrow-right::before{content:""}.sharkicon-arrow-up::before{content:""}.sharkicon-arrow-down::before{content:""}.sharkicon-mail-forward::before{content:""}.sharkicon-expand::before{content:""}.sharkicon-compress::before{content:""}.sharkicon-plus::before{content:""}.sharkicon-minus::before{content:""}.sharkicon-asterisk::before{content:""}.sharkicon-exclamation-circle::before{content:""}.sharkicon-gift::before{content:""}.sharkicon-leaf::before{content:""}.sharkicon-fire::before{content:""}.sharkicon-eye::before{content:""}.sharkicon-eye-slash::before{content:""}.sharkicon-exclamation-triangle::before{content:""}.sharkicon-plane::before{content:""}.sharkicon-calendar::before{content:""}.sharkicon-random::before{content:""}.sharkicon-comment::before{content:""}.sharkicon-magnet::before{content:""}.sharkicon-chevron-up::before{content:""}.sharkicon-chevron-down::before{content:""}.sharkicon-retweet::before{content:""}.sharkicon-shopping-cart::before{content:""}.sharkicon-folder::before{content:""}.sharkicon-folder-open::before{content:""}.sharkicon-arrows-v::before{content:""}.sharkicon-arrows-h::before{content:""}.sharkicon-bar-chart::before{content:""}.sharkicon-twitter-square::before{content:""}.sharkicon-facebook-square::before{content:""}.sharkicon-camera-retro::before{content:""}.sharkicon-key::before{content:""}.sharkicon-cogs::before{content:""}.sharkicon-comments::before{content:""}.sharkicon-thumbs-o-up::before{content:""}.sharkicon-thumbs-o-down::before{content:""}.sharkicon-star-half::before{content:""}.sharkicon-heart-o::before{content:""}.sharkicon-sign-out::before{content:""}.sharkicon-linkedin-square::before{content:""}.sharkicon-thumb-tack::before{content:""}.sharkicon-external-link::before{content:""}.sharkicon-sign-in::before{content:""}.sharkicon-trophy::before{content:""}.sharkicon-github-square::before{content:""}.sharkicon-upload::before{content:""}.sharkicon-lemon-o::before{content:""}.sharkicon-phone::before{content:""}.sharkicon-square-o::before{content:""}.sharkicon-bookmark-o::before{content:""}.sharkicon-phone-square::before{content:""}.sharkicon-twitter::before{content:""}.sharkicon-facebook::before{content:""}.sharkicon-github::before{content:""}.sharkicon-unlock::before{content:""}.sharkicon-credit-card::before{content:""}.sharkicon-feed::before{content:""}.sharkicon-hdd-o::before{content:""}.sharkicon-bullhorn::before{content:""}.sharkicon-bell-o::before{content:""}.sharkicon-certificate::before{content:""}.sharkicon-hand-o-right::before{content:""}.sharkicon-hand-o-left::before{content:""}.sharkicon-hand-o-up::before{content:""}.sharkicon-hand-o-down::before{content:""}.sharkicon-arrow-circle-left::before{content:""}.sharkicon-arrow-circle-right::before{content:""}.sharkicon-arrow-circle-up::before{content:""}.sharkicon-arrow-circle-down::before{content:""}.sharkicon-globe::before{content:""}.sharkicon-wrench::before{content:""}.sharkicon-tasks::before{content:""}.sharkicon-filter::before{content:""}.sharkicon-briefcase::before{content:""}.sharkicon-arrows-alt::before{content:""}.sharkicon-group::before{content:""}.sharkicon-chain::before{content:""}.sharkicon-cloud::before{content:""}.sharkicon-flask::before{content:""}.sharkicon-cut::before{content:""}.sharkicon-copy::before{content:""}.sharkicon-paperclip::before{content:""}.sharkicon-floppy-o::before{content:""}.sharkicon-square::before{content:""}.sharkicon-bars::before{content:""}.sharkicon-list-ul::before{content:""}.sharkicon-list-ol::before{content:""}.sharkicon-strikethrough::before{content:""}.sharkicon-underline::before{content:""}.sharkicon-table::before{content:""}.sharkicon-magic::before{content:""}.sharkicon-truck::before{content:""}.sharkicon-pinterest::before{content:""}.sharkicon-pinterest-square::before{content:""}.sharkicon-google-plus-square::before{content:""}.sharkicon-google-plus::before{content:""}.sharkicon-money::before{content:""}.sharkicon-caret-down::before{content:""}.sharkicon-caret-up::before{content:""}.sharkicon-caret-left::before{content:""}.sharkicon-caret-right::before{content:""}.sharkicon-columns::before{content:""}.sharkicon-sort::before{content:""}.sharkicon-sort-desc::before{content:""}.sharkicon-sort-asc::before{content:""}.sharkicon-envelope::before{content:""}.sharkicon-linkedin::before{content:""}.sharkicon-rotate-left::before{content:""}.sharkicon-gavel::before{content:""}.sharkicon-dashboard::before{content:""}.sharkicon-comment-o::before{content:""}.sharkicon-comments-o::before{content:""}.sharkicon-bolt::before{content:""}.sharkicon-sitemap::before{content:""}.sharkicon-umbrella::before{content:""}.sharkicon-clipboard::before{content:""}.sharkicon-lightbulb-o::before{content:""}.sharkicon-exchange::before{content:""}.sharkicon-cloud-download::before{content:""}.sharkicon-cloud-upload::before{content:""}.sharkicon-user-md::before{content:""}.sharkicon-stethoscope::before{content:""}.sharkicon-suitcase::before{content:""}.sharkicon-bell::before{content:""}.sharkicon-coffee::before{content:""}.sharkicon-cutlery::before{content:""}.sharkicon-file-text-o::before{content:""}.sharkicon-building-o::before{content:""}.sharkicon-hospital-o::before{content:""}.sharkicon-ambulance::before{content:""}.sharkicon-medkit::before{content:""}.sharkicon-fighter-jet::before{content:""}.sharkicon-beer::before{content:""}.sharkicon-h-square::before{content:""}.sharkicon-plus-square::before{content:""}.sharkicon-angle-double-left::before{content:""}.sharkicon-angle-double-right::before{content:""}.sharkicon-angle-double-up::before{content:""}.sharkicon-angle-double-down::before{content:""}.sharkicon-angle-left::before{content:""}.sharkicon-angle-right::before{content:""}.sharkicon-angle-up::before{content:""}.sharkicon-angle-down::before{content:""}.sharkicon-desktop::before{content:""}.sharkicon-laptop::before{content:""}.sharkicon-tablet::before{content:""}.sharkicon-mobile::before{content:""}.sharkicon-circle-o::before{content:""}.sharkicon-quote-left::before{content:""}.sharkicon-quote-right::before{content:""}.sharkicon-spinner::before{content:""}.sharkicon-circle::before{content:""}.sharkicon-mail-reply::before{content:""}.sharkicon-github-alt::before{content:""}.sharkicon-folder-o::before{content:""}.sharkicon-folder-open-o::before{content:""}.sharkicon-smile-o::before{content:""}.sharkicon-frown-o::before{content:""}.sharkicon-meh-o::before{content:""}.sharkicon-gamepad::before{content:""}.sharkicon-keyboard-o::before{content:""}.sharkicon-flag-o::before{content:""}.sharkicon-flag-checkered::before{content:""}.sharkicon-terminal::before{content:""}.sharkicon-code::before{content:""}.sharkicon-mail-reply-all::before{content:""}.sharkicon-star-half-empty::before{content:""}.sharkicon-location-arrow::before{content:""}.sharkicon-crop::before{content:""}.sharkicon-code-fork::before{content:""}.sharkicon-chain-broken::before{content:""}.sharkicon-question::before{content:""}.sharkicon-info::before{content:""}.sharkicon-exclamation::before{content:""}.sharkicon-superscript::before{content:""}.sharkicon-subscript::before{content:""}.sharkicon-eraser::before{content:""}.sharkicon-puzzle-piece::before{content:""}.sharkicon-microphone::before{content:""}.sharkicon-microphone-slash::before{content:""}.sharkicon-shield::before{content:""}.sharkicon-calendar-o::before{content:""}.sharkicon-fire-extinguisher::before{content:""}.sharkicon-rocket::before{content:""}.sharkicon-maxcdn::before{content:""}.sharkicon-chevron-circle-left::before{content:""}.sharkicon-chevron-circle-right::before{content:""}.sharkicon-chevron-circle-up::before{content:""}.sharkicon-chevron-circle-down::before{content:""}.sharkicon-html5::before{content:""}.sharkicon-css3::before{content:""}.sharkicon-anchor::before{content:""}.sharkicon-unlock-alt::before{content:""}.sharkicon-bullseye::before{content:""}.sharkicon-ellipsis-h::before{content:""}.sharkicon-ellipsis-v::before{content:""}.sharkicon-rss-square::before{content:""}.sharkicon-play-circle::before{content:""}.sharkicon-ticket::before{content:""}.sharkicon-minus-square::before{content:""}.sharkicon-minus-square-o::before{content:""}.sharkicon-level-up::before{content:""}.sharkicon-level-down::before{content:""}.sharkicon-check-square::before{content:""}.sharkicon-pencil-square::before{content:""}.sharkicon-external-link-square::before{content:""}.sharkicon-share-square::before{content:""}.sharkicon-compass::before{content:""}.sharkicon-caret-square-o-down::before{content:""}.sharkicon-caret-square-o-up::before{content:""}.sharkicon-caret-square-o-right::before{content:""}.sharkicon-eur::before{content:""}.sharkicon-gbp::before{content:""}.sharkicon-dollar::before{content:""}.sharkicon-inr::before{content:""}.sharkicon-cny::before{content:""}.sharkicon-rouble::before{content:""}.sharkicon-krw::before{content:""}.sharkicon-bitcoin::before{content:""}.sharkicon-file::before{content:""}.sharkicon-file-text::before{content:""}.sharkicon-sort-alpha-asc::before{content:""}.sharkicon-sort-alpha-desc::before{content:""}.sharkicon-sort-amount-asc::before{content:""}.sharkicon-sort-amount-desc::before{content:""}.sharkicon-sort-numeric-asc::before{content:""}.sharkicon-sort-numeric-desc::before{content:""}.sharkicon-thumbs-up::before{content:""}.sharkicon-thumbs-down::before{content:""}.sharkicon-youtube-square::before{content:""}.sharkicon-youtube::before{content:""}.sharkicon-xing::before{content:""}.sharkicon-xing-square::before{content:""}.sharkicon-youtube-play::before{content:""}.sharkicon-dropbox::before{content:""}.sharkicon-stack-overflow::before{content:""}.sharkicon-instagram::before{content:""}.sharkicon-flickr::before{content:""}.sharkicon-adn::before{content:""}.sharkicon-bitbucket::before{content:""}.sharkicon-bitbucket-square::before{content:""}.sharkicon-tumblr::before{content:""}.sharkicon-tumblr-square::before{content:""}.sharkicon-long-arrow-down::before{content:""}.sharkicon-long-arrow-up::before{content:""}.sharkicon-long-arrow-left::before{content:""}.sharkicon-long-arrow-right::before{content:""}.sharkicon-apple::before{content:""}.sharkicon-windows::before{content:""}.sharkicon-android::before{content:""}.sharkicon-linux::before{content:""}.sharkicon-dribbble::before{content:""}.sharkicon-skype::before{content:""}.sharkicon-foursquare::before{content:""}.sharkicon-trello::before{content:""}.sharkicon-female::before{content:""}.sharkicon-male::before{content:""}.sharkicon-gittip::before{content:""}.sharkicon-sun-o::before{content:""}.sharkicon-moon-o::before{content:""}.sharkicon-archive::before{content:""}.sharkicon-bug::before{content:""}.sharkicon-vk::before{content:""}.sharkicon-weibo::before{content:""}.sharkicon-renren::before{content:""}.sharkicon-pagelines::before{content:""}.sharkicon-stack-exchange::before{content:""}.sharkicon-arrow-circle-o-right::before{content:""}.sharkicon-arrow-circle-o-left::before{content:""}.sharkicon-caret-square-o-left::before{content:""}.sharkicon-dot-circle-o::before{content:""}.sharkicon-wheelchair::before{content:""}.sharkicon-vimeo-square::before{content:""}.sharkicon-try::before{content:""}.sharkicon-plus-square-o::before{content:""}.sharkicon-space-shuttle::before{content:""}.sharkicon-slack::before{content:""}.sharkicon-envelope-square::before{content:""}.sharkicon-wordpress::before{content:""}.sharkicon-openid::before{content:""}.sharkicon-bank::before{content:""}.sharkicon-graduation-cap::before{content:""}.sharkicon-yahoo::before{content:""}.sharkicon-google::before{content:""}.sharkicon-reddit::before{content:""}.sharkicon-reddit-square::before{content:""}.sharkicon-stumbleupon-circle::before{content:""}.sharkicon-stumbleupon::before{content:""}.sharkicon-delicious::before{content:""}.sharkicon-digg::before{content:""}.sharkicon-pied-piper::before{content:""}.sharkicon-pied-piper-alt::before{content:""}.sharkicon-drupal::before{content:""}.sharkicon-joomla::before{content:""}.sharkicon-language::before{content:""}.sharkicon-fax::before{content:""}.sharkicon-building::before{content:""}.sharkicon-child::before{content:""}.sharkicon-paw::before{content:""}.sharkicon-spoon::before{content:""}.sharkicon-cube::before{content:""}.sharkicon-cubes::before{content:""}.sharkicon-behance::before{content:""}.sharkicon-behance-square::before{content:""}.sharkicon-steam::before{content:""}.sharkicon-steam-square::before{content:""}.sharkicon-recycle::before{content:""}.sharkicon-automobile::before{content:""}.sharkicon-cab::before{content:""}.sharkicon-tree::before{content:""}.sharkicon-spotify::before{content:""}.sharkicon-deviantart::before{content:""}.sharkicon-soundcloud::before{content:""}.sharkicon-database::before{content:""}.sharkicon-file-pdf-o::before{content:""}.sharkicon-file-word-o::before{content:""}.sharkicon-file-excel-o::before{content:""}.sharkicon-file-powerpoint-o::before{content:""}.sharkicon-file-image-o::before{content:""}.sharkicon-file-archive-o::before{content:""}.sharkicon-file-audio-o::before{content:""}.sharkicon-file-movie-o::before{content:""}.sharkicon-file-code-o::before{content:""}.sharkicon-vine::before{content:""}.sharkicon-codepen::before{content:""}.sharkicon-jsfiddle::before{content:""}.sharkicon-life-bouy::before{content:""}.sharkicon-circle-o-notch::before{content:""}.sharkicon-ra::before{content:""}.sharkicon-empire::before{content:""}.sharkicon-git-square::before{content:""}.sharkicon-git::before{content:""}.sharkicon-hacker-news::before{content:""}.sharkicon-tencent-weibo::before{content:""}.sharkicon-qq::before{content:""}.sharkicon-wechat::before{content:""}.sharkicon-paper-plane::before{content:""}.sharkicon-paper-plane-o::before{content:""}.sharkicon-history::before{content:""}.sharkicon-circle-thin::before{content:""}.sharkicon-header::before{content:""}.sharkicon-paragraph::before{content:""}.sharkicon-sliders::before{content:""}.sharkicon-share-alt::before{content:""}.sharkicon-share-alt-square::before{content:""}.sharkicon-bomb::before{content:""}.sharkicon-futbol-o::before{content:""}.sharkicon-tty::before{content:""}.sharkicon-binoculars::before{content:""}.sharkicon-plug::before{content:""}.sharkicon-slideshare::before{content:""}.sharkicon-twitch::before{content:""}.sharkicon-yelp::before{content:""}.sharkicon-newspaper-o::before{content:""}.sharkicon-wifi::before{content:""}.sharkicon-calculator::before{content:""}.sharkicon-paypal::before{content:""}.sharkicon-google-wallet::before{content:""}.sharkicon-cc-visa::before{content:""}.sharkicon-cc-mastercard::before{content:""}.sharkicon-cc-discover::before{content:""}.sharkicon-cc-amex::before{content:""}.sharkicon-cc-paypal::before{content:""}.sharkicon-cc-stripe::before{content:""}.sharkicon-bell-slash::before{content:""}.sharkicon-bell-slash-o::before{content:""}.sharkicon-trash::before{content:""}.sharkicon-copyright::before{content:""}.sharkicon-at::before{content:""}.sharkicon-eyedropper::before{content:""}.sharkicon-paint-brush::before{content:""}.sharkicon-birthday-cake::before{content:""}.sharkicon-area-chart::before{content:""}.sharkicon-pie-chart::before{content:""}.sharkicon-line-chart::before{content:""}.sharkicon-lastfm::before{content:""}.sharkicon-lastfm-square::before{content:""}.sharkicon-toggle-off::before{content:""}.sharkicon-toggle-on::before{content:""}.sharkicon-bicycle::before{content:""}.sharkicon-bus::before{content:""}.sharkicon-ioxhost::before{content:""}.sharkicon-angellist::before{content:""}.sharkicon-cc::before{content:""}.sharkicon-ils::before{content:""}.sharkicon-meanpath::before{content:""}.sharkicon-buysellads::before{content:""}.sharkicon-connectdevelop::before{content:""}.sharkicon-dashcube::before{content:""}.sharkicon-forumbee::before{content:""}.sharkicon-leanpub::before{content:""}.sharkicon-sellsy::before{content:""}.sharkicon-shirtsinbulk::before{content:""}.sharkicon-simplybuilt::before{content:""}.sharkicon-skyatlas::before{content:""}.sharkicon-cart-plus::before{content:""}.sharkicon-cart-arrow-down::before{content:""}.sharkicon-diamond::before{content:""}.sharkicon-ship::before{content:""}.sharkicon-user-secret::before{content:""}.sharkicon-motorcycle::before{content:""}.sharkicon-street-view::before{content:""}.sharkicon-heartbeat::before{content:""}.sharkicon-venus::before{content:""}.sharkicon-mars::before{content:""}.sharkicon-mercury::before{content:""}.sharkicon-intersex::before{content:""}.sharkicon-transgender-alt::before{content:""}.sharkicon-venus-double::before{content:""}.sharkicon-mars-double::before{content:""}.sharkicon-venus-mars::before{content:""}.sharkicon-mars-stroke::before{content:""}.sharkicon-mars-stroke-v::before{content:""}.sharkicon-mars-stroke-h::before{content:""}.sharkicon-neuter::before{content:""}.sharkicon-genderless::before{content:""}.sharkicon-facebook-official::before{content:""}.sharkicon-pinterest-p::before{content:""}.sharkicon-whatsapp::before{content:""}.sharkicon-server::before{content:""}.sharkicon-user-plus::before{content:""}.sharkicon-user-times::before{content:""}.sharkicon-bed::before{content:""}.sharkicon-viacoin::before{content:""}.sharkicon-train::before{content:""}.sharkicon-subway::before{content:""}.sharkicon-medium::before{content:""}.sharkicon-y-combinator::before{content:""}.sharkicon-optin-monster::before{content:""}.sharkicon-opencart::before{content:""}.sharkicon-expeditedssl::before{content:""}.sharkicon-battery-4::before{content:""}.sharkicon-battery-3::before{content:""}.sharkicon-battery-2::before{content:""}.sharkicon-battery-1::before{content:""}.sharkicon-battery-0::before{content:""}.sharkicon-mouse-pointer::before{content:""}.sharkicon-i-cursor::before{content:""}.sharkicon-object-group::before{content:""}.sharkicon-object-ungroup::before{content:""}.sharkicon-sticky-note::before{content:""}.sharkicon-sticky-note-o::before{content:""}.sharkicon-cc-jcb::before{content:""}.sharkicon-cc-diners-club::before{content:""}.sharkicon-clone::before{content:""}.sharkicon-balance-scale::before{content:""}.sharkicon-hourglass-o::before{content:""}.sharkicon-hourglass-1::before{content:""}.sharkicon-hourglass-2::before{content:""}.sharkicon-hourglass-3::before{content:""}.sharkicon-hourglass::before{content:""}.sharkicon-hand-grab-o::before{content:""}.sharkicon-hand-paper-o::before{content:""}.sharkicon-hand-scissors-o::before{content:""}.sharkicon-hand-lizard-o::before{content:""}.sharkicon-hand-spock-o::before{content:""}.sharkicon-hand-pointer-o::before{content:""}.sharkicon-hand-peace-o::before{content:""}.sharkicon-trademark::before{content:""}.sharkicon-registered::before{content:""}.sharkicon-creative-commons::before{content:""}.sharkicon-gg::before{content:""}.sharkicon-gg-circle::before{content:""}.sharkicon-tripadvisor::before{content:""}.sharkicon-odnoklassniki::before{content:""}.sharkicon-odnoklassniki-square::before{content:""}.sharkicon-get-pocket::before{content:""}.sharkicon-wikipedia-w::before{content:""}.sharkicon-safari::before{content:""}.sharkicon-chrome::before{content:""}.sharkicon-firefox::before{content:""}.sharkicon-opera::before{content:""}.sharkicon-internet-explorer::before{content:""}.sharkicon-television::before{content:""}.sharkicon-contao::before{content:""}.sharkicon-500px::before{content:""}.sharkicon-amazon::before{content:""}.sharkicon-calendar-plus-o::before{content:""}.sharkicon-calendar-minus-o::before{content:""}.sharkicon-calendar-times-o::before{content:""}.sharkicon-calendar-check-o::before{content:""}.sharkicon-industry::before{content:""}.sharkicon-map-pin::before{content:""}.sharkicon-map-signs::before{content:""}.sharkicon-map-o::before{content:""}.sharkicon-map::before{content:""}.sharkicon-commenting::before{content:""}.sharkicon-commenting-o::before{content:""}.sharkicon-houzz::before{content:""}.sharkicon-vimeo::before{content:""}.sharkicon-black-tie::before{content:""}.sharkicon-fonticons::before{content:""}.sharkicon-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.sharkicon-2x{font-size:2em}.sharkicon-3x{font-size:3em}.sharkicon-4x{font-size:4em}.sharkicon-5x{font-size:5em}.sharkicon-fw{text-align:center;width:1.28571429em}.sharkicon-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.sharkicon-pull-left{float:left;margin-right:.3em}.sharkicon-pull-right{float:right;margin-left:.3em}.sharkicon-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.sharkicon-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.sharkicon-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.sharkicon-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.sharkicon-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.sharkicon-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.sharkicon-spin{-webkit-animation:sharkicon-animation-spin 2s infinite linear;-moz-animation:sharkicon-animation-spin 2s infinite linear;animation:sharkicon-animation-spin 2s infinite linear}.sharkicon-pulse{-webkit-animation:sharkicon-animation-spin 1s infinite steps(8);-moz-animation:sharkicon-animation-spin 1s infinite steps(8);animation:sharkicon-animation-spin 1s infinite steps(8)}.sharkicon-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.sharkicon-ul>li{position:relative}.sharkicon-ul>li .sharkicon-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.sharkicon-ul>li .sharkicon-li .sharkicon-lg{left:-1.85714286em}.sharkicon-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.sharkicon-stack .sharkicon-stack-1x,.sharkicon-stack .sharkicon-stack-2x{left:0;width:100%;text-align:center;position:absolute}.sharkicon-stack .sharkicon-stack-1x{line-height:inherit}.sharkicon-stack .sharkicon-stack-2x{font-size:2em}@-webkit-keyframes sharkicon-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes sharkicon-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes sharkicon-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}
2
 
3
- /*# sourceMappingURL=long-classes.min.css.map */
1
  @font-face{font-family:sharkicons;src:url("fonts/sharkicons.eot?v160221");src:url("fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("fonts/sharkicons.ttf?v160221") format("truetype"),url("fonts/sharkicons.woff?v160221") format("woff"),url("fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.sharkicon::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.sharkicon-broom::before{content:""}.sharkicon-comment-mail-one::before{content:""}.sharkicon-comment-mail::before{content:""}.sharkicon-s2member::before{content:""}.sharkicon-websharks::before{content:""}.sharkicon-wp-kb-articles::before{content:""}.sharkicon-zencache-logo::before{content:""}.sharkicon-zencache::before{content:""}.sharkicon-wp-sharks::before{content:""}.sharkicon-wp-sharks-fin::before{content:""}.sharkicon-comet-cache::before{content:""}.sharkicon-comet-cache-logo::before{content:""}.sharkicon-comet-cache-comet::before{content:""}.sharkicon-feat-watch::before{content:""}.sharkicon-feat-server::before{content:""}.sharkicon-feat-layers::before{content:""}.sharkicon-feat-box::before{content:""}.sharkicon-feat-ellipsis::before{content:""}.sharkicon-typi-group::before{content:""}.sharkicon-enty-bookmark::before{content:""}.sharkicon-enty-bookmarks::before{content:""}.sharkicon-enty-open-book::before{content:""}.sharkicon-enty-archive::before{content:""}.sharkicon-enty-area-graph::before{content:""}.sharkicon-enty-bucket::before{content:""}.sharkicon-enty-colors::before{content:""}.sharkicon-enty-copy::before{content:""}.sharkicon-enty-drive::before{content:""}.sharkicon-enty-feather::before{content:""}.sharkicon-enty-gauge::before{content:""}.sharkicon-enty-hand::before{content:""}.sharkicon-enty-lab-flask::before{content:""}.sharkicon-enty-mask::before{content:""}.sharkicon-enty-medal::before{content:""}.sharkicon-enty-exclamation::before{content:""}.sharkicon-enty-palette::before{content:""}.sharkicon-enty-ruler::before{content:""}.sharkicon-enty-shop::before{content:""}.sharkicon-enty-basket::before{content:""}.sharkicon-enty-cart::before{content:""}.sharkicon-enty-traffic-cone::before{content:""}.sharkicon-enty-tree::before{content:""}.sharkicon-enty-trophy::before{content:""}.sharkicon-enty-v-card::before{content:""}.sharkicon-enty-google-hangouts::before{content:""}.sharkicon-eleg-line-graph::before{content:""}.sharkicon-eleg-male::before{content:""}.sharkicon-eleg-female::before{content:""}.sharkicon-eleg-atom::before{content:""}.sharkicon-broc-cart::before{content:""}.sharkicon-broc-crap::before{content:""}.sharkicon-broc-atom::before{content:""}.sharkicon-icom-headphones::before{content:""}.sharkicon-icom-barcode::before{content:""}.sharkicon-icom-user::before{content:""}.sharkicon-icom-users::before{content:""}.sharkicon-icom-user-plus::before{content:""}.sharkicon-icom-user-minus::before{content:""}.sharkicon-icom-user-check::before{content:""}.sharkicon-icom-user-tie::before{content:""}.sharkicon-icom-key::before{content:""}.sharkicon-icom-key2::before{content:""}.sharkicon-icom-happy::before{content:""}.sharkicon-icom-happy2::before{content:""}.sharkicon-icom-smile::before{content:""}.sharkicon-icom-smile2::before{content:""}.sharkicon-icom-tongue::before{content:""}.sharkicon-icom-tongue2::before{content:""}.sharkicon-icom-sad::before{content:""}.sharkicon-icom-sad2::before{content:""}.sharkicon-icom-wink::before{content:""}.sharkicon-icom-wink2::before{content:""}.sharkicon-icom-grin::before{content:""}.sharkicon-icom-grin2::before{content:""}.sharkicon-icom-cool::before{content:""}.sharkicon-icom-cool2::before{content:""}.sharkicon-icom-angry::before{content:""}.sharkicon-icom-angry2::before{content:""}.sharkicon-icom-evil::before{content:""}.sharkicon-icom-evil2::before{content:""}.sharkicon-icom-shocked::before{content:""}.sharkicon-icom-shocked2::before{content:""}.sharkicon-icom-baffled::before{content:""}.sharkicon-icom-baffled2::before{content:""}.sharkicon-icom-confused::before{content:""}.sharkicon-icom-confused2::before{content:""}.sharkicon-icom-neutral::before{content:""}.sharkicon-icom-neutral2::before{content:""}.sharkicon-icom-hipster::before{content:""}.sharkicon-icom-hipster2::before{content:""}.sharkicon-icom-wondering::before{content:""}.sharkicon-icom-wondering2::before{content:""}.sharkicon-icom-sleepy::before{content:""}.sharkicon-icom-sleepy2::before{content:""}.sharkicon-icom-frustrated::before{content:""}.sharkicon-icom-frustrated2::before{content:""}.sharkicon-icom-crying::before{content:""}.sharkicon-icom-crying2::before{content:""}.sharkicon-icom-spell-check::before{content:""}.sharkicon-icom-command-key::before{content:""}.sharkicon-icom-shift-key::before{content:""}.sharkicon-icom-control-key::before{content:""}.sharkicon-icom-option-key::before{content:""}.sharkicon-icom-wordpress::before{content:""}.sharkicon-icom-wordpress-square::before{content:""}.sharkicon-icom-yahoo::before{content:""}.sharkicon-icom-linux::before{content:""}.sharkicon-icom-finder::before{content:""}.sharkicon-icom-android::before{content:""}.sharkicon-icom-reddit::before{content:""}.sharkicon-icom-paypal::before{content:""}.sharkicon-icom-git::before{content:""}.sharkicon-octi-alignment-align::before{content:""}.sharkicon-octi-alignment-aligned-to::before{content:""}.sharkicon-octi-alignment-unalign::before{content:""}.sharkicon-octi-bookmark::before{content:""}.sharkicon-octi-broadcast::before{content:""}.sharkicon-octi-browser::before{content:""}.sharkicon-octi-checklist::before{content:""}.sharkicon-octi-circuit-board::before{content:""}.sharkicon-octi-clippy::before{content:""}.sharkicon-octi-cloud-download::before{content:""}.sharkicon-octi-cloud-upload::before{content:""}.sharkicon-octi-comment::before{content:""}.sharkicon-octi-comments::before{content:""}.sharkicon-octi-tach::before{content:""}.sharkicon-octi-device-camera::before{content:""}.sharkicon-octi-device-camera-video::before{content:""}.sharkicon-octi-device-desktop::before{content:""}.sharkicon-octi-diff::before{content:""}.sharkicon-octi-file-binary::before{content:""}.sharkicon-octi-file-media::before{content:""}.sharkicon-octi-file-submodule::before{content:""}.sharkicon-octi-file-symlink-directory::before{content:""}.sharkicon-octi-file-symlink-file::before{content:""}.sharkicon-octi-fold::before{content:""}.sharkicon-octi-git-branch::before{content:""}.sharkicon-octi-git-commit::before{content:""}.sharkicon-octi-git-compare::before{content:""}.sharkicon-octi-git-merge::before{content:""}.sharkicon-octi-git-pull-request::before{content:""}.sharkicon-octi-graph::before{content:""}.sharkicon-octi-home::before{content:""}.sharkicon-octi-horizontal-rule::before{content:""}.sharkicon-octi-key::before{content:""}.sharkicon-octi-light-bulb::before{content:""}.sharkicon-octi-link-external::before{content:""}.sharkicon-octi-lock::before{content:""}.sharkicon-octi-markdown::before{content:""}.sharkicon-octi-microscope::before{content:""}.sharkicon-octi-mirror::before{content:""}.sharkicon-octi-move-down::before{content:""}.sharkicon-octi-move-left::before{content:""}.sharkicon-octi-move-right::before{content:""}.sharkicon-octi-move-up::before{content:""}.sharkicon-octi-mute::before{content:""}.sharkicon-octi-organization::before{content:""}.sharkicon-octi-package::before{content:""}.sharkicon-octi-paintcan::before{content:""}.sharkicon-octi-person::before{content:""}.sharkicon-octi-plug::before{content:""}.sharkicon-octi-podium::before{content:""}.sharkicon-octi-pulse::before{content:""}.sharkicon-octi-puzzle::before{content:""}.sharkicon-octi-repo::before{content:""}.sharkicon-octi-repo-clone::before{content:""}.sharkicon-octi-repo-force-push::before{content:""}.sharkicon-octi-repo-forked::before{content:""}.sharkicon-octi-repo-pull::before{content:""}.sharkicon-octi-repo-push::before{content:""}.sharkicon-octi-rocket::before{content:""}.sharkicon-octi-ruby::before{content:""}.sharkicon-octi-screen-full::before{content:""}.sharkicon-octi-screen-normal::before{content:""}.sharkicon-octi-sign-in::before{content:""}.sharkicon-octi-sign-out::before{content:""}.sharkicon-octi-split::before{content:""}.sharkicon-octi-squirrel::before{content:""}.sharkicon-octi-steps::before{content:""}.sharkicon-octi-tag::before{content:""}.sharkicon-octi-telescope::before{content:""}.sharkicon-octi-terminal::before{content:""}.sharkicon-octi-unfold::before{content:""}.sharkicon-octi-versions::before{content:""}.sharkicon-glass::before{content:""}.sharkicon-music::before{content:""}.sharkicon-search::before{content:""}.sharkicon-envelope-o::before{content:""}.sharkicon-heart::before{content:""}.sharkicon-star::before{content:""}.sharkicon-star-o::before{content:""}.sharkicon-user::before{content:""}.sharkicon-film::before{content:""}.sharkicon-th-large::before{content:""}.sharkicon-th::before{content:""}.sharkicon-th-list::before{content:""}.sharkicon-check::before{content:""}.sharkicon-close::before{content:""}.sharkicon-search-plus::before{content:""}.sharkicon-search-minus::before{content:""}.sharkicon-power-off::before{content:""}.sharkicon-signal::before{content:""}.sharkicon-cog::before{content:""}.sharkicon-trash-o::before{content:""}.sharkicon-home::before{content:""}.sharkicon-file-o::before{content:""}.sharkicon-clock-o::before{content:""}.sharkicon-road::before{content:""}.sharkicon-download::before{content:""}.sharkicon-arrow-circle-o-down::before{content:""}.sharkicon-arrow-circle-o-up::before{content:""}.sharkicon-inbox::before{content:""}.sharkicon-play-circle-o::before{content:""}.sharkicon-repeat::before{content:""}.sharkicon-refresh::before{content:""}.sharkicon-list-alt::before{content:""}.sharkicon-lock::before{content:""}.sharkicon-flag::before{content:""}.sharkicon-headphones::before{content:""}.sharkicon-volume-off::before{content:""}.sharkicon-volume-down::before{content:""}.sharkicon-volume-up::before{content:""}.sharkicon-qrcode::before{content:""}.sharkicon-barcode::before{content:""}.sharkicon-tag::before{content:""}.sharkicon-tags::before{content:""}.sharkicon-book::before{content:""}.sharkicon-bookmark::before{content:""}.sharkicon-print::before{content:""}.sharkicon-camera::before{content:""}.sharkicon-font::before{content:""}.sharkicon-bold::before{content:""}.sharkicon-italic::before{content:""}.sharkicon-text-height::before{content:""}.sharkicon-text-width::before{content:""}.sharkicon-align-left::before{content:""}.sharkicon-align-center::before{content:""}.sharkicon-align-right::before{content:""}.sharkicon-align-justify::before{content:""}.sharkicon-list::before{content:""}.sharkicon-dedent::before{content:""}.sharkicon-indent::before{content:""}.sharkicon-video-camera::before{content:""}.sharkicon-image::before{content:""}.sharkicon-pencil::before{content:""}.sharkicon-map-marker::before{content:""}.sharkicon-adjust::before{content:""}.sharkicon-tint::before{content:""}.sharkicon-edit::before{content:""}.sharkicon-share-square-o::before{content:""}.sharkicon-check-square-o::before{content:""}.sharkicon-arrows::before{content:""}.sharkicon-step-backward::before{content:""}.sharkicon-fast-backward::before{content:""}.sharkicon-backward::before{content:""}.sharkicon-play::before{content:""}.sharkicon-pause::before{content:""}.sharkicon-stop::before{content:""}.sharkicon-forward::before{content:""}.sharkicon-fast-forward::before{content:""}.sharkicon-step-forward::before{content:""}.sharkicon-eject::before{content:""}.sharkicon-chevron-left::before{content:""}.sharkicon-chevron-right::before{content:""}.sharkicon-plus-circle::before{content:""}.sharkicon-minus-circle::before{content:""}.sharkicon-times-circle::before{content:""}.sharkicon-check-circle::before{content:""}.sharkicon-question-circle::before{content:""}.sharkicon-info-circle::before{content:""}.sharkicon-crosshairs::before{content:""}.sharkicon-times-circle-o::before{content:""}.sharkicon-check-circle-o::before{content:""}.sharkicon-ban::before{content:""}.sharkicon-arrow-left::before{content:""}.sharkicon-arrow-right::before{content:""}.sharkicon-arrow-up::before{content:""}.sharkicon-arrow-down::before{content:""}.sharkicon-mail-forward::before{content:""}.sharkicon-expand::before{content:""}.sharkicon-compress::before{content:""}.sharkicon-plus::before{content:""}.sharkicon-minus::before{content:""}.sharkicon-asterisk::before{content:""}.sharkicon-exclamation-circle::before{content:""}.sharkicon-gift::before{content:""}.sharkicon-leaf::before{content:""}.sharkicon-fire::before{content:""}.sharkicon-eye::before{content:""}.sharkicon-eye-slash::before{content:""}.sharkicon-exclamation-triangle::before{content:""}.sharkicon-plane::before{content:""}.sharkicon-calendar::before{content:""}.sharkicon-random::before{content:""}.sharkicon-comment::before{content:""}.sharkicon-magnet::before{content:""}.sharkicon-chevron-up::before{content:""}.sharkicon-chevron-down::before{content:""}.sharkicon-retweet::before{content:""}.sharkicon-shopping-cart::before{content:""}.sharkicon-folder::before{content:""}.sharkicon-folder-open::before{content:""}.sharkicon-arrows-v::before{content:""}.sharkicon-arrows-h::before{content:""}.sharkicon-bar-chart::before{content:""}.sharkicon-twitter-square::before{content:""}.sharkicon-facebook-square::before{content:""}.sharkicon-camera-retro::before{content:""}.sharkicon-key::before{content:""}.sharkicon-cogs::before{content:""}.sharkicon-comments::before{content:""}.sharkicon-thumbs-o-up::before{content:""}.sharkicon-thumbs-o-down::before{content:""}.sharkicon-star-half::before{content:""}.sharkicon-heart-o::before{content:""}.sharkicon-sign-out::before{content:""}.sharkicon-linkedin-square::before{content:""}.sharkicon-thumb-tack::before{content:""}.sharkicon-external-link::before{content:""}.sharkicon-sign-in::before{content:""}.sharkicon-trophy::before{content:""}.sharkicon-github-square::before{content:""}.sharkicon-upload::before{content:""}.sharkicon-lemon-o::before{content:""}.sharkicon-phone::before{content:""}.sharkicon-square-o::before{content:""}.sharkicon-bookmark-o::before{content:""}.sharkicon-phone-square::before{content:""}.sharkicon-twitter::before{content:""}.sharkicon-facebook::before{content:""}.sharkicon-github::before{content:""}.sharkicon-unlock::before{content:""}.sharkicon-credit-card::before{content:""}.sharkicon-feed::before{content:""}.sharkicon-hdd-o::before{content:""}.sharkicon-bullhorn::before{content:""}.sharkicon-bell-o::before{content:""}.sharkicon-certificate::before{content:""}.sharkicon-hand-o-right::before{content:""}.sharkicon-hand-o-left::before{content:""}.sharkicon-hand-o-up::before{content:""}.sharkicon-hand-o-down::before{content:""}.sharkicon-arrow-circle-left::before{content:""}.sharkicon-arrow-circle-right::before{content:""}.sharkicon-arrow-circle-up::before{content:""}.sharkicon-arrow-circle-down::before{content:""}.sharkicon-globe::before{content:""}.sharkicon-wrench::before{content:""}.sharkicon-tasks::before{content:""}.sharkicon-filter::before{content:""}.sharkicon-briefcase::before{content:""}.sharkicon-arrows-alt::before{content:""}.sharkicon-group::before{content:""}.sharkicon-chain::before{content:""}.sharkicon-cloud::before{content:""}.sharkicon-flask::before{content:""}.sharkicon-cut::before{content:""}.sharkicon-copy::before{content:""}.sharkicon-paperclip::before{content:""}.sharkicon-floppy-o::before{content:""}.sharkicon-square::before{content:""}.sharkicon-bars::before{content:""}.sharkicon-list-ul::before{content:""}.sharkicon-list-ol::before{content:""}.sharkicon-strikethrough::before{content:""}.sharkicon-underline::before{content:""}.sharkicon-table::before{content:""}.sharkicon-magic::before{content:""}.sharkicon-truck::before{content:""}.sharkicon-pinterest::before{content:""}.sharkicon-pinterest-square::before{content:""}.sharkicon-google-plus-square::before{content:""}.sharkicon-google-plus::before{content:""}.sharkicon-money::before{content:""}.sharkicon-caret-down::before{content:""}.sharkicon-caret-up::before{content:""}.sharkicon-caret-left::before{content:""}.sharkicon-caret-right::before{content:""}.sharkicon-columns::before{content:""}.sharkicon-sort::before{content:""}.sharkicon-sort-desc::before{content:""}.sharkicon-sort-asc::before{content:""}.sharkicon-envelope::before{content:""}.sharkicon-linkedin::before{content:""}.sharkicon-rotate-left::before{content:""}.sharkicon-gavel::before{content:""}.sharkicon-dashboard::before{content:""}.sharkicon-comment-o::before{content:""}.sharkicon-comments-o::before{content:""}.sharkicon-bolt::before{content:""}.sharkicon-sitemap::before{content:""}.sharkicon-umbrella::before{content:""}.sharkicon-clipboard::before{content:""}.sharkicon-lightbulb-o::before{content:""}.sharkicon-exchange::before{content:""}.sharkicon-cloud-download::before{content:""}.sharkicon-cloud-upload::before{content:""}.sharkicon-user-md::before{content:""}.sharkicon-stethoscope::before{content:""}.sharkicon-suitcase::before{content:""}.sharkicon-bell::before{content:""}.sharkicon-coffee::before{content:""}.sharkicon-cutlery::before{content:""}.sharkicon-file-text-o::before{content:""}.sharkicon-building-o::before{content:""}.sharkicon-hospital-o::before{content:""}.sharkicon-ambulance::before{content:""}.sharkicon-medkit::before{content:""}.sharkicon-fighter-jet::before{content:""}.sharkicon-beer::before{content:""}.sharkicon-h-square::before{content:""}.sharkicon-plus-square::before{content:""}.sharkicon-angle-double-left::before{content:""}.sharkicon-angle-double-right::before{content:""}.sharkicon-angle-double-up::before{content:""}.sharkicon-angle-double-down::before{content:""}.sharkicon-angle-left::before{content:""}.sharkicon-angle-right::before{content:""}.sharkicon-angle-up::before{content:""}.sharkicon-angle-down::before{content:""}.sharkicon-desktop::before{content:""}.sharkicon-laptop::before{content:""}.sharkicon-tablet::before{content:""}.sharkicon-mobile::before{content:""}.sharkicon-circle-o::before{content:""}.sharkicon-quote-left::before{content:""}.sharkicon-quote-right::before{content:""}.sharkicon-spinner::before{content:""}.sharkicon-circle::before{content:""}.sharkicon-mail-reply::before{content:""}.sharkicon-github-alt::before{content:""}.sharkicon-folder-o::before{content:""}.sharkicon-folder-open-o::before{content:""}.sharkicon-smile-o::before{content:""}.sharkicon-frown-o::before{content:""}.sharkicon-meh-o::before{content:""}.sharkicon-gamepad::before{content:""}.sharkicon-keyboard-o::before{content:""}.sharkicon-flag-o::before{content:""}.sharkicon-flag-checkered::before{content:""}.sharkicon-terminal::before{content:""}.sharkicon-code::before{content:""}.sharkicon-mail-reply-all::before{content:""}.sharkicon-star-half-empty::before{content:""}.sharkicon-location-arrow::before{content:""}.sharkicon-crop::before{content:""}.sharkicon-code-fork::before{content:""}.sharkicon-chain-broken::before{content:""}.sharkicon-question::before{content:""}.sharkicon-info::before{content:""}.sharkicon-exclamation::before{content:""}.sharkicon-superscript::before{content:""}.sharkicon-subscript::before{content:""}.sharkicon-eraser::before{content:""}.sharkicon-puzzle-piece::before{content:""}.sharkicon-microphone::before{content:""}.sharkicon-microphone-slash::before{content:""}.sharkicon-shield::before{content:""}.sharkicon-calendar-o::before{content:""}.sharkicon-fire-extinguisher::before{content:""}.sharkicon-rocket::before{content:""}.sharkicon-maxcdn::before{content:""}.sharkicon-chevron-circle-left::before{content:""}.sharkicon-chevron-circle-right::before{content:""}.sharkicon-chevron-circle-up::before{content:""}.sharkicon-chevron-circle-down::before{content:""}.sharkicon-html5::before{content:""}.sharkicon-css3::before{content:""}.sharkicon-anchor::before{content:""}.sharkicon-unlock-alt::before{content:""}.sharkicon-bullseye::before{content:""}.sharkicon-ellipsis-h::before{content:""}.sharkicon-ellipsis-v::before{content:""}.sharkicon-rss-square::before{content:""}.sharkicon-play-circle::before{content:""}.sharkicon-ticket::before{content:""}.sharkicon-minus-square::before{content:""}.sharkicon-minus-square-o::before{content:""}.sharkicon-level-up::before{content:""}.sharkicon-level-down::before{content:""}.sharkicon-check-square::before{content:""}.sharkicon-pencil-square::before{content:""}.sharkicon-external-link-square::before{content:""}.sharkicon-share-square::before{content:""}.sharkicon-compass::before{content:""}.sharkicon-caret-square-o-down::before{content:""}.sharkicon-caret-square-o-up::before{content:""}.sharkicon-caret-square-o-right::before{content:""}.sharkicon-eur::before{content:""}.sharkicon-gbp::before{content:""}.sharkicon-dollar::before{content:""}.sharkicon-inr::before{content:""}.sharkicon-cny::before{content:""}.sharkicon-rouble::before{content:""}.sharkicon-krw::before{content:""}.sharkicon-bitcoin::before{content:""}.sharkicon-file::before{content:""}.sharkicon-file-text::before{content:""}.sharkicon-sort-alpha-asc::before{content:""}.sharkicon-sort-alpha-desc::before{content:""}.sharkicon-sort-amount-asc::before{content:""}.sharkicon-sort-amount-desc::before{content:""}.sharkicon-sort-numeric-asc::before{content:""}.sharkicon-sort-numeric-desc::before{content:""}.sharkicon-thumbs-up::before{content:""}.sharkicon-thumbs-down::before{content:""}.sharkicon-youtube-square::before{content:""}.sharkicon-youtube::before{content:""}.sharkicon-xing::before{content:""}.sharkicon-xing-square::before{content:""}.sharkicon-youtube-play::before{content:""}.sharkicon-dropbox::before{content:""}.sharkicon-stack-overflow::before{content:""}.sharkicon-instagram::before{content:""}.sharkicon-flickr::before{content:""}.sharkicon-adn::before{content:""}.sharkicon-bitbucket::before{content:""}.sharkicon-bitbucket-square::before{content:""}.sharkicon-tumblr::before{content:""}.sharkicon-tumblr-square::before{content:""}.sharkicon-long-arrow-down::before{content:""}.sharkicon-long-arrow-up::before{content:""}.sharkicon-long-arrow-left::before{content:""}.sharkicon-long-arrow-right::before{content:""}.sharkicon-apple::before{content:""}.sharkicon-windows::before{content:""}.sharkicon-android::before{content:""}.sharkicon-linux::before{content:""}.sharkicon-dribbble::before{content:""}.sharkicon-skype::before{content:""}.sharkicon-foursquare::before{content:""}.sharkicon-trello::before{content:""}.sharkicon-female::before{content:""}.sharkicon-male::before{content:""}.sharkicon-gittip::before{content:""}.sharkicon-sun-o::before{content:""}.sharkicon-moon-o::before{content:""}.sharkicon-archive::before{content:""}.sharkicon-bug::before{content:""}.sharkicon-vk::before{content:""}.sharkicon-weibo::before{content:""}.sharkicon-renren::before{content:""}.sharkicon-pagelines::before{content:""}.sharkicon-stack-exchange::before{content:""}.sharkicon-arrow-circle-o-right::before{content:""}.sharkicon-arrow-circle-o-left::before{content:""}.sharkicon-caret-square-o-left::before{content:""}.sharkicon-dot-circle-o::before{content:""}.sharkicon-wheelchair::before{content:""}.sharkicon-vimeo-square::before{content:""}.sharkicon-try::before{content:""}.sharkicon-plus-square-o::before{content:""}.sharkicon-space-shuttle::before{content:""}.sharkicon-slack::before{content:""}.sharkicon-envelope-square::before{content:""}.sharkicon-wordpress::before{content:""}.sharkicon-openid::before{content:""}.sharkicon-bank::before{content:""}.sharkicon-graduation-cap::before{content:""}.sharkicon-yahoo::before{content:""}.sharkicon-google::before{content:""}.sharkicon-reddit::before{content:""}.sharkicon-reddit-square::before{content:""}.sharkicon-stumbleupon-circle::before{content:""}.sharkicon-stumbleupon::before{content:""}.sharkicon-delicious::before{content:""}.sharkicon-digg::before{content:""}.sharkicon-pied-piper::before{content:""}.sharkicon-pied-piper-alt::before{content:""}.sharkicon-drupal::before{content:""}.sharkicon-joomla::before{content:""}.sharkicon-language::before{content:""}.sharkicon-fax::before{content:""}.sharkicon-building::before{content:""}.sharkicon-child::before{content:""}.sharkicon-paw::before{content:""}.sharkicon-spoon::before{content:""}.sharkicon-cube::before{content:""}.sharkicon-cubes::before{content:""}.sharkicon-behance::before{content:""}.sharkicon-behance-square::before{content:""}.sharkicon-steam::before{content:""}.sharkicon-steam-square::before{content:""}.sharkicon-recycle::before{content:""}.sharkicon-automobile::before{content:""}.sharkicon-cab::before{content:""}.sharkicon-tree::before{content:""}.sharkicon-spotify::before{content:""}.sharkicon-deviantart::before{content:""}.sharkicon-soundcloud::before{content:""}.sharkicon-database::before{content:""}.sharkicon-file-pdf-o::before{content:""}.sharkicon-file-word-o::before{content:""}.sharkicon-file-excel-o::before{content:""}.sharkicon-file-powerpoint-o::before{content:""}.sharkicon-file-image-o::before{content:""}.sharkicon-file-archive-o::before{content:""}.sharkicon-file-audio-o::before{content:""}.sharkicon-file-movie-o::before{content:""}.sharkicon-file-code-o::before{content:""}.sharkicon-vine::before{content:""}.sharkicon-codepen::before{content:""}.sharkicon-jsfiddle::before{content:""}.sharkicon-life-bouy::before{content:""}.sharkicon-circle-o-notch::before{content:""}.sharkicon-ra::before{content:""}.sharkicon-empire::before{content:""}.sharkicon-git-square::before{content:""}.sharkicon-git::before{content:""}.sharkicon-hacker-news::before{content:""}.sharkicon-tencent-weibo::before{content:""}.sharkicon-qq::before{content:""}.sharkicon-wechat::before{content:""}.sharkicon-paper-plane::before{content:""}.sharkicon-paper-plane-o::before{content:""}.sharkicon-history::before{content:""}.sharkicon-circle-thin::before{content:""}.sharkicon-header::before{content:""}.sharkicon-paragraph::before{content:""}.sharkicon-sliders::before{content:""}.sharkicon-share-alt::before{content:""}.sharkicon-share-alt-square::before{content:""}.sharkicon-bomb::before{content:""}.sharkicon-futbol-o::before{content:""}.sharkicon-tty::before{content:""}.sharkicon-binoculars::before{content:""}.sharkicon-plug::before{content:""}.sharkicon-slideshare::before{content:""}.sharkicon-twitch::before{content:""}.sharkicon-yelp::before{content:""}.sharkicon-newspaper-o::before{content:""}.sharkicon-wifi::before{content:""}.sharkicon-calculator::before{content:""}.sharkicon-paypal::before{content:""}.sharkicon-google-wallet::before{content:""}.sharkicon-cc-visa::before{content:""}.sharkicon-cc-mastercard::before{content:""}.sharkicon-cc-discover::before{content:""}.sharkicon-cc-amex::before{content:""}.sharkicon-cc-paypal::before{content:""}.sharkicon-cc-stripe::before{content:""}.sharkicon-bell-slash::before{content:""}.sharkicon-bell-slash-o::before{content:""}.sharkicon-trash::before{content:""}.sharkicon-copyright::before{content:""}.sharkicon-at::before{content:""}.sharkicon-eyedropper::before{content:""}.sharkicon-paint-brush::before{content:""}.sharkicon-birthday-cake::before{content:""}.sharkicon-area-chart::before{content:""}.sharkicon-pie-chart::before{content:""}.sharkicon-line-chart::before{content:""}.sharkicon-lastfm::before{content:""}.sharkicon-lastfm-square::before{content:""}.sharkicon-toggle-off::before{content:""}.sharkicon-toggle-on::before{content:""}.sharkicon-bicycle::before{content:""}.sharkicon-bus::before{content:""}.sharkicon-ioxhost::before{content:""}.sharkicon-angellist::before{content:""}.sharkicon-cc::before{content:""}.sharkicon-ils::before{content:""}.sharkicon-meanpath::before{content:""}.sharkicon-buysellads::before{content:""}.sharkicon-connectdevelop::before{content:""}.sharkicon-dashcube::before{content:""}.sharkicon-forumbee::before{content:""}.sharkicon-leanpub::before{content:""}.sharkicon-sellsy::before{content:""}.sharkicon-shirtsinbulk::before{content:""}.sharkicon-simplybuilt::before{content:""}.sharkicon-skyatlas::before{content:""}.sharkicon-cart-plus::before{content:""}.sharkicon-cart-arrow-down::before{content:""}.sharkicon-diamond::before{content:""}.sharkicon-ship::before{content:""}.sharkicon-user-secret::before{content:""}.sharkicon-motorcycle::before{content:""}.sharkicon-street-view::before{content:""}.sharkicon-heartbeat::before{content:""}.sharkicon-venus::before{content:""}.sharkicon-mars::before{content:""}.sharkicon-mercury::before{content:""}.sharkicon-intersex::before{content:""}.sharkicon-transgender-alt::before{content:""}.sharkicon-venus-double::before{content:""}.sharkicon-mars-double::before{content:""}.sharkicon-venus-mars::before{content:""}.sharkicon-mars-stroke::before{content:""}.sharkicon-mars-stroke-v::before{content:""}.sharkicon-mars-stroke-h::before{content:""}.sharkicon-neuter::before{content:""}.sharkicon-genderless::before{content:""}.sharkicon-facebook-official::before{content:""}.sharkicon-pinterest-p::before{content:""}.sharkicon-whatsapp::before{content:""}.sharkicon-server::before{content:""}.sharkicon-user-plus::before{content:""}.sharkicon-user-times::before{content:""}.sharkicon-bed::before{content:""}.sharkicon-viacoin::before{content:""}.sharkicon-train::before{content:""}.sharkicon-subway::before{content:""}.sharkicon-medium::before{content:""}.sharkicon-y-combinator::before{content:""}.sharkicon-optin-monster::before{content:""}.sharkicon-opencart::before{content:""}.sharkicon-expeditedssl::before{content:""}.sharkicon-battery-4::before{content:""}.sharkicon-battery-3::before{content:""}.sharkicon-battery-2::before{content:""}.sharkicon-battery-1::before{content:""}.sharkicon-battery-0::before{content:""}.sharkicon-mouse-pointer::before{content:""}.sharkicon-i-cursor::before{content:""}.sharkicon-object-group::before{content:""}.sharkicon-object-ungroup::before{content:""}.sharkicon-sticky-note::before{content:""}.sharkicon-sticky-note-o::before{content:""}.sharkicon-cc-jcb::before{content:""}.sharkicon-cc-diners-club::before{content:""}.sharkicon-clone::before{content:""}.sharkicon-balance-scale::before{content:""}.sharkicon-hourglass-o::before{content:""}.sharkicon-hourglass-1::before{content:""}.sharkicon-hourglass-2::before{content:""}.sharkicon-hourglass-3::before{content:""}.sharkicon-hourglass::before{content:""}.sharkicon-hand-grab-o::before{content:""}.sharkicon-hand-paper-o::before{content:""}.sharkicon-hand-scissors-o::before{content:""}.sharkicon-hand-lizard-o::before{content:""}.sharkicon-hand-spock-o::before{content:""}.sharkicon-hand-pointer-o::before{content:""}.sharkicon-hand-peace-o::before{content:""}.sharkicon-trademark::before{content:""}.sharkicon-registered::before{content:""}.sharkicon-creative-commons::before{content:""}.sharkicon-gg::before{content:""}.sharkicon-gg-circle::before{content:""}.sharkicon-tripadvisor::before{content:""}.sharkicon-odnoklassniki::before{content:""}.sharkicon-odnoklassniki-square::before{content:""}.sharkicon-get-pocket::before{content:""}.sharkicon-wikipedia-w::before{content:""}.sharkicon-safari::before{content:""}.sharkicon-chrome::before{content:""}.sharkicon-firefox::before{content:""}.sharkicon-opera::before{content:""}.sharkicon-internet-explorer::before{content:""}.sharkicon-television::before{content:""}.sharkicon-contao::before{content:""}.sharkicon-500px::before{content:""}.sharkicon-amazon::before{content:""}.sharkicon-calendar-plus-o::before{content:""}.sharkicon-calendar-minus-o::before{content:""}.sharkicon-calendar-times-o::before{content:""}.sharkicon-calendar-check-o::before{content:""}.sharkicon-industry::before{content:""}.sharkicon-map-pin::before{content:""}.sharkicon-map-signs::before{content:""}.sharkicon-map-o::before{content:""}.sharkicon-map::before{content:""}.sharkicon-commenting::before{content:""}.sharkicon-commenting-o::before{content:""}.sharkicon-houzz::before{content:""}.sharkicon-vimeo::before{content:""}.sharkicon-black-tie::before{content:""}.sharkicon-fonticons::before{content:""}.sharkicon-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.sharkicon-2x{font-size:2em}.sharkicon-3x{font-size:3em}.sharkicon-4x{font-size:4em}.sharkicon-5x{font-size:5em}.sharkicon-fw{text-align:center;width:1.28571429em}.sharkicon-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.sharkicon-pull-left{float:left;margin-right:.3em}.sharkicon-pull-right{float:right;margin-left:.3em}.sharkicon-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.sharkicon-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.sharkicon-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.sharkicon-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.sharkicon-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.sharkicon-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.sharkicon-spin{-webkit-animation:sharkicon-animation-spin 2s infinite linear;-moz-animation:sharkicon-animation-spin 2s infinite linear;animation:sharkicon-animation-spin 2s infinite linear}.sharkicon-pulse{-webkit-animation:sharkicon-animation-spin 1s infinite steps(8);-moz-animation:sharkicon-animation-spin 1s infinite steps(8);animation:sharkicon-animation-spin 1s infinite steps(8)}.sharkicon-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.sharkicon-ul>li{position:relative}.sharkicon-ul>li .sharkicon-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.sharkicon-ul>li .sharkicon-li .sharkicon-lg{left:-1.85714286em}.sharkicon-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.sharkicon-stack .sharkicon-stack-1x,.sharkicon-stack .sharkicon-stack-2x{left:0;width:100%;text-align:center;position:absolute}.sharkicon-stack .sharkicon-stack-1x{line-height:inherit}.sharkicon-stack .sharkicon-stack-2x{font-size:2em}@-webkit-keyframes sharkicon-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes sharkicon-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes sharkicon-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}
2
 
 
src/vendor/websharks/sharkicons/src/short-classes.min.css CHANGED
@@ -1,3 +1,2 @@
1
  @font-face{font-family:sharkicons;src:url("fonts/sharkicons.eot?v160221");src:url("fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("fonts/sharkicons.ttf?v160221") format("truetype"),url("fonts/sharkicons.woff?v160221") format("woff"),url("fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}
2
 
3
- /*# sourceMappingURL=short-classes.min.css.map */
1
  @font-face{font-family:sharkicons;src:url("fonts/sharkicons.eot?v160221");src:url("fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("fonts/sharkicons.ttf?v160221") format("truetype"),url("fonts/sharkicons.woff?v160221") format("woff"),url("fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}
2
 
 
src/vendor/websharks/wp-i18n-tools/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ ## v15xxxx
2
+
3
+ - Initial release.
src/vendor/websharks/wp-i18n-tools/README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## WP i18n Tools
2
+
3
+ Modified slightly by WebSharks, Inc.
4
+
5
+ #### Differences from original:
6
+
7
+ - Adding shebang line to the top of `makepot.php`.
8
+ - Now distributing a packaged PHAR binary w/ each release.
9
+ - Setting executable bit on `makepot.php` and preserving that with Git.
10
+ - Updated to support PHP/translations embedded into `.js` files too.
11
+ - Disabling line wrapping from final output to ensure better consistency.
12
+ - Adding support for plugin directories that use a `plugin.php` file instead of `[slug].php`.
13
+ - Adding `composer.json` and package on Packagist.org.
14
+ - Auto-exclude `(?:.+?/)?vendor/.*` in themes/plugins.
src/vendor/websharks/wp-i18n-tools/add-textdomain.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Console application, which adds textdomain argument
4
+ * to all i18n function calls
5
+ *
6
+ * @author
7
+ * @version $Id$
8
+ * @package wordpress-i18n
9
+ */
10
+ error_reporting(E_ALL);
11
+
12
+ require_once dirname( __FILE__ ) . '/makepot.php';
13
+
14
+ class AddTextdomain {
15
+
16
+ var $modified_contents = '';
17
+ var $funcs;
18
+
19
+ function AddTextdomain() {
20
+ $makepot = new MakePOT;
21
+ $this->funcs = array_keys( $makepot->rules );
22
+ }
23
+
24
+ function usage() {
25
+ $usage = "Usage: php add-textdomain.php [-i] <domain> <file>\n\nAdds the string <domain> as a last argument to all i18n function calls in <file>\nand prints the modified php file on standard output.\n\nOptions:\n -i Modifies the PHP file in place, instead of printing it to standard output.\n";
26
+ fwrite(STDERR, $usage);
27
+ exit(1);
28
+ }
29
+
30
+ function process_token($token_text, $inplace) {
31
+ if ($inplace)
32
+ $this->modified_contents .= $token_text;
33
+ else
34
+ echo $token_text;
35
+ }
36
+
37
+
38
+ function process_file($domain, $source_filename, $inplace) {
39
+
40
+ $this->modified_contents = '';
41
+ $domain = addslashes($domain);
42
+
43
+ $source = file_get_contents($source_filename);
44
+ $tokens = token_get_all($source);
45
+
46
+ $in_func = false;
47
+ $args_started = false;
48
+ $parens_balance = 0;
49
+ $found_domain = false;
50
+
51
+ foreach($tokens as $token) {
52
+ $string_success = false;
53
+ if (is_array($token)) {
54
+ list($id, $text) = $token;
55
+ if (T_STRING == $id && in_array($text, $this->funcs)) {
56
+ $in_func = true;
57
+ $parens_balance = 0;
58
+ $args_started = false;
59
+ $found_domain = false;
60
+ } elseif (T_CONSTANT_ENCAPSED_STRING == $id && ("'$domain'" == $text || "\"$domain\"" == $text)) {
61
+ if ($in_func && $args_started) {
62
+ $found_domain = true;
63
+ }
64
+ }
65
+ $token = $text;
66
+ } elseif ('(' == $token){
67
+ $args_started = true;
68
+ ++$parens_balance;
69
+ } elseif (')' == $token) {
70
+ --$parens_balance;
71
+ if ($in_func && 0 == $parens_balance) {
72
+ $token = $found_domain? ')' : ", '$domain')";
73
+ $in_func = false;
74
+ $args_started = false;
75
+ $found_domain = false;
76
+ }
77
+ }
78
+ $this->process_token($token, $inplace);
79
+ }
80
+
81
+ if ($inplace) {
82
+ $f = fopen($source_filename, 'w');
83
+ fwrite($f, $this->modified_contents);
84
+ fclose($f);
85
+ }
86
+ }
87
+ }
88
+
89
+
90
+ // run the CLI only if the file
91
+ // wasn't included
92
+ $included_files = get_included_files();
93
+ if ($included_files[0] == __FILE__) {
94
+ $adddomain = new AddTextdomain;
95
+
96
+ if (!isset($argv[1]) || !isset($argv[2])) {
97
+ $adddomain->usage();
98
+ }
99
+
100
+ $inplace = false;
101
+ if ('-i' == $argv[1]) {
102
+ $inplace = true;
103
+ if (!isset($argv[3])) $adddomain->usage();
104
+ array_shift($argv);
105
+ }
106
+
107
+ $adddomain->process_file($argv[1], $argv[2], $inplace);
108
+ }
109
+
110
+ ?>
src/vendor/websharks/wp-i18n-tools/cron-svn-pots.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once dirname( __FILE__ ) . '/makepot.php';
3
+
4
+ function silent_system( $command ) {
5
+ global $at_least_one_error;
6
+ ob_start();
7
+ system( "$command 2>&1", $exit_code );
8
+ $output = ob_get_contents();
9
+ ob_end_clean();
10
+ if ( $exit_code != 0 ) {
11
+ echo "ERROR:\t$command\nCODE:\t$exit_code\nOUTPUT:\n";
12
+ echo $output."\n";
13
+ } else {
14
+ echo "OK:\t$command\n";
15
+ }
16
+ return $exit_code;
17
+ }
18
+
19
+
20
+ $options = getopt( 'c:p:m:n:sa:b:u:w:df' );
21
+ if ( empty( $options ) ) {
22
+ ?>
23
+ -s No branch/version directories, it's all flat
24
+ -c Application svn checkout
25
+ -p POT svn checkout
26
+ -m MakePOT project
27
+ -n POT filename
28
+ -a Relative path of application inside version dir in -c
29
+ -b Relative patch of POT dir inside version dir in -p
30
+ -u SVN username (optional)
31
+ -w SVN password (optional)
32
+ -d Dry-run
33
+ -f Fast - do not update checkouts
34
+ <?php
35
+ die;
36
+ }
37
+
38
+ $application_svn_checkout = realpath( $options['c'] );
39
+ $pot_svn_checkout = realpath( $options['p'] );
40
+ $makepot_project = str_replace( '-', '_', $options['m'] );
41
+ $pot_name = $options['n'];
42
+ $no_branch_dirs = isset( $options['s'] );
43
+ $relative_application_path = isset( $options['a'] )? '/'.$options['a'] : '';
44
+ $relative_pot_path = isset( $options['b'] )? '/'.$options['b'] : '';
45
+ $dry_run = isset( $options['d'] );
46
+
47
+ $makepot = new MakePOT;
48
+ $svn_args = array('--non-interactive');
49
+ if ( isset( $options['u'] ) && isset( $options['w'] ) ) {
50
+ $svn_args[] = '--username='.$options['u'];
51
+ $svn_args[] = '--password='.$options['w'];
52
+ $svn_args[] = '--no-auth-cache';
53
+ }
54
+ $svn_args_str = implode( ' ', array_map( 'escapeshellarg', $svn_args ) );
55
+ $svn = 'svn '.$svn_args_str;
56
+
57
+
58
+ $versions = array();
59
+
60
+ chdir( $application_svn_checkout );
61
+ if ( ! isset( $options['f'] ) ) {
62
+ $exit = silent_system( "$svn cleanup" );
63
+ if ( 0 != $exit ) die();
64
+ $exit = silent_system( "$svn up" );
65
+ if ( 0 != $exit ) die();
66
+ }
67
+ if ( is_dir( 'trunk' ) ) $versions[] = 'trunk';
68
+ $branches = glob( 'branches/*' );
69
+ if ( false !== $branches ) $versions = array_merge( $versions, $branches );
70
+ $tags = glob( 'tags/*' );
71
+ if ( false !== $tags ) $versions = array_merge( $versions, $tags );
72
+
73
+ if ( $no_branch_dirs ) {
74
+ $versions = array( '.' );
75
+ }
76
+
77
+ chdir( $pot_svn_checkout );
78
+ if ( $application_svn_checkout != $pot_svn_checkout && ! isset( $options['f'] ) ) {
79
+ $exit = silent_system( "$svn cleanup" );
80
+ if ( 0 != $exit ) die();
81
+ $exit = silent_system( "$svn up" );
82
+ if ( 0 != $exit ) die();
83
+ }
84
+ $real_application_svn_checkout = realpath( $application_svn_checkout );
85
+ foreach( $versions as $version ) {
86
+ $application_path = "$real_application_svn_checkout/$version{$relative_application_path}";
87
+ if ( !is_dir( $application_path ) ) continue;
88
+ $pot = "$version{$relative_pot_path}/$pot_name";
89
+ $exists = is_file( $pot );
90
+ // do not update old tag pots
91
+ if ( 'tags/' == substr( $version, 0, 5 ) && $exists ) continue;
92
+ if ( !is_dir( $version ) ) {
93
+ $exit = silent_system( "$svn mkdir $version" );
94
+ if ( 0 != $exit ) continue;
95
+ }
96
+ if ( !is_dir(dirname("$pot_svn_checkout/$pot")) ) continue;
97
+ if ( !call_user_func( array( &$makepot, $makepot_project ), $application_path, "$pot_svn_checkout/$pot" ) ) continue;
98
+ if ( !file_exists( "$pot_svn_checkout/$pot" ) ) continue;
99
+ if ( !$exists ) {
100
+ $exit = silent_system( "$svn add $pot" );
101
+ if ( 0 != $exit ) continue;
102
+ }
103
+ // do not commit if the difference is only in the header, but always commit a new file
104
+ $real_differences = `svn diff $pot | wc -l` > 16;
105
+ $target = $exists ? $pot : $version;
106
+ if ( !$exists || $real_differences ) {
107
+ preg_match( '/Revision:\s+(\d+)/', `svn info $application_path`, $matches );
108
+ $logmsg = isset( $matches[1] ) && intval( $matches[1] )? "POT, generated from r".intval( $matches[1] ) : 'Automatic POT update';
109
+ $command = "$svn ci $target --non-interactive --message='$logmsg'";
110
+ if ( !$dry_run )
111
+ silent_system( $command );
112
+ else
113
+ echo "CMD:\t$command\n";
114
+ } else {
115
+ silent_system( "$svn revert $target" );
116
+ }
117
+ }
src/vendor/websharks/wp-i18n-tools/extract/ExtractTest.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname( __FILE__ ) . '/extract.php';
4
+
5
+ class ExtractTest extends PHPUnit_Framework_TestCase {
6
+
7
+ function setUp() {
8
+ $this->extractor = new StringExtractor;
9
+ $this->extractor->rules = array(
10
+ '__' => array('string'),
11
+ );
12
+ }
13
+
14
+ function test_with_just_a_string() {
15
+ $expected = new Translation_Entry( array( 'singular' => 'baba', 'references' => array('baba.php:1') ) );
16
+ $result = $this->extractor->extract_entries('<?php __("baba"); ?>', 'baba.php' );
17
+ $this->assertEquals( $expected, $result->entries['baba'] );
18
+ }
19
+
20
+ function test_entry_from_call_simple() {
21
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba') ), 'baba.php' );
22
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba' ) ) );
23
+ }
24
+
25
+ function test_entry_from_call_nonexisting_function() {
26
+ $entry = $this->extractor->entry_from_call( array( 'name' => 'f', 'args' => array('baba') ), 'baba.php' );
27
+ $this->assertEquals( $entry, null );
28
+ }
29
+
30
+ function test_entry_from_call_too_few_args() {
31
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array() ), 'baba.php' );
32
+ $this->assertEquals( $entry, null );
33
+ }
34
+
35
+ function test_entry_from_call_non_expected_null_arg() {
36
+ $this->extractor->rules = array( '_nx' => array( 'singular', 'plural', 'context' ) );
37
+ $entry = $this->extractor->entry_from_call( array( 'name' => '_nx', 'args' => array('%s baba', null, 'noun') ), 'baba.php' );
38
+ $this->assertEquals( $entry, null );
39
+ }
40
+
41
+ function test_entry_from_call_more_args_should_be_ok() {
42
+ $this->extractor->rules = array( '__' => array('string') );
43
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba', 5, 'pijo', null) ), 'baba.php' );
44
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba' ) ) );
45
+ }
46
+
47
+
48
+ function test_entry_from_call_context() {
49
+ $this->extractor->rules = array( '_x' => array( 'string', 'context' ) );
50
+ $entry = $this->extractor->entry_from_call( array( 'name' => '_x', 'args' => array('baba', 'noun') ), 'baba.php' );
51
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'context' => 'noun' ) ) );
52
+ }
53
+
54
+ function test_entry_from_call_plural() {
55
+ $this->extractor->rules = array( '_n' => array( 'singular', 'plural' ) );
56
+ $entry = $this->extractor->entry_from_call( array( 'name' => '_n', 'args' => array('%s baba', '%s babas') ), 'baba.php' );
57
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '%s baba', 'plural' => '%s babas' ) ) );
58
+ }
59
+
60
+ function test_entry_from_call_plural_and_context() {
61
+ $this->extractor->rules = array( '_nx' => array( 'singular', 'plural', 'context' ) );
62
+ $entry = $this->extractor->entry_from_call( array( 'name' => '_nx', 'args' => array('%s baba', '%s babas', 'noun') ), 'baba.php' );
63
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '%s baba', 'plural' => '%s babas', 'context' => 'noun' ) ) );
64
+ }
65
+
66
+ function test_entry_from_call_extracted_comment() {
67
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba'), 'comment' => 'translators: give me back my pants!' ), 'baba.php' );
68
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'extracted_comments' => "translators: give me back my pants!\n" ) ) );
69
+ }
70
+
71
+ function test_entry_from_call_line_number() {
72
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba'), 'line' => 10 ), 'baba.php' );
73
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'references' => array('baba.php:10') ) ) );
74
+ }
75
+
76
+ function test_entry_from_call_zero() {
77
+ $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('0') ), 'baba.php' );
78
+ $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '0' ) ) );
79
+ }
80
+
81
+ function test_entry_from_call_multiple() {
82
+ $this->extractor->rules = array( 'c' => array( 'string', 'singular', 'plural' ) );
83
+ $entries = $this->extractor->entry_from_call( array( 'name' => 'c', 'args' => array('baba', 'dyado', 'dyados') ), 'baba.php' );
84
+ $this->assertEquals( array(
85
+ new Translation_Entry( array( 'singular' => 'baba' ) ), new Translation_Entry( array( 'singular' => 'dyado', 'plural' => 'dyados' ) ) ), $entries );
86
+ }
87
+
88
+ function test_entry_from_call_multiple_first_plural_then_two_strings() {
89
+ $this->extractor->rules = array( 'c' => array( 'singular', 'plural', null, 'string', 'string' ) );
90
+ $entries = $this->extractor->entry_from_call( array( 'name' => 'c', 'args' => array('dyado', 'dyados', 'baba', 'foo', 'bar') ), 'baba.php' );
91
+ $this->assertEquals( array(
92
+ new Translation_Entry( array( 'singular' => 'dyado', 'plural' => 'dyados' ) ),
93
+ new Translation_Entry( array( 'singular' => 'foo' ) ),
94
+ new Translation_Entry( array( 'singular' => 'bar' ) ) ), $entries );
95
+ }
96
+
97
+ function test_find_function_calls_one_arg_literal() {
98
+ $this->assertEquals( array( array( 'name' => '__', 'args' => array( 'baba' ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("baba"); ?>' ) );
99
+ }
100
+
101
+ function test_find_function_calls_one_arg_zero() {
102
+ $this->assertEquals( array( array( 'name' => '__', 'args' => array( '0' ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("0"); ?>' ) );
103
+ }
104
+
105
+ function test_find_function_calls_one_arg_non_literal() {
106
+ $this->assertEquals( array( array( 'name' => '__', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("baba" . "dudu"); ?>' ) );
107
+ }
108
+
109
+ function test_find_function_calls_shouldnt_be_mistaken_by_a_class() {
110
+ $this->assertEquals( array(), $this->extractor->find_function_calls( array('__'), '<?php class __ { }; ("dyado");' ) );
111
+ }
112
+
113
+ function test_find_function_calls_2_args_bad_literal() {
114
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba" ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f(5, "baba" ); ' ) );
115
+ }
116
+
117
+ function test_find_function_calls_2_args_bad_literal_bad() {
118
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba", null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f(5, "baba", 5 ); ' ) );
119
+ }
120
+
121
+ function test_find_function_calls_1_arg_bad_concat() {
122
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( "baba" . "baba" ); ' ) );
123
+ }
124
+
125
+ function test_find_function_calls_1_arg_bad_function_call() {
126
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( g( "baba" ) ); ' ) );
127
+ }
128
+
129
+ function test_find_function_calls_2_arg_literal_bad() {
130
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( "baba", null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( "baba", null ); ' ) );
131
+ }
132
+
133
+ function test_find_function_calls_2_arg_bad_with_parens_literal() {
134
+ $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba" ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( g( "dyado", "chicho", "lelya "), "baba" ); ' ) );
135
+ }
136
+
137
+ function test_find_function_calls_with_comment() {
138
+ $this->assertEquals(
139
+ array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
140
+ $this->extractor->find_function_calls( array('f'), '<?php /* translators: let your ears fly! */ f( "baba" ); ' ) );
141
+ }
142
+
143
+ function test_find_function_calls_with_not_immediate_comment() {
144
+ $this->assertEquals(
145
+ array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
146
+ $this->extractor->find_function_calls( array('f'), '<?php /* translators: let your ears fly! */ $foo = g ( f( "baba" ) ); ' ) );
147
+ }
148
+
149
+ function test_find_function_calls_with_not_immediate_comment_include_only_latest() {
150
+ $this->assertEquals(
151
+ array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
152
+ $this->extractor->find_function_calls( array('f'), '<?php /* translators: boo */ /* translators: let your ears fly! */ /* baba */ $foo = g ( f( "baba" ) ); ' ) );
153
+ }
154
+
155
+ function test_comment_prefix_should_be_case_insensitive() {
156
+ $this->assertEquals(
157
+ array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'Translators: let your ears fly!' ) ),
158
+ $this->extractor->find_function_calls( array('f'), '<?php /* Translators: let your ears fly! */ f( "baba" ); ' ) );
159
+ }
160
+ }
src/vendor/websharks/wp-i18n-tools/extract/TODO ADDED
@@ -0,0 +1 @@
 
1
+ * php-format
src/vendor/websharks/wp-i18n-tools/extract/extract.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once dirname( __FILE__ ) . '/../pomo/entry.php';
3
+ require_once dirname( __FILE__ ) . '/../pomo/translations.php';
4
+
5
+ class StringExtractor {
6
+
7
+ var $rules = array();
8
+ var $comment_prefix = 'translators:';
9
+
10
+ function __construct( $rules = array() ) {
11
+ $this->rules = $rules;
12
+ }
13
+
14
+ function extract_from_directory( $dir, $excludes = array(), $includes = array(), $prefix = '' ) {
15
+ $old_cwd = getcwd();
16
+ chdir( $dir );
17
+ $translations = new Translations;
18
+ $file_names = (array) scandir( '.' );
19
+ foreach ( $file_names as $file_name ) {
20
+ if ( '.' == $file_name || '..' == $file_name ) continue;
21
+ if ( preg_match( '/\.(?:php|js)$/', $file_name ) && $this->does_file_name_match( $prefix . $file_name, $excludes, $includes ) ) {
22
+ $translations->merge_originals_with( $this->extract_from_file( $file_name, $prefix ) );
23
+ }
24
+ if ( is_dir( $file_name ) ) {
25
+ $translations->merge_originals_with( $this->extract_from_directory( $file_name, $excludes, $includes, $prefix . $file_name . '/' ) );
26
+ }
27
+ }
28
+ chdir( $old_cwd );
29
+ return $translations;
30
+ }
31
+
32
+ function extract_from_file( $file_name, $prefix ) {
33
+ $code = file_get_contents( $file_name );
34
+ return $this->extract_entries( $code, $prefix . $file_name );
35
+ }
36
+
37
+ function does_file_name_match( $path, $excludes, $includes ) {
38
+ if ( $includes ) {
39
+ $matched_any_include = false;
40
+ foreach( $includes as $include ) {
41
+ if ( preg_match( '|^'.$include.'$|', $path ) ) {
42
+ $matched_any_include = true;
43
+ break;
44
+ }
45
+ }
46
+ if ( !$matched_any_include ) return false;
47
+ }
48
+ if ( $excludes ) {
49
+ foreach( $excludes as $exclude ) {
50
+ if ( preg_match( '|^'.$exclude.'$|', $path ) ) {
51
+ return false;
52
+ }
53
+ }
54
+ }
55
+ return true;
56
+ }
57
+
58
+ function entry_from_call( $call, $file_name ) {
59
+ $rule = isset( $this->rules[$call['name']] )? $this->rules[$call['name']] : null;
60
+ if ( !$rule ) return null;
61
+ $entry = new Translation_Entry;
62
+ $multiple = array();
63
+ $complete = false;
64
+ for( $i = 0; $i < count( $rule ); ++$i ) {
65
+ if ( $rule[$i] && ( !isset( $call['args'][$i] ) || !is_string( $call['args'][$i] ) || '' == $call['args'][$i] ) ) return false;
66
+ switch( $rule[$i] ) {
67
+ case 'string':
68
+ if ( $complete ) {
69
+ $multiple[] = $entry;
70
+ $entry = new Translation_Entry;
71
+ $complete = false;
72
+ }
73
+ $entry->singular = $call['args'][$i];
74
+ $complete = true;
75
+ break;
76
+ case 'singular':
77
+ if ( $complete ) {
78
+ $multiple[] = $entry;
79
+ $entry = new Translation_Entry;
80
+ $complete = false;
81
+ }
82
+ $entry->singular = $call['args'][$i];
83
+ $entry->is_plural = true;
84
+ break;
85
+ case 'plural':
86
+ $entry->plural = $call['args'][$i];
87
+ $entry->is_plural = true;
88
+ $complete = true;
89
+ break;
90
+ case 'context':
91
+ $entry->context = $call['args'][$i];
92
+ foreach( $multiple as &$single_entry ) {
93
+ $single_entry->context = $entry->context;
94
+ }
95
+ break;
96
+ }
97
+ }
98
+ if ( isset( $call['line'] ) && $call['line'] ) {
99
+ $references = array( $file_name . ':' . $call['line'] );
100
+ $entry->references = $references;
101
+ foreach( $multiple as &$single_entry ) {
102
+ $single_entry->references = $references;
103
+ }
104
+ }
105
+ if ( isset( $call['comment'] ) && $call['comment'] ) {
106
+ $comments = rtrim( $call['comment'] ) . "\n";
107
+ $entry->extracted_comments = $comments;
108
+ foreach( $multiple as &$single_entry ) {
109
+ $single_entry->extracted_comments = $comments;
110
+ }
111
+ }
112
+ if ( $multiple && $entry ) {
113
+ $multiple[] = $entry;
114
+ return $multiple;
115
+ }
116
+
117
+ return $entry;
118
+ }
119
+
120
+ function extract_entries( $code, $file_name ) {
121
+ $translations = new Translations;
122
+ $function_calls = $this->find_function_calls( array_keys( $this->rules ), $code );
123
+ foreach( $function_calls as $call ) {
124
+ $entry = $this->entry_from_call( $call, $file_name );
125
+ if ( is_array( $entry ) )
126
+ foreach( $entry as $single_entry )
127
+ $translations->add_entry_or_merge( $single_entry );
128
+ elseif ( $entry)
129
+ $translations->add_entry_or_merge( $entry );
130
+ }
131
+ return $translations;
132
+ }
133
+
134
+ /**
135
+ * Finds all function calls in $code and returns an array with an associative array for each function:
136
+ * - name - name of the function
137
+ * - args - array for the function arguments. Each string literal is represented by itself, other arguments are represented by null.
138
+ * - line - line number
139
+ */
140
+ function find_function_calls( $function_names, $code ) {
141
+ $tokens = token_get_all( $code );
142
+ $function_calls = array();
143
+ $latest_comment = false;
144
+ $in_func = false;
145
+ foreach( $tokens as $token ) {
146
+ $id = $text = null;
147
+ if ( is_array( $token ) ) list( $id, $text, $line ) = $token;
148
+ if ( T_WHITESPACE == $id ) continue;
149
+ if ( T_STRING == $id && in_array( $text, $function_names ) && !$in_func ) {
150
+ $in_func = true;
151
+ $paren_level = -1;
152
+ $args = array();
153
+ $func_name = $text;
154
+ $func_line = $line;
155
+ $func_comment = $latest_comment? $latest_comment : '';
156
+
157
+ $just_got_into_func = true;
158
+ $latest_comment = false;
159
+ continue;
160
+ }
161
+ if ( T_COMMENT == $id ) {
162
+ $text = trim( preg_replace( '%^/\*|//%', '', preg_replace( '%\*/$%', '', $text ) ) );
163
+ if ( 0 === stripos( $tex