Wordfence Security – Firewall & Malware Scan - Version 6.2.8

Version Description

  • Improvement: Added support for hiding the username information revealed by the WordPress 4.7 REST API. Thanks Vladimir Smitka.
  • Improvement: Added vulnerability scanning for themes.
  • Improvement: Reduced memory usage by up to 90% when scanning comments.
  • Improvement: Performance improvements for the dashboard widget.
  • Improvement: Added progressive loading of addresses on the blocked IP list.
  • Improvement: The diagnostics page now displays a config reading/writing test.
  • Change: Support for the Falcon cache has been removed.
  • Fix: Better messaging when the WAF rules are manually updated.
  • Fix: The proxy detection check frequency has been reduced and no longer alerts if the server is unreachable.
  • Fix: Adjusted the behavior of parsing the X-Forwarded-For header for better accuracy. Thanks Jason Woods.
  • Fix: Typo fix on the options page.
  • Fix: Scan issue for known core file now shows the correct links.
  • Fix: Links in "unlock" emails now work for IPv6 and IPv4-mapped-IPv6 addresses.
  • Fix: Restricted caching of responses from the Wordfence Security Network.
  • Fix: Fixed a recording issue with Wordfence Security Network statistics.
Download this release

Release Info

Developer wfryan
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 6.2.8
Comparing to
See all releases

Code changes from version 6.2.7 to 6.2.8

css/main.css CHANGED
@@ -537,48 +537,6 @@ h3.wfConfigHeading {
537
  padding: 10px;
538
  margin: 20px;
539
  }
540
- .wfFalconNotice {
541
- width: 500px;
542
- background-color: #FFD7CE;
543
- border: 1px solid #000;
544
- padding: 10px;
545
- margin: 20px;
546
- }
547
- .wfFalcon {
548
- width: 63px;
549
- height: 63px;
550
- border-width: 0;
551
- background-color: transparent;
552
- background-image: url(../images/wordfenceFalcon.png);
553
- background-position: 0 0;
554
- background-repeat: no-repeat;
555
- position: absolute;
556
- right: 2px;
557
- top: 3px;
558
- }
559
- .wfFalconImage {
560
- width: 63px;
561
- height: 63px;
562
- border-width: 0;
563
- background-color: transparent;
564
- background-image: url(../images/wordfenceFalcon.png);
565
- background-position: 0 0;
566
- background-repeat: no-repeat;
567
- margin: 5px auto 15px auto;
568
- }
569
- .wfSmallFalcon {
570
- width: 33px;
571
- height: 16px;
572
- border-width: 0;
573
- background-color: transparent;
574
- background-image: url(../images/wordfenceFalconSmall.png);
575
- background-position: 0 0;
576
- background-repeat: no-repeat;
577
- margin: 0;
578
- padding: 0;
579
- display: inline;
580
- float: right;
581
- }
582
 
583
 
584
 
@@ -1241,4 +1199,9 @@ tr.wf-table-filters input {
1241
 
1242
  .wf-hex-sequence {
1243
  color: #587ECB;
 
 
 
 
 
1244
  }
537
  padding: 10px;
538
  margin: 20px;
539
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
 
541
 
542
 
1199
 
1200
  .wf-hex-sequence {
1201
  color: #587ECB;
1202
+ }
1203
+
1204
+ .wfLoadMoreButton.disabled, .wfLoadMoreButton[disabled] {
1205
+ pointer-events: none;
1206
+ opacity: 0.65;
1207
  }
images/wordfenceFalcon.png DELETED
Binary file
images/wordfenceFalconEngineSmall.png DELETED
Binary file
images/wordfenceFalconSmall.png DELETED
Binary file
js/admin.js CHANGED
@@ -42,6 +42,7 @@
42
  serverTimestampOffset: 0,
43
  serverMicrotime: 0,
44
  wfLiveTraffic: null,
 
45
 
46
  init: function() {
47
  this.nonce = WordfenceAdminVars.firstNonce;
@@ -159,14 +160,9 @@
159
  this.setupSwitches('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
160
  });
161
  jQuery('#wfLiveTrafficOnOff').change(function() {
162
- if (/^(?:falcon|php)$/.test(WordfenceAdminVars.cacheType)) {
163
- jQuery('#wfLiveTrafficOnOff').attr('checked', false);
164
- self.colorbox('400px', "Live Traffic not available in high performance mode", "Please note that you can't enable live traffic when Falcon Engine or basic caching is enabled. This is done for performance reasons. If you want live traffic, go to the 'Performance Setup' menu and disable caching.");
165
- } else {
166
- self.updateSwitch('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
167
- window.location.reload(true);
168
- });
169
- }
170
  });
171
 
172
  if (WordfenceAdminVars.liveTrafficEnabled) {
@@ -210,6 +206,25 @@
210
  self.tourRedir('WordfencePasswdAudit');
211
  });
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  } else if (jQuery('#wordfenceMode_passwd').length > 0) {
214
  this.mode = 'passwd';
215
  startTicker = false;
@@ -267,15 +282,6 @@
267
  self.tourRedir('WordfenceWhois');
268
  });
269
  }
270
- } else if (jQuery('#wordfenceMode_caching').length > 0) {
271
- this.mode = 'caching';
272
- startTicker = false;
273
- if (this.needTour()) {
274
- this.tour('wfWelcomeContentCaching', 'wfHeading', 'top', 'left', "Learn about IP Blocking", function() {
275
- self.tourRedir('WordfenceBlockedIPs');
276
- });
277
- }
278
- this.loadCacheExclusions();
279
  } else {
280
  this.mode = false;
281
  }
@@ -1172,7 +1178,7 @@
1172
  var title = "Full Path Disclosure";
1173
  issueID = parseInt(issueID);
1174
 
1175
- this.ajax('wordfence_checkFalconHtaccess', {}, function(res) {
1176
  if (res.ok) {
1177
  self.colorbox("400px", title, 'We are about to change your <em>.htaccess</em> file. Please make a backup of this file proceeding'
1178
  + '<br/>'
@@ -1246,7 +1252,7 @@
1246
  var nginx = "You will need to manually delete those files";
1247
  issueID = parseInt(issueID, 10);
1248
 
1249
- this.ajax('wordfence_checkFalconHtaccess', {}, this._handleHtAccess(issueID, '_hideFile', title, nginx));
1250
  },
1251
 
1252
  restoreFile: function(issueID) {
@@ -1279,7 +1285,7 @@
1279
  var title = "Disable Directory Listing";
1280
  issueID = parseInt(issueID);
1281
 
1282
- this.ajax('wordfence_checkFalconHtaccess', {}, function(res) {
1283
  if (res.ok) {
1284
  self.colorbox("400px", title, 'We are about to change your <em>.htaccess</em> file. Please make a backup of this file proceeding'
1285
  + '<br/>'
@@ -1458,38 +1464,76 @@
1458
  }
1459
  this.activityMode = mode;
1460
 
 
 
 
 
1461
  var self = this;
1462
- this.ajax('wordfence_loadStaticPanel', {
1463
- mode: this.activityMode
 
 
 
 
1464
  }, function(res) {
1465
  self.completeLoadStaticPanel(res);
 
1466
  });
1467
  },
1468
  completeLoadStaticPanel: function(res) {
1469
  var contentElem = '#wfActivity_' + this.activityMode;
1470
- jQuery(contentElem).empty();
1471
- if (res.results && res.results.length > 0) {
 
 
 
 
 
 
 
 
 
 
 
1472
  var tmpl;
 
 
1473
  if (this.activityMode == 'topScanners' || this.activityMode == 'topLeechers') {
1474
  tmpl = '#wfLeechersTmpl';
 
 
1475
  } else if (this.activityMode == 'blockedIPs') {
1476
  tmpl = '#wfBlockedIPsTmpl';
 
 
1477
  } else if (this.activityMode == 'lockedOutIPs') {
1478
  tmpl = '#wfLockedOutIPsTmpl';
 
 
1479
  } else if (this.activityMode == 'throttledIPs') {
1480
  tmpl = '#wfThrottledIPsTmpl';
 
 
1481
  } else {
1482
  return;
1483
  }
1484
- var i, j, chunk = 1000;
1485
- var bigArray = res.results.slice(0);
1486
- res.results = false;
1487
- for (i = 0, j = bigArray.length; i < j; i += chunk) {
1488
- res.results = bigArray.slice(i, i + chunk);
1489
- jQuery(tmpl).tmpl(res).appendTo(contentElem);
 
 
 
 
1490
  }
 
 
1491
  this.reverseLookupIPs();
1492
- } else {
 
 
1493
  if (this.activityMode == 'topScanners' || this.activityMode == 'topLeechers') {
1494
  jQuery(contentElem).html("No site hits have been logged yet. Check back soon.");
1495
  } else if (this.activityMode == 'blockedIPs') {
@@ -1916,76 +1960,6 @@
1916
  }, 2000);
1917
  });
1918
  },
1919
- getCacheStats: function() {
1920
- var self = this;
1921
- this.ajax('wordfence_getCacheStats', {}, function(res) {
1922
- if (res.ok) {
1923
- self.colorbox('400px', res.heading, res.body);
1924
- }
1925
- });
1926
- },
1927
- clearPageCache: function() {
1928
- var self = this;
1929
- this.ajax('wordfence_clearPageCache', {}, function(res) {
1930
- if (res.ok) {
1931
- self.colorbox('400px', res.heading, res.body);
1932
- }
1933
- });
1934
- },
1935
- switchToFalcon: function() {
1936
- var self = this;
1937
- this.ajax('wordfence_checkFalconHtaccess', {}, function(res) {
1938
- if (res.ok) {
1939
- self.colorbox('400px', "Enabling Falcon Engine", 'First read this <a href="http://www.wordfence.com/introduction-to-wordfence-falcon-engine/" target="_blank">Introduction to Falcon Engine</a>. Falcon modifies your website configuration file which is called your .htaccess file. To enable Falcon we ask that you make a backup of this file. This is a safety precaution in case for some reason Falcon is not compatible with your site.<br /><br /><a href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + self.nonce + '" onclick="jQuery(\'#wfNextBut\').prop(\'disabled\', false); return true;">Click here to download a backup copy of your .htaccess file now</a><br /><br /><input type="button" name="but1" id="wfNextBut" value="Click to Enable Falcon Engine" disabled="disabled" onclick="WFAD.confirmSwitchToFalcon(0);" />');
1940
- } else if (res.nginx) {
1941
- self.colorbox('400px', "Enabling Falcon Engine", 'You are using an Nginx web server and using a FastCGI processor like PHP5-FPM. To use Falcon you will need to manually modify your nginx.conf configuration file and reload your Nginx server for the changes to take effect. You can find the <a href="http://www.wordfence.com/blog/2014/05/nginx-wordfence-falcon-engine-php-fpm-fastcgi-fast-cgi/" target="_blank">rules you need to make these changes to nginx.conf on this page on wordfence.com</a>. Once you have made these changes, compressed cached files will be served to your visitors directly from Nginx making your site extremely fast. When you have made the changes and reloaded your Nginx server, you can click the button below to enable Falcon.<br /><br /><input type="button" name="but1" id="wfNextBut" value="Click to Enable Falcon Engine" onclick="WFAD.confirmSwitchToFalcon(1);" />');
1942
- } else if (res.err) {
1943
- self.colorbox('400px', "We encountered a problem", "We can't modify your .htaccess file for you because: " + res.err + "<br /><br />Advanced users: If you would like to manually enable Falcon yourself by editing your .htaccess, you can add the rules below to the beginning of your .htaccess file. Then click the button below to enable Falcon. Don't do this unless you understand website configuration.<br /><textarea style='width: 300px; height:100px;' readonly>" + jQuery('<div/>').text(res.code).html() + "</textarea><br /><input type='button' value='Enable Falcon after manually editing .htaccess' onclick='WFAD.confirmSwitchToFalcon(1);' />");
1944
- }
1945
- });
1946
- },
1947
- confirmSwitchToFalcon: function(noEditHtaccess) {
1948
- jQuery.colorbox.close();
1949
- var cacheType = 'falcon';
1950
- var self = this;
1951
- this.ajax('wordfence_saveCacheConfig', {
1952
- cacheType: cacheType,
1953
- noEditHtaccess: noEditHtaccess
1954
- }, function(res) {
1955
- if (res.ok) {
1956
- self.colorbox('400px', res.heading, res.body);
1957
- }
1958
- }
1959
- );
1960
- },
1961
- saveCacheConfig: function() {
1962
- var cacheType = jQuery('input:radio[name=cacheType]:checked').val();
1963
- if (cacheType == 'falcon') {
1964
- return this.switchToFalcon();
1965
- }
1966
- var self = this;
1967
- this.ajax('wordfence_saveCacheConfig', {
1968
- cacheType: cacheType
1969
- }, function(res) {
1970
- if (res.ok) {
1971
- self.colorbox('400px', res.heading, res.body);
1972
- }
1973
- }
1974
- );
1975
- },
1976
- saveCacheOptions: function() {
1977
- var self = this;
1978
- this.ajax('wordfence_saveCacheOptions', {
1979
- allowHTTPSCaching: (jQuery('#wfallowHTTPSCaching').is(':checked') ? 1 : 0),
1980
- addCacheComment: (jQuery('#wfaddCacheComment').is(':checked') ? 1 : 0),
1981
- clearCacheSched: (jQuery('#wfclearCacheSched').is(':checked') ? 1 : 0)
1982
- }, function(res) {
1983
- if (res.updateErr) {
1984
- self.colorbox('400px', "You need to manually update your .htaccess", res.updateErr + "<br />Your option was updated but you need to change the Wordfence code in your .htaccess to the following:<br /><textarea style='width: 300px; height: 120px;'>" + jQuery('<div/>').text(res.code).html() + '</textarea>');
1985
- }
1986
- }
1987
- );
1988
- },
1989
  saveConfig: function() {
1990
  var qstr = jQuery('#wfConfigForm').serialize();
1991
  var self = this;
@@ -2470,40 +2444,6 @@
2470
  }
2471
  },
2472
 
2473
- removeCacheExclusion: function(id) {
2474
- this.ajax('wordfence_removeCacheExclusion', {id: id}, function(res) {
2475
- window.location.reload(true);
2476
- });
2477
- },
2478
- addCacheExclusion: function(patternType, pattern) {
2479
- if (/^https?:\/\//.test(pattern)) {
2480
- this.colorbox('400px', "Incorrect pattern for exclusion", "You can not enter full URL's for exclusion from caching. You entered a full URL that started with http:// or https://. You must enter relative URL's e.g. /exclude/this/page/. You can also enter text that might be contained in the path part of a URL or at the end of the path part of a URL.");
2481
- return;
2482
- }
2483
-
2484
- this.ajax('wordfence_addCacheExclusion', {
2485
- patternType: patternType,
2486
- pattern: pattern
2487
- }, function(res) {
2488
- if (res.ok) { //Otherwise errorMsg will get caught
2489
- window.location.reload(true);
2490
- }
2491
- });
2492
- },
2493
- loadCacheExclusions: function() {
2494
- this.ajax('wordfence_loadCacheExclusions', {}, function(res) {
2495
- if (res.ex instanceof Array && res.ex.length > 0) {
2496
- for (var i = 0; i < res.ex.length; i++) {
2497
- var newElem = jQuery('#wfCacheExclusionTmpl').tmpl(res.ex[i]);
2498
- newElem.prependTo('#wfCacheExclusions').fadeIn();
2499
- }
2500
- jQuery('<h2>Cache Exclusions</h2>').prependTo('#wfCacheExclusions');
2501
- } else {
2502
- jQuery('<h2>Cache Exclusions</h2><p style="width: 500px;">There are not currently any exclusions. If you have a site that does not change often, it is perfectly normal to not have any pages you want to exclude from the cache.</p>').prependTo('#wfCacheExclusions');
2503
- }
2504
-
2505
- });
2506
- },
2507
  exportSettings: function() {
2508
  var self = this;
2509
  this.ajax('wordfence_exportSettings', {}, function(res) {
@@ -2748,14 +2688,19 @@
2748
  this.ajax('wordfence_updateWAFRules', {}, function(res) {
2749
  self.wafData = res;
2750
  self.wafConfigPageRender();
2751
- if (!self.wafData['isPaid']) {
2752
- self.colorbox('400px', 'Rules Updated', 'Your rules have been updated successfully. You are ' +
2753
- 'currently using the the free version of Wordfence. ' +
2754
- 'Upgrade to Wordfence premium to have your rules updated automatically as new threats emerge. ' +
2755
- '<a href="https://www.wordfence.com/wafUpdateRules1/wordfence-signup/">Click here to purchase a premium API key</a>. ' +
2756
- '<em>Note: Your rules will still update every 30 days as a free user.</em>');
2757
- } else {
2758
- self.colorbox('400px', 'Rules Updated', 'Your rules have been updated successfully.');
 
 
 
 
 
2759
  }
2760
  if (typeof onSuccess === 'function') {
2761
  return onSuccess.apply(this, arguments);
42
  serverTimestampOffset: 0,
43
  serverMicrotime: 0,
44
  wfLiveTraffic: null,
45
+ loadingBlockedIPs: false,
46
 
47
  init: function() {
48
  this.nonce = WordfenceAdminVars.firstNonce;
160
  this.setupSwitches('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
161
  });
162
  jQuery('#wfLiveTrafficOnOff').change(function() {
163
+ self.updateSwitch('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
164
+ window.location.reload(true);
165
+ });
 
 
 
 
 
166
  });
167
 
168
  if (WordfenceAdminVars.liveTrafficEnabled) {
206
  self.tourRedir('WordfencePasswdAudit');
207
  });
208
  }
209
+
210
+ var self = this;
211
+ var hasScrolled = false;
212
+ $(window).on('scroll', function() {
213
+ var win = $(this);
214
+ var wrapper = $('#wfActivity_' + self.activityMode);
215
+ // console.log(win.scrollTop() + window.innerHeight, liveTrafficWrapper.outerHeight() + liveTrafficWrapper.offset().top);
216
+ var currentScrollBottom = win.scrollTop() + window.innerHeight;
217
+ var scrollThreshold = wrapper.outerHeight() + wrapper.offset().top;
218
+ if (hasScrolled && !self.loadingBlockedIPs && currentScrollBottom >= scrollThreshold) {
219
+ // console.log('infinite scroll');
220
+ hasScrolled = false;
221
+
222
+ self.loadStaticPanelContent(true);
223
+ } else if (currentScrollBottom < scrollThreshold) {
224
+ hasScrolled = true;
225
+ // console.log('no infinite scroll');
226
+ }
227
+ });
228
  } else if (jQuery('#wordfenceMode_passwd').length > 0) {
229
  this.mode = 'passwd';
230
  startTicker = false;
282
  self.tourRedir('WordfenceWhois');
283
  });
284
  }
 
 
 
 
 
 
 
 
 
285
  } else {
286
  this.mode = false;
287
  }
1178
  var title = "Full Path Disclosure";
1179
  issueID = parseInt(issueID);
1180
 
1181
+ this.ajax('wordfence_checkHtaccess', {}, function(res) {
1182
  if (res.ok) {
1183
  self.colorbox("400px", title, 'We are about to change your <em>.htaccess</em> file. Please make a backup of this file proceeding'
1184
  + '<br/>'
1252
  var nginx = "You will need to manually delete those files";
1253
  issueID = parseInt(issueID, 10);
1254
 
1255
+ this.ajax('wordfence_checkHtaccess', {}, this._handleHtAccess(issueID, '_hideFile', title, nginx));
1256
  },
1257
 
1258
  restoreFile: function(issueID) {
1285
  var title = "Disable Directory Listing";
1286
  issueID = parseInt(issueID);
1287
 
1288
+ this.ajax('wordfence_checkHtaccess', {}, function(res) {
1289
  if (res.ok) {
1290
  self.colorbox("400px", title, 'We are about to change your <em>.htaccess</em> file. Please make a backup of this file proceeding'
1291
  + '<br/>'
1464
  }
1465
  this.activityMode = mode;
1466
 
1467
+ this.loadStaticPanelContent(false);
1468
+ },
1469
+ loadStaticPanelContent: function(append) {
1470
+ append = !!append;
1471
  var self = this;
1472
+ var offset = append ? $('tr.' + self.activityMode + 'Record').length : 0;
1473
+ self.loadingBlockedIPs = true;
1474
+ $('.wfLoadMoreButton').attr("disabled", "disabled");
1475
+ self.ajax('wordfence_loadStaticPanel', {
1476
+ mode: self.activityMode,
1477
+ offset: offset
1478
  }, function(res) {
1479
  self.completeLoadStaticPanel(res);
1480
+ self.loadingBlockedIPs = false;
1481
  });
1482
  },
1483
  completeLoadStaticPanel: function(res) {
1484
  var contentElem = '#wfActivity_' + this.activityMode;
1485
+ if (!res.continuation) {
1486
+ jQuery(contentElem).empty();
1487
+ }
1488
+
1489
+ if (res.hasMore) {
1490
+ $('.wfLoadMoreButton').removeAttr("disabled");
1491
+ }
1492
+
1493
+ if ((res.results && res.results.length > 0) || res.continuation) {
1494
+ if (!(res.results && res.results.length > 0)) {
1495
+ return;
1496
+ }
1497
+
1498
  var tmpl;
1499
+ var wrapperTmpl;
1500
+ var wrapperID;
1501
  if (this.activityMode == 'topScanners' || this.activityMode == 'topLeechers') {
1502
  tmpl = '#wfLeechersTmpl';
1503
+ wrapperTmpl = '#wfLeechersWrapperTmpl';
1504
+ wrapperID = '#wfLeechersWrapper';
1505
  } else if (this.activityMode == 'blockedIPs') {
1506
  tmpl = '#wfBlockedIPsTmpl';
1507
+ wrapperTmpl = '#wfBlockedIPsWrapperTmpl';
1508
+ wrapperID = '#wfBlockedIPsWrapper';
1509
  } else if (this.activityMode == 'lockedOutIPs') {
1510
  tmpl = '#wfLockedOutIPsTmpl';
1511
+ wrapperTmpl = '#wfLockedOutIPsWrapperTmpl';
1512
+ wrapperID = '#wfLockedOutIPsWrapper';
1513
  } else if (this.activityMode == 'throttledIPs') {
1514
  tmpl = '#wfThrottledIPsTmpl';
1515
+ wrapperTmpl = '#wfThrottledIPsWrapperTmpl';
1516
+ wrapperID = '#wfThrottledIPsWrapper';
1517
  } else {
1518
  return;
1519
  }
1520
+
1521
+ if (!res.continuation) {
1522
+ jQuery(wrapperTmpl).tmpl(res).appendTo(contentElem);
1523
+
1524
+ var self = this;
1525
+ $('.wfLoadMoreButton').on('click', function(event) {
1526
+ event.stopPropagation();
1527
+ event.preventDefault();
1528
+ self.loadStaticPanelContent(true);
1529
+ });
1530
  }
1531
+
1532
+ jQuery(tmpl).tmpl(res).appendTo(jQuery(wrapperID));
1533
  this.reverseLookupIPs();
1534
+ }
1535
+ else {
1536
+ $('.wfLoadMoreButton').hide();
1537
  if (this.activityMode == 'topScanners' || this.activityMode == 'topLeechers') {
1538
  jQuery(contentElem).html("No site hits have been logged yet. Check back soon.");
1539
  } else if (this.activityMode == 'blockedIPs') {
1960
  }, 2000);
1961
  });
1962
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1963
  saveConfig: function() {
1964
  var qstr = jQuery('#wfConfigForm').serialize();
1965
  var self = this;
2444
  }
2445
  },
2446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2447
  exportSettings: function() {
2448
  var self = this;
2449
  this.ajax('wordfence_exportSettings', {}, function(res) {
2688
  this.ajax('wordfence_updateWAFRules', {}, function(res) {
2689
  self.wafData = res;
2690
  self.wafConfigPageRender();
2691
+ if (self.wafData['updated']) {
2692
+ if (!self.wafData['isPaid']) {
2693
+ self.colorbox('400px', 'Rules Updated', 'Your rules have been updated successfully. You are ' +
2694
+ 'currently using the the free version of Wordfence. ' +
2695
+ 'Upgrade to Wordfence premium to have your rules updated automatically as new threats emerge. ' +
2696
+ '<a href="https://www.wordfence.com/wafUpdateRules1/wordfence-signup/">Click here to purchase a premium API key</a>. ' +
2697
+ '<em>Note: Your rules will still update every 30 days as a free user.</em>');
2698
+ } else {
2699
+ self.colorbox('400px', 'Rules Updated', 'Your rules have been updated successfully.');
2700
+ }
2701
+ }
2702
+ else {
2703
+ self.colorbox('400px', 'Rule Update Failed', 'No rules were updated. Please verify you have permissions to write to the /wp-content/wflogs directory.');
2704
  }
2705
  if (typeof onSuccess === 'function') {
2706
  return onSuccess.apply(this, arguments);
js/tourTip.js CHANGED
@@ -41,14 +41,6 @@ window['wordfenceExt'] = {
41
  function(){ jQuery('#wordfenceSuPHPUpdateWarning').fadeOut(); }
42
  );
43
  },
44
- falconDeprecationChoice: function(choice) {
45
- this.ajax('wordfence_falconDeprecationChoice', {
46
- choice: choice
47
- },
48
- function(res){ jQuery('#wordfenceFalconDeprecationWarning').fadeOut(); },
49
- function(){ jQuery('#wordfenceFalconDeprecationWarning').fadeOut(); }
50
- );
51
- },
52
  misconfiguredHowGetIPsChoice : function(choice) {
53
  this.ajax('wordfence_misconfiguredHowGetIPsChoice', {
54
  choice: choice
@@ -57,14 +49,6 @@ window['wordfenceExt'] = {
57
  function(){ jQuery('#wordfenceMisconfiguredHowGetIPsNotice').fadeOut(); }
58
  );
59
  },
60
- removeFromCache: function(postID){
61
- this.ajax('wordfence_removeFromCache', {
62
- id: postID
63
- },
64
- function(res){ if(res.ok){ alert("Item removed from the Wordfence cache."); } },
65
- function(){}
66
- );
67
- },
68
  ajax: function(action, data, cb, cbErr, noLoading){
69
  if(typeof(data) == 'string'){
70
  if(data.length > 0){
41
  function(){ jQuery('#wordfenceSuPHPUpdateWarning').fadeOut(); }
42
  );
43
  },
 
 
 
 
 
 
 
 
44
  misconfiguredHowGetIPsChoice : function(choice) {
45
  this.ajax('wordfence_misconfiguredHowGetIPsChoice', {
46
  choice: choice
49
  function(){ jQuery('#wordfenceMisconfiguredHowGetIPsNotice').fadeOut(); }
50
  );
51
  },
 
 
 
 
 
 
 
 
52
  ajax: function(action, data, cb, cbErr, noLoading){
53
  if(typeof(data) == 'string'){
54
  if(data.length > 0){
lib/email_newIssues.php CHANGED
@@ -24,6 +24,8 @@
24
  <p>* <?php echo htmlspecialchars($i['shortMsg']) ?></p>
25
  <?php if (isset($i['tmplData']['wpURL'])): ?>
26
  <p><?php if ($i['tmplData']['vulnerabilityPatched']) { ?><strong>Update includes security-related fixes.</strong> <?php } echo $i['tmplData']['wpURL']; ?>/changelog</p>
 
 
27
  <?php endif ?>
28
  <?php if (!empty($i['tmplData']['badURL'])): ?>
29
  <p><img src="<?php echo WORDFENCE_API_URL_BASE_NONSEC . "?" . http_build_query(array(
24
  <p>* <?php echo htmlspecialchars($i['shortMsg']) ?></p>
25
  <?php if (isset($i['tmplData']['wpURL'])): ?>
26
  <p><?php if ($i['tmplData']['vulnerabilityPatched']) { ?><strong>Update includes security-related fixes.</strong> <?php } echo $i['tmplData']['wpURL']; ?>/changelog</p>
27
+ <?php elseif (isset($i['tmplData']['vulnerabilityPatched']) && $i['tmplData']['vulnerabilityPatched']): ?>
28
+ <p><strong>Update includes security-related fixes.</strong></p>
29
  <?php endif ?>
30
  <?php if (!empty($i['tmplData']['badURL'])): ?>
31
  <p><img src="<?php echo WORDFENCE_API_URL_BASE_NONSEC . "?" . http_build_query(array(
lib/menuHeader.php DELETED
@@ -1,4 +0,0 @@
1
- <?php if(wfConfig::get('cacheType') == 'falcon'){ ?>
2
- <div title="Wordfence Falcon Engine Enabled for Maximum Site Performance" class="wfFalcon"></div>
3
- <?php } ?>
4
-
 
 
 
 
lib/menu_activity.php CHANGED
@@ -5,7 +5,6 @@
5
  </div>
6
  <?php endif ?>
7
  <div class="wrap wordfence">
8
- <?php require('menuHeader.php'); ?>
9
 
10
  <h2 id="wfHeading">
11
  <div style="float: left;">
@@ -47,7 +46,7 @@
47
  echo $rightRail;
48
  ?>
49
  <?php if (!wfConfig::liveTrafficEnabled()): ?>
50
- <div id="wordfenceLiveActivityDisabled"><p><strong>Live activity is disabled.</strong> <?php if (wfConfig::get('cacheType') == 'falcon') { ?>This is done to improve performance because you have Wordfence Falcon Engine enabled.<?php } ?> Login and firewall activity will still appear below.</p></div>
51
  <?php endif ?>
52
 
53
  <div id="wf-live-traffic" class="wfTabsContainer">
5
  </div>
6
  <?php endif ?>
7
  <div class="wrap wordfence">
 
8
 
9
  <h2 id="wfHeading">
10
  <div style="float: left;">
46
  echo $rightRail;
47
  ?>
48
  <?php if (!wfConfig::liveTrafficEnabled()): ?>
49
+ <div id="wordfenceLiveActivityDisabled"><p><strong>Live activity is disabled.</strong> Login and firewall activity will still appear below.</p></div>
50
  <?php endif ?>
51
 
52
  <div id="wf-live-traffic" class="wfTabsContainer">
lib/menu_blockedIPs.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
  <div class="wrap wordfence">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
5
  <div class="wordfenceLive">
6
  <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveActivity">
@@ -40,139 +39,156 @@
40
  </div>
41
 
42
  </div>
43
- <script type="text/x-jquery-template" id="wfThrottledIPsTmpl">
44
- <div>
45
- <div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
46
- <table border="0" style="width: 100%">
47
- {{each(idx, elem) results}}
48
- <tr><td style="vertical-align: top;">
49
- <div>
50
- {{if loc}}
51
- <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
52
- <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
53
- {{else}}
54
- An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
55
- {{/if}}
56
- </div>
57
- <div>
58
- <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
59
- </div>
60
- <div>
61
- <strong>Reason:</strong>&nbsp;${lastReason}
62
- </div>
63
- <div>
64
- <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
65
- </div>
66
  <div>
67
- <span>Throttled <strong>${timesThrottled}</strong> times starting <strong>${startTimeAgo} ago</strong> and ending <strong>${endTimeAgo} ago</strong>.</span>
 
 
 
 
68
  </div>
69
- </td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  </tr>
71
  {{/each}}
72
- </table>
73
- </div>
74
- <!--<p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('throttled'); return false;">Permanently block all throttled IP addresses</a></p>-->
75
- </div>
76
  </script>
77
 
78
- <script type="text/x-jquery-template" id="wfLockedOutIPsTmpl">
79
- <div>
80
- <p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('lockedOut'); return false;">Permanently block all locked out IP addresses</a></p>
81
- <div style="border-top: 1px solid #CCC; padding-top: 10px; margin-top: 10px;">
82
- <table border="0" style="width: 100%">
83
- {{each(idx, elem) results}}
84
- <tr><td>
85
- <div>
86
- {{if loc}}
87
- <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
88
- <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
89
- {{else}}
90
- An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
91
- {{/if}}
92
- </div>
93
- <div>
94
- <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a> [<a href="#" onclick="WFAD.unlockOutIP('${IP}'); return false;">unlock</a>]
95
- </div>
96
  <div>
97
- <strong>Reason:</strong>&nbsp;${reason}
98
- </div>
99
- <div>
100
- <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
 
 
101
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  <div>
103
- {{if lastAttemptAgo}}
104
- <span class="wfTimeAgo">Last blocked attempt to sign-in or use the forgot password form was <span class="wfTimeAgo-timestamp" data-timestamp="${lastAttempt}">${lastAttemptAgo} ago</span>.</span>
105
- {{else}}
106
- <span class="wfTimeAgo">No attempts have been made to sign-in or use the forgot password form since this IP was locked out.</span>
107
- {{/if}}
 
108
  </div>
109
- </td>
110
- <td style="color: #999;">
111
- <ul>
112
- <li>${blockedHits} attempts have been blocked</li>
113
- <li>Will be unlocked in ${blockedForAgo}</li>
114
- </ul>
115
- </td></tr>
116
- {{/each}}
117
- </table>
118
- </div>
119
- </div>
120
  </script>
121
 
122
  <script type="text/x-jquery-template" id="wfBlockedIPsTmpl">
123
- <div>
124
- <p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('blocked'); return false;">Permanently block all temporarily blocked IP addresses</a></p>
125
- <div style="border-top: 1px solid #CCC; padding-top: 10px; margin-top: 10px;">
126
- <table border="0" style="width: 100%">
127
  {{each(idx, elem) results}}
128
- <tr><td>
129
- <div>
130
- {{if loc}}
131
- <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
132
- <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
133
- {{else}}
134
- An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
135
- {{/if}}
136
- </div>
137
- <div>
138
- <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a> [<a href="#" onclick="WFAD.unblockIPTwo('${IP}'); return false;">unblock</a>]
139
- {{if permanent == '1'}}
140
- [<span style="color: #F00;">permanently blocked</span>]
141
- {{else}}&nbsp;&nbsp;[<a href="#" onclick="WFAD.permBlockIP('${IP}'); return false;">make permanent</a>]{{/if}}
142
- </div>
143
- <div>
144
- <strong>Reason:</strong>&nbsp;${reason}
145
- </div>
146
- <div>
147
- <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
148
- </div>
149
- <div>
150
- {{if lastAttemptAgo}}
151
- <span class="wfTimeAgo">Last blocked attempt to access the site was <span class="wfTimeAgo-timestamp" data-timestamp="${lastAttempt}">${lastAttemptAgo} ago</span>.</span>
152
- {{else}}
153
- <span class="wfTimeAgo">No attempts have been made to access the site since this IP was blocked.</span>
154
- {{/if}}
155
- </div>
156
- <div>
157
- {{if lastHitAgo}}
158
- <span class="wfTimeAgo">Last site access before this IP was blocked was <span class="wfTimeAgo-timestamp" data-timestamp="${lastHit}">${lastHitAgo} ago</span></span>
159
- {{/if}}
160
- </div>
161
- </td>
162
- <td style="color: #999;">
163
- <ul>
164
- <li>${totalHits} hits before blocked</li>
165
- <li>${blockedHits} blocked hits</li>
166
- <li>
167
- {{if permanent == '1'}}Permanently blocked{{else}}
168
- Will be unblocked in ${blockedForAgo}{{/if}}
169
- </li>
170
- </ul>
171
- </td></tr>
 
 
172
  {{/each}}
173
- </table>
174
- </div>
175
- </div>
176
  </script>
177
 
178
  <script type="text/x-jquery-template" id="wfWelcomeContent4">
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
  <div class="wrap wordfence">
 
3
  <?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
4
  <div class="wordfenceLive">
5
  <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveActivity">
39
  </div>
40
 
41
  </div>
42
+
43
+ <script type="text/x-jquery-template" id="wfThrottledIPsWrapperTmpl">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  <div>
45
+ <div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
46
+ <table border="0" style="width: 100%" id="wfThrottledIPsWrapper">
47
+ </table>
48
+ </div>
49
+ <!--<p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('throttled'); return false;">Permanently block all throttled IP addresses</a></p>-->
50
  </div>
51
+ </script>
52
+
53
+ <script type="text/x-jquery-template" id="wfThrottledIPsTmpl">
54
+ {{each(idx, elem) results}}
55
+ <tr class="throttledIPsRecord">
56
+ <td style="vertical-align: top;">
57
+ <div>
58
+ {{if loc}}
59
+ <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
60
+ <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
61
+ {{else}}
62
+ An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
63
+ {{/if}}
64
+ </div>
65
+ <div>
66
+ <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
67
+ </div>
68
+ <div>
69
+ <strong>Reason:</strong>&nbsp;${lastReason}
70
+ </div>
71
+ <div>
72
+ <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
73
+ </div>
74
+ <div>
75
+ <span>Throttled <strong>${timesThrottled}</strong> times starting <strong>${startTimeAgo} ago</strong> and ending <strong>${endTimeAgo} ago</strong>.</span>
76
+ </div>
77
+ </td>
78
  </tr>
79
  {{/each}}
 
 
 
 
80
  </script>
81
 
82
+ <script type="text/x-jquery-template" id="wfLockedOutIPsWrapperTmpl">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  <div>
84
+ <p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('lockedOut'); return false;">Permanently block all locked out IP addresses</a></p>
85
+ <div style="border-top: 1px solid #CCC; padding-top: 10px; margin-top: 10px;">
86
+ <table border="0" style="width: 100%" id="wfLockedOutIPsWrapper">
87
+ </table>
88
+ </div>
89
+ <p><a class="button wfLoadMoreButton" href="#">Load More</a></p>
90
  </div>
91
+ </script>
92
+
93
+ <script type="text/x-jquery-template" id="wfLockedOutIPsTmpl">
94
+ {{each(idx, elem) results}}
95
+ <tr class="lockedOutIPsRecord">
96
+ <td>
97
+ <div>
98
+ {{if loc}}
99
+ <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
100
+ <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
101
+ {{else}}
102
+ An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
103
+ {{/if}}
104
+ </div>
105
+ <div>
106
+ <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a> [<a href="#" onclick="WFAD.unlockOutIP('${IP}'); return false;">unlock</a>]
107
+ </div>
108
+ <div>
109
+ <strong>Reason:</strong>&nbsp;${reason}
110
+ </div>
111
+ <div>
112
+ <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
113
+ </div>
114
+ <div>
115
+ {{if lastAttemptAgo}}
116
+ <span class="wfTimeAgo">Last blocked attempt to sign-in or use the forgot password form was <span class="wfTimeAgo-timestamp" data-timestamp="${lastAttempt}">${lastAttemptAgo} ago</span>.</span>
117
+ {{else}}
118
+ <span class="wfTimeAgo">No attempts have been made to sign-in or use the forgot password form since this IP was locked out.</span>
119
+ {{/if}}
120
+ </div>
121
+ </td>
122
+ <td style="color: #999;">
123
+ <ul>
124
+ <li>${blockedHits} attempts have been blocked</li>
125
+ <li>Will be unlocked in ${blockedForAgo}</li>
126
+ </ul>
127
+ </td>
128
+ </tr>
129
+ {{/each}}
130
+ </script>
131
+
132
+ <script type="text/x-jquery-template" id="wfBlockedIPsWrapperTmpl">
133
  <div>
134
+ <p><a class="button" href="#" onclick="WFAD.permanentlyBlockAllIPs('blocked'); return false;">Permanently block all temporarily blocked IP addresses</a></p>
135
+ <div style="border-top: 1px solid #CCC; padding-top: 10px; margin-top: 10px;">
136
+ <table border="0" style="width: 100%" id="wfBlockedIPsWrapper">
137
+ </table>
138
+ </div>
139
+ <p><a class="button wfLoadMoreButton" href="#">Load More</a></p>
140
  </div>
 
 
 
 
 
 
 
 
 
 
 
141
  </script>
142
 
143
  <script type="text/x-jquery-template" id="wfBlockedIPsTmpl">
 
 
 
 
144
  {{each(idx, elem) results}}
145
+ <tr class="blockedIPsRecord">
146
+ <td>
147
+ <div>
148
+ {{if loc}}
149
+ <img src="<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>${loc.countryCode.toLowerCase()}.png" width="16" height="11" alt="${loc.countryName}" title="${loc.countryName}" class="wfFlag" />
150
+ <a href="http://maps.google.com/maps?q=${loc.lat},${loc.lon}&z=6" target="_blank">{{if loc.city}}${loc.city}, {{/if}}${loc.countryName}</a>
151
+ {{else}}
152
+ An unknown location at IP <a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a>
153
+ {{/if}}
154
+ </div>
155
+ <div>
156
+ <strong>IP:</strong>&nbsp;<a href="${WFAD.makeIPTrafLink(IP)}" target="_blank">${IP}</a> [<a href="#" onclick="WFAD.unblockIPTwo('${IP}'); return false;">unblock</a>]
157
+ {{if permanent == '1'}}
158
+ [<span style="color: #F00;">permanently blocked</span>]
159
+ {{else}}&nbsp;&nbsp;[<a href="#" onclick="WFAD.permBlockIP('${IP}'); return false;">make permanent</a>]{{/if}}
160
+ </div>
161
+ <div>
162
+ <strong>Reason:</strong>&nbsp;${reason}
163
+ </div>
164
+ <div>
165
+ <span class="wfReverseLookup"><span style="display:none;">${IP}</span></span>
166
+ </div>
167
+ <div>
168
+ {{if lastAttemptAgo}}
169
+ <span class="wfTimeAgo">Last blocked attempt to access the site was <span class="wfTimeAgo-timestamp" data-timestamp="${lastAttempt}">${lastAttemptAgo} ago</span>.</span>
170
+ {{else}}
171
+ <span class="wfTimeAgo">No attempts have been made to access the site since this IP was blocked.</span>
172
+ {{/if}}
173
+ </div>
174
+ <div>
175
+ {{if lastHitAgo}}
176
+ <span class="wfTimeAgo">Last site access before this IP was blocked was <span class="wfTimeAgo-timestamp" data-timestamp="${lastHit}">${lastHitAgo} ago</span></span>
177
+ {{/if}}
178
+ </div>
179
+ </td>
180
+ <td style="color: #999;">
181
+ <ul>
182
+ <li>${totalHits} hits before blocked</li>
183
+ <li>${blockedHits} blocked hits</li>
184
+ <li>
185
+ {{if permanent == '1'}}Permanently blocked{{else}}
186
+ Will be unblocked in ${blockedForAgo}{{/if}}
187
+ </li>
188
+ </ul>
189
+ </td>
190
+ </tr>
191
  {{/each}}
 
 
 
192
  </script>
193
 
194
  <script type="text/x-jquery-template" id="wfWelcomeContent4">
lib/menu_countryBlocking.php CHANGED
@@ -6,7 +6,6 @@ WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
8
  <div class="wrap wordfence" id="paidWrap">
9
- <?php require('menuHeader.php'); ?>
10
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
11
  <?php
12
  $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailCountryBlocking'));
@@ -29,18 +28,6 @@ WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
29
  href="https://www.wordfence.com/gnl1countryBlock1/wordfence-signup/" target="_blank">Get Premium</a></p>
30
  </div>
31
  <?php } ?>
32
- <?php if(wfConfig::get('cacheType') == 'falcon'){ ?>
33
- <div class="wfFalconNotice">
34
- <b>Note regarding country blocking with Falcon Engine enabled:</b><br /><br />
35
- Country blocking will only work on the login page and other dynamic pages with
36
- Wordfence Falcon Engine enabled. We do this to keep your site fast and avoid
37
- a country lookup on every request.
38
- Serving cached pages only uses 2 to 3% of the resources that a non-cached page uses,
39
- so malicious countries won't eat up your server resources when they load cached pages.
40
- If you would like full country blocking, you can enable Basic Caching on the "Site Performance" page.
41
- </div>
42
- <?php } ?>
43
-
44
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 900px;">
45
  <table class="wfConfigForm">
46
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
8
  <div class="wrap wordfence" id="paidWrap">
 
9
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
10
  <?php
11
  $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailCountryBlocking'));
28
  href="https://www.wordfence.com/gnl1countryBlock1/wordfence-signup/" target="_blank">Get Premium</a></p>
29
  </div>
30
  <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
31
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 900px;">
32
  <table class="wfConfigForm">
33
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
lib/menu_diagnostic.php CHANGED
@@ -12,7 +12,6 @@ $w = new wfConfig();
12
  ?>
13
 
14
  <div class="wrap wordfence">
15
- <?php require('menuHeader.php'); ?>
16
  <h2 id="wfHeading">
17
  Diagnostics
18
  </h2>
@@ -491,15 +490,6 @@ $w = new wfConfig();
491
  <h3>Debugging Options</h3>
492
  <form action="#" id="wfDebuggingConfigForm">
493
  <table class="wfConfigForm">
494
- <tr>
495
- <th>Add a debugging comment to HTML source of cached pages.<a
496
- href="http://docs.wordfence.com/en/Wordfence_options#Add_a_debugging_comment_to_HTML_source_of_cached_pages"
497
- target="_blank" class="wfhelp"></a></th>
498
- <td><input type="checkbox" id="addCacheComment" class="wfConfigElem" name="addCacheComment"
499
- value="1" <?php $w->cb('addCacheComment'); ?> />
500
- </td>
501
- </tr>
502
-
503
  <tr>
504
  <th>Enable debugging mode (increases database load)<a
505
  href="http://docs.wordfence.com/en/Wordfence_options#Enable_debugging_mode_.28increases_database_load.29"
12
  ?>
13
 
14
  <div class="wrap wordfence">
 
15
  <h2 id="wfHeading">
16
  Diagnostics
17
  </h2>
490
  <h3>Debugging Options</h3>
491
  <form action="#" id="wfDebuggingConfigForm">
492
  <table class="wfConfigForm">
 
 
 
 
 
 
 
 
 
493
  <tr>
494
  <th>Enable debugging mode (increases database load)<a
495
  href="http://docs.wordfence.com/en/Wordfence_options#Enable_debugging_mode_.28increases_database_load.29"
lib/menu_options.php CHANGED
@@ -3,7 +3,6 @@ $w = new wfConfig();
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
5
  <div class="wrap wordfence">
6
- <?php require( 'menuHeader.php' ); ?>
7
  <?php $helpLink = "http://docs.wordfence.com/en/Wordfence_options";
8
  $helpLabel = "Learn more about Wordfence Options";
9
  $pageTitle = "Wordfence Options";
@@ -456,7 +455,7 @@ $w = new wfConfig();
456
  </td>
457
  </tr>
458
  <tr>
459
- <th>Scan for publically accessible configuration, backup, or log files<a
460
  href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable"
461
  target="_blank" class="wfhelp"></a></th>
462
  <td><input type="checkbox" id="scansEnabled_checkReadableConfig" class="wfConfigElem"
@@ -889,7 +888,7 @@ $w = new wfConfig();
889
  name="loginSec_blockAdminReg" <?php $w->cb( 'loginSec_blockAdminReg' ); ?> /></td>
890
  </tr>
891
  <tr>
892
- <th>Prevent discovery of usernames through '/?author=N' scans and the oEmbed API<a
893
  href="http://docs.wordfence.com/en/Wordfence_options#Prevent_discovery_of_usernames_through_.27.3F.2Fauthor.3DN.27_scans"
894
  target="_blank" class="wfhelp"></a></th>
895
  <td><input type="checkbox" id="loginSec_disableAuthorScan" class="wfConfigElem"
3
  ?>
4
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
5
  <div class="wrap wordfence">
 
6
  <?php $helpLink = "http://docs.wordfence.com/en/Wordfence_options";
7
  $helpLabel = "Learn more about Wordfence Options";
8
  $pageTitle = "Wordfence Options";
455
  </td>
456
  </tr>
457
  <tr>
458
+ <th>Scan for publicly accessible configuration, backup, or log files<a
459
  href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable"
460
  target="_blank" class="wfhelp"></a></th>
461
  <td><input type="checkbox" id="scansEnabled_checkReadableConfig" class="wfConfigElem"
888
  name="loginSec_blockAdminReg" <?php $w->cb( 'loginSec_blockAdminReg' ); ?> /></td>
889
  </tr>
890
  <tr>
891
+ <th>Prevent discovery of usernames through '/?author=N' scans, the oEmbed API, and the WordPress REST API<a
892
  href="http://docs.wordfence.com/en/Wordfence_options#Prevent_discovery_of_usernames_through_.27.3F.2Fauthor.3DN.27_scans"
893
  target="_blank" class="wfhelp"></a></th>
894
  <td><input type="checkbox" id="loginSec_disableAuthorScan" class="wfConfigElem"
lib/menu_passwd.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_passwd"></div>
2
  <div class="wrap wordfence" id="paidWrap">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Audit the Strength of your Passwords";
5
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
6
  $helpLabel = "Learn more about Password Auditing";
1
  <div class="wordfenceModeElem" id="wordfenceMode_passwd"></div>
2
  <div class="wrap wordfence" id="paidWrap">
 
3
  <?php $pageTitle = "Audit the Strength of your Passwords";
4
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
5
  $helpLabel = "Learn more about Password Auditing";
lib/menu_rangeBlocking.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
2
  <div class="wrap wordfence" id="paidWrap">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
5
  <?php
6
  $rightRail = new wfView('marketing/rightrail');
@@ -47,7 +46,7 @@
47
  <tr><td>
48
  {{if patternDisabled}}
49
  <div style="width: 500px; margin-top: 20px;">
50
- <span style="color: #F00;">Pattern Below has been DISABLED:</span> Falcon engine does not support advanced blocks that include combinations of IP range, browser pattern and referring website. You can only specify one of the three in patterns when using Falcon.
51
  </div>
52
  <div style="color: #AAA;">
53
  {{/if}}
1
  <div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
2
  <div class="wrap wordfence" id="paidWrap">
 
3
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
4
  <?php
5
  $rightRail = new wfView('marketing/rightrail');
46
  <tr><td>
47
  {{if patternDisabled}}
48
  <div style="width: 500px; margin-top: 20px;">
49
+ <span style="color: #F00;">Pattern Below has been DISABLED:</span>
50
  </div>
51
  <div style="color: #AAA;">
52
  {{/if}}
lib/menu_scan.php CHANGED
@@ -30,7 +30,6 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
30
 
31
  <?php else: ?>
32
 
33
- <?php require('menuHeader.php'); ?>
34
  <?php $pageTitle = "Wordfence Scan"; $helpLink="http://docs.wordfence.com/en/Wordfence_scanning"; $helpLabel="Learn more about scanning"; include('pageTitle.php'); ?>
35
  <div class="wordfenceWrap">
36
  <?php
@@ -411,6 +410,7 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
411
  </td></tr>
412
  </table>
413
  </p>
 
414
  <p>
415
  {{html longMsg}}
416
  <a href="<?php echo get_admin_url() . 'update-core.php'; ?>">Click here to update now</a>.
30
 
31
  <?php else: ?>
32
 
 
33
  <?php $pageTitle = "Wordfence Scan"; $helpLink="http://docs.wordfence.com/en/Wordfence_scanning"; $helpLabel="Learn more about scanning"; include('pageTitle.php'); ?>
34
  <div class="wordfenceWrap">
35
  <?php
410
  </td></tr>
411
  </table>
412
  </p>
413
+ {{if data.vulnerabilityPatched}}<p><strong>Update includes security-related fixes.</strong></p>{{/if}}
414
  <p>
415
  {{html longMsg}}
416
  <a href="<?php echo get_admin_url() . 'update-core.php'; ?>">Click here to update now</a>.
lib/menu_scanSchedule.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
  <div class="wrap wordfence" id="paidWrap">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
5
  <?php
6
  $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailScanSchedule'));
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
  <div class="wrap wordfence" id="paidWrap">
 
3
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
4
  <?php
5
  $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailScanSchedule'));
lib/menu_twoFactor.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_twoFactor"></div>
2
  <div class="wrap wordfence" id="paidWrap">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
5
  <?php
6
  $rightRail = new wfView('marketing/rightrail');
1
  <div class="wordfenceModeElem" id="wordfenceMode_twoFactor"></div>
2
  <div class="wrap wordfence" id="paidWrap">
 
3
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
4
  <?php
5
  $rightRail = new wfView('marketing/rightrail');
lib/menu_waf.php CHANGED
@@ -6,7 +6,6 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
6
  /** @var array $wafData */
7
  ?>
8
  <div class="wrap wordfence" id="paidWrap">
9
- <?php require('menuHeader.php'); ?>
10
  <?php
11
  $pageTitle = "Wordfence Web Application Firewall";
12
  $helpLink = "http://docs.wordfence.com/en/WAF";
6
  /** @var array $wafData */
7
  ?>
8
  <div class="wrap wordfence" id="paidWrap">
 
9
  <?php
10
  $pageTitle = "Wordfence Web Application Firewall";
11
  $helpLink = "http://docs.wordfence.com/en/WAF";
lib/menu_whois.php CHANGED
@@ -1,6 +1,5 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
2
  <div class="wrap wordfence" id="paidWrap">
3
- <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
5
  <?php
6
  $rightRail = new wfView('marketing/rightrail');
1
  <div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
2
  <div class="wrap wordfence" id="paidWrap">
 
3
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
4
  <?php
5
  $rightRail = new wfView('marketing/rightrail');
lib/wfCache.php CHANGED
@@ -1,345 +1,28 @@
1
  <?php
2
  class wfCache {
3
- private static $cacheType = false;
4
- private static $fileCache = array();
5
  private static $cacheStats = array();
6
  private static $cacheClearedThisRequest = false;
7
- private static $clearScheduledThisRequest = false;
8
  private static $lastRecursiveDeleteError = false;
9
- public static function setupCaching(){
10
- self::$cacheType = wfConfig::get('cacheType');
11
- if(self::$cacheType != 'php' && self::$cacheType != 'falcon'){
12
- return; //cache is disabled
13
- }
14
- if(wfUtils::hasLoginCookie()){
15
- add_action('publish_post', 'wfCache::action_publishPost');
16
- add_action('publish_page', 'wfCache::action_publishPost');
17
- foreach(array('clean_object_term_cache', 'clean_post_cache', 'clean_term_cache', 'clean_page_cache', 'after_switch_theme', 'customize_save_after', 'activated_plugin', 'deactivated_plugin', 'update_option_sidebars_widgets') as $action){
18
- add_action($action, 'wfCache::action_clearPageCache'); //Schedules a cache clear for immediately so it won't lag current request.
19
- }
20
- if($_SERVER['REQUEST_METHOD'] == 'POST'){
21
- foreach(array(
22
- '/\/wp\-admin\/options\.php$/',
23
- '/\/wp\-admin\/options\-permalink\.php$/'
24
- ) as $pattern){
25
- if(preg_match($pattern, $_SERVER['REQUEST_URI'])){
26
- self::scheduleCacheClear();
27
- break;
28
- }
29
- }
30
- }
31
- }
32
- add_action('wordfence_cache_clear', 'wfCache::scheduledCacheClear');
33
- add_action('wordfence_update_blocked_IPs', 'wfCache::scheduleUpdateBlockedIPs');
34
- add_action('comment_post', 'wfCache::action_commentPost'); //Might not be logged in
35
- add_filter('wp_redirect', 'wfCache::redirectFilter');
36
-
37
- //Routines to clear cache run even if cache is disabled
38
- $file = self::fileFromRequest( ($_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']), $_SERVER['REQUEST_URI']);
39
- $fileDeleted = false;
40
- $doDelete = false;
41
- if($_SERVER['REQUEST_METHOD'] != 'GET'){ //If our URL is hit with a POST, PUT, DELETE or any other non 'GET' request, then clear cache.
42
- $doDelete = true;
43
- }
44
-
45
- if($doDelete){
46
- @unlink($file);
47
- $fileDeleted = true;
48
- }
49
-
50
-
51
- add_action('wp_logout', 'wfCache::logout');
52
- if(self::isCachable()){
53
- if( (! $fileDeleted) && self::$cacheType == 'php'){ //Then serve the file if it's still valid
54
- $stat = @stat($file);
55
- if($stat){
56
- $age = time() - $stat[9];
57
- if($age < 10000){
58
- readfile($file); //sends file to stdout
59
- die();
60
- }
61
- }
62
- }
63
- ob_start('wfCache::obComplete'); //Setup routine to store the file
64
- }
65
- }
66
- public static function redirectFilter($status){
67
- if(! defined('WFDONOTCACHE')){
68
- define('WFDONOTCACHE', true);
69
- }
70
- return $status;
71
- }
72
- public static function isCachable(){
73
- if(defined('WFDONOTCACHE') || defined('DONOTCACHEPAGE') || defined('DONOTCACHEDB') || defined('DONOTCACHEOBJECT')){ //If you want to tell Wordfence not to cache something in another plugin, simply define one of these.
74
- return false;
75
- }
76
- if(! wfConfig::get('allowHTTPSCaching')){
77
- if(self::isHTTPSPage()){
78
- return false;
79
- }
80
- }
81
-
82
- if(is_admin()){ return false; } //dont cache any admin pages.
83
- $uri = $_SERVER['REQUEST_URI'];
84
-
85
- if(strrpos($uri, '/') !== strlen($uri) - 1){ //must end with a '/' char.
86
- return false;
87
- }
88
- if($_SERVER['REQUEST_METHOD'] != 'GET'){ return false; } //Only cache GET's
89
- if(isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 && (! preg_match('/^\d+=\d+$/', $_SERVER['QUERY_STRING'])) ){ //Don't cache query strings unless they are /?123132423=123123234 DDoS style.
90
- return false;
91
- }
92
- //wordpress_logged_in_[hash] cookies indicates logged in
93
- if(is_array($_COOKIE)){
94
- foreach(array_keys($_COOKIE) as $c){
95
- foreach(array('comment_author','wp-postpass','wf_logout','wordpress_logged_in','wptouch_switch_toggle','wpmp_switcher') as $b){
96
- if(strpos($c, $b) !== false){ return false; } //contains a cookie which indicates user must not be cached
97
- }
98
- }
99
- }
100
- $ex = wfConfig::get('cacheExclusions', false);
101
- if($ex){
102
- $ex = unserialize($ex);
103
- foreach($ex as $v){
104
- if($v['pt'] == 'eq'){ if(strtolower($uri) == strtolower($v['p'])){ return false; } }
105
- if($v['pt'] == 's'){ if(stripos($uri, $v['p']) === 0){ return false; } }
106
- if($v['pt'] == 'e'){ if(stripos($uri, $v['p']) === (strlen($uri) - strlen($v['p'])) ){ return false; } }
107
- if($v['pt'] == 'c'){ if(stripos($uri, $v['p']) !== false){ return false; } }
108
- if($v['pt'] == 'uac'){ if(stripos($_SERVER['HTTP_USER_AGENT'], $v['p']) !== false){ return false; } } //User-agent contains
109
- if($v['pt'] == 'uaeq'){ if(strtolower($_SERVER['HTTP_USER_AGENT']) == strtolower($v['p'])){ return false; } } //user-agent equals
110
- if($v['pt'] == 'cc'){
111
- foreach($_COOKIE as $cookieName){
112
- if(stripos($cookieName, $v['p']) !== false){ //Cookie name contains pattern
113
- return false;
114
- }
115
- }
116
- }
117
- }
118
- }
119
- return true;
120
- }
121
- public static function isHTTPSPage(){
122
- if( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] != 'off'){
123
- return true;
124
- }
125
- if( !empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ){ //In case we're behind a proxy and user used HTTPS.
126
- return true;
127
- }
128
- return false;
129
- }
130
- public static function obComplete($buffer = ''){
131
- if(function_exists('is_404') && is_404()){
132
- return false;
133
- }
134
-
135
- if(defined('WFDONOTCACHE') || defined('DONOTCACHEPAGE') || defined('DONOTCACHEDB') || defined('DONOTCACHEOBJECT')){
136
- //These constants may have been set after we did the initial isCachable check by e.g. wp_redirect filter. If they're set then just return the buffer and don't cache.
137
- return $buffer;
138
- }
139
- if(strlen($buffer) < 1000){ //The average web page size is 1246,000 bytes. If web page is less than 1000 bytes, don't cache it.
140
- return $buffer;
141
- }
142
-
143
- $file = self::fileFromRequest( ($_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']), $_SERVER['REQUEST_URI']);
144
- self::makeDirIfNeeded($file);
145
- // self::writeCacheDirectoryHtaccess();
146
- $append = "";
147
- $appendGzip = "";
148
- if(wfConfig::get('addCacheComment', false)){
149
- $append = "\n<!-- Cached by Wordfence ";
150
- if(wfConfig::get('cacheType', false) == 'falcon'){
151
- $append .= "Falcon Engine. ";
152
- } else {
153
- $append .= "PHP Caching Engine. ";
154
- }
155
- $append .= "Time created on server: " . date('Y-m-d H:i:s T') . ". ";
156
- $append .= "Is HTTPS page: " . (self::isHTTPSPage() ? 'HTTPS' : 'no') . ". ";
157
- $append .= "Page size: " . strlen($buffer) . " bytes. ";
158
- $append .= "Host: " . ($_SERVER['HTTP_HOST'] ? wp_kses($_SERVER['HTTP_HOST'], array()) : wp_kses($_SERVER['SERVER_NAME'], array())) . ". ";
159
- $append .= "Request URI: " . wp_kses($_SERVER['REQUEST_URI'], array()) . " ";
160
- $appendGzip = $append . " Encoding: GZEncode -->\n";
161
- $append .= " Encoding: Uncompressed -->\n";
162
- }
163
-
164
- @file_put_contents($file, $buffer . $append, LOCK_EX);
165
- chmod($file, 0644);
166
- if(self::$cacheType == 'falcon'){ //create gzipped files so we can send precompressed files
167
- $file .= '_gzip';
168
- @file_put_contents($file, gzencode($buffer . $appendGzip, 9), LOCK_EX);
169
- chmod($file, 0644);
170
- }
171
- return $buffer;
172
- }
173
- public static function fileFromRequest($host, $URI){
174
- return self::fileFromURI($host, $URI, self::isHTTPSPage());
175
- }
176
- public static function fileFromURI($host, $URI, $isHTTPS){
177
- $key = $host . $URI . ($isHTTPS ? '_HTTPS' : '');
178
- if(isset(self::$fileCache[$key])){ return self::$fileCache[$key]; }
179
- $host = preg_replace('/[^a-zA-Z0-9\-\.]+/', '', $host);
180
- $URI = preg_replace('/(?:[^a-zA-Z0-9\-\_\.\~\/]+|\.{2,})/', '', $URI); //Strip out bad chars and multiple dots
181
- if(preg_match('/\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$/', $URI, $matches)){
182
- $URI = $matches[1] . '/';
183
- for($i = 2; $i <= 6; $i++){
184
- $URI .= strlen($matches[$i]) > 0 ? $matches[$i] : '';
185
- $URI .= $i < 6 ? '~' : '';
186
- }
187
- }
188
- $ext = '';
189
- if($isHTTPS){ $ext = '_https'; }
190
- $file = WP_CONTENT_DIR . '/wfcache/' . $host . '_' . $URI . '_wfcache' . $ext . '.html';
191
- self::$fileCache[$key] = $file;
192
- return $file;
193
- }
194
- public static function makeDirIfNeeded($file){
195
- $file = preg_replace('/\/[^\/]*$/', '', $file);
196
- if(! is_dir($file)){
197
- @mkdir($file, 0755, true);
198
- }
199
- }
200
- public static function logout(){
201
- wfUtils::setcookie('wf_logout', '1', 0, null, null, null, true);
202
- }
203
- public static function cacheDirectoryTest(){
204
- $cacheDir = WP_CONTENT_DIR . '/wfcache/';
205
- if(! is_dir($cacheDir)){
206
- if(! @mkdir($cacheDir, 0755, true)){
207
- $err = error_get_last();
208
- $msg = "The directory $cacheDir does not exist and we could not create it.";
209
- if($err){
210
- $msg .= ' The error we received was: ' . $err['message'];
211
- }
212
- return $msg;
213
- }
214
- }
215
- if(! @file_put_contents($cacheDir . 'test.php', 'test')){
216
- $err = error_get_last();
217
- $msg = "We could not write to the file $cacheDir" . "test.php when testing if the cache directory is writable.";
218
- if($err){
219
- $msg .= " The error was: " . $err['message'];
220
- }
221
- return $msg;
222
- }
223
- self::removeCacheDirectoryHtaccess();
224
- return false;
225
- // return self::writeCacheDirectoryHtaccess(); //Everything is OK
226
- }
227
-
228
- /**
229
- * Returns false on success to match wfCache::cacheDirectoryTest
230
- *
231
- * @see wfCache::cacheDirectoryTest
232
- *
233
- * @return bool|string
234
- */
235
- public static function writeCacheDirectoryHtaccess() {
236
- $cacheDir = WP_CONTENT_DIR . '/wfcache/';
237
- if (!file_exists($cacheDir . '.htaccess') && !@file_put_contents($cacheDir . '.htaccess', 'Deny from all', LOCK_EX)) {
238
- $err = error_get_last();
239
- $msg = "We could not write to the file $cacheDir" . ".htaccess.";
240
- if($err){
241
- $msg .= " The error was: " . $err['message'];
242
- }
243
- return $msg;
244
- }
245
- return false;
246
- }
247
-
248
- public static function removeCacheDirectoryHtaccess() {
249
  $cacheDir = WP_CONTENT_DIR . '/wfcache/';
250
  if (file_exists($cacheDir . '.htaccess')) {
251
  unlink($cacheDir . '.htaccess');
252
  }
253
- }
254
-
255
- public static function action_publishPost($id){
256
- $perm = get_permalink($id);
257
- self::deleteFileFromPermalink($perm);
258
- self::scheduleCacheClear();
259
- }
260
- public static function action_commentPost($commentID){
261
- $c = get_comment($commentID, ARRAY_A);
262
- $perm = get_permalink($c['comment_post_ID']);
263
- self::deleteFileFromPermalink($perm);
264
- self::scheduleCacheClear();
265
- }
266
- public static function action_clearPageCache(){ //Can safely call this as many times as we like because it'll only schedule one clear
267
- self::scheduleCacheClear();
268
- }
269
- public static function scheduleCacheClear(){
270
- if(self::$clearScheduledThisRequest){ return; }
271
- self::$clearScheduledThisRequest = true;
272
- wp_schedule_single_event(time() - 15, 'wordfence_cache_clear', array( rand(0,999999999) )); //rand makes sure this is called every time and isn't subject to the 10 minute window where the same event won't be run twice with wp_schedule_single_event
273
- $url = admin_url('admin-ajax.php');
274
- wp_remote_get($url);
275
- }
276
- public static function scheduledCacheClear($random){
277
- self::clearPageCacheSafe(); //Will only run if clearPageCache() has not run this request
278
- }
279
- public static function deleteFileFromPermalink($perm){
280
- if(preg_match('/\/\/([^\/]+)(\/.*)$/', $perm, $matches)){
281
- $host = $matches[1];
282
- $uri = $matches[2];
283
- $file = self::fileFromRequest($host, $uri);
284
- if(is_file($file)){
285
- @unlink($file);
286
- }
287
- }
288
- }
289
- public static function getCacheStats(){
290
- self::$cacheStats = array(
291
- 'files' => 0,
292
- 'dirs' => 0,
293
- 'data' => 0,
294
- 'compressedFiles' => 0,
295
- 'compressedKBytes' => 0,
296
- 'uncompressedFiles' => 0,
297
- 'uncompressedKBytes' => 0,
298
- 'oldestFile' => false,
299
- 'newestFile' => false,
300
- 'largestFile' => 0,
301
- );
302
- self::recursiveStats(WP_CONTENT_DIR . '/wfcache/');
303
- return self::$cacheStats;
304
- }
305
- private static function recursiveStats($dir){
306
- $files = array_diff(scandir($dir), array('.','..'));
307
- foreach($files as $file){
308
- $fullPath = $dir . '/' . $file;
309
- if(is_dir($fullPath)){
310
- self::$cacheStats['dirs']++;
311
- self::recursiveStats($fullPath);
312
- } else {
313
- if($file == 'clear.lock'){ continue; }
314
- self::$cacheStats['files']++;
315
- $stat = stat($fullPath);
316
- if(is_array($stat)){
317
- $size = $stat[7];
318
- if($size){
319
- $size = round($size / 1024);
320
- self::$cacheStats['data'] += $size;
321
- if(strrpos($file, '_gzip') == strlen($file) - 6){
322
- self::$cacheStats['compressedFiles']++;
323
- self::$cacheStats['compressedKBytes'] += $size;
324
- } else {
325
- self::$cacheStats['uncompressedFiles']++;
326
- self::$cacheStats['uncompressedKBytes'] += $size;
327
- }
328
- if(self::$cacheStats['largestFile'] < $size){
329
- self::$cacheStats['largestFile'] = $size;
330
- }
331
- }
332
-
333
- $ctime = $stat[10];
334
- if(self::$cacheStats['oldestFile'] > $ctime || self::$cacheStats['oldestFile'] === false){
335
- self::$cacheStats['oldestFile'] = $ctime;
336
- }
337
- if(self::$cacheStats['newestFile'] === false || self::$cacheStats['newestFile'] < $ctime){
338
- self::$cacheStats['newestFile'] = $ctime;
339
- }
340
- }
341
- }
342
- }
343
  }
344
  public static function clearPageCacheSafe(){
345
  if(self::$cacheClearedThisRequest){ return; }
@@ -354,6 +37,12 @@ class wfCache {
354
  'totalErrors' => 0,
355
  'error' => '',
356
  );
 
 
 
 
 
 
357
  $cacheClearLock = WP_CONTENT_DIR . '/wfcache/clear.lock';
358
  if(! is_file($cacheClearLock)){
359
  if(! touch($cacheClearLock)){
@@ -378,12 +67,14 @@ class wfCache {
378
  self::$cacheStats['totalErrors']++;
379
  }
380
  flock($fp, LOCK_UN);
 
 
381
  }
382
  fclose($fp);
383
 
384
  return self::$cacheStats;
385
  }
386
- public static function recursiveDelete($dir){
387
  $files = array_diff(scandir($dir), array('.','..'));
388
  foreach ($files as $file) {
389
  if(is_dir($dir . '/' . $file)){
@@ -429,8 +120,8 @@ class wfCache {
429
  }
430
  }
431
  public static function addHtaccessCode($action){
432
- if($action != 'add' && $action != 'remove'){
433
- die("Error: addHtaccessCode must be called with 'add' or 'remove' as param");
434
  }
435
  $htaccessPath = self::getHtaccessPath();
436
  if(! $htaccessPath){
@@ -450,10 +141,6 @@ class wfCache {
450
  return "Could not read from $htaccessPath";
451
  }
452
  $contents = preg_replace('/#WFCACHECODE.*WFCACHECODE[\r\s\n\t]*/s', '', $contents);
453
- if($action == 'add'){
454
- $code = self::getHtaccessCode();
455
- $contents = $code . "\n" . $contents;
456
- }
457
  ftruncate($fh, 0);
458
  fflush($fh);
459
  fseek($fh, 0, SEEK_SET);
@@ -462,131 +149,12 @@ class wfCache {
462
  fclose($fh);
463
  return false;
464
  }
465
- public static function getHtaccessCode(){
466
- $siteURL = site_url();
467
- $homeURL = home_url();
468
- $pathPrefix = "";
469
- if(preg_match('/^https?:\/\/[^\/]+\/(.+)$/i', $siteURL, $matches)){
470
- $path = $matches[1];
471
- $path = preg_replace('/^\//', '', $path);
472
- $path = preg_replace('/\/$/', '', $path);
473
- $pathPrefix = '/' . $path; // Which is: /my/path
474
- }
475
- $matchCaps = '$1/$2~$3~$4~$5~$6';
476
- if(preg_match('/^https?:\/\/[^\/]+\/(.+)$/i', $homeURL, $matches)){
477
- $path = $matches[1];
478
- $path = preg_replace('/^\//', '', $path);
479
- $path = preg_replace('/\/$/', '', $path);
480
- $pieces = explode('/', $path);
481
- if(count($pieces) == 1){
482
- # No path: "/wp-content/wfcache/%{HTTP_HOST}_$1/$2~$3~$4~$5~$6_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
483
- # One path: "/mdm/wp-content/wfcache/%{HTTP_HOST}_mdm/$1~$2~$3~$4~$5_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
484
- $matchCaps = $pieces[0] . '/$1~$2~$3~$4~$5';
485
- } else if(count($pieces) == 2){
486
- $matchCaps = $pieces[0] . '/' . $pieces[1] . '/$1~$2~$3~$4';
487
- } else {
488
- $matchCaps = '$1/$2~$3~$4~$5~$6'; #defaults to the regular setting but this won't work. However user should already have gotten a warning that we don't support sites more than 2 dirs deep with falcon.
489
- }
490
- }
491
- $sslString = "RewriteCond %{HTTPS} off";
492
- if(wfConfig::get('allowHTTPSCaching')){
493
- $sslString = "";
494
- }
495
- $otherRewriteConds = "";
496
- $ex = wfConfig::get('cacheExclusions', false);
497
- if($ex){
498
- $ex = unserialize($ex);
499
- foreach($ex as $v){
500
- if($v['pt'] == 'uac'){
501
- $otherRewriteConds .= "\n\tRewriteCond %{HTTP_USER_AGENT} !" . self::regexSpaceFix(preg_quote($v['p'])) . " [NC]";
502
- }
503
- if($v['pt'] == 'uaeq'){
504
- $otherRewriteConds .= "\n\tRewriteCond %{HTTP_USER_AGENT} !^" . self::regexSpaceFix(preg_quote($v['p'])) . "$ [NC]";
505
- }
506
- if($v['pt'] == 'cc'){
507
- $otherRewriteConds .= "\n\tRewriteCond %{HTTP_COOKIE} !" . self::regexSpaceFix(preg_quote($v['p'])) . " [NC]";
508
- }
509
- }
510
- }
511
-
512
- //We exclude URLs that are banned so that Wordfence PHP code can catch the IP address, then ban that IP and the ban is added to .htaccess.
513
- $excludedURLs = "";
514
- if(wfConfig::get('bannedURLs', false)){
515
- foreach(explode(',', wfConfig::get('bannedURLs', false)) as $URL){
516
- $excludedURLs .= "RewriteCond %{REQUEST_URI} !" . wfUtils::patternToRegex($URL, '', '') . "\n\t";
517
- }
518
- }
519
-
520
- $code = <<<EOT
521
- #WFCACHECODE - Do not remove this line. Disable Web Caching in Wordfence to remove this data.
522
- <IfModule mod_deflate.c>
523
- AddOutputFilterByType DEFLATE text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/html text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon application/json
524
- <IfModule mod_headers.c>
525
- Header append Vary User-Agent env=!dont-vary
526
- </IfModule>
527
- <IfModule mod_mime.c>
528
- AddOutputFilter DEFLATE js css htm html xml
529
- </IfModule>
530
- </IfModule>
531
- <IfModule mod_mime.c>
532
- AddType text/html .html_gzip
533
- AddEncoding gzip .html_gzip
534
- AddType text/xml .xml_gzip
535
- AddEncoding gzip .xml_gzip
536
- </IfModule>
537
- <IfModule mod_setenvif.c>
538
- SetEnvIfNoCase Request_URI \.html_gzip$ no-gzip
539
- SetEnvIfNoCase Request_URI \.xml_gzip$ no-gzip
540
- </IfModule>
541
- <IfModule mod_headers.c>
542
- Header set Vary "Accept-Encoding, Cookie"
543
- </IfModule>
544
- <IfModule mod_rewrite.c>
545
- #Prevents garbled chars in cached files if there is no default charset.
546
- AddDefaultCharset utf-8
547
-
548
- #Cache rules:
549
- RewriteEngine On
550
- RewriteBase /
551
- RewriteCond %{HTTPS} on
552
- RewriteRule .* - [E=WRDFNC_HTTPS:_https]
553
- RewriteCond %{HTTP:Accept-Encoding} gzip
554
- RewriteRule .* - [E=WRDFNC_ENC:_gzip]
555
- RewriteCond %{REQUEST_METHOD} !=POST
556
- {$sslString}
557
- RewriteCond %{QUERY_STRING} ^(?:\d+=\d+)?$
558
- RewriteCond %{REQUEST_URI} (?:\/|\.html)$ [NC]
559
- {$excludedURLs}
560
- RewriteCond %{HTTP_COOKIE} !(comment_author|wp\-postpass|wf_logout|wordpress_logged_in|wptouch_switch_toggle|wpmp_switcher) [NC]
561
- {$otherRewriteConds}
562
- RewriteCond %{REQUEST_URI} \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$
563
- RewriteCond "%{DOCUMENT_ROOT}{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_%1/%2~%3~%4~%5~%6_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" -f
564
- RewriteRule \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$ "{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_{$matchCaps}_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
565
- </IfModule>
566
- #Do not remove this line. Disable Web caching in Wordfence to remove this data - WFCACHECODE
567
- EOT;
568
- return $code;
569
- }
570
- private static function regexSpaceFix($str){
571
- return str_replace(' ', '\\s', $str);
572
- }
573
- public static function scheduleUpdateBlockedIPs(){
574
- wp_clear_scheduled_hook('wordfence_update_blocked_IPs');
575
- if(wfConfig::get('cacheType') != 'falcon'){
576
- self::updateBlockedIPs('remove'); //Fail silently if .htaccess is not readable. Will fall back to old blocking via WP
577
- return;
578
- }
579
- self::updateBlockedIPs('add'); //Fail silently if .htaccess is not readable. Will fall back to old blocking via WP
580
- wp_schedule_single_event(time() + 300, 'wordfence_update_blocked_IPs');
581
- }
582
 
583
  /**
584
  * @param $action
585
  * @return bool|string|void
586
  */
587
  public static function updateBlockedIPs($action){ //'add' or 'remove'
588
- if(wfConfig::get('cacheType') != 'falcon'){ return; }
589
-
590
  $htaccessPath = self::getHtaccessPath();
591
  if(! $htaccessPath){
592
  return "Wordfence could not find your .htaccess file.";
@@ -615,101 +183,7 @@ EOT;
615
  flock($fh, LOCK_UN);
616
  fclose($fh);
617
  return false;
618
- } else if($action == 'add'){
619
- $fh = @fopen($htaccessPath, 'r+');
620
- if(! $fh){
621
- $err = error_get_last();
622
- return $err['message'];
623
- }
624
-
625
- $lines = array();
626
- $wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
627
- $IPs = $wfLog->getBlockedIPsAddrOnly();
628
- if(sizeof($IPs) > 0){
629
- foreach($IPs as $IP){
630
- $lines[] = "Deny from $IP\n";
631
- }
632
- }
633
- $ranges = $wfLog->getRangesBasic();
634
- $browserAdded = false;
635
- $browserLines = array();
636
- if($ranges){
637
- foreach($ranges as $r){
638
- $arr = explode('|', $r);
639
- $range = isset($arr[0]) ? $arr[0] : false;
640
- $browser = isset($arr[1]) ? $arr[1] : false;
641
- $referer = isset($arr[2]) ? $arr[2] : false;
642
-
643
- if($range){
644
- if($browser || $referer){ continue; } //We don't allow combos in falcon
645
-
646
- list($start_range, $end_range) = explode('-', $range);
647
- if (preg_match('/[\.:]/', $start_range)) {
648
- $start_range = wfUtils::inet_pton($start_range);
649
- $end_range = wfUtils::inet_pton($end_range);
650
- } else {
651
- $start_range = wfUtils::inet_pton(long2ip($start_range));
652
- $end_range = wfUtils::inet_pton(long2ip($end_range));
653
- }
654
-
655
- $cidrs = wfUtils::rangeToCIDRs($start_range, $end_range);
656
-
657
- $hIPs = wfUtils::inet_ntop($start_range) . ' - ' . wfUtils::inet_ntop($end_range);
658
- if(sizeof($cidrs) > 0){
659
- $lines[] = '#Start of blocking code for IP range: ' . $hIPs . "\n";
660
- foreach($cidrs as $c){
661
- $lines[] = "Deny from $c\n";
662
- }
663
- $lines[] = '#End of blocking code for IP range: ' . $hIPs . "\n";
664
- }
665
- } else if($browser){
666
- if($range || $referer){ continue; }
667
- $browserLines[] = "\t#Blocking code for browser pattern: $browser\n";
668
- $browser = preg_replace('/([\-\_\.\+\!\@\#\$\%\^\&\(\)\[\]\{\}\/])/', "\\\\$1", $browser);
669
- $browser = preg_replace('/\*/', '.*', $browser);
670
- $browserLines[] = "\tSetEnvIf User-Agent \"" . $browser . "\" WordfenceBadBrowser=1\n";
671
- $browserAdded = true;
672
- } else if($referer){
673
- if($browser || $range){ continue; }
674
- $browserLines[] = "\t#Blocking code for referer pattern: $referer\n";
675
- $referer = preg_replace('/([\-\_\.\+\!\@\#\$\%\^\&\(\)\[\]\{\}\/])/', "\\\\$1", $referer);
676
- $referer = preg_replace('/\*/', '.*', $referer);
677
- $browserLines[] = "\tSetEnvIf Referer \"" . $referer . "\" WordfenceBadBrowser=1\n";
678
- $browserAdded = true;
679
- }
680
- }
681
- }
682
- if($browserAdded){
683
- $lines[] = "<IfModule mod_setenvif.c>\n";
684
- foreach($browserLines as $l){
685
- $lines[] = $l;
686
- }
687
- $lines[] = "\tDeny from env=WordfenceBadBrowser\n";
688
- $lines[] = "</IfModule>\n";
689
- }
690
  }
691
- $blockCode = "#WFIPBLOCKS - Do not remove this line. Disable Web Caching in Wordfence to remove this data.\nOrder Deny,Allow\n";
692
- $blockCode .= implode('', $lines);
693
- $blockCode .= "#Do not remove this line. Disable Web Caching in Wordfence to remove this data - WFIPBLOCKS\n";
694
-
695
-
696
- //Minimize time between lock/unlock
697
- flock($fh, LOCK_EX);
698
- fseek($fh, 0, SEEK_SET); //start of file
699
- clearstatcache(); //Or we get the wrong size from a cached entry and corrupt the file
700
- $contents = @fread($fh, filesize($htaccessPath));
701
- if(! $contents){
702
- fclose($fh);
703
- return "Could not read from $htaccessPath";
704
- }
705
- $contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[\r\s\n\t]*/s', '', $contents);
706
- $contents = $blockCode . $contents;
707
- ftruncate($fh, 0);
708
- fflush($fh);
709
- fseek($fh, 0, SEEK_SET);
710
- @fwrite($fh, $contents);
711
- flock($fh, LOCK_UN);
712
- fclose($fh);
713
  return false;
714
  }
715
  public static function getHtaccessPath(){
1
  <?php
2
  class wfCache {
 
 
3
  private static $cacheStats = array();
4
  private static $cacheClearedThisRequest = false;
 
5
  private static $lastRecursiveDeleteError = false;
6
+
7
+ public static function removeCaching() {
8
+ $cacheType = wfConfig::get('cacheType', false);
9
+ if ($cacheType === 'disabled') {
10
+ return;
11
+ }
12
+
13
+ if ($cacheType == 'falcon') {
14
+ self::addHtaccessCode('remove');
15
+ self::updateBlockedIPs('remove');
16
+ }
17
+
18
+ wfConfig::set('cacheType', 'disabled');
19
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  $cacheDir = WP_CONTENT_DIR . '/wfcache/';
21
  if (file_exists($cacheDir . '.htaccess')) {
22
  unlink($cacheDir . '.htaccess');
23
  }
24
+
25
+ self::clearPageCacheSafe();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
  public static function clearPageCacheSafe(){
28
  if(self::$cacheClearedThisRequest){ return; }
37
  'totalErrors' => 0,
38
  'error' => '',
39
  );
40
+
41
+ $cacheDir = WP_CONTENT_DIR . '/wfcache/';
42
+ if (!file_exists($cacheDir)) {
43
+ return self::$cacheStats;
44
+ }
45
+
46
  $cacheClearLock = WP_CONTENT_DIR . '/wfcache/clear.lock';
47
  if(! is_file($cacheClearLock)){
48
  if(! touch($cacheClearLock)){
67
  self::$cacheStats['totalErrors']++;
68
  }
69
  flock($fp, LOCK_UN);
70
+ @unlink($cacheClearLock);
71
+ @rmdir($cacheDir);
72
  }
73
  fclose($fp);
74
 
75
  return self::$cacheStats;
76
  }
77
+ private static function recursiveDelete($dir) {
78
  $files = array_diff(scandir($dir), array('.','..'));
79
  foreach ($files as $file) {
80
  if(is_dir($dir . '/' . $file)){
120
  }
121
  }
122
  public static function addHtaccessCode($action){
123
+ if($action != 'remove'){
124
+ die("Error: addHtaccessCode must be called with 'remove' as param");
125
  }
126
  $htaccessPath = self::getHtaccessPath();
127
  if(! $htaccessPath){
141
  return "Could not read from $htaccessPath";
142
  }
143
  $contents = preg_replace('/#WFCACHECODE.*WFCACHECODE[\r\s\n\t]*/s', '', $contents);
 
 
 
 
144
  ftruncate($fh, 0);
145
  fflush($fh);
146
  fseek($fh, 0, SEEK_SET);
149
  fclose($fh);
150
  return false;
151
  }