W3 Total Cache - Version 0.9.7.1

Version Description

  • Fixed undefined variable notice
  • Fixed "No such file or directory" warning
  • Fixed writing to PHP error log rather than WordPress debug log
  • Fixed default referrer policy should be "no-referrer-when-downgrade"
  • Fixed php_flag error related to browser cache, using ini_set instead
  • Fixed CloudFlare IPv6 check undefined offset
  • Fixed Undefined constant WP_ROOT
  • Fixed frame-ancestors being overwritten by frame-src
  • Fixed missing semicolon in nginx configuration
  • Fixed HTTP/2 URLs handling for browser cache and CDN modules
  • Fixed display of CDN debug information
  • Fixed CSS Minification with Google Fonts when included via "Include external files/libraries" and non-latin character-sets are loaded
  • Fixed media query string not updating when all caches were purged
  • Fixed double slash with ABSPATH if file exists
  • Fixed setting max-age and expires header simultaneously
  • Fixed SASL detection for PECL Memcached
  • Fixed handling of manually entered objects to be purged on CDN
  • Fixed query string handling in Nginx
  • Improved error handling with Cloudfront
  • Improved page cache logging
  • Improved multi-tenant support for memory-based caching engines
  • Improved CSS minification
  • Improved purge behavior for changed media objects when using CDN
  • Improved compatibility with sitemap plugins
  • Added support for Memcached for Nginx
  • Added support for caching webm files
  • Added Brotli HTTP compression support
  • Added StackPath full site delivery support
  • Added wc_session to the list of ignored query stems for improved WooCommerce compatibility
Download this release

Release Info

Developer fredericktownes
Plugin Icon 128x128 W3 Total Cache
Version 0.9.7.1
Comparing to
See all releases

Code changes from version 0.9.7 to 0.9.7.1

Files changed (177) hide show
  1. BrowserCache_ConfigLabels.php +4 -1
  2. BrowserCache_Environment.php +84 -53
  3. BrowserCache_Page.php +18 -10
  4. BrowserCache_Page_View_QuickReference.php +78 -0
  5. BrowserCache_Plugin.php +83 -17
  6. BrowserCache_Plugin_Admin.php +3 -0
  7. Cache.php +21 -17
  8. CacheFlush.php +2 -2
  9. CacheFlush_Locally.php +14 -9
  10. Cache_Base.php +6 -2
  11. Cache_File_Generic.php +5 -0
  12. Cache_Memcache.php +3 -1
  13. Cache_Memcached.php +13 -11
  14. Cache_Nginx_Memcached.php +310 -0
  15. Cache_Redis.php +9 -3
  16. CdnEngine.php +4 -0
  17. CdnEngine_Ftp.php +271 -13
  18. CdnEngine_GoogleDrive.php +1 -1
  19. CdnEngine_Mirror_StackPath2.php +109 -0
  20. CdnEngine_S3_Cf.php +1 -1
  21. Cdn_AdminActions.php +9 -5
  22. Cdn_ConfigLabels.php +1 -1
  23. Cdn_Core.php +25 -1
  24. Cdn_GeneralPage_View.php +3 -3
  25. Cdn_GoogleDrive_Page.php +1 -1
  26. Cdn_Highwinds_Page_View.php +2 -2
  27. Cdn_Highwinds_Popup_View_ConfigureCnamesForm.php +1 -1
  28. Cdn_Highwinds_Widget.php +1 -1
  29. Cdn_MaxCdn_Page_View.php +9 -9
  30. Cdn_MaxCdn_Popup_View_Intro.php +2 -2
  31. Cdn_Plugin.php +103 -36
  32. Cdn_Plugin_Admin.php +38 -9
  33. Cdn_Plugin_WidgetMaxCdn.php +2 -2
  34. Cdn_Plugin_WidgetMaxCdn_View_Unauthorized.php +3 -3
  35. Cdn_RackSpaceCdn_AdminActions.php +1 -1
  36. Cdn_RackSpaceCdn_Page_View.php +2 -2
  37. Cdn_RackSpaceCdn_Popup_View_ConfigureDomains.php +1 -1
  38. Cdn_RackSpaceCdn_Popup_View_Service_Create.php +2 -2
  39. Cdn_RackSpaceCloudFiles_Page_View.php +1 -1
  40. Cdn_StackPath2_Api.php +257 -0
  41. Cdn_StackPath2_Page.php +28 -0
  42. Cdn_StackPath2_Page_View.js +71 -0
  43. Cdn_StackPath2_Page_View.php +96 -0
  44. Cdn_StackPath2_Popup.php +211 -0
  45. Cdn_StackPath2_Popup_View_Intro.php +47 -0
  46. Cdn_StackPath2_Popup_View_Sites.php +54 -0
  47. Cdn_StackPath2_Popup_View_Stacks.php +51 -0
  48. Cdn_StackPath2_Popup_View_Success.php +23 -0
  49. Cdn_StackPath2_Widget.php +131 -0
  50. Cdn_StackPath2_Widget_View.css +78 -0
  51. Cdn_StackPath2_Widget_View.js +46 -0
  52. Cdn_StackPath2_Widget_View_Authorized.php +40 -0
  53. Cdn_StackPath2_Widget_View_Unauthorized.php +17 -0
  54. Cdn_StackPath_Page_View.php +23 -23
  55. Cdn_StackPath_Popup.php +1 -1
  56. Cdn_StackPath_Widget.php +1 -1
  57. Cdn_StackPath_Widget_View.css +1 -1
  58. Cdn_StackPath_Widget_View_Unauthorized.php +8 -8
  59. Cdn_Util.php +4 -1
  60. Cdnfsd_CacheFlush.php +25 -3
  61. Cdnfsd_CloudFront_Api.php +5 -0
  62. Cdnfsd_CloudFront_Page_View.php +2 -2
  63. Cdnfsd_CloudFront_Popup_View_Distribution.php +1 -1
  64. Cdnfsd_CloudFront_Popup_View_Intro.php +1 -1
  65. Cdnfsd_CloudFront_Popup_View_Success.php +1 -1
  66. Cdnfsd_Core.php +25 -0
  67. Cdnfsd_GeneralPage_View.php +3 -3
  68. Cdnfsd_MaxCdn_Page_View.php +2 -2
  69. Cdnfsd_MaxCdn_Popup_View_Intro.php +2 -2
  70. Cdnfsd_Plugin.php +3 -3
  71. Cdnfsd_Plugin_Admin.php +21 -8
  72. Cdnfsd_StackPath2_Engine.php +69 -0
  73. Cdnfsd_StackPath2_Page.php +20 -0
  74. Cdnfsd_StackPath2_Page_View.js +71 -0
  75. Cdnfsd_StackPath2_Page_View.php +61 -0
  76. Cdnfsd_StackPath2_Popup.php +201 -0
  77. Cdnfsd_StackPath2_Popup_View_Intro.php +47 -0
  78. Cdnfsd_StackPath2_Popup_View_Sites.php +54 -0
  79. Cdnfsd_StackPath2_Popup_View_Stacks.php +50 -0
  80. Cdnfsd_StackPath2_Popup_View_Success.php +23 -0
  81. Cdnfsd_StackPath_Page_View.php +2 -2
  82. Cdnfsd_StackPath_Popup.php +1 -1
  83. Cdnfsd_StackPath_Popup_View_Intro.php +26 -26
  84. Cli.php +7 -1
  85. ConfigCompiler.php +0 -9
  86. ConfigDbStorage.php +5 -1
  87. ConfigKeys.php +221 -45
  88. ConfigState.php +6 -0
  89. DbCache_Environment.php +4 -2
  90. Extension_CloudFlare_Plugin.php +0 -3
  91. Extension_CloudFlare_Widget.php +3 -3
  92. Extension_NewRelic_GeneralPage_View.php +4 -4
  93. Extension_NewRelic_Plugin_Admin.php +13 -8
  94. Extension_NewRelic_Widget.php +2 -2
  95. Extension_NewRelic_Widget_View_Browser.php +1 -1
  96. Extension_Swarmify_Widget.php +3 -2
  97. Generic_AdminActions_Config.php +7 -4
  98. Generic_AdminActions_Default.php +71 -30
  99. Generic_AdminActions_Flush.php +7 -7
  100. Generic_Faq.php +11 -13
  101. Generic_Page_Dashboard_View.css +6 -0
  102. Generic_Page_General.php +1 -0
  103. Generic_Plugin_Admin.php +5 -5
  104. Generic_WidgetServices.php +7 -7
  105. Generic_WidgetSpreadTheWord.js +6 -6
  106. Generic_WidgetSpreadTheWord_Plugin.php +2 -2
  107. Licensing_AdminActions.php +60 -2
  108. Licensing_Core.php +25 -8
  109. Licensing_Plugin_Admin.php +121 -42
  110. Minify_AutoCss.php +305 -0
  111. Minify_AutoJs.php +316 -0
  112. Minify_Environment.php +70 -6
  113. Minify_MinifiedFileRequestHandler.php +16 -2
  114. Minify_Plugin.php +35 -440
  115. PageSpeed_Plugin_Widget.php +2 -2
  116. PgCache_ConfigLabels.php +2 -2
  117. PgCache_ContentGrabber.php +56 -7
  118. PgCache_Environment.php +173 -41
  119. PgCache_Page_CookieGroups_View.js +1 -1
  120. PgCache_Plugin.php +0 -1
  121. Root_Loader.php +2 -5
  122. Support_Page.php +4 -0
  123. UsageStatistics_Widget.php +1 -1
  124. Util_Admin.php +0 -10
  125. Util_Http.php +2 -2
  126. Util_Installed.php +8 -4
  127. Util_Ui.php +38 -25
  128. inc/lightbox/purchase.php +1 -1
  129. inc/lightbox/self_test.php +21 -1
  130. inc/lightbox/support_us.php +11 -7
  131. inc/lightbox/upgrade.php +6 -6
  132. inc/mime/all.php +1 -0
  133. inc/mime/other.php +1 -0
  134. inc/options/browsercache.php +72 -33
  135. inc/options/cdn.php +26 -11
  136. inc/options/cdn/azure.php +1 -1
  137. inc/options/cdn/cf.php +33 -33
  138. inc/options/cdn/cf2.php +12 -12
  139. inc/options/cdn/common/cnames.php +27 -27
  140. inc/options/cdn/ftp.php +22 -1
  141. inc/options/common/header.php +92 -74
  142. inc/options/dashboard.php +1 -1
  143. inc/options/dbcache.php +2 -1
  144. inc/options/general.php +11 -6
  145. inc/options/install.php +21 -224
  146. inc/options/minify.php +2 -2
  147. inc/options/minify/yuicss2.php +4 -4
  148. inc/options/parts/memcached.php +41 -41
  149. inc/options/parts/memcached_extension.php +13 -13
  150. inc/options/pgcache.php +7 -4
  151. languages/w3-total-cache-ar_AR.po +23 -3
  152. languages/w3-total-cache-nl_NL.po +23 -3
  153. languages/w3-total-cache-pl_PL.po +23 -3
  154. languages/w3-total-cache-sr_RS.mo +0 -0
  155. languages/w3-total-cache-sr_RS.po +25 -5
  156. languages/w3-total-cache.pot +23 -3
  157. lib/Minify/HTTP/Encoder.php +18 -1
  158. lib/Minify/Minify.php +12 -1
  159. lib/Minify/Minify/CSS/UriRewriter.php +1 -1
  160. lib/Minify/Minify/Cache/File.php +6 -2
  161. lib/Minify/Minify/Controller/Files.php +5 -1
  162. lib/Minify/Minify/HTML.php +72 -19
  163. lib/Minify/Minify/Inline.php +24 -3
  164. lib/Nusoap/nusoap.php +27 -2
  165. lib/SNS/sdk.class.php +16 -0
  166. pub/css/lightbox.css +2 -2
  167. pub/css/options.css +15 -5
  168. pub/img/cspref.png +0 -0
  169. pub/img/w3tc_stackpath-logo-retina.png +0 -0
  170. pub/img/w3tc_stackpath-logo.png +0 -0
  171. pub/img/w3tc_stackpath_logo.svg +40 -0
  172. pub/js/lightbox.js +2 -2
  173. pub/js/options.js +37 -31
  174. pub/js/widget.js +1 -1
  175. readme.txt +36 -18
  176. w3-total-cache-api.php +98 -57
  177. w3-total-cache.php +1 -1
BrowserCache_ConfigLabels.php CHANGED
@@ -16,6 +16,7 @@ class BrowserCache_ConfigLabels {
16
  'browsercache.cssjs.etag' => __( 'Set entity tag (eTag)', 'w3-total-cache' ),
17
  'browsercache.cssjs.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
18
  'browsercache.cssjs.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression', 'w3-total-cache' ),
 
19
  'browsercache.cssjs.replace' => __( 'Prevent caching of objects after settings change', 'w3-total-cache' ),
20
  'browsercache.cssjs.nocookies' => __( 'Disable cookies for static files', 'w3-total-cache' ),
21
  'browsercache.html.last_modified' => __( 'Set Last-Modified header', 'w3-total-cache' ),
@@ -26,6 +27,7 @@ class BrowserCache_ConfigLabels {
26
  'browsercache.html.etag' => __( 'Set entity tag (ETag)', 'w3-total-cache' ),
27
  'browsercache.html.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
28
  'browsercache.html.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression', 'w3-total-cache' ),
 
29
  'browsercache.other.last_modified' => __( 'Set Last-Modified header', 'w3-total-cache' ),
30
  'browsercache.other.expires' => __( 'Set expires header', 'w3-total-cache' ),
31
  'browsercache.other.lifetime' => __( 'Expires header lifetime:', 'w3-total-cache' ),
@@ -34,6 +36,7 @@ class BrowserCache_ConfigLabels {
34
  'browsercache.other.etag' => __( 'Set entity tag (ETag)', 'w3-total-cache' ),
35
  'browsercache.other.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
36
  'browsercache.other.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression</label>', 'w3-total-cache' ),
 
37
  'browsercache.other.replace' => __( 'Prevent caching of objects after settings change', 'w3-total-cache' ),
38
  'browsercache.other.nocookies' => __( 'Disable cookies for static files', 'w3-total-cache' ),
39
  'browsercache.security.session.cookie_httponly' => __( 'Access session cookies through the <acronym title="Hypertext Transfer Protocol">HTTP</acronym> only:', 'w3-total-cache' ),
@@ -43,7 +46,7 @@ class BrowserCache_ConfigLabels {
43
  'browsercache.security.hsts.directive' => __( 'Directive:', 'w3-total-cache' ),
44
  'browsercache.security.xfo' => __( 'X-Frame-Options', 'w3-total-cache' ),
45
  'browsercache.security.xfo.directive' => __( 'Directive:', 'w3-total-cache' ),
46
- 'browsercache.security.xss' => __( 'X-XSS-Protection', 'w3-total-cache' ),
47
  'browsercache.security.xss.directive' => __( 'Directive:', 'w3-total-cache' ),
48
  'browsercache.security.xcto' => __( 'X-Content-Type-Options', 'w3-total-cache' ),
49
  'browsercache.security.pkp' => __( '<acronym title="Hypertext Transfer Protocol">HTTP</acronym> Public Key Pinning', 'w3-total-cache' ),
16
  'browsercache.cssjs.etag' => __( 'Set entity tag (eTag)', 'w3-total-cache' ),
17
  'browsercache.cssjs.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
18
  'browsercache.cssjs.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression', 'w3-total-cache' ),
19
+ 'browsercache.cssjs.brotli' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (brotli) compression', 'w3-total-cache' ),
20
  'browsercache.cssjs.replace' => __( 'Prevent caching of objects after settings change', 'w3-total-cache' ),
21
  'browsercache.cssjs.nocookies' => __( 'Disable cookies for static files', 'w3-total-cache' ),
22
  'browsercache.html.last_modified' => __( 'Set Last-Modified header', 'w3-total-cache' ),
27
  'browsercache.html.etag' => __( 'Set entity tag (ETag)', 'w3-total-cache' ),
28
  'browsercache.html.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
29
  'browsercache.html.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression', 'w3-total-cache' ),
30
+ 'browsercache.html.brotli' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (brotli) compression', 'w3-total-cache' ),
31
  'browsercache.other.last_modified' => __( 'Set Last-Modified header', 'w3-total-cache' ),
32
  'browsercache.other.expires' => __( 'Set expires header', 'w3-total-cache' ),
33
  'browsercache.other.lifetime' => __( 'Expires header lifetime:', 'w3-total-cache' ),
36
  'browsercache.other.etag' => __( 'Set entity tag (ETag)', 'w3-total-cache' ),
37
  'browsercache.other.w3tc' => __( 'Set W3 Total Cache header', 'w3-total-cache' ),
38
  'browsercache.other.compression' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (gzip) compression</label>', 'w3-total-cache' ),
39
+ 'browsercache.other.brotli' => __( 'Enable <acronym title="Hypertext Transfer Protocol">HTTP</acronym> (brotli) compression</label>', 'w3-total-cache' ),
40
  'browsercache.other.replace' => __( 'Prevent caching of objects after settings change', 'w3-total-cache' ),
41
  'browsercache.other.nocookies' => __( 'Disable cookies for static files', 'w3-total-cache' ),
42
  'browsercache.security.session.cookie_httponly' => __( 'Access session cookies through the <acronym title="Hypertext Transfer Protocol">HTTP</acronym> only:', 'w3-total-cache' ),
46
  'browsercache.security.hsts.directive' => __( 'Directive:', 'w3-total-cache' ),
47
  'browsercache.security.xfo' => __( 'X-Frame-Options', 'w3-total-cache' ),
48
  'browsercache.security.xfo.directive' => __( 'Directive:', 'w3-total-cache' ),
49
+ 'browsercache.security.xss' => __( 'X-<acronym title="Cross-Site Scripting">XSS</acronym>-Protection', 'w3-total-cache' ),
50
  'browsercache.security.xss.directive' => __( 'Directive:', 'w3-total-cache' ),
51
  'browsercache.security.xcto' => __( 'X-Content-Type-Options', 'w3-total-cache' ),
52
  'browsercache.security.pkp' => __( '<acronym title="Hypertext Transfer Protocol">HTTP</acronym> Public Key Pinning', 'w3-total-cache' ),
BrowserCache_Environment.php CHANGED
@@ -112,6 +112,7 @@ class BrowserCache_Environment {
112
  unset( $other_compression['avi'] );
113
  unset( $other_compression['divx'] );
114
  unset( $other_compression['gif'] );
 
115
  unset( $other_compression['gz|gzip'] );
116
  unset( $other_compression['jpg|jpeg|jpe'] );
117
  unset( $other_compression['mid|midi'] );
@@ -286,6 +287,42 @@ class BrowserCache_Environment {
286
  $rules .= "</IfModule>\n";
287
  }
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  $cssjs_compression = $config->get_boolean( 'browsercache.cssjs.compression' );
290
  $html_compression = $config->get_boolean( 'browsercache.html.compression' );
291
  $other_compression = $config->get_boolean( 'browsercache.other.compression' );
@@ -334,35 +371,6 @@ class BrowserCache_Environment {
334
  $rules .= $this->_rules_cache_generate_apache_for_type( $config,
335
  $extensions, $type );
336
 
337
- $sec = '';
338
- $v = $config->get_string( 'browsercache.security.session.cookie_httponly' );
339
- if ( !empty( $v ) ) {
340
- $sec .= ' php_flag session.cookie_httponly ' .
341
- ( $v == 'on' ? 'on' : 'off' ) . "\n";
342
- }
343
- $v = $config->get_string( 'browsercache.security.session.cookie_secure' );
344
- if ( !empty( $v ) ) {
345
- $sec .= ' php_flag session.cookie_secure ' .
346
- ( $v == 'on' ? 'on' : 'off' ) . "\n";
347
- }
348
- $v = $config->get_string( 'browsercache.security.session.use_only_cookies' );
349
- if ( !empty( $v ) ) {
350
- $sec .= ' php_flag session.use_only_cookies ' .
351
- ( $v == 'on' ? 'on' : 'off' ) . "\n";
352
- }
353
-
354
- if ( !empty( $sec ) ) {
355
- $rules .= "<IfModule mod_php5.c>\n";
356
- $rules .= $sec;
357
- $rules .= "</IfModule>\n";
358
- $rules .= "<IfModule mod_php7.c>\n";
359
- $rules .= $sec;
360
- $rules .= "</IfModule>\n";
361
- $rules .= "<IfModule mod_suphp.c>\n";
362
- $rules .= $sec;
363
- $rules .= "</IfModule>\n";
364
- }
365
-
366
  if ( $config->get_boolean( 'browsercache.hsts' ) ||
367
  $config->get_boolean( 'browsercache.security.xfo' ) ||
368
  $config->get_boolean( 'browsercache.security.xss' ) ||
@@ -623,6 +631,36 @@ class BrowserCache_Environment {
623
 
624
  }
625
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  $cssjs_compression = $config->get_boolean( 'browsercache.cssjs.compression' );
627
  $html_compression = $config->get_boolean( 'browsercache.html.compression' );
628
  $other_compression = $config->get_boolean( 'browsercache.other.compression' );
@@ -668,28 +706,11 @@ class BrowserCache_Environment {
668
  }
669
  }
670
 
671
- foreach ( $mime_types as $type => $extensions )
672
- $this->_rules_cache_generate_nginx_for_type( $config, $rules,
673
- $extensions, $type );
674
-
675
- $sec = '';
676
- $v = $config->get_string( 'browsercache.security.session.cookie_httponly' );
677
- if ( !empty( $v ) ) {
678
- $sec .= 'session.cookie_httponly=' .
679
- ( $v == 'on' ? "on" : "off" ) . "\n";
680
- }
681
- $v = $config->get_string( 'browsercache.security.session.cookie_secure' );
682
- if ( !empty( $v ) ) {
683
- $sec .= 'session.cookie_secure=' .
684
- ( $v == 'on' ? "on" : "off" ) . "\n";
685
- }
686
- $v = $config->get_string( 'browsercache.security.session.use_only_cookies' );
687
- if ( !empty( $v ) ) {
688
- $sec .= 'session.use_only_cookies=' .
689
- ( $v == 'on' ? "on" : "off" ) . "\n";
690
- }
691
- if ( !empty( $sec ) ) {
692
- $rules .= "fastcgi_param PHP_FLAG \"$sec\";";
693
  }
694
 
695
  if ( $config->get_boolean( 'browsercache.hsts' ) ||
@@ -842,7 +863,12 @@ class BrowserCache_Environment {
842
 
843
  case 'cache_public_maxage':
844
  $add_header_rules .= " add_header Pragma \"public\";\n";
845
- $add_header_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
 
 
 
 
 
846
  break;
847
 
848
  case 'cache_validation':
@@ -857,7 +883,12 @@ class BrowserCache_Environment {
857
 
858
  case 'cache_maxage':
859
  $add_header_rules .= " add_header Pragma \"public\";\n";
860
- $add_header_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
 
 
 
 
 
861
  break;
862
 
863
  case 'no_cache':
112
  unset( $other_compression['avi'] );
113
  unset( $other_compression['divx'] );
114
  unset( $other_compression['gif'] );
115
+ unset( $other_compression['br'] );
116
  unset( $other_compression['gz|gzip'] );
117
  unset( $other_compression['jpg|jpeg|jpe'] );
118
  unset( $other_compression['mid|midi'] );
287
  $rules .= "</IfModule>\n";
288
  }
289
 
290
+ $cssjs_brotli = $config->get_boolean( 'browsercache.cssjs.brotli' );
291
+ $html_brotli = $config->get_boolean( 'browsercache.html.brotli' );
292
+ $other_brotli = $config->get_boolean( 'browsercache.other.brotli' );
293
+
294
+ if ( $cssjs_brotli || $html_brotli || $other_brotli ) {
295
+ $brotli_types = array();
296
+
297
+ if ( $cssjs_brotli ) {
298
+ $brotli_types = array_merge( $brotli_types, $cssjs_types );
299
+ }
300
+
301
+ if ( $html_brotli ) {
302
+ $brotli_types = array_merge( $brotli_types, $html_types );
303
+ }
304
+
305
+ if ( $other_brotli ) {
306
+ $brotli_types = array_merge( $brotli_types,
307
+ $other_compression_types );
308
+ }
309
+
310
+ $rules .= "<IfModule mod_brotli.c>\n";
311
+ if ( version_compare( Util_Environment::get_server_version(), '2.3.7', '>=' ) ) {
312
+ $rules .= " <IfModule mod_filter.c>\n";
313
+ }
314
+ $rules .= " AddOutputFilterByType BROTLI_COMPRESS " . implode( ' ', $brotli_types ) . "\n";
315
+ $rules .= " <IfModule mod_mime.c>\n";
316
+ $rules .= " # BROTLI_COMPRESS by extension\n";
317
+ $rules .= " AddOutputFilter BROTLI_COMPRESS js css htm html xml\n";
318
+ $rules .= " </IfModule>\n";
319
+
320
+ if ( version_compare( Util_Environment::get_server_version(), '2.3.7', '>=' ) ) {
321
+ $rules .= " </IfModule>\n";
322
+ }
323
+ $rules .= "</IfModule>\n";
324
+ }
325
+
326
  $cssjs_compression = $config->get_boolean( 'browsercache.cssjs.compression' );
327
  $html_compression = $config->get_boolean( 'browsercache.html.compression' );
328
  $other_compression = $config->get_boolean( 'browsercache.other.compression' );
371
  $rules .= $this->_rules_cache_generate_apache_for_type( $config,
372
  $extensions, $type );
373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  if ( $config->get_boolean( 'browsercache.hsts' ) ||
375
  $config->get_boolean( 'browsercache.security.xfo' ) ||
376
  $config->get_boolean( 'browsercache.security.xss' ) ||
631
 
632
  }
633
 
634
+ $cssjs_brotli = $config->get_boolean( 'browsercache.cssjs.brotli' );
635
+ $html_brotli = $config->get_boolean( 'browsercache.html.brotli' );
636
+ $other_brotli = $config->get_boolean( 'browsercache.other.brotli' );
637
+
638
+ if ( $cssjs_brotli || $html_brotli || $other_brotli ) {
639
+ $brotli_types = array();
640
+
641
+ if ( $cssjs_brotli ) {
642
+ $brotli_types = array_merge( $brotli_types, $cssjs_types );
643
+ }
644
+
645
+ if ( $html_brotli ) {
646
+ $brotli_types = array_merge( $brotli_types, $html_types );
647
+ }
648
+
649
+ if ( $other_brotli ) {
650
+ $brotli_types = array_merge( $brotli_types,
651
+ $other_compression_types );
652
+ }
653
+
654
+ unset( $brotli_types['html|htm'] );
655
+
656
+ // some nginx cant handle values longer than 47 chars
657
+ unset( $brotli_types['odp'] );
658
+
659
+ $rules .= "brotli on;\n";
660
+ $rules .= "brotli_types " .
661
+ implode( ' ', array_unique( $brotli_types ) ) . ";\n";
662
+ }
663
+
664
  $cssjs_compression = $config->get_boolean( 'browsercache.cssjs.compression' );
665
  $html_compression = $config->get_boolean( 'browsercache.html.compression' );
666
  $other_compression = $config->get_boolean( 'browsercache.other.compression' );
706
  }
707
  }
708
 
709
+ foreach ( $mime_types as $type => $extensions ) {
710
+ if ( $type != 'other_compression' ) {
711
+ $this->_rules_cache_generate_nginx_for_type( $config, $rules,
712
+ $extensions, $type );
713
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  }
715
 
716
  if ( $config->get_boolean( 'browsercache.hsts' ) ||
863
 
864
  case 'cache_public_maxage':
865
  $add_header_rules .= " add_header Pragma \"public\";\n";
866
+
867
+ if ( $expires ) {
868
+ $add_header_rules .= " add_header Cache-Control \"public\";\n";
869
+ } else {
870
+ $add_header_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
871
+ }
872
  break;
873
 
874
  case 'cache_validation':
883
 
884
  case 'cache_maxage':
885
  $add_header_rules .= " add_header Pragma \"public\";\n";
886
+
887
+ if ( $expires ) {
888
+ $add_header_rules .= " add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n";
889
+ } else {
890
+ $add_header_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
891
+ }
892
  break;
893
 
894
  case 'no_cache':
BrowserCache_Page.php CHANGED
@@ -4,19 +4,24 @@ namespace W3TC;
4
 
5
 
6
  class BrowserCache_Page extends Base_Page_Settings {
7
- /**
8
- * Current page
9
- *
10
- * @var string
11
- */
12
  protected $_page = 'w3tc_browsercache';
13
 
14
 
15
- /**
16
- * Browser cache tab
17
- *
18
- * @return void
19
- */
 
 
 
 
 
 
 
 
 
 
20
  function view() {
21
  $browsercache_enabled = $this->_config->get_boolean( 'browsercache.enabled' );
22
  $browsercache_last_modified = ( $this->_config->get_boolean( 'browsercache.cssjs.last_modified' ) && $this->_config->get_boolean( 'browsercache.html.last_modified' ) && $this->_config->get_boolean( 'browsercache.other.last_modified' ) );
@@ -25,6 +30,7 @@ class BrowserCache_Page extends Base_Page_Settings {
25
  $browsercache_etag = ( $this->_config->get_boolean( 'browsercache.cssjs.etag' ) && $this->_config->get_boolean( 'browsercache.html.etag' ) && $this->_config->get_boolean( 'browsercache.other.etag' ) );
26
  $browsercache_w3tc = ( $this->_config->get_boolean( 'browsercache.cssjs.w3tc' ) && $this->_config->get_boolean( 'browsercache.html.w3tc' ) && $this->_config->get_boolean( 'browsercache.other.w3tc' ) );
27
  $browsercache_compression = ( $this->_config->get_boolean( 'browsercache.cssjs.compression' ) && $this->_config->get_boolean( 'browsercache.html.compression' ) && $this->_config->get_boolean( 'browsercache.other.compression' ) );
 
28
  $browsercache_replace = ( $this->_config->get_boolean( 'browsercache.cssjs.replace' ) && $this->_config->get_boolean( 'browsercache.other.replace' ) );
29
  $browsercache_querystring = ( $this->_config->get_boolean( 'browsercache.cssjs.querystring' ) && $this->_config->get_boolean( 'browsercache.other.querystring' ) );
30
  $browsercache_update_media_qs = ( $this->_config->get_boolean( 'browsercache.cssjs.replace' ) || $this->_config->get_boolean( 'browsercache.other.replace' ) );
@@ -32,6 +38,8 @@ class BrowserCache_Page extends Base_Page_Settings {
32
  ( $this->_config->get_boolean( 'browsercache.cssjs.nocookies' ) &&
33
  $this->_config->get_boolean( 'browsercache.other.nocookies' ) );
34
 
 
 
35
  include W3TC_INC_DIR . '/options/browsercache.php';
36
  }
37
  }
4
 
5
 
6
  class BrowserCache_Page extends Base_Page_Settings {
 
 
 
 
 
7
  protected $_page = 'w3tc_browsercache';
8
 
9
 
10
+ static public function w3tc_ajax() {
11
+ add_action( 'w3tc_ajax_browsercache_quick_reference', array(
12
+ '\W3TC\BrowserCache_Page',
13
+ 'w3tc_ajax_browsercache_quick_reference' ) );
14
+ }
15
+
16
+
17
+
18
+ public function w3tc_ajax_browsercache_quick_reference() {
19
+ include W3TC_DIR . '/BrowserCache_Page_View_QuickReference.php';
20
+ exit();
21
+ }
22
+
23
+
24
+
25
  function view() {
26
  $browsercache_enabled = $this->_config->get_boolean( 'browsercache.enabled' );
27
  $browsercache_last_modified = ( $this->_config->get_boolean( 'browsercache.cssjs.last_modified' ) && $this->_config->get_boolean( 'browsercache.html.last_modified' ) && $this->_config->get_boolean( 'browsercache.other.last_modified' ) );
30
  $browsercache_etag = ( $this->_config->get_boolean( 'browsercache.cssjs.etag' ) && $this->_config->get_boolean( 'browsercache.html.etag' ) && $this->_config->get_boolean( 'browsercache.other.etag' ) );
31
  $browsercache_w3tc = ( $this->_config->get_boolean( 'browsercache.cssjs.w3tc' ) && $this->_config->get_boolean( 'browsercache.html.w3tc' ) && $this->_config->get_boolean( 'browsercache.other.w3tc' ) );
32
  $browsercache_compression = ( $this->_config->get_boolean( 'browsercache.cssjs.compression' ) && $this->_config->get_boolean( 'browsercache.html.compression' ) && $this->_config->get_boolean( 'browsercache.other.compression' ) );
33
+ $browsercache_brotli = ( $this->_config->get_boolean( 'browsercache.cssjs.brotli' ) && $this->_config->get_boolean( 'browsercache.html.brotli' ) && $this->_config->get_boolean( 'browsercache.other.brotli' ) );
34
  $browsercache_replace = ( $this->_config->get_boolean( 'browsercache.cssjs.replace' ) && $this->_config->get_boolean( 'browsercache.other.replace' ) );
35
  $browsercache_querystring = ( $this->_config->get_boolean( 'browsercache.cssjs.querystring' ) && $this->_config->get_boolean( 'browsercache.other.querystring' ) );
36
  $browsercache_update_media_qs = ( $this->_config->get_boolean( 'browsercache.cssjs.replace' ) || $this->_config->get_boolean( 'browsercache.other.replace' ) );
38
  ( $this->_config->get_boolean( 'browsercache.cssjs.nocookies' ) &&
39
  $this->_config->get_boolean( 'browsercache.other.nocookies' ) );
40
 
41
+ $is_nginx = Util_Environment::is_nginx();
42
+
43
  include W3TC_INC_DIR . '/options/browsercache.php';
44
  }
45
  }
BrowserCache_Page_View_QuickReference.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace W3TC;
3
+
4
+ if ( !defined( 'W3TC' ) )
5
+ die();
6
+
7
+ ?>
8
+ <div class="lightbox-content-padded">
9
+ <h3><?php _e( 'Security Headers: Quick Reference', 'w3-total-cache' ); ?></h3>
10
+
11
+ <fieldset>
12
+ <legend><?php _e( 'Legend', 'w3-total-cache' ); ?></legend>
13
+
14
+ <p>
15
+ All of the directives that end with -src support similar values known as
16
+ a source list. Multiple source list values can be space separated with the exception of
17
+ 'none' which should be the only value.
18
+ </p>
19
+ </fieldset>
20
+
21
+ <table class="w3tcbc_qrf">
22
+ <tr>
23
+ <th>Source Value</th>
24
+ <th>Example</th>
25
+ <th>Description</th>
26
+ </tr>
27
+ <tr>
28
+ <td><code>*</code></td>
29
+ <td><code>img-src *</code></td>
30
+ <td>Wildcard, allows any URL except data: blob: filesystem: schemes</td>
31
+ </tr>
32
+ <tr>
33
+ <td><code>'none'</code></td>
34
+ <td><code>object-src 'none'</code></td>
35
+ <td>Prevents loading resources from any source</td>
36
+ </tr>
37
+ <tr>
38
+ <td><code>'self'</code></td>
39
+ <td><code>script-src 'self'</code></td>
40
+ <td>Allows loading resources from the same origin (same scheme, host and port)</td>
41
+ </tr>
42
+ <tr>
43
+ <td><code>data:</code></td>
44
+ <td><code>img-src 'self' data:</code></td>
45
+ <td>Allows loading resources via the data scheme (e.g. Base64 encoded images)</td>
46
+ </tr>
47
+ <tr>
48
+ <td><code>domain.example.com</code></td>
49
+ <td><code>img-src domain.example.com</code></td>
50
+ <td>Allows loading resources from the specified domain name</td>
51
+ </tr>
52
+ <tr>
53
+ <td><code>*.example.com</code></td>
54
+ <td><code>img-src *.example.com</code></td>
55
+ <td>Allows loading resources from any subdomain under example.com</td>
56
+ </tr>
57
+ <tr>
58
+ <td><code>https://cdn.com</code></td>
59
+ <td><code>img-src https://cdn.com</code></td>
60
+ <td>Allows loading resources only over <acronym title="HyperText Transfer Protocol over SSL">HTTPS</acronym> matching the given domain</td>
61
+ </tr>
62
+ <tr>
63
+ <td><code>https:</code></td>
64
+ <td><code>img-src https:</code></td>
65
+ <td>Allows loading resources only over <acronym title="HyperText Transfer Protocol over SSL">HTTPS</acronym> on any domain</td>
66
+ </tr>
67
+ <tr>
68
+ <td><code>'unsafe-inline'</code></td>
69
+ <td><code>script-src 'unsafe-inline'</code></td>
70
+ <td>Allows use of inline source elements such as style attribute, onclick, or script tag bodies (depends on the context of the source it is applied to)</td>
71
+ </tr>
72
+ <tr>
73
+ <td><code>'unsafe-eval'</code></td>
74
+ <td><code>script-src 'unsafe-eval'</code></td>
75
+ <td>Allows unsafe dynamic code evaluation such as Javascript eval()</td>
76
+ </tr>
77
+ </table>
78
+ </div>
BrowserCache_Plugin.php CHANGED
@@ -30,16 +30,64 @@ class BrowserCache_Plugin {
30
  0, 2 );
31
  }
32
 
33
- if ( $this->can_ob() ) {
 
 
34
  $this->browsercache_rewrite =
35
  $this->_config->get_boolean( 'browsercache.rewrite' );
36
- Util_Bus::add_ob_callback( 'browsercache', array( $this, 'ob_callback' ) );
37
 
38
- // modify CDN urls too
39
  add_filter( 'w3tc_cdn_url',
40
- array( $this, 'w3tc_cdn_url' ),
41
- 0, 3 );
 
 
 
 
 
 
 
 
 
 
42
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
 
45
  /**
@@ -48,18 +96,6 @@ class BrowserCache_Plugin {
48
  * @return boolean
49
  */
50
  function can_ob() {
51
- /**
52
- * Replace feature should be enabled
53
- */
54
- if ( !$this->_config->get_boolean( 'browsercache.cssjs.replace' ) &&
55
- !$this->_config->get_boolean( 'browsercache.html.replace' ) &&
56
- !$this->_config->get_boolean( 'browsercache.other.replace' ) &&
57
- !$this->_config->get_boolean( 'browsercache.cssjs.querystring' ) &&
58
- !$this->_config->get_boolean( 'browsercache.html.querystring' ) &&
59
- !$this->_config->get_boolean( 'browsercache.other.querystring' )) {
60
- return false;
61
- }
62
-
63
  /**
64
  * Skip if admin
65
  */
@@ -155,6 +191,36 @@ class BrowserCache_Plugin {
155
  return sprintf( '%s\'%s\'', $attr, $url );
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  /**
159
  * Link replace for CDN url
160
  *
30
  0, 2 );
31
  }
32
 
33
+ $url_uniqualize_enabled = $this->url_uniqualize_enabled();
34
+
35
+ if ( $this->url_clean_enabled() || $url_uniqualize_enabled ) {
36
  $this->browsercache_rewrite =
37
  $this->_config->get_boolean( 'browsercache.rewrite' );
 
38
 
39
+ // modify CDN urls
40
  add_filter( 'w3tc_cdn_url',
41
+ array( $this, 'w3tc_cdn_url' ), 0, 3 );
42
+
43
+ if ( $url_uniqualize_enabled ) {
44
+ add_action( 'w3tc_flush_all',
45
+ array( $this, 'w3tc_flush_all' ), 1050, 1 );
46
+ }
47
+
48
+
49
+ if ( $this->can_ob() ) {
50
+ Util_Bus::add_ob_callback( 'browsercache',
51
+ array( $this, 'ob_callback' ) );
52
+ }
53
  }
54
+
55
+ $v = $this->_config->get_string( 'browsercache.security.session.cookie_httponly' );
56
+ if ( !empty( $v ) ) {
57
+ @ini_set( 'session.cookie_httponly', $v == 'on' ? '1': '0' );
58
+ }
59
+ $v = $this->_config->get_string( 'browsercache.security.session.cookie_secure' );
60
+ if ( !empty( $v ) ) {
61
+ @ini_set( 'session.cookie_secure', $v == 'on' ? '1': '0' );
62
+ }
63
+ $v = $this->_config->get_string( 'browsercache.security.session.use_only_cookies' );
64
+ if ( !empty( $v ) ) {
65
+ @ini_set( 'session.use_only_cookies', $v == 'on' ? '1': '0' );
66
+ }
67
+
68
+ add_filter( 'w3tc_minify_http2_preload_url',
69
+ array( $this, 'w3tc_minify_http2_preload_url' ), 4000 );
70
+ }
71
+
72
+ private function url_clean_enabled() {
73
+ return
74
+ $this->_config->get_boolean( 'browsercache.cssjs.querystring' ) ||
75
+ $this->_config->get_boolean( 'browsercache.html.querystring' ) ||
76
+ $this->_config->get_boolean( 'browsercache.other.querystring' );
77
+ }
78
+
79
+ private function url_uniqualize_enabled() {
80
+ return $this->_config->get_boolean( 'browsercache.cssjs.replace' ) ||
81
+ $this->_config->get_boolean( 'browsercache.html.replace' ) ||
82
+ $this->_config->get_boolean( 'browsercache.other.replace' );
83
+ }
84
+
85
+ public function w3tc_flush_all( $extras = array() ) {
86
+ if ( isset( $extras['only'] ) && $extras['only'] != 'browsercache' )
87
+ return;
88
+
89
+ update_option( 'w3tc_browsercache_flush_timestamp',
90
+ rand( 10000, 99999 ) . '' );
91
  }
92
 
93
  /**
96
  * @return boolean
97
  */
98
  function can_ob() {
 
 
 
 
 
 
 
 
 
 
 
 
99
  /**
100
  * Skip if admin
101
  */
191
  return sprintf( '%s\'%s\'', $attr, $url );
192
  }
193
 
194
+ /**
195
+ * Mutate http/2 header links
196
+ */
197
+ public function w3tc_minify_http2_preload_url( $data ) {
198
+ if ( isset( $data['browsercache_processed'] ) ) {
199
+ return $data;
200
+ }
201
+
202
+ $data['browsercache_processed'] = '*';
203
+ $url = $data['result_link'];
204
+
205
+ // decouple extension
206
+ $matches = array();
207
+ if ( !preg_match( '/\.([a-zA-Z0-9]+)($|[\?])/', $url, $matches ) ) {
208
+ return $data;
209
+ }
210
+ $extension = $matches[1];
211
+
212
+ $ops = $this->_get_url_mutation_operations( $url, $extension );
213
+ if ( is_null( $ops ) ) {
214
+ return $data;
215
+ }
216
+
217
+ $mutate_by_querystring = !$this->browsercache_rewrite;
218
+
219
+ $url = $this->mutate_url( $url, $ops, $mutate_by_querystring );
220
+ $data['result_link'] = $url;
221
+ return $data;
222
+ }
223
+
224
  /**
225
  * Link replace for CDN url
226
  *
BrowserCache_Plugin_Admin.php CHANGED
@@ -6,5 +6,8 @@ class BrowserCache_Plugin_Admin {
6
  $config_labels = new BrowserCache_ConfigLabels();
7
  add_filter( 'w3tc_config_labels', array(
8
  $config_labels, 'config_labels' ) );
 
 
 
9
  }
10
  }
6
  $config_labels = new BrowserCache_ConfigLabels();
7
  add_filter( 'w3tc_config_labels', array(
8
  $config_labels, 'config_labels' ) );
9
+
10
+ add_action( 'w3tc_ajax',
11
+ array( '\W3TC\BrowserCache_Page', 'w3tc_ajax' ) );
12
  }
13
  }
Cache.php CHANGED
@@ -54,6 +54,10 @@ class Cache {
54
  }
55
  break;
56
 
 
 
 
 
57
  case 'redis':
58
  $instances[$instance_key] = new Cache_Redis( $config );
59
  break;
@@ -99,6 +103,10 @@ class Cache {
99
 
100
  break;
101
 
 
 
 
 
102
  case 'apc':
103
  $engine_name = 'apc';
104
  break;
@@ -138,6 +146,10 @@ class Cache {
138
  $engine_name = 'amazon simple storage service (s3)';
139
  break;
140
 
 
 
 
 
141
  case 'cf':
142
  $engine_name = 'amazon cloudfront';
143
  break;
@@ -162,22 +174,6 @@ class Cache {
162
  $engine_name = 'microsoft azure storage';
163
  break;
164
 
165
- case 'mirror':
166
- $engine_name = 'mirror';
167
- break;
168
-
169
- case 'maxcdn':
170
- $engine_name = 'maxcdn';
171
- break;
172
-
173
- case 'cotendo':
174
- $engine_name = 'cotendo';
175
- break;
176
-
177
- case 'akamai':
178
- $engine_name = 'akamai';
179
- break;
180
-
181
  case 'edgecast':
182
  $engine_name = 'media template procdn / edgecast';
183
  break;
@@ -186,8 +182,16 @@ class Cache {
186
  $engine_name = 'at&amp;t';
187
  break;
188
 
 
 
 
 
 
 
 
 
189
  default:
190
- $engine_name = 'n/a';
191
  break;
192
  }
193
 
54
  }
55
  break;
56
 
57
+ case 'nginx_memcached':
58
+ $instances[$instance_key] = new Cache_Nginx_Memcached( $config );
59
+ break;
60
+
61
  case 'redis':
62
  $instances[$instance_key] = new Cache_Redis( $config );
63
  break;
103
 
104
  break;
105
 
106
+ case 'nginx_memcached':
107
+ $engine_name = 'nginx + memcached';
108
+ break;
109
+
110
  case 'apc':
111
  $engine_name = 'apc';
112
  break;
146
  $engine_name = 'amazon simple storage service (s3)';
147
  break;
148
 
149
+ case 's3_compatible':
150
+ $engine_name = 's3 compatible';
151
+ break;
152
+
153
  case 'cf':
154
  $engine_name = 'amazon cloudfront';
155
  break;
174
  $engine_name = 'microsoft azure storage';
175
  break;
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  case 'edgecast':
178
  $engine_name = 'media template procdn / edgecast';
179
  break;
182
  $engine_name = 'at&amp;t';
183
  break;
184
 
185
+ case 'rackspace_cdn':
186
+ $engine_name = 'rackspace';
187
+ break;
188
+
189
+ case 'stackpath2':
190
+ $engine_name = 'stackpath';
191
+ break;
192
+
193
  default:
194
+ $engine_name = $engine;
195
  break;
196
  }
197
 
CacheFlush.php CHANGED
@@ -92,9 +92,9 @@ class CacheFlush {
92
  /**
93
  * Purge CDN mirror cache
94
  */
95
- function cdn_purge_all() {
96
  if ( $this->_config->get_boolean( 'cdn.enabled' ) )
97
- return $this->_executor->cdn_purge_all();
98
 
99
  return false;
100
  }
92
  /**
93
  * Purge CDN mirror cache
94
  */
95
+ function cdn_purge_all( $extras = array() ) {
96
  if ( $this->_config->get_boolean( 'cdn.enabled' ) )
97
+ return $this->_executor->cdn_purge_all( $extras );
98
 
99
  return false;
100
  }
CacheFlush_Locally.php CHANGED
@@ -103,13 +103,18 @@ class CacheFlush_Locally {
103
  /**
104
  * Purge CDN mirror cache
105
  */
106
- function cdn_purge_all() {
107
- do_action( 'w3tc_cdn_purge_all' );
108
- $cdn_core = Dispatcher::component( 'Cdn_Core' );
109
- $cdn = $cdn_core->get_cdn();
110
- $results = array();
111
- $v = $cdn->purge_all( $results );
112
- do_action( 'w3tc_cdn_purge_all_after' );
 
 
 
 
 
113
 
114
  return $v;
115
  }
@@ -159,7 +164,7 @@ class CacheFlush_Locally {
159
  function flush_post( $post_id, $extras = null ) {
160
  $do_flush = apply_filters( 'w3tc_preflush_post', true, $extras );
161
  if ( $do_flush )
162
- do_action( 'w3tc_flush_post', $post_id );
163
  }
164
 
165
  /**
@@ -219,7 +224,7 @@ class CacheFlush_Locally {
219
  function flush_url( $url, $extras = null ) {
220
  $do_flush = apply_filters( 'w3tc_preflush_url', true, $extras );
221
  if ( $do_flush )
222
- do_action( 'w3tc_flush_url', $url );
223
  }
224
 
225
  /**
103
  /**
104
  * Purge CDN mirror cache
105
  */
106
+ function cdn_purge_all( $extras = array() ) {
107
+ $do_flush = apply_filters( 'w3tc_preflush_cdn_all', true, $extras );
108
+
109
+ $v = false;
110
+ if ( $do_flush ) {
111
+ do_action( 'w3tc_cdn_purge_all' );
112
+ $cdn_core = Dispatcher::component( 'Cdn_Core' );
113
+ $cdn = $cdn_core->get_cdn();
114
+ $results = array();
115
+ $v = $cdn->purge_all( $results );
116
+ do_action( 'w3tc_cdn_purge_all_after' );
117
+ }
118
 
119
  return $v;
120
  }
164
  function flush_post( $post_id, $extras = null ) {
165
  $do_flush = apply_filters( 'w3tc_preflush_post', true, $extras );
166
  if ( $do_flush )
167
+ do_action( 'w3tc_flush_post', $post_id, $extras );
168
  }
169
 
170
  /**
224
  function flush_url( $url, $extras = null ) {
225
  $do_flush = apply_filters( 'w3tc_preflush_url', true, $extras );
226
  if ( $do_flush )
227
+ do_action( 'w3tc_flush_url', $url, $extras );
228
  }
229
 
230
  /**
Cache_Base.php CHANGED
@@ -184,7 +184,9 @@ class Cache_Base {
184
  * @return string
185
  */
186
  protected function _get_key_version_key( $group = '' ) {
187
- return sprintf( 'w3tc_%d_%s_%s_%d_key_version', $this->_blog_id, $this->_module, $group, $this->_instance_id );
 
 
188
  }
189
 
190
  /**
@@ -194,7 +196,9 @@ class Cache_Base {
194
  * @return string
195
  */
196
  public function get_item_key( $name ) {
197
- $key = sprintf( 'w3tc_%s_%d_%s_%s', $this->_host, $this->_blog_id, $this->_module, $name );
 
 
198
  return $key;
199
  }
200
 
184
  * @return string
185
  */
186
  protected function _get_key_version_key( $group = '' ) {
187
+ return sprintf( 'w3tc_%d_%d_%s_%s_key_version',
188
+ $this->_instance_id, $this->_blog_id,
189
+ $this->_module, $group );
190
  }
191
 
192
  /**
196
  * @return string
197
  */
198
  public function get_item_key( $name ) {
199
+ $key = sprintf( 'w3tc_%d_%s_%d_%s_%s',
200
+ $this->_instance_id, $this->_host, $this->_blog_id,
201
+ $this->_module, $name );
202
  return $key;
203
  }
204
 
Cache_File_Generic.php CHANGED
@@ -209,6 +209,11 @@ class Cache_File_Generic extends Cache_File {
209
  if ( !file_exists( $path ) )
210
  return true;
211
 
 
 
 
 
 
212
  $old_entry_path = $path . '_old';
213
  if ( ! @rename( $path, $old_entry_path ) ) {
214
  // if we can delete old entry - do second attempt to store in old-entry file
209
  if ( !file_exists( $path ) )
210
  return true;
211
 
212
+ $dir = dirname( $path );
213
+ if ( file_exists( $dir . DIRECTORY_SEPARATOR . '.htaccess' ) ) {
214
+ @unlink( $dir . DIRECTORY_SEPARATOR . '.htaccess' );
215
+ }
216
+
217
  $old_entry_path = $path . '_old';
218
  if ( ! @rename( $path, $old_entry_path ) ) {
219
  // if we can delete old entry - do second attempt to store in old-entry file
Cache_Memcache.php CHANGED
@@ -325,7 +325,9 @@ class Cache_Memcache extends Cache_Base {
325
 
326
  public function get_item_key( $name ) {
327
  // memcached doesn't survive spaces in a key
328
- $key = sprintf( 'w3tc_%s_%d_%s_%s', $this->_host, $this->_blog_id, $this->_module, md5( $name ) );
 
 
329
  return $key;
330
  }
331
  }
325
 
326
  public function get_item_key( $name ) {
327
  // memcached doesn't survive spaces in a key
328
+ $key = sprintf( 'w3tc_%d_%s_%d_%s_%s',
329
+ $this->_instance_id, $this->_host, $this->_blog_id,
330
+ $this->_module, md5( $name ) );
331
  return $key;
332
  }
333
  }
Cache_Memcached.php CHANGED
@@ -13,17 +13,17 @@ class Cache_Memcached extends Cache_Base {
13
  private $_memcache = null;
14
 
15
  /*
16
- * Used for faster flushing
17
- *
18
- * @var integer $_key_version
19
- */
20
  private $_key_version = array();
21
 
22
  /*
23
- * Configuration used to reinitialize persistent object
24
- *
25
- * @var integer $_key_version
26
- */
27
  private $_config = null;
28
 
29
  /**
@@ -77,10 +77,10 @@ class Cache_Memcached extends Cache_Base {
77
  }
78
 
79
  if ( isset( $config['username'] ) && !empty( $config['username'] ) &&
80
- method_exists( $this->_memcache, 'setSaslAuthData' ) &&
81
- ini_get( 'memcached.use_sasl' ) )
82
  $this->_memcache->setSaslAuthData( $config['username'],
83
  $config['password'] );
 
84
 
85
  // when disabled - no extra requests are made to obtain key version,
86
  // but flush operations not supported as a result
@@ -397,7 +397,9 @@ class Cache_Memcached extends Cache_Base {
397
 
398
  public function get_item_key( $name ) {
399
  // memcached doesn't survive spaces in a key
400
- $key = sprintf( 'w3tc_%s_%d_%s_%s', $this->_host, $this->_blog_id, $this->_module, md5( $name ) );
 
 
401
  return $key;
402
  }
403
  }
13
  private $_memcache = null;
14
 
15
  /*
16
+ * Used for faster flushing
17
+ *
18
+ * @var integer $_key_version
19
+ */
20
  private $_key_version = array();
21
 
22
  /*
23
+ * Configuration used to reinitialize persistent object
24
+ *
25
+ * @var integer $_key_version
26
+ */
27
  private $_config = null;
28
 
29
  /**
77
  }
78
 
79
  if ( isset( $config['username'] ) && !empty( $config['username'] ) &&
80
+ method_exists( $this->_memcache, 'setSaslAuthData' ) ) {
 
81
  $this->_memcache->setSaslAuthData( $config['username'],
82
  $config['password'] );
83
+ }
84
 
85
  // when disabled - no extra requests are made to obtain key version,
86
  // but flush operations not supported as a result
397
 
398
  public function get_item_key( $name ) {
399
  // memcached doesn't survive spaces in a key
400
+ $key = sprintf( 'w3tc_%d_%s_%d_%s_%s',
401
+ $this->_instance_id, $this->_host, $this->_blog_id,
402
+ $this->_module, md5( $name ) );
403
  return $key;
404
  }
405
  }
Cache_Nginx_Memcached.php ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace W3TC;
3
+
4
+ /**
5
+ * PECL Memcached class
6
+ */
7
+ class Cache_Nginx_Memcached extends Cache_Base {
8
+ /**
9
+ * Memcache object
10
+ */
11
+ private $_memcache = null;
12
+
13
+ /*
14
+ * Configuration used to reinitialize persistent object
15
+ */
16
+ private $_config = null;
17
+
18
+ /**
19
+ * constructor
20
+ */
21
+ function __construct( $config ) {
22
+ parent::__construct( $config );
23
+
24
+ if ( isset( $config['persistent'] ) && $config['persistent'] ) {
25
+ $this->_config = $config;
26
+ $this->_memcache = new \Memcached( $this->_get_key_version_key( '' ) );
27
+ $server_list = $this->_memcache->getServerList();
28
+
29
+ if ( empty( $server_list ) )
30
+ return $this->initialize( $config );
31
+ else
32
+ return true;
33
+ } else {
34
+ $this->_memcache = new \Memcached();
35
+ return $this->initialize( $config );
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Initializes
41
+ */
42
+ private function initialize( $config ) {
43
+ if ( empty( $config['servers'] ) )
44
+ return false;
45
+
46
+ if ( defined( '\Memcached::OPT_REMOVE_FAILED_SERVERS' ) ) {
47
+ $this->_memcache->setOption( \Memcached::OPT_REMOVE_FAILED_SERVERS, true );
48
+ }
49
+
50
+ $this->_memcache->setOption( \Memcached::OPT_COMPRESSION, false );
51
+
52
+ if ( isset( $config['aws_autodiscovery'] ) &&
53
+ $config['aws_autodiscovery'] &&
54
+ defined( '\Memcached::OPT_CLIENT_MODE' ) &&
55
+ defined( '\Memcached::DYNAMIC_CLIENT_MODE' ) )
56
+ $this->_memcache->setOption( \Memcached::OPT_CLIENT_MODE,
57
+ \Memcached::DYNAMIC_CLIENT_MODE );
58
+
59
+ foreach ( (array)$config['servers'] as $server ) {
60
+ if ( substr( $server, 0, 5 ) == 'unix:' )
61
+ $this->_memcache->addServer( trim( $server ), 0 );
62
+ else {
63
+ list( $ip, $port ) = explode( ':', $server );
64
+ $this->_memcache->addServer( trim( $ip ), (integer) trim( $port ) );
65
+ }
66
+ }
67
+
68
+ if ( isset( $config['username'] ) && !empty( $config['username'] ) &&
69
+ method_exists( $this->_memcache, 'setSaslAuthData' ) ) {
70
+ $this->_memcache->setSaslAuthData( $config['username'],
71
+ $config['password'] );
72
+ }
73
+
74
+ return true;
75
+ }
76
+
77
+ /**
78
+ * Adds data
79
+ *
80
+ * @param string $key
81
+ * @param mixed $var
82
+ * @param integer $expire
83
+ * @param string $group Used to differentiate between groups of cache values
84
+ * @return boolean
85
+ */
86
+ function add( $key, &$var, $expire = 0, $group = '' ) {
87
+ return $this->set( $key, $var, $expire, $group );
88
+ }
89
+
90
+ /**
91
+ * Sets data
92
+ *
93
+ * @param string $key
94
+ * @param mixed $var
95
+ * @param integer $expire
96
+ * @param string $group Used to differentiate between groups of cache values
97
+ * @return boolean
98
+ */
99
+ function set( $key, $var, $expire = 0, $group = '' ) {
100
+ $this->_memcache->setOption( \Memcached::OPT_USER_FLAGS,
101
+ ( isset( $var['c'] ) ? 1 : 0 ) );
102
+
103
+ return @$this->_memcache->set( $key, $var['content'], $expire );
104
+ }
105
+
106
+ /**
107
+ * Returns data
108
+ *
109
+ * @param string $key
110
+ * @param string $group Used to differentiate between groups of cache values
111
+ * @return mixed
112
+ */
113
+ function get_with_old( $key, $group = '' ) {
114
+ $has_old_data = false;
115
+
116
+ $v = @$this->_memcache->get( $key );
117
+ if ( $v === FALSE ) {
118
+ return null;
119
+ }
120
+
121
+ $data = array( 'content' => $v );
122
+ $data['compression'] = ( substr( $key, -5 ) == '_gzip' ? 'gzip' : '' );
123
+ return array( $data, false );
124
+ }
125
+
126
+ /**
127
+ * Replaces data
128
+ *
129
+ * @param string $key
130
+ * @param mixed $var
131
+ * @param integer $expire
132
+ * @param string $group Used to differentiate between groups of cache values
133
+ * @return boolean
134
+ */
135
+ function replace( $key, &$var, $expire = 0, $group = '' ) {
136
+ return $this->set( $key, $var, $expire, $group );
137
+ }
138
+
139
+ /**
140
+ * Deletes data
141
+ *
142
+ * @param string $key
143
+ * @param string $group
144
+ * @return boolean
145
+ */
146
+ function delete( $key, $group = '' ) {
147
+ return @$this->_memcache->delete( $key );
148
+ }
149
+
150
+ /**
151
+ * Key to delete, deletes _old and primary if exists.
152
+ *
153
+ * @param unknown $key
154
+ * @return bool
155
+ */
156
+ function hard_delete( $key, $group = '' ) {
157
+ return @$this->_memcache->delete( $key );
158
+ }
159
+
160
+ /**
161
+ * Flushes all data
162
+ *
163
+ * @param string $group Used to differentiate between groups of cache values
164
+ * @return boolean
165
+ */
166
+ function flush( $group = '' ) {
167
+ // can only flush everything from memcached, no way to flush only
168
+ // pgcache cache
169
+ return @$this->_memcache->flush();
170
+ }
171
+
172
+ /**
173
+ * Checks if engine can function properly in this environment
174
+ *
175
+ * @return bool
176
+ */
177
+ public function available() {
178
+ return class_exists( 'Memcached' );
179
+ }
180
+
181
+ public function get_statistics() {
182
+ $a = $this->_memcache->getStats();
183
+ if ( count( $a ) > 0 ) {
184
+ $keys = array_keys( $a );
185
+ $key = $keys[0];
186
+ return $a[$key];
187
+ }
188
+
189
+ return $a;
190
+ }
191
+
192
+ /**
193
+ * Returns size used by cache
194
+ */
195
+ public function get_stats_size( $timeout_time ) {
196
+ $size = array(
197
+ 'bytes' => 0,
198
+ 'items' => 0,
199
+ 'timeout_occurred' => false,
200
+ );
201
+
202
+ $key_prefix = $this->get_item_key( '' );
203
+ $error_occurred = false;
204
+
205
+ $server_list = $this->_memcache->getServerList();
206
+ $n = 0;
207
+
208
+ foreach ( $server_list as $server ) {
209
+ $loader = new Cache_Memcached_Stats( $server['host'], $server['port'] );
210
+ $slabs = $loader->slabs();
211
+ if ( !is_array( $slabs ) ) {
212
+ $error_occurred = true;
213
+ continue;
214
+ }
215
+
216
+ foreach ( $slabs as $slab_id ) {
217
+ $cdump = $loader->cachedump( $slab_id );
218
+ if ( !is_array( $cdump ) )
219
+ continue;
220
+
221
+ foreach ( $cdump as $line ) {
222
+ $key_data = explode( ' ', $line );
223
+ if ( !is_array( $key_data ) || count( $key_data ) < 3 )
224
+ continue;
225
+ $n++;
226
+ if ( $n % 10 == 0 ) {
227
+ $size['timeout_occurred'] = ( time() > $timeout_time );
228
+ if ( $size['timeout_occurred'] )
229
+ return $size;
230
+ }
231
+
232
+ $key = $key_data[1];
233
+ $bytes = substr( $key_data[2], 1 );
234
+
235
+ if ( substr( $key, 0, strlen( $key_prefix ) ) == $key_prefix ) {
236
+ $size['bytes'] += $bytes;
237
+ $size['items']++;
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ if ( $error_occurred && $size['items'] <= 0 ) {
244
+ $size['bytes'] = null;
245
+ $size['items'] = null;
246
+ }
247
+
248
+ return $size;
249
+ }
250
+
251
+ /**
252
+ * Used to replace as atomically as possible known value to new one
253
+ */
254
+ public function set_if_maybe_equals( $key, $old_value, $new_value ) {
255
+ $storage_key = $this->get_item_key( $key );
256
+
257
+ $cas = null;
258
+ $value = @$this->_memcache->get( $storage_key, null, $cas );
259
+
260
+ if ( !is_array( $value ) )
261
+ return false;
262
+
263
+ if ( isset( $old_value['content'] ) &&
264
+ $value['content'] != $old_value['content'] )
265
+ return false;
266
+
267
+ return @$this->_memcache->cas( $cas, $storage_key, $new_value );
268
+ }
269
+
270
+ /**
271
+ * Use key as a counter and add integet value to it
272
+ */
273
+ public function counter_add( $key, $value ) {
274
+ if ( $value == 0 )
275
+ return true;
276
+
277
+ $storage_key = $this->get_item_key( $key );
278
+ $r = @$this->_memcache->increment( $storage_key, $value );
279
+ if ( !$r ) // it doesnt initialize counter by itself
280
+ $this->counter_set( $key, 0 );
281
+
282
+ return $r;
283
+ }
284
+
285
+ /**
286
+ * Use key as a counter and add integet value to it
287
+ */
288
+ public function counter_set( $key, $value ) {
289
+ $storage_key = $this->get_item_key( $key );
290
+ return @$this->_memcache->set( $storage_key, $value );
291
+ }
292
+
293
+ /**
294
+ * Get counter's value
295
+ */
296
+ public function counter_get( $key ) {
297
+ $storage_key = $this->get_item_key( $key );
298
+ $v = (int)@$this->_memcache->get( $storage_key );
299
+
300
+ return $v;
301
+ }
302
+
303
+ public function get_item_key( $name ) {
304
+ // memcached doesn't survive spaces in a key
305
+ $key = sprintf( 'w3tc_%d_%s_%d_%s_%s',
306
+ $this->_instance_id, $this->_host, $this->_blog_id,
307
+ $this->_module, md5( $name ) );
308
+ return $key;
309
+ }
310
+ }
Cache_Redis.php CHANGED
@@ -216,9 +216,15 @@ class Cache_Redis extends Cache_Base {
216
  if ( is_null( $accessor ) )
217
  return 0;
218
 
219
- $v = $accessor->get( $storage_key );
220
- $v = intval( $v );
221
- $this->_key_version[$group] = ( $v > 0 ? $v : 1 );
 
 
 
 
 
 
222
  }
223
 
224
  return $this->_key_version[$group];
216
  if ( is_null( $accessor ) )
217
  return 0;
218
 
219
+ $v_original = $accessor->get( $storage_key );
220
+ $v = intval( $v_original );
221
+ $v = ( $v > 0 ? $v : 1 );
222
+
223
+ if ( (string)$v_original !== (string)$v ) {
224
+ $accessor->set( $storage_key, $v );
225
+ }
226
+
227
+ $this->_key_version[$group] = $v;
228
  }
229
 
230
  return $this->_key_version[$group];
CdnEngine.php CHANGED
@@ -92,6 +92,10 @@ class CdnEngine {
92
  $instances[$instance_key] = new CdnEngine_Mirror_StackPath( $config );
93
  break;
94
 
 
 
 
 
95
  default :
96
  trigger_error( 'Incorrect CDN engine', E_USER_WARNING );
97
  $instances[$instance_key] = new CdnEngine_Base();
92
  $instances[$instance_key] = new CdnEngine_Mirror_StackPath( $config );
93
  break;
94
 
95
+ case 'stackpath2':
96
+ $instances[$instance_key] = new CdnEngine_Mirror_StackPath2( $config );
97
+ break;
98
+
99
  default :
100
  trigger_error( 'Incorrect CDN engine', E_USER_WARNING );
101
  $instances[$instance_key] = new CdnEngine_Base();
CdnEngine_Ftp.php CHANGED
@@ -25,15 +25,18 @@ class CdnEngine_Ftp extends CdnEngine_Base {
25
  */
26
  function __construct( $config = array() ) {
27
  $config = array_merge( array(
28
- 'host' => '',
29
- 'type' => '',
30
- 'user' => '',
31
- 'pass' => '',
32
- 'path' => '',
33
- 'pasv' => false,
34
- 'domain' => array(),
35
- 'docroot' => ''
36
- ), $config );
 
 
 
37
 
38
  $host_port = explode( ':', $config['host'] );
39
  if ( sizeof( $host_port ) == 2 ) {
@@ -41,6 +44,11 @@ class CdnEngine_Ftp extends CdnEngine_Base {
41
  $config['port'] = $host_port[1];
42
  }
43
 
 
 
 
 
 
44
  parent::__construct( $config );
45
  }
46
 
@@ -63,6 +71,21 @@ class CdnEngine_Ftp extends CdnEngine_Base {
63
 
64
  $this->_set_error_handler();
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if ( $this->_config['type'] == 'ftps' )
67
  $this->_ftp = @ftp_ssl_connect( $this->_config['host'],
68
  (int) $this->_config['port'], W3TC_CDN_FTP_CONNECT_TIMEOUT );
@@ -112,11 +135,59 @@ class CdnEngine_Ftp extends CdnEngine_Base {
112
  return true;
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  /**
116
  * Disconnects from FTP server
117
  */
118
  function _disconnect() {
119
- @ftp_close( $this->_ftp );
 
 
 
 
 
 
 
120
  }
121
 
122
  /**
@@ -141,7 +212,7 @@ class CdnEngine_Ftp extends CdnEngine_Base {
141
  * @return boolean
142
  */
143
  function upload( $files, &$results, $force_rewrite = false,
144
- $timeout_time = NULL ) {
145
  $error = null;
146
 
147
  if ( !$this->_connect( $error ) ) {
@@ -152,6 +223,10 @@ class CdnEngine_Ftp extends CdnEngine_Base {
152
 
153
  $this->_set_error_handler();
154
 
 
 
 
 
155
  $home = @ftp_pwd( $this->_ftp );
156
 
157
  if ( $home === false ) {
@@ -250,6 +325,83 @@ class CdnEngine_Ftp extends CdnEngine_Base {
250
  return !$this->_is_error( $results );
251
  }
252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  /**
254
  * Deletes files from FTP
255
  *
@@ -272,7 +424,12 @@ class CdnEngine_Ftp extends CdnEngine_Base {
272
  $local_path = $file['local_path'];
273
  $remote_path = $file['remote_path'];
274
 
275
- $result = @ftp_delete( $this->_ftp, $remote_path );
 
 
 
 
 
276
 
277
  if ( $result ) {
278
  $results[] = $this->_get_result( $local_path, $remote_path,
@@ -288,7 +445,13 @@ class CdnEngine_Ftp extends CdnEngine_Base {
288
  while ( true ) {
289
  $remote_path = dirname( $remote_path );
290
 
291
- if ( $remote_path == '.' || !@ftp_rmdir( $this->_ftp, $remote_path ) ) {
 
 
 
 
 
 
292
  break;
293
  }
294
  }
@@ -311,6 +474,10 @@ class CdnEngine_Ftp extends CdnEngine_Base {
311
  return false;
312
  }
313
 
 
 
 
 
314
  $rand = md5( time() );
315
  $tmp_dir = 'test_dir_' . $rand;
316
  $tmp_file = 'test_file_' . $rand;
@@ -407,6 +574,97 @@ class CdnEngine_Ftp extends CdnEngine_Base {
407
  return true;
408
  }
409
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  /**
411
  * Returns array of CDN domains
412
  *
25
  */
26
  function __construct( $config = array() ) {
27
  $config = array_merge( array(
28
+ 'host' => '',
29
+ 'type' => '',
30
+ 'user' => '',
31
+ 'pass' => '',
32
+ 'default_keys' => false,
33
+ 'pubkey' => '',
34
+ 'privkey' => '',
35
+ 'path' => '',
36
+ 'pasv' => false,
37
+ 'domain' => array(),
38
+ 'docroot' => ''
39
+ ), $config );
40
 
41
  $host_port = explode( ':', $config['host'] );
42
  if ( sizeof( $host_port ) == 2 ) {
44
  $config['port'] = $host_port[1];
45
  }
46
 
47
+ if ( $config['type'] == 'sftp' && $config['default_keys'] ) {
48
+ $config['pubkey'] = $_SERVER['HOME'] . '/.ssh/id_rsa.pub';
49
+ $config['privkey'] = $_SERVER['HOME'] . '/.ssh/id_rsa';
50
+ }
51
+
52
  parent::__construct( $config );
53
  }
54
 
71
 
72
  $this->_set_error_handler();
73
 
74
+ if ( $this->_config['type'] == 'sftp' ) {
75
+ if ( !function_exists( 'ssh2_connect' ) ) {
76
+ $error = sprintf('Missing required php-ssh2 extension.');
77
+
78
+ $this->_restore_error_handler();
79
+ $this->_disconnect();
80
+
81
+ return false;
82
+ }
83
+
84
+ $this->_ftp = @ssh2_connect( $this->_config['host'], (int) $this->_config['port'] );
85
+
86
+ return $this->_connect_sftp( $error );
87
+ }
88
+
89
  if ( $this->_config['type'] == 'ftps' )
90
  $this->_ftp = @ftp_ssl_connect( $this->_config['host'],
91
  (int) $this->_config['port'], W3TC_CDN_FTP_CONNECT_TIMEOUT );
135
  return true;
136
  }
137
 
138
+ /**
139
+ * Connects to SFTP server
140
+ *
141
+ * @param string $error
142
+ * @return boolean
143
+ */
144
+ function _connect_sftp( &$error ) {
145
+ if ( is_file( $this->_config['pass'] ) ) {
146
+ if ( !@ssh2_auth_pubkey_file( $this->_ftp, $this->_config['user'], $this->_config['pubkey'], $this->_config['privkey'], $this->_config['pass'] ) ) {
147
+ $error = sprintf('Public key authentication failed (%s).', $this->_get_last_error());
148
+
149
+ $this->_restore_error_handler();
150
+ $this->_disconnect();
151
+
152
+ return false;
153
+ }
154
+ } else {
155
+ if ( !@ssh2_auth_password( $this->_ftp, $this->_config['user'], $this->_config['pass'] ) ) {
156
+ $error = sprintf('Incorrect login or password (%s).', $this->_get_last_error());
157
+
158
+ $this->_restore_error_handler();
159
+ $this->_disconnect();
160
+
161
+ return false;
162
+ }
163
+ }
164
+
165
+ if ( !empty( $this->_config['path'] ) && !@ssh2_exec( $this->_ftp, 'cd ' . $this->_config['path'] ) ) {
166
+ $error = sprintf( 'Unable to change directory to: %s (%s).', $this->_config['path'], $this->_get_last_error() );
167
+
168
+ $this->_restore_error_handler();
169
+ $this->_disconnect();
170
+
171
+ return false;
172
+ }
173
+
174
+ $this->_restore_error_handler();
175
+
176
+ return true;
177
+ }
178
+
179
  /**
180
  * Disconnects from FTP server
181
  */
182
  function _disconnect() {
183
+ if ( $this->_config['type'] == 'sftp' ) {
184
+ if ( function_exists( 'ssh2_connect' ) ) {
185
+ @ssh2_exec( $this->_ftp, 'echo "EXITING" && exit;' );
186
+ $this->_ftp = null;
187
+ }
188
+ } else {
189
+ @ftp_close( $this->_ftp );
190
+ }
191
  }
192
 
193
  /**