Wordfence Security – Firewall & Malware Scan - Version 3.1.2

Version Description

  • Fixed permanent IP blocking bug which caused permanently blocked IP's to no longer display in the list after some time, even though there were still blocked. (Incorrect SQL query)
  • Fixed "Can't get admin ID" on scan starts for both MU and single site installs.
  • Improved status messages for sites with very large numbers of comments.
  • Fixed bug that caused sites in subdirectories to not be able to view site config or run the memory test on the Wordfence "options" page.
  • Fixed database disconnect bug (mysql server has gone away). An additional fix was required to finally squash this bug.
  • Removed the code that prevented you from installing Wordfence on Windows. Sorry Windows customers!
  • Improved scheduling so that it is now more reliable.
  • Fixed bug that caused a loop for customers who could not contact the Wordfence servers on install.
  • Added helpful message if you get the "can't connect to itself" error message with some additional documentation to help solve this issue.
  • Improved error reporting when Wordfence can't connect to the scanning servers. Now features a helpful explanation rather than a generic message.
  • Added Country Geo-Blocking feature for paid customers.
  • Added Scan Scheduling feature for paid customers.
Download this release

Release Info

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

Code changes from version 3.1.1 to 3.1.2

css/main.css CHANGED
@@ -285,3 +285,18 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
285
  background-position: 2px 2px;
286
  background-repeat: no-repeat;
287
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  background-position: 2px 2px;
286
  background-repeat: no-repeat;
287
  }
288
+ #paidWrap {
289
+ position: relative;
290
+ }
291
+ #paidCover {
292
+ }
293
+ .paidInnerMsg {
294
+ width: 400px;
295
+ margin: 200px auto 0 auto;
296
+ color: #000;
297
+ font-size: 18px;
298
+ font-family: Georgia, Times;
299
+ line-height: 1.8em;
300
+ text-align: center;
301
+ -webkit-font-smoothing: antialiased;
302
+ }
js/admin.js CHANGED
@@ -27,6 +27,9 @@ window['wordfenceAdmin'] = {
27
  maxActivityLogItems: 1000,
28
  scanReqAnimation: false,
29
  debugOn: false,
 
 
 
30
  init: function(){
31
  this.nonce = WordfenceAdminVars.firstNonce;
32
  this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
@@ -53,6 +56,14 @@ window['wordfenceAdmin'] = {
53
  this.staticTabChanged();
54
  this.updateTicker(true);
55
  startTicker = true;
 
 
 
 
 
 
 
 
56
  } else {
57
  this.mode = false;
58
  }
@@ -63,8 +74,6 @@ window['wordfenceAdmin'] = {
63
  }
64
  jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
65
  }
66
- this.showLoading();
67
-
68
  },
69
  showLoading: function(){
70
  this.removeLoading();
@@ -848,6 +857,176 @@ window['wordfenceAdmin'] = {
848
  this.ajax('wordfence_clearAllBlocked', { op: op }, function(res){
849
  self.staticTabChanged();
850
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
  }
852
  };
853
  window['WFAD'] = window['wordfenceAdmin'];
27
  maxActivityLogItems: 1000,
28
  scanReqAnimation: false,
29
  debugOn: false,
30
+ blockedCountriesPending: [],
31
+ ownCountry: "",
32
+ schedStartHour: false,
33
  init: function(){
34
  this.nonce = WordfenceAdminVars.firstNonce;
35
  this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
56
  this.staticTabChanged();
57
  this.updateTicker(true);
58
  startTicker = true;
59
+ } else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
60
+ this.mode = 'countryBlocking';
61
+ startTicker = false;
62
+ this.drawBlockedCountries();
63
+ } else if(jQuery('#wordfenceMode_scanScheduling').length > 0){
64
+ this.mode = 'scanScheduling';
65
+ startTicker = false;
66
+ this.sched_modeChange();
67
  } else {
68
  this.mode = false;
69
  }
74
  }
75
  jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
76
  }
 
 
77
  },
78
  showLoading: function(){
79
  this.removeLoading();
857
  this.ajax('wordfence_clearAllBlocked', { op: op }, function(res){
858
  self.staticTabChanged();
859
  });
860
+ },
861
+ setOwnCountry: function(code){
862
+ this.ownCountry = (code + "").toUpperCase();
863
+ },
864
+ addBlockedCountry: function(code, name){
865
+ code = (code + "").toUpperCase();
866
+ if(code == this.ownCountry){
867
+ this.colorbox('400px', "Please confirm blocking yourself", "You are about to block your own country. This could lead to you being locked out. Please make sure that your user profile on this machine has a current and valid email address and make sure you know what it is. That way if you are locked out, you can send yourself an unlock email. If you're sure you want to block your own country, click 'Confirm' below, otherwise click 'Cancel'.<br />" +
868
+ '<input type="button" name="but1" value="Confirm" onclick="jQuery.colorbox.close(); WFAD.addBlockedCountryConfirm(\'' + code + '\',\'' + name + '\');" />&nbsp;<input type="button" name="but1" value="Cancel" onclick="jQuery.colorbox.close();" />');
869
+ } else {
870
+ this.addBlockedCountryConfirm(code, name);
871
+ }
872
+ },
873
+ addBlockedCountryConfirm: function(code, name){
874
+ var exists = false;
875
+ for(var i = 0; i < this.blockedCountriesPending.length; i++){
876
+ if(this.blockedCountriesPending[i][0] == code){
877
+ return;
878
+ }
879
+ }
880
+ this.blockedCountriesPending.push([code, name]);
881
+ this.drawBlockedCountries();
882
+ },
883
+ loadBlockedCountries: function(str){
884
+ var codes = str.split(',');
885
+ var self = this;
886
+ jQuery("#wfBlockedCountry > option").each(function() {
887
+ for(var i = 0; i < codes.length; i++){
888
+ if(codes[i] == this.value){
889
+ self.addBlockedCountryConfirm(this.value, this.text);
890
+ }
891
+ }
892
+ });
893
+ this.drawBlockedCountries();
894
+ },
895
+ drawBlockedCountries: function(){
896
+ var html = "";
897
+ var self = this;
898
+ if(this.blockedCountriesPending.length < 1){
899
+ jQuery('#wfCountryList').html('<span style="color: #999;">There are no countries currently blocked.</span>');
900
+ return;
901
+ }
902
+ jQuery("#wfBlockedCountry > option").each(function() {
903
+ for(var i = 0; i < self.blockedCountriesPending.length; i++){
904
+ if(self.blockedCountriesPending[i][0] == this.value){
905
+ html += "Blocking: " + this.text + '&nbsp;&nbsp;<a href="#" onclick="WFAD.removeBlockedCountry(\'' + this.value + '\'); return false;">[remove]</a><br />';
906
+ }
907
+ }
908
+ });
909
+ jQuery('#wfCountryList').html(html);
910
+
911
+ },
912
+ removeBlockedCountry: function(code){
913
+ var newArr = [];
914
+ for(var i = 0; i < this.blockedCountriesPending.length; i++){
915
+ if(this.blockedCountriesPending[i][0] != code){
916
+ newArr.push(this.blockedCountriesPending[i]);
917
+ }
918
+ }
919
+ this.blockedCountriesPending = newArr;
920
+ this.drawBlockedCountries();
921
+ },
922
+ saveCountryBlocking: function(){
923
+ var action = jQuery('#wfBlockAction').val();
924
+ var redirURL = jQuery('#wfRedirURL').val();
925
+ if(action == 'redir' && (! /^https?:\/\/[^\/]+/i.test(redirURL))){
926
+ this.colorbox('400px', "Please enter a URL for redirection", "You have chosen to redirect blocked countries to a specific page. You need to enter a URL in the text box provided that starts with http:// or https://");
927
+ return;
928
+ }
929
+ var loggedInBlocked = jQuery('#wfLoggedInBlocked').is(':checked') ? '1' : '0';
930
+ var loginFormBlocked = jQuery('#wfLoginFormBlocked').is(':checked') ? '1' : '0';
931
+ var codesArr = [];
932
+ for(var i = 0; i < this.blockedCountriesPending.length; i++){
933
+ codesArr.push(this.blockedCountriesPending[i][0]);
934
+ }
935
+ var codes = codesArr.join(',');
936
+ jQuery('.wfAjax24').show();
937
+ var self = this;
938
+ this.ajax('wordfence_saveCountryBlocking', {
939
+ blockAction: action,
940
+ redirURL: redirURL,
941
+ loggedInBlocked: loggedInBlocked,
942
+ loginFormBlocked: loginFormBlocked,
943
+ codes: codes
944
+ }, function(res){
945
+ jQuery('.wfAjax24').hide();
946
+ self.pulse('.wfSavedMsg');
947
+ });
948
+ },
949
+ paidUsersOnly: function(msg){
950
+ var pos = jQuery('#paidWrap').position();
951
+ var width = jQuery('#paidWrap').width();
952
+ var height = jQuery('#paidWrap').height();
953
+ jQuery('<div style="position: absolute; left: ' + pos.left + 'px; top: ' + pos.top + 'px; background-color: #FFF; width: ' + width + 'px; height: ' + height + 'px;"><div class="paidInnerMsg">' + msg + ' <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">Click here to upgrade and gain access to this feature.</div></div>').insertAfter('#paidWrap').fadeTo(10000, 0.7);
954
+ },
955
+ sched_modeChange: function(){
956
+ var self = this;
957
+ if(jQuery('#schedMode').val() == 'auto'){
958
+ jQuery('.wfSchedCheckbox').attr('disabled', true);
959
+ } else {
960
+ jQuery('.wfSchedCheckbox').attr('disabled', false);
961
+ }
962
+ },
963
+ sched_shortcut: function(mode){
964
+ if(jQuery('#schedMode').val() == 'auto'){
965
+ this.colorbox('400px', 'Change the scan mode', "You need to change the scan mode to manually scheduled scans if you want to select scan times.");
966
+ return;
967
+ }
968
+ jQuery('.wfSchedCheckbox').prop('checked', false);
969
+ if(this.schedStartHour === false){
970
+ this.schedStartHour = Math.floor((Math.random()*24));
971
+ } else {
972
+ this.schedStartHour++;
973
+ if(this.schedStartHour > 23){
974
+ this.schedStartHour = 0;
975
+ }
976
+ }
977
+ if(mode == 'onceDaily'){
978
+ for(var i = 0; i <= 6; i++){
979
+ jQuery('#wfSchedDay_' + i + '_' + this.schedStartHour).attr('checked', true);
980
+ }
981
+ } else if(mode == 'twiceDaily'){
982
+ var secondHour = this.schedStartHour + 12;
983
+ if(secondHour >= 24){ secondHour = secondHour - 24; }
984
+ for(var i = 0; i <= 6; i++){
985
+ jQuery('#wfSchedDay_' + i + '_' + this.schedStartHour).attr('checked', true);
986
+ jQuery('#wfSchedDay_' + i + '_' + secondHour).attr('checked', true);
987
+ }
988
+ } else if(mode == 'oddDaysWE'){
989
+ var startDay = Math.floor((Math.random()));
990
+ jQuery('#wfSchedDay_1_' + this.schedStartHour).attr('checked', true);
991
+ jQuery('#wfSchedDay_3_' + this.schedStartHour).attr('checked', true);
992
+ jQuery('#wfSchedDay_5_' + this.schedStartHour).attr('checked', true);
993
+ jQuery('#wfSchedDay_6_' + this.schedStartHour).attr('checked', true);
994
+ jQuery('#wfSchedDay_0_' + this.schedStartHour).attr('checked', true);
995
+ } else if(mode == 'weekends'){
996
+ var startDay = Math.floor((Math.random()));
997
+ jQuery('#wfSchedDay_6_' + this.schedStartHour).attr('checked', true);
998
+ jQuery('#wfSchedDay_0_' + this.schedStartHour).attr('checked', true);
999
+ } else if(mode == 'every6hours'){
1000
+ for(var i = 0; i <= 6; i++){
1001
+ for(var hour = this.schedStartHour; hour < this.schedStartHour + 24; hour = hour + 6){
1002
+ var displayHour = hour;
1003
+ if(displayHour >= 24){ displayHour = displayHour - 24; }
1004
+ jQuery('#wfSchedDay_' + i + '_' + displayHour).attr('checked', true);
1005
+ }
1006
+ }
1007
+ }
1008
+
1009
+ },
1010
+ sched_save: function(){
1011
+ var schedMode = jQuery('#schedMode').val();
1012
+ var schedule = [];
1013
+ for(var day = 0; day <= 6; day++){
1014
+ var hours = [];
1015
+ for(var hour = 0; hour <= 23; hour++){
1016
+ var elemID = '#wfSchedDay_' + day + '_' + hour;
1017
+ hours[hour] = jQuery(elemID).is(':checked') ? '1' : '0';
1018
+ }
1019
+ schedule[day] = hours.join(',');
1020
+ }
1021
+ scheduleTxt = schedule.join('|');
1022
+ var self = this;
1023
+ this.ajax('wordfence_saveScanSchedule', {
1024
+ schedMode: schedMode,
1025
+ schedTxt: scheduleTxt
1026
+ }, function(res){
1027
+ jQuery('.wfAjax24').hide();
1028
+ self.pulse('.wfSaveMsg');
1029
+ });
1030
  }
1031
  };
1032
  window['WFAD'] = window['wordfenceAdmin'];
lib/GeoIP.dat ADDED
Binary file
lib/menu_countryBlocking.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
2
+ <div class="wrap" id="paidWrap">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Block specific countries from accessing your site</h2>
4
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
+ <table class="wfConfigForm">
6
+ <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
7
+ <tr><th>What to do when we block someone:</th><td>
8
+ <select id="wfBlockAction">
9
+ <option value="block"<?php if(wfConfig::get('cbl_action') == 'block'){ echo ' selected'; } ?>>Show the standard Wordfence blocked message</option>
10
+ <option value="redir"<?php if(wfConfig::get('cbl_action') == 'redir'){ echo ' selected'; } ?>>Redirect to the URL below</option>
11
+ </select>
12
+ </td></tr>
13
+ <tr><th>URL to redirect blocked users to:</th><td><input type="text" id="wfRedirURL" value="<?php if(wfConfig::get('cbl_redirURL')){ echo htmlspecialchars(wfConfig::get('cbl_redirURL')); } ?>" /></td></tr>
14
+ <tr><th>Block countries even if they are logged in:</th><td><input type="checkbox" id="wfLoggedInBlocked" value="1" <?php if(wfConfig::get('cbl_loggedInBlocked')){ echo 'checked'; } ?> /></td></tr>
15
+ <tr><th>Block access to the login form too:</th><td><input type="checkbox" id="wfLoginFormBlocked" value="1" <?php if(wfConfig::get('cbl_loginFormBlocked')){ echo 'checked'; } ?> /></td></tr>
16
+ <tr><td colspan="2" style="padding-top: 10px;" >
17
+ <h2>Select which countries to block</h2>
18
+ </td></tr>
19
+ <tr><th>Select individual countries to block and hit "Add":</th><td><select name="country" id="wfBlockedCountry">
20
+ <?php require('wfCountrySelect.php'); ?>
21
+ </select><input type="button" name="but3" class="button-primary" value="Add Country" onclick="var cVal = jQuery('#wfBlockedCountry').val(); WFAD.addBlockedCountry(cVal, jQuery('#wfBlockedCountry option[value=\'' + cVal + '\']').text());" /></td></tr>
22
+ <tr><td colspan="2">
23
+ <div id="wfCountryList" style="width: 350px; height: 200px; border: 1px solid #999; padding: 5px; margin: 5px;">
24
+ </div>
25
+ <b>Changes to the country list will only take effect once you hit the save button below.</b>
26
+ </td></tr>
27
+ <tr><td colspan="2">
28
+ <table border="0" cellpadding="0" cellspacing="0"><tr>
29
+ <td><input type="button" name="but4" class="button-primary" value="Save blocking options and country list" onclick="WFAD.saveCountryBlocking();" /></td>
30
+ <td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table>
31
+ </td></tr>
32
+ </table>
33
+ <span style="font-size: 10px;">Note that we use an IP to country database that is 99.5% accurate to identify which country a visitor is from.</span>
34
+ </div>
35
+ </div>
36
+ <script type="text/javascript">
37
+ WFAD.setOwnCountry('<?php echo wfUtils::IP2Country(wfUtils::getIP()); ?>');
38
+ <?php
39
+ if(wfConfig::get('cbl_countries')){
40
+ ?>
41
+ WFAD.loadBlockedCountries('<?php echo wfConfig::get('cbl_countries'); ?>');
42
+ <?php
43
+ }
44
+ ?>
45
+ <?php
46
+ if(! wfConfig::get('isPaid')){
47
+ echo 'WFAD.paidUsersOnly("Country blocking is only available to paid members because we have licensed a commercial geolocation database to provide this feature.");';
48
+ }
49
+ ?>
50
+ </script>
51
+
lib/menu_options.php CHANGED
@@ -207,8 +207,8 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
207
  <tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
208
  <tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
209
  <tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
210
- <tr><th colspan="2"><a href="/?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
211
- <tr><th colspan="2"><a href="/?_wfsf=testmem&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Test your WordPress host's available memory</a></th></tr>
212
  </table>
213
  <p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
214
  </div>
207
  <tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
208
  <tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
209
  <tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
210
+ <tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
211
+ <tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=testmem&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Test your WordPress host's available memory</a></th></tr>
212
  </table>
213
  <p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
214
  </div>
lib/menu_scanSchedule.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
+ <div class="wrap" id="paidWrap">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Schedule Wordfence Scanning</h2>
4
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
+ <p>
6
+ <strong>Current time: <?php echo date('l jS \of F Y H:i:s A', current_time('timestamp')); ?></strong>
7
+ </p>
8
+ <p style="width: 600px;">
9
+ Wordfence provides continuous real-time security for your site. Occasionally we run a full scan of all files, posts, pages, comments, user password and other site components.
10
+ The scheduler below lets you choose when those full scans will run.<br /><br />
11
+
12
+ We have displayed the current time your WordPress site uses above.
13
+ You can go to the Settings/General menu to change your timezone.
14
+ Use the links provided as shortcuts to select scan times. Try clicking
15
+ the links several times to advance the time. You can also manually select scan start times for each day.
16
+ </p>
17
+ <p>
18
+ <strong>Scan mode:</strong><select id="schedMode" onchange="WFAD.sched_modeChange();">
19
+ <option value="auto"<?php echo (wfConfig::get('schedMode') == 'auto' ? ' selected' : ''); ?>>Let Wordfence automatically schedule scans (recommended)</option>
20
+ <option value="manual"<?php echo (wfConfig::get('schedMode') == 'manual' ? ' selected' : ''); ?>>Manually schedule scans using calendar below</option>
21
+ </select>
22
+ <p>
23
+ <strong>Shortcuts</strong>:
24
+ <a href="#" onclick="WFAD.sched_shortcut('onceDaily'); return false;">Once a day</a>,
25
+ <a href="#" onclick="WFAD.sched_shortcut('twiceDaily'); return false;">Twice a day</a>,
26
+ <a href="#" onclick="WFAD.sched_shortcut('weekends'); return false;">Weekends</a>,
27
+ <a href="#" onclick="WFAD.sched_shortcut('oddDaysWE'); return false;">Odd days and weekends</a>,
28
+ <a href="#" onclick="WFAD.sched_shortcut('every6hours'); return false;">Every 6 hours</a>,
29
+ </p>
30
+
31
+ <table border="0">
32
+ <?php
33
+ $daysOfWeek = array(
34
+ array(1, 'Monday'),
35
+ array(2, 'Tuesday'),
36
+ array(3, 'Wednesday'),
37
+ array(4, 'Thursday'),
38
+ array(5, 'Friday'),
39
+ array(6, 'Saturday'),
40
+ array(0, 'Sunday')
41
+ );
42
+ $sched = wfConfig::get_ser('scanSched', array());
43
+ foreach($daysOfWeek as $elem){
44
+ $dayIndex = $elem[0];
45
+ $dayName = $elem[1];
46
+ require('schedWeekEntry.php');
47
+ }
48
+ ?>
49
+ </table>
50
+ <table border="0" cellpadding="0" cellspacing="0"><tr>
51
+ <td>
52
+ <input type="button" name="but3" class="button-primary" value="Save Scan Schedule" onclick="WFAD.sched_save();" />
53
+ </td>
54
+ <td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td>
55
+ </tr>
56
+ </table>
57
+ </div>
58
+ <br />
59
+ </div>
60
+
61
+ <script type="text/javascript">
62
+ <?php
63
+ if(! wfConfig::get('isPaid')){
64
+ echo 'WFAD.paidUsersOnly("Scan scheduling is only available to paid members because it puts significant additional load on our cloud scanning servers. As a free customer, Wordfence will automatically schedule scans to run approximately once daily.");';
65
+ }
66
+ ?>
67
+
68
+ </script>
lib/schedWeekEntry.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <tr>
2
+ <th style="text-align: right;"><?php echo $dayName; ?></th>
3
+ <td>Morning:</td>
4
+ <?php
5
+ for($i = 0; $i <= 23; $i++){
6
+ $cell = '<td>';
7
+ if($i > 11){
8
+ $hour = $i - 12;
9
+ if($hour == 0){ $hour = 12; }
10
+
11
+ $cell .= '<span style="color: #3366CC;">' . sprintf('%02d', $hour) . '</span>';
12
+ } else {
13
+ $cell .= '<span style="color: #CC6633;">' . sprintf('%02d', $i) . '</span>';
14
+ }
15
+ if($i == 11){
16
+ $cell .= '&nbsp;&nbsp;Afternoon:';
17
+ }
18
+ $cell .= '</td>';
19
+ echo $cell;
20
+ }
21
+ echo '</tr><tr><th></th><td></td>';
22
+ for($hour = 0; $hour <= 23; $hour++){
23
+ $checked = ($sched[$dayIndex][$hour] ? 'checked' : '');
24
+ echo '<td><input class="wfSchedCheckbox" type="checkbox" id="wfSchedDay_' . $dayIndex . '_' . $hour . '" ' . $checked . ' /></td>';
25
+ }
26
+ ?>
27
+ </td>
28
+ </tr>
29
+ <tr><td colspan="27">&nbsp;</td></tr>
lib/wfAPI.php CHANGED
@@ -8,7 +8,7 @@ class wfAPI {
8
  private $curlContent = 0;
9
  private $APIKey = '';
10
  private $wordpressVersion = '';
11
- private static $maintMsg = "The Wordfence scanning server may be down for maintenance.";
12
  public function __construct($apiKey, $wordpressVersion){
13
  $this->APIKey = $apiKey;
14
  $this->wordpressVersion = $wordpressVersion;
@@ -20,12 +20,12 @@ class wfAPI {
20
  $getParams
21
  )), $postParams);
22
  if(! $json){
23
- throw new Exception(self::$maintMsg);
24
  }
25
 
26
  $dat = json_decode($json, true);
27
  if(! is_array($dat)){
28
- throw new Exception("We could not understand the Wordfence API response when calling '$action'.");
29
  }
30
  if(is_array($dat) && isset($dat['errorMsg'])){
31
  throw new Exception($dat['errorMsg']);
@@ -64,13 +64,17 @@ class wfAPI {
64
  } else {
65
  $cerror = curl_error($curl);
66
  curl_close($curl);
67
- throw new Exception(self::$maintMsg . " Got HTTP status code [$httpStatus] and curl error: $cerror");
68
  }
69
  } else {
70
  $data = $this->fileGet($url, $postParams);
71
  if($data === false){
72
  $err = error_get_last();
73
- throw new Exception(self::$maintMsg . " Got HTTP error: " . $err);
 
 
 
 
74
  }
75
  return $data;
76
  }
@@ -119,12 +123,21 @@ class wfAPI {
119
  if($httpStatus != 200){
120
  $cError = curl_error($curl);
121
  curl_close($curl);
122
- throw new Exception(self::$maintMsg . " Got HTTP status [$httpStatus] and curl error: $cError");
 
 
 
 
123
  }
124
  } else {
125
  $data = $this->fileGet($url, $postData);
126
  if($data === false){
127
- throw new Exception(self::$maintMsg . " Got HTTP error: " . error_get_last());
 
 
 
 
 
128
  }
129
  $httpStatus = '200';
130
  }
8
  private $curlContent = 0;
9
  private $APIKey = '';
10
  private $wordpressVersion = '';
11
+ private static $maintMsg = "The Wordfence scanning server could not be contacted.";
12
  public function __construct($apiKey, $wordpressVersion){
13
  $this->APIKey = $apiKey;
14
  $this->wordpressVersion = $wordpressVersion;
20
  $getParams
21
  )), $postParams);
22
  if(! $json){
23
+ throw new Exception("We received an empty data response from the Wordfence scanning servers when calling the '$action' function.");
24
  }
25
 
26
  $dat = json_decode($json, true);
27
  if(! is_array($dat)){
28
+ throw new Exception("We received a data structure that is not the expected array when contacting the Wordfence scanning servers and calling the '$action' function.");
29
  }
30
  if(is_array($dat) && isset($dat['errorMsg'])){
31
  throw new Exception($dat['errorMsg']);
64
  } else {
65
  $cerror = curl_error($curl);
66
  curl_close($curl);
67
+ throw new Exception("We received an error response when trying to contact the Wordfence scanning servers. The HTTP status code was [$httpStatus]" . ($cerror ? (' and the error from CURL was ' . $cerror) : ''));
68
  }
69
  } else {
70
  $data = $this->fileGet($url, $postParams);
71
  if($data === false){
72
  $err = error_get_last();
73
+ if($err){
74
+ throw new Exception("We received an error response when trying to contact the Wordfence scanning servers using PHP's file_get_contents function. The error was: " . $err);
75
+ } else {
76
+ throw new Exception("We received an empty response when trying to contact the Wordfence scanning servers using PHP's file_get_contents function.");
77
+ }
78
  }
79
  return $data;
80
  }
123
  if($httpStatus != 200){
124
  $cError = curl_error($curl);
125
  curl_close($curl);
126
+ if($cError){
127
+ throw new Exception("We received an error response when trying to fetch binary data from the Wordfence scanning server. The HTTP status was [$httpStatus] with error: $cError");
128
+ } else {
129
+ throw new Exception("We received an error HTTP response when trying to fetch binary data from the Wordfence scanning server: [$httpStatus]");
130
+ }
131
  }
132
  } else {
133
  $data = $this->fileGet($url, $postData);
134
  if($data === false){
135
+ $err = error_get_last();
136
+ if($err){
137
+ throw new Exception("We received an error response when trying to fetch binary data from the Wordfence scanning server using file_get_contents: $err");
138
+ } else {
139
+ throw new Exception("We received an error when trying to fetch binary data from the Wordfence scanning server using file_get_contents. There was no message explaining the error.");
140
+ }
141
  }
142
  $httpStatus = '200';
143
  }
lib/wfConfig.php CHANGED
@@ -411,7 +411,8 @@ class wfConfig {
411
  }
412
  }
413
  }
414
-
 
415
  $dbh = self::getDB()->getDBH();
416
  $res = mysql_query("select val from " . self::table() . " where name='" . mysql_real_escape_string($key) . "'", $dbh);
417
  $err = mysql_error();
@@ -431,6 +432,7 @@ class wfConfig {
431
  public static function set_ser($key, $val, $canUseDisk = false){
432
  //We serialize some very big values so this is ultra-memory efficient. We don't make any copies of $val and don't use ON DUPLICATE KEY UPDATE
433
  // because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
 
434
  $dbh = self::getDB()->getDBH();
435
  $serialized = serialize($val);
436
  $tempFilename = 'wordfence_tmpfile_' . $key . '.php';
411
  }
412
  }
413
  }
414
+ self::getDB()->reconnect();
415
+ //We do our own query handling here because we are dealing with some very big strings
416
  $dbh = self::getDB()->getDBH();
417
  $res = mysql_query("select val from " . self::table() . " where name='" . mysql_real_escape_string($key) . "'", $dbh);
418
  $err = mysql_error();
432
  public static function set_ser($key, $val, $canUseDisk = false){
433
  //We serialize some very big values so this is ultra-memory efficient. We don't make any copies of $val and don't use ON DUPLICATE KEY UPDATE
434
  // because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
435
+ self::getDB()->reconnect();
436
  $dbh = self::getDB()->getDBH();
437
  $serialized = serialize($val);
438
  $tempFilename = 'wordfence_tmpfile_' . $key . '.php';
lib/wfCountryMap.php ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class wfCountryMap {
3
+ public static $map = array(
4
+ 'A1' => "Anonymous Proxy",
5
+ 'A2' => "Satellite Provider",
6
+ 'O1' => "Other Country",
7
+ 'AD' => "Andorra",
8
+ 'AE' => "United Arab Emirates",
9
+ 'AF' => "Afghanistan",
10
+ 'AG' => "Antigua and Barbuda",
11
+ 'AI' => "Anguilla",
12
+ 'AL' => "Albania",
13
+ 'AM' => "Armenia",
14
+ 'AO' => "Angola",
15
+ 'AP' => "Asia/Pacific Region",
16
+ 'AQ' => "Antarctica",
17
+ 'AR' => "Argentina",
18
+ 'AS' => "American Samoa",
19
+ 'AT' => "Austria",
20
+ 'AU' => "Australia",
21
+ 'AW' => "Aruba",
22
+ 'AX' => "Aland Islands",
23
+ 'AZ' => "Azerbaijan",
24
+ 'BA' => "Bosnia and Herzegovina",
25
+ 'BB' => "Barbados",
26
+ 'BD' => "Bangladesh",
27
+ 'BE' => "Belgium",
28
+ 'BF' => "Burkina Faso",
29
+ 'BG' => "Bulgaria",
30
+ 'BH' => "Bahrain",
31
+ 'BI' => "Burundi",
32
+ 'BJ' => "Benin",
33
+ 'BL' => "Saint Bartelemey",
34
+ 'BM' => "Bermuda",
35
+ 'BN' => "Brunei Darussalam",
36
+ 'BO' => "Bolivia",
37
+ 'BQ' => "Bonaire, Saint Eustatius and Saba",
38
+ 'BR' => "Brazil",
39
+ 'BS' => "Bahamas",
40
+ 'BT' => "Bhutan",
41
+ 'BV' => "Bouvet Island",
42
+ 'BW' => "Botswana",
43
+ 'BY' => "Belarus",
44
+ 'BZ' => "Belize",
45
+ 'CA' => "Canada",
46
+ 'CC' => "Cocos (Keeling) Islands",
47
+ 'CD' => "Congo, The Democratic Republic of the",
48
+ 'CF' => "Central African Republic",
49
+ 'CG' => "Congo",
50
+ 'CH' => "Switzerland",
51
+ 'CI' => "Cote d'Ivoire",
52
+ 'CK' => "Cook Islands",
53
+ 'CL' => "Chile",
54
+ 'CM' => "Cameroon",
55
+ 'CN' => "China",
56
+ 'CO' => "Colombia",
57
+ 'CR' => "Costa Rica",
58
+ 'CU' => "Cuba",
59
+ 'CV' => "Cape Verde",
60
+ 'CW' => "Curacao",
61
+ 'CX' => "Christmas Island",
62
+ 'CY' => "Cyprus",
63
+ 'CZ' => "Czech Republic",
64
+ 'DE' => "Germany",
65
+ 'DJ' => "Djibouti",
66
+ 'DK' => "Denmark",
67
+ 'DM' => "Dominica",
68
+ 'DO' => "Dominican Republic",
69
+ 'DZ' => "Algeria",
70
+ 'EC' => "Ecuador",
71
+ 'EE' => "Estonia",
72
+ 'EG' => "Egypt",
73
+ 'EH' => "Western Sahara",
74
+ 'ER' => "Eritrea",
75
+ 'ES' => "Spain",
76
+ 'ET' => "Ethiopia",
77
+ 'EU' => "Europe",
78
+ 'FI' => "Finland",
79
+ 'FJ' => "Fiji",
80
+ 'FK' => "Falkland Islands (Malvinas)",
81
+ 'FM' => "Micronesia, Federated States of",
82
+ 'FO' => "Faroe Islands",
83
+ 'FR' => "France",
84
+ 'GA' => "Gabon",
85
+ 'GB' => "United Kingdom",
86
+ 'GD' => "Grenada",
87
+ 'GE' => "Georgia",
88
+ 'GF' => "French Guiana",
89
+ 'GG' => "Guernsey",
90
+ 'GH' => "Ghana",
91
+ 'GI' => "Gibraltar",
92
+ 'GL' => "Greenland",
93
+ 'GM' => "Gambia",
94
+ 'GN' => "Guinea",
95
+ 'GP' => "Guadeloupe",
96
+ 'GQ' => "Equatorial Guinea",
97
+ 'GR' => "Greece",
98
+ 'GS' => "South Georgia and the South Sandwich Islands",
99
+ 'GT' => "Guatemala",
100
+ 'GU' => "Guam",
101
+ 'GW' => "Guinea-Bissau",
102
+ 'GY' => "Guyana",
103
+ 'HK' => "Hong Kong",
104
+ 'HM' => "Heard Island and McDonald Islands",
105
+ 'HN' => "Honduras",
106
+ 'HR' => "Croatia",
107
+ 'HT' => "Haiti",
108
+ 'HU' => "Hungary",
109
+ 'ID' => "Indonesia",
110
+ 'IE' => "Ireland",
111
+ 'IL' => "Israel",
112
+ 'IM' => "Isle of Man",
113
+ 'IN' => "India",
114
+ 'IO' => "British Indian Ocean Territory",
115
+ 'IQ' => "Iraq",
116
+ 'IR' => "Iran, Islamic Republic of",
117
+ 'IS' => "Iceland",
118
+ 'IT' => "Italy",
119
+ 'JE' => "Jersey",
120
+ 'JM' => "Jamaica",
121
+ 'JO' => "Jordan",
122
+ 'JP' => "Japan",
123
+ 'KE' => "Kenya",
124
+ 'KG' => "Kyrgyzstan",
125
+ 'KH' => "Cambodia",
126
+ 'KI' => "Kiribati",
127
+ 'KM' => "Comoros",
128
+ 'KN' => "Saint Kitts and Nevis",
129
+ 'KP' => "Korea, Democratic People's Republic of",
130
+ 'KR' => "Korea, Republic of",
131
+ 'KW' => "Kuwait",
132
+ 'KY' => "Cayman Islands",
133
+ 'KZ' => "Kazakhstan",
134
+ 'LA' => "Lao People's Democratic Republic",
135
+ 'LB' => "Lebanon",
136
+ 'LC' => "Saint Lucia",
137
+ 'LI' => "Liechtenstein",
138
+ 'LK' => "Sri Lanka",
139
+ 'LR' => "Liberia",
140
+ 'LS' => "Lesotho",
141
+ 'LT' => "Lithuania",
142
+ 'LU' => "Luxembourg",
143
+ 'LV' => "Latvia",
144
+ 'LY' => "Libyan Arab Jamahiriya",
145
+ 'MA' => "Morocco",
146
+ 'MC' => "Monaco",
147
+ 'MD' => "Moldova, Republic of",
148
+ 'ME' => "Montenegro",
149
+ 'MF' => "Saint Martin",
150
+ 'MG' => "Madagascar",
151
+ 'MH' => "Marshall Islands",
152
+ 'MK' => "Macedonia",
153
+ 'ML' => "Mali",
154
+ 'MM' => "Myanmar",
155
+ 'MN' => "Mongolia",
156
+ 'MO' => "Macao",
157
+ 'MP' => "Northern Mariana Islands",
158
+ 'MQ' => "Martinique",
159
+ 'MR' => "Mauritania",
160
+ 'MS' => "Montserrat",
161
+ 'MT' => "Malta",
162
+ 'MU' => "Mauritius",
163
+ 'MV' => "Maldives",
164
+ 'MW' => "Malawi",
165
+ 'MX' => "Mexico",
166
+ 'MY' => "Malaysia",
167
+ 'MZ' => "Mozambique",
168
+ 'NA' => "Namibia",
169
+ 'NC' => "New Caledonia",
170
+ 'NE' => "Niger",
171
+ 'NF' => "Norfolk Island",
172
+ 'NG' => "Nigeria",
173
+ 'NI' => "Nicaragua",
174
+ 'NL' => "Netherlands",
175
+ 'NO' => "Norway",
176
+ 'NP' => "Nepal",
177
+ 'NR' => "Nauru",
178
+ 'NU' => "Niue",
179
+ 'NZ' => "New Zealand",
180
+ 'OM' => "Oman",
181
+ 'PA' => "Panama",
182
+ 'PE' => "Peru",
183
+ 'PF' => "French Polynesia",
184
+ 'PG' => "Papua New Guinea",
185
+ 'PH' => "Philippines",
186
+ 'PK' => "Pakistan",
187
+ 'PL' => "Poland",
188
+ 'PM' => "Saint Pierre and Miquelon",
189
+ 'PN' => "Pitcairn",
190
+ 'PR' => "Puerto Rico",
191
+ 'PS' => "Palestinian Territory",
192
+ 'PT' => "Portugal",
193
+ 'PW' => "Palau",
194
+ 'PY' => "Paraguay",
195
+ 'QA' => "Qatar",
196
+ 'RE' => "Reunion",
197
+ 'RO' => "Romania",
198
+ 'RS' => "Serbia",
199
+ 'RU' => "Russian Federation",
200
+ 'RW' => "Rwanda",
201
+ 'SA' => "Saudi Arabia",
202
+ 'SB' => "Solomon Islands",
203
+ 'SC' => "Seychelles",
204
+ 'SD' => "Sudan",
205
+ 'SE' => "Sweden",
206
+ 'SG' => "Singapore",
207
+ 'SH' => "Saint Helena",
208
+ 'SI' => "Slovenia",
209
+ 'SJ' => "Svalbard and Jan Mayen",
210
+ 'SK' => "Slovakia",
211
+ 'SL' => "Sierra Leone",
212
+ 'SM' => "San Marino",
213
+ 'SN' => "Senegal",
214
+ 'SO' => "Somalia",
215
+ 'SR' => "Suriname",
216
+ 'ST' => "Sao Tome and Principe",
217
+ 'SV' => "El Salvador",
218
+ 'SX' => "Sint Maarten",
219
+ 'SY' => "Syrian Arab Republic",
220
+ 'SZ' => "Swaziland",
221
+ 'TC' => "Turks and Caicos Islands",
222
+ 'TD' => "Chad",
223
+ 'TF' => "French Southern Territories",
224
+ 'TG' => "Togo",
225
+ 'TH' => "Thailand",
226
+ 'TJ' => "Tajikistan",
227
+ 'TK' => "Tokelau",
228
+ 'TL' => "Timor-Leste",
229
+ 'TM' => "Turkmenistan",
230
+ 'TN' => "Tunisia",
231
+ 'TO' => "Tonga",
232
+ 'TR' => "Turkey",
233
+ 'TT' => "Trinidad and Tobago",
234
+ 'TV' => "Tuvalu",
235
+ 'TW' => "Taiwan",
236
+ 'TZ' => "Tanzania, United Republic of",
237
+ 'UA' => "Ukraine",
238
+ 'UG' => "Uganda",
239
+ 'UM' => "United States Minor Outlying Islands",
240
+ 'US' => "United States",
241
+ 'UY' => "Uruguay",
242
+ 'UZ' => "Uzbekistan",
243
+ 'VA' => "Holy See (Vatican City State)",
244
+ 'VC' => "Saint Vincent and the Grenadines",
245
+ 'VE' => "Venezuela",
246
+ 'VG' => "Virgin Islands, British",
247
+ 'VI' => "Virgin Islands, U.S.",
248
+ 'VN' => "Vietnam",
249
+ 'VU' => "Vanuatu",
250
+ 'WF' => "Wallis and Futuna",
251
+ 'WS' => "Samoa",
252
+ 'YE' => "Yemen",
253
+ 'YT' => "Mayotte",
254
+ 'ZA' => "South Africa",
255
+ 'ZM' => "Zambia",
256
+ 'ZW' => "Zimbabwe"
257
+ );
258
+ }
259
+ ?>
lib/wfCountrySelect.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <option value="AD">Andorra</option>
2
+ <option value="AE">United Arab Emirates</option>
3
+ <option value="AF">Afghanistan</option>
4
+ <option value="AG">Antigua and Barbuda</option>
5
+ <option value="AI">Anguilla</option>
6
+ <option value="AL">Albania</option>
7
+ <option value="AM">Armenia</option>
8
+ <option value="AO">Angola</option>
9
+ <?php // <option value="AP">Asia/Pacific Region</option>
10
+ ?>
11
+ <option value="AQ">Antarctica</option>
12
+ <option value="AR">Argentina</option>
13
+ <option value="AS">American Samoa</option>
14
+ <option value="AT">Austria</option>
15
+ <option value="AU">Australia</option>
16
+ <option value="AW">Aruba</option>
17
+ <option value="AX">Aland Islands</option>
18
+ <option value="AZ">Azerbaijan</option>
19
+ <option value="BA">Bosnia and Herzegovina</option>
20
+ <option value="BB">Barbados</option>
21
+ <option value="BD">Bangladesh</option>
22
+ <option value="BE">Belgium</option>
23
+ <option value="BF">Burkina Faso</option>
24
+ <option value="BG">Bulgaria</option>
25
+ <option value="BH">Bahrain</option>
26
+ <option value="BI">Burundi</option>
27
+ <option value="BJ">Benin</option>
28
+ <option value="BL">Saint Bartelemey</option>
29
+ <option value="BM">Bermuda</option>
30
+ <option value="BN">Brunei Darussalam</option>
31
+ <option value="BO">Bolivia</option>
32
+ <option value="BQ">Bonaire, Saint Eustatius and Saba</option>
33
+ <option value="BR">Brazil</option>
34
+ <option value="BS">Bahamas</option>
35
+ <option value="BT">Bhutan</option>
36
+ <option value="BV">Bouvet Island</option>
37
+ <option value="BW">Botswana</option>
38
+ <option value="BY">Belarus</option>
39
+ <option value="BZ">Belize</option>
40
+ <option value="CA">Canada</option>
41
+ <option value="CC">Cocos (Keeling) Islands</option>
42
+ <option value="CD">Congo, The Democratic Republic of the</option>
43
+ <option value="CF">Central African Republic</option>
44
+ <option value="CG">Congo</option>
45
+ <option value="CH">Switzerland</option>
46
+ <option value="CI">Cote dIvoire</option>
47
+ <option value="CK">Cook Islands</option>
48
+ <option value="CL">Chile</option>
49
+ <option value="CM">Cameroon</option>
50
+ <option value="CN">China</option>
51
+ <option value="CO">Colombia</option>
52
+ <option value="CR">Costa Rica</option>
53
+ <option value="CU">Cuba</option>
54
+ <option value="CV">Cape Verde</option>
55
+ <option value="CW">Curacao</option>
56
+ <option value="CX">Christmas Island</option>
57
+ <option value="CY">Cyprus</option>
58
+ <option value="CZ">Czech Republic</option>
59
+ <option value="DE">Germany</option>
60
+ <option value="DJ">Djibouti</option>
61
+ <option value="DK">Denmark</option>
62
+ <option value="DM">Dominica</option>
63
+ <option value="DO">Dominican Republic</option>
64
+ <option value="DZ">Algeria</option>
65
+ <option value="EC">Ecuador</option>
66
+ <option value="EE">Estonia</option>
67
+ <option value="EG">Egypt</option>
68
+ <option value="EH">Western Sahara</option>
69
+ <option value="ER">Eritrea</option>
70
+ <option value="ES">Spain</option>
71
+ <option value="ET">Ethiopia</option>
72
+ <option value="EU">Europe</option>
73
+ <option value="FI">Finland</option>
74
+ <option value="FJ">Fiji</option>
75
+ <option value="FK">Falkland Islands (Malvinas)</option>
76
+ <option value="FM">Micronesia, Federated States of</option>
77
+ <option value="FO">Faroe Islands</option>
78
+ <option value="FR">France</option>
79
+ <option value="GA">Gabon</option>
80
+ <option value="GB">United Kingdom</option>
81
+ <option value="GD">Grenada</option>
82
+ <option value="GE">Georgia</option>
83
+ <option value="GF">French Guiana</option>
84
+ <option value="GG">Guernsey</option>
85
+ <option value="GH">Ghana</option>
86
+ <option value="GI">Gibraltar</option>
87
+ <option value="GL">Greenland</option>
88
+ <option value="GM">Gambia</option>
89
+ <option value="GN">Guinea</option>
90
+ <option value="GP">Guadeloupe</option>
91
+ <option value="GQ">Equatorial Guinea</option>
92
+ <option value="GR">Greece</option>
93
+ <option value="GS">South Georgia and the South Sandwich Islands</option>
94
+ <option value="GT">Guatemala</option>
95
+ <option value="GU">Guam</option>
96
+ <option value="GW">Guinea-Bissau</option>
97
+ <option value="GY">Guyana</option>
98
+ <option value="HK">Hong Kong</option>
99
+ <option value="HM">Heard Island and McDonald Islands</option>
100
+ <option value="HN">Honduras</option>
101
+ <option value="HR">Croatia</option>
102
+ <option value="HT">Haiti</option>
103
+ <option value="HU">Hungary</option>
104
+ <option value="ID">Indonesia</option>
105
+ <option value="IE">Ireland</option>
106
+ <option value="IL">Israel</option>
107
+ <option value="IM">Isle of Man</option>
108
+ <option value="IN">India</option>
109
+ <option value="IO">British Indian Ocean Territory</option>
110
+ <option value="IQ">Iraq</option>
111
+ <option value="IR">Iran, Islamic Republic of</option>
112
+ <option value="IS">Iceland</option>
113
+ <option value="IT">Italy</option>
114
+ <option value="JE">Jersey</option>
115
+ <option value="JM">Jamaica</option>
116
+ <option value="JO">Jordan</option>
117
+ <option value="JP">Japan</option>
118
+ <option value="KE">Kenya</option>
119
+ <option value="KG">Kyrgyzstan</option>
120
+ <option value="KH">Cambodia</option>
121
+ <option value="KI">Kiribati</option>
122
+ <option value="KM">Comoros</option>
123
+ <option value="KN">Saint Kitts and Nevis</option>
124
+ <option value="KP">Korea, Democratic Peoples Republic of</option>
125
+ <option value="KR">Korea, Republic of</option>
126
+ <option value="KW">Kuwait</option>
127
+ <option value="KY">Cayman Islands</option>
128
+ <option value="KZ">Kazakhstan</option>
129
+ <option value="LA">Lao Peoples Democratic Republic</option>
130
+ <option value="LB">Lebanon</option>
131
+ <option value="LC">Saint Lucia</option>
132
+ <option value="LI">Liechtenstein</option>
133
+ <option value="LK">Sri Lanka</option>
134
+ <option value="LR">Liberia</option>
135
+ <option value="LS">Lesotho</option>
136
+ <option value="LT">Lithuania</option>
137
+ <option value="LU">Luxembourg</option>
138
+ <option value="LV">Latvia</option>
139
+ <option value="LY">Libyan Arab Jamahiriya</option>
140
+ <option value="MA">Morocco</option>
141
+ <option value="MC">Monaco</option>
142
+ <option value="MD">Moldova, Republic of</option>
143
+ <option value="ME">Montenegro</option>
144
+ <option value="MF">Saint Martin</option>
145
+ <option value="MG">Madagascar</option>
146
+ <option value="MH">Marshall Islands</option>
147
+ <option value="MK">Macedonia</option>
148
+ <option value="ML">Mali</option>
149
+ <option value="MM">Myanmar</option>
150
+ <option value="MN">Mongolia</option>
151
+ <option value="MO">Macao</option>
152
+ <option value="MP">Northern Mariana Islands</option>
153
+ <option value="MQ">Martinique</option>
154
+ <option value="MR">Mauritania</option>
155
+ <option value="MS">Montserrat</option>
156
+ <option value="MT">Malta</option>
157
+ <option value="MU">Mauritius</option>
158
+ <option value="MV">Maldives</option>
159
+ <option value="MW">Malawi</option>
160
+ <option value="MX">Mexico</option>
161
+ <option value="MY">Malaysia</option>
162
+ <option value="MZ">Mozambique</option>
163
+ <option value="NA">Namibia</option>
164
+ <option value="NC">New Caledonia</option>
165
+ <option value="NE">Niger</option>
166
+ <option value="NF">Norfolk Island</option>
167
+ <option value="NG">Nigeria</option>
168
+ <option value="NI">Nicaragua</option>
169
+ <option value="NL">Netherlands</option>
170
+ <option value="NO">Norway</option>
171
+ <option value="NP">Nepal</option>
172
+ <option value="NR">Nauru</option>
173
+ <option value="NU">Niue</option>
174
+ <option value="NZ">New Zealand</option>
175
+ <option value="OM">Oman</option>
176
+ <option value="PA">Panama</option>
177
+ <option value="PE">Peru</option>
178
+ <option value="PF">French Polynesia</option>
179
+ <option value="PG">Papua New Guinea</option>
180
+ <option value="PH">Philippines</option>
181
+ <option value="PK">Pakistan</option>
182
+ <option value="PL">Poland</option>
183
+ <option value="PM">Saint Pierre and Miquelon</option>
184
+ <option value="PN">Pitcairn</option>
185
+ <option value="PR">Puerto Rico</option>
186
+ <option value="PS">Palestinian Territory</option>
187
+ <option value="PT">Portugal</option>
188
+ <option value="PW">Palau</option>
189
+ <option value="PY">Paraguay</option>
190
+ <option value="QA">Qatar</option>
191
+ <option value="RE">Reunion</option>
192
+ <option value="RO">Romania</option>
193
+ <option value="RS">Serbia</option>
194
+ <option value="RU">Russian Federation</option>
195
+ <option value="RW">Rwanda</option>
196
+ <option value="SA">Saudi Arabia</option>
197
+ <option value="SB">Solomon Islands</option>
198
+ <option value="SC">Seychelles</option>
199
+ <option value="SD">Sudan</option>
200
+ <option value="SE">Sweden</option>
201
+ <option value="SG">Singapore</option>
202
+ <option value="SH">Saint Helena</option>
203
+ <option value="SI">Slovenia</option>
204
+ <option value="SJ">Svalbard and Jan Mayen</option>
205
+ <option value="SK">Slovakia</option>
206
+ <option value="SL">Sierra Leone</option>
207
+ <option value="SM">San Marino</option>
208
+ <option value="SN">Senegal</option>
209
+ <option value="SO">Somalia</option>
210
+ <option value="SR">Suriname</option>
211
+ <option value="ST">Sao Tome and Principe</option>
212
+ <option value="SV">El Salvador</option>
213
+ <option value="SX">Sint Maarten</option>
214
+ <option value="SY">Syrian Arab Republic</option>
215
+ <option value="SZ">Swaziland</option>
216
+ <option value="TC">Turks and Caicos Islands</option>
217
+ <option value="TD">Chad</option>
218
+ <option value="TF">French Southern Territories</option>
219
+ <option value="TG">Togo</option>
220
+ <option value="TH">Thailand</option>
221
+ <option value="TJ">Tajikistan</option>
222
+ <option value="TK">Tokelau</option>
223
+ <option value="TL">Timor-Leste</option>
224
+ <option value="TM">Turkmenistan</option>
225
+ <option value="TN">Tunisia</option>
226
+ <option value="TO">Tonga</option>
227
+ <option value="TR">Turkey</option>
228
+ <option value="TT">Trinidad and Tobago</option>
229
+ <option value="TV">Tuvalu</option>
230
+ <option value="TW">Taiwan</option>
231
+ <option value="TZ">Tanzania, United Republic of</option>
232
+ <option value="UA">Ukraine</option>
233
+ <option value="UG">Uganda</option>
234
+ <option value="UM">United States Minor Outlying Islands</option>
235
+ <option value="US">United States</option>
236
+ <option value="UY">Uruguay</option>
237
+ <option value="UZ">Uzbekistan</option>
238
+ <option value="VA">Holy See (Vatican City State)</option>
239
+ <option value="VC">Saint Vincent and the Grenadines</option>
240
+ <option value="VE">Venezuela</option>
241
+ <option value="VG">Virgin Islands, British</option>
242
+ <option value="VI">Virgin Islands, U.S.</option>
243
+ <option value="VN">Vietnam</option>
244
+ <option value="VU">Vanuatu</option>
245
+ <option value="WF">Wallis and Futuna</option>
246
+ <option value="WS">Samoa</option>
247
+ <option value="YE">Yemen</option>
248
+ <option value="YT">Mayotte</option>
249
+ <option value="ZA">South Africa</option>
250
+ <option value="ZM">Zambia</option>
251
+ <option value="ZW">Zimbabwe</option>
252
+ <?php /*
253
+ <option value="A1">Anonymous Proxy</option>
254
+ <option value="A2">Satellite Provider</option>
255
+ <option value="O1">Other Country</option>
256
+ */ ?>
lib/wfDB.php CHANGED
@@ -67,7 +67,7 @@ class wfDB {
67
  $this->queryIgnoreError("SET @@wait_timeout=30800"); //Changing to session setting bc user may not have super privilege
68
  }
69
  }
70
- private function reconnect(){
71
  if(! mysql_ping($this->dbh)){
72
  $this->connectHandle();
73
  }
67
  $this->queryIgnoreError("SET @@wait_timeout=30800"); //Changing to session setting bc user may not have super privilege
68
  }
69
  }
70
+ public function reconnect(){
71
  if(! mysql_ping($this->dbh)){
72
  $this->connectHandle();
73
  }
lib/wfGeoIP.php ADDED
@@ -0,0 +1,713 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
4
+ /* geoip.inc
5
+ *
6
+ * Copyright (C) 2007 MaxMind LLC
7
+ *
8
+ * This library is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public
10
+ * License as published by the Free Software Foundation; either
11
+ * version 2.1 of the License, or (at your option) any later version.
12
+ *
13
+ * This library is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with this library; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ */
22
+
23
+ define("GEOIP_COUNTRY_BEGIN", 16776960);
24
+ define("GEOIP_STATE_BEGIN_REV0", 16700000);
25
+ define("GEOIP_STATE_BEGIN_REV1", 16000000);
26
+ define("GEOIP_STANDARD", 0);
27
+ define("GEOIP_MEMORY_CACHE", 1);
28
+ define("GEOIP_SHARED_MEMORY", 2);
29
+ define("STRUCTURE_INFO_MAX_SIZE", 20);
30
+ define("DATABASE_INFO_MAX_SIZE", 100);
31
+ define("GEOIP_COUNTRY_EDITION", 106);
32
+ define("GEOIP_PROXY_EDITION", 8);
33
+ define("GEOIP_ASNUM_EDITION", 9);
34
+ define("GEOIP_NETSPEED_EDITION", 10);
35
+ define("GEOIP_REGION_EDITION_REV0", 112);
36
+ define("GEOIP_REGION_EDITION_REV1", 3);
37
+ define("GEOIP_CITY_EDITION_REV0", 111);
38
+ define("GEOIP_CITY_EDITION_REV1", 2);
39
+ define("GEOIP_ORG_EDITION", 110);
40
+ define("GEOIP_ISP_EDITION", 4);
41
+ define("SEGMENT_RECORD_LENGTH", 3);
42
+ define("STANDARD_RECORD_LENGTH", 3);
43
+ define("ORG_RECORD_LENGTH", 4);
44
+ define("MAX_RECORD_LENGTH", 4);
45
+ define("MAX_ORG_RECORD_LENGTH", 300);
46
+ define("GEOIP_SHM_KEY", 0x4f415401);
47
+ define("US_OFFSET", 1);
48
+ define("CANADA_OFFSET", 677);
49
+ define("WORLD_OFFSET", 1353);
50
+ define("FIPS_RANGE", 360);
51
+ define("GEOIP_UNKNOWN_SPEED", 0);
52
+ define("GEOIP_DIALUP_SPEED", 1);
53
+ define("GEOIP_CABLEDSL_SPEED", 2);
54
+ define("GEOIP_CORPORATE_SPEED", 3);
55
+ define("GEOIP_DOMAIN_EDITION", 11);
56
+ define("GEOIP_COUNTRY_EDITION_V6", 12);
57
+ define("GEOIP_LOCATIONA_EDITION", 13);
58
+ define("GEOIP_ACCURACYRADIUS_EDITION", 14);
59
+ define("GEOIP_CITYCOMBINED_EDITION", 15);
60
+ define("GEOIP_CITY_EDITION_REV1_V6", 30);
61
+ define("GEOIP_CITY_EDITION_REV0_V6",31);
62
+ define("GEOIP_NETSPEED_EDITION_REV1",32);
63
+ define("GEOIP_NETSPEED_EDITION_REV1_V6",33);
64
+ define("GEOIP_USERTYPE_EDITION",28);
65
+ define("GEOIP_USERTYPE_EDITION_V6",29);
66
+ define("GEOIP_ASNUM_EDITION_V6",21);
67
+ define("GEOIP_ISP_EDITION_V6",22);
68
+ define("GEOIP_ORG_EDITION_V6",23);
69
+ define("GEOIP_DOMAIN_EDITION_V6",24);
70
+
71
+ define("CITYCOMBINED_FIXED_RECORD", 7 );
72
+
73
+ class GeoIP {
74
+ var $flags;
75
+ var $filehandle;
76
+ var $memory_buffer;
77
+ var $databaseType;
78
+ var $databaseSegments;
79
+ var $record_length;
80
+ var $shmid;
81
+ var $GEOIP_COUNTRY_CODE_TO_NUMBER = array(
82
+ "" => 0, "AP" => 1, "EU" => 2, "AD" => 3, "AE" => 4, "AF" => 5,
83
+ "AG" => 6, "AI" => 7, "AL" => 8, "AM" => 9, "CW" => 10, "AO" => 11,
84
+ "AQ" => 12, "AR" => 13, "AS" => 14, "AT" => 15, "AU" => 16, "AW" => 17,
85
+ "AZ" => 18, "BA" => 19, "BB" => 20, "BD" => 21, "BE" => 22, "BF" => 23,
86
+ "BG" => 24, "BH" => 25, "BI" => 26, "BJ" => 27, "BM" => 28, "BN" => 29,
87
+ "BO" => 30, "BR" => 31, "BS" => 32, "BT" => 33, "BV" => 34, "BW" => 35,
88
+ "BY" => 36, "BZ" => 37, "CA" => 38, "CC" => 39, "CD" => 40, "CF" => 41,
89
+ "CG" => 42, "CH" => 43, "CI" => 44, "CK" => 45, "CL" => 46, "CM" => 47,
90
+ "CN" => 48, "CO" => 49, "CR" => 50, "CU" => 51, "CV" => 52, "CX" => 53,
91
+ "CY" => 54, "CZ" => 55, "DE" => 56, "DJ" => 57, "DK" => 58, "DM" => 59,
92
+ "DO" => 60, "DZ" => 61, "EC" => 62, "EE" => 63, "EG" => 64, "EH" => 65,
93
+ "ER" => 66, "ES" => 67, "ET" => 68, "FI" => 69, "FJ" => 70, "FK" => 71,
94
+ "FM" => 72, "FO" => 73, "FR" => 74, "SX" => 75, "GA" => 76, "GB" => 77,
95
+ "GD" => 78, "GE" => 79, "GF" => 80, "GH" => 81, "GI" => 82, "GL" => 83,
96
+ "GM" => 84, "GN" => 85, "GP" => 86, "GQ" => 87, "GR" => 88, "GS" => 89,
97
+ "GT" => 90, "GU" => 91, "GW" => 92, "GY" => 93, "HK" => 94, "HM" => 95,
98
+ "HN" => 96, "HR" => 97, "HT" => 98, "HU" => 99, "ID" => 100, "IE" => 101,
99
+ "IL" => 102, "IN" => 103, "IO" => 104, "IQ" => 105, "IR" => 106, "IS" => 107,
100
+ "IT" => 108, "JM" => 109, "JO" => 110, "JP" => 111, "KE" => 112, "KG" => 113,
101
+ "KH" => 114, "KI" => 115, "KM" => 116, "KN" => 117, "KP" => 118, "KR" => 119,
102
+ "KW" => 120, "KY" => 121, "KZ" => 122, "LA" => 123, "LB" => 124, "LC" => 125,
103
+ "LI" => 126, "LK" => 127, "LR" => 128, "LS" => 129, "LT" => 130, "LU" => 131,
104
+ "LV" => 132, "LY" => 133, "MA" => 134, "MC" => 135, "MD" => 136, "MG" => 137,
105
+ "MH" => 138, "MK" => 139, "ML" => 140, "MM" => 141, "MN" => 142, "MO" => 143,
106
+ "MP" => 144, "MQ" => 145, "MR" => 146, "MS" => 147, "MT" => 148, "MU" => 149,
107
+ "MV" => 150, "MW" => 151, "MX" => 152, "MY" => 153, "MZ" => 154, "NA" => 155,
108
+ "NC" => 156, "NE" => 157, "NF" => 158, "NG" => 159, "NI" => 160, "NL" => 161,
109
+ "NO" => 162, "NP" => 163, "NR" => 164, "NU" => 165, "NZ" => 166, "OM" => 167,
110
+ "PA" => 168, "PE" => 169, "PF" => 170, "PG" => 171, "PH" => 172, "PK" => 173,
111
+ "PL" => 174, "PM" => 175, "PN" => 176, "PR" => 177, "PS" => 178, "PT" => 179,
112
+ "PW" => 180, "PY" => 181, "QA" => 182, "RE" => 183, "RO" => 184, "RU" => 185,
113
+ "RW" => 186, "SA" => 187, "SB" => 188, "SC" => 189, "SD" => 190, "SE" => 191,
114
+ "SG" => 192, "SH" => 193, "SI" => 194, "SJ" => 195, "SK" => 196, "SL" => 197,
115
+ "SM" => 198, "SN" => 199, "SO" => 200, "SR" => 201, "ST" => 202, "SV" => 203,
116
+ "SY" => 204, "SZ" => 205, "TC" => 206, "TD" => 207, "TF" => 208, "TG" => 209,
117
+ "TH" => 210, "TJ" => 211, "TK" => 212, "TM" => 213, "TN" => 214, "TO" => 215,
118
+ "TL" => 216, "TR" => 217, "TT" => 218, "TV" => 219, "TW" => 220, "TZ" => 221,
119
+ "UA" => 222, "UG" => 223, "UM" => 224, "US" => 225, "UY" => 226, "UZ" => 227,
120
+ "VA" => 228, "VC" => 229, "VE" => 230, "VG" => 231, "VI" => 232, "VN" => 233,
121
+ "VU" => 234, "WF" => 235, "WS" => 236, "YE" => 237, "YT" => 238, "RS" => 239,
122
+ "ZA" => 240, "ZM" => 241, "ME" => 242, "ZW" => 243, "A1" => 244, "A2" => 245,
123
+ "O1" => 246, "AX" => 247, "GG" => 248, "IM" => 249, "JE" => 250, "BL" => 251,
124
+ "MF" => 252, "BQ" => 253,
125
+ );
126
+ var $GEOIP_COUNTRY_CODES = array(
127
+ "","AP","EU","AD","AE","AF","AG","AI","AL","AM","CW",
128
+ "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
129
+ "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
130
+ "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
131
+ "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
132
+ "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
133
+ "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
134
+ "FK","FM","FO","FR","SX","GA","GB","GD","GE","GF",
135
+ "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
136
+ "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
137
+ "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
138
+ "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
139
+ "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
140
+ "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
141
+ "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
142
+ "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
143
+ "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
144
+ "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
145
+ "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
146
+ "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
147
+ "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
148
+ "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
149
+ "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
150
+ "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
151
+ "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE",
152
+ "BL","MF", "BQ");
153
+ var $GEOIP_COUNTRY_CODES3 = array(
154
+ "","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","CUW",
155
+ "AGO","ATA","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
156
+ "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
157
+ "BRA","BHS","BTN","BVT","BWA","BLR","BLZ","CAN","CCK","COD",
158
+ "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
159
+ "CUB","CPV","CXR","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
160
+ "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
161
+ "FLK","FSM","FRO","FRA","SXM","GAB","GBR","GRD","GEO","GUF",
162
+ "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","SGS","GTM",
163
+ "GUM","GNB","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN",
164
+ "IRL","ISR","IND","IOT","IRQ","IRN","ISL","ITA","JAM","JOR",
165
+ "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
166
+ "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
167
+ "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
168
+ "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
169
+ "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
170
+ "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
171
+ "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
172
+ "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
173
+ "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
174
+ "SUR","STP","SLV","SYR","SWZ","TCA","TCD","ATF","TGO","THA",
175
+ "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
176
+ "TZA","UKR","UGA","UMI","USA","URY","UZB","VAT","VCT","VEN",
177
+ "VGB","VIR","VNM","VUT","WLF","WSM","YEM","MYT","SRB","ZAF",
178
+ "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY",
179
+ "BLM","MAF", "BES"
180
+ );
181
+ var $GEOIP_COUNTRY_NAMES = array(
182
+ "","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Curacao",
183
+ "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
184
+ "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
185
+ "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
186
+ "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
187
+ "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
188
+ "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
189
+ "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","Sint Maarten (Dutch part)","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
190
+ "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
191
+ "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
192
+ "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
193
+ "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
194
+ "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
195
+ "Luxembourg","Latvia","Libya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
196
+ "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
197
+ "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
198
+ "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
199
+ "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
200
+ "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
201
+ "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
202
+ "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
203
+ "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
204
+ "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
205
+ "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
206
+ "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
207
+ "Saint Barthelemy","Saint Martin", "Bonaire, Saint Eustatius and Saba"
208
+ );
209
+
210
+ var $GEOIP_CONTINENT_CODES = array(
211
+ "--", "AS","EU","EU","AS","AS","NA","NA","EU","AS","NA",
212
+ "AF","AN","SA","OC","EU","OC","NA","AS","EU","NA",
213
+ "AS","EU","AF","EU","AS","AF","AF","NA","AS","SA",
214
+ "SA","NA","AS","AN","AF","EU","NA","NA","AS","AF",
215
+ "AF","AF","EU","AF","OC","SA","AF","AS","SA","NA",
216
+ "NA","AF","AS","AS","EU","EU","AF","EU","NA","NA",
217
+ "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
218
+ "SA","OC","EU","EU","NA","AF","EU","NA","AS","SA",
219
+ "AF","EU","NA","AF","AF","NA","AF","EU","AN","NA",
220
+ "OC","AF","SA","AS","AN","NA","EU","NA","EU","AS",
221
+ "EU","AS","AS","AS","AS","AS","EU","EU","NA","AS",
222
+ "AS","AF","AS","AS","OC","AF","NA","AS","AS","AS",
223
+ "NA","AS","AS","AS","NA","EU","AS","AF","AF","EU",
224
+ "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
225
+ "AS","AS","AS","OC","NA","AF","NA","EU","AF","AS",
226
+ "AF","NA","AS","AF","AF","OC","AF","OC","AF","NA",
227
+ "EU","EU","AS","OC","OC","OC","AS","NA","SA","OC",
228
+ "OC","AS","AS","EU","NA","OC","NA","AS","EU","OC",
229
+ "SA","AS","AF","EU","EU","AF","AS","OC","AF","AF",
230
+ "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
231
+ "SA","AF","NA","AS","AF","NA","AF","AN","AF","AS",
232
+ "AS","OC","AS","AF","OC","AS","EU","NA","OC","AS",
233
+ "AF","EU","AF","OC","NA","SA","AS","EU","NA","SA",
234
+ "NA","NA","AS","OC","OC","OC","AS","AF","EU","AF",
235
+ "AF","EU","AF","--","--","--","EU","EU","EU","EU",
236
+ "NA","NA","NA"
237
+ );
238
+
239
+ }
240
+ function geoip_load_shared_mem ($file) {
241
+
242
+ $fp = fopen($file, "rb");
243
+ if (!$fp) {
244
+ print "error opening $file: $php_errormsg\n";
245
+ exit;
246
+ }
247
+ $s_array = fstat($fp);
248
+ $size = $s_array['size'];
249
+ if ($shmid = @shmop_open (GEOIP_SHM_KEY, "w", 0, 0)) {
250
+ shmop_delete ($shmid);
251
+ shmop_close ($shmid);
252
+ }
253
+ $shmid = shmop_open (GEOIP_SHM_KEY, "c", 0644, $size);
254
+ shmop_write ($shmid, fread($fp, $size), 0);
255
+ shmop_close ($shmid);
256
+ }
257
+
258
+ function _setup_segments($gi){
259
+ $gi->databaseType = GEOIP_COUNTRY_EDITION;
260
+ $gi->record_length = STANDARD_RECORD_LENGTH;
261
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
262
+ $offset = @shmop_size ($gi->shmid) - 3;
263
+ for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
264
+ $delim = @shmop_read ($gi->shmid, $offset, 3);
265
+ $offset += 3;
266
+ if ($delim == (chr(255).chr(255).chr(255))) {
267
+ $gi->databaseType = ord(@shmop_read ($gi->shmid, $offset, 1));
268
+ $offset++;
269
+
270
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
271
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
272
+ } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
273
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
274
+ } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)||
275
+ ($gi->databaseType == GEOIP_CITY_EDITION_REV1)
276
+ || ($gi->databaseType == GEOIP_ORG_EDITION)
277
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
278
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
279
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
280
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
281
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)
282
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION)
283
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6)
284
+ || ($gi->databaseType == GEOIP_LOCATIONA_EDITION)
285
+ || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION)
286
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
287
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
288
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1)
289
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6)
290
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION)
291
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){
292
+ $gi->databaseSegments = 0;
293
+ $buf = @shmop_read ($gi->shmid, $offset, SEGMENT_RECORD_LENGTH);
294
+ for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
295
+ $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
296
+ }
297
+ if (($gi->databaseType == GEOIP_ORG_EDITION)
298
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
299
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
300
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
301
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
302
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)) {
303
+ $gi->record_length = ORG_RECORD_LENGTH;
304
+ }
305
+ }
306
+ break;
307
+ } else {
308
+ $offset -= 4;
309
+ }
310
+ }
311
+ if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
312
+ ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)||
313
+ ($gi->databaseType == GEOIP_PROXY_EDITION)||
314
+ ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
315
+ $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
316
+ }
317
+ } else {
318
+ $filepos = ftell($gi->filehandle);
319
+ fseek($gi->filehandle, -3, SEEK_END);
320
+ for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
321
+ $delim = fread($gi->filehandle,3);
322
+ if ($delim == (chr(255).chr(255).chr(255))){
323
+ $gi->databaseType = ord(fread($gi->filehandle,1));
324
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
325
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
326
+ }
327
+ else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
328
+ $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
329
+ } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)
330
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1)
331
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
332
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
333
+ || ($gi->databaseType == GEOIP_ORG_EDITION)
334
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION)
335
+ || ($gi->databaseType == GEOIP_ISP_EDITION)
336
+ || ($gi->databaseType == GEOIP_ORG_EDITION_V6)
337
+ || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6)
338
+ || ($gi->databaseType == GEOIP_ISP_EDITION_V6)
339
+ || ($gi->databaseType == GEOIP_LOCATIONA_EDITION)
340
+ || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION)
341
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6)
342
+ || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6)
343
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1)
344
+ || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6)
345
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION)
346
+ || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6)
347
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION)
348
+ || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){
349
+ $gi->databaseSegments = 0;
350
+ $buf = fread($gi->filehandle,SEGMENT_RECORD_LENGTH);
351
+ for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
352
+ $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
353
+ }
354
+ if ( ( $gi->databaseType == GEOIP_ORG_EDITION )
355
+ || ( $gi->databaseType == GEOIP_DOMAIN_EDITION )
356
+ || ( $gi->databaseType == GEOIP_ISP_EDITION )
357
+ || ( $gi->databaseType == GEOIP_ORG_EDITION_V6 )
358
+ || ( $gi->databaseType == GEOIP_DOMAIN_EDITION_V6 )
359
+ || ( $gi->databaseType == GEOIP_ISP_EDITION_V6 )) {
360
+ $gi->record_length = ORG_RECORD_LENGTH;
361
+ }
362
+ }
363
+ break;
364
+ } else {
365
+ fseek($gi->filehandle, -4, SEEK_CUR);
366
+ }
367
+ }
368
+ if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
369
+ ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)||
370
+ ($gi->databaseType == GEOIP_PROXY_EDITION)||
371
+ ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
372
+ $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
373
+ }
374
+ fseek($gi->filehandle,$filepos,SEEK_SET);
375
+ }
376
+ return $gi;
377
+ }
378
+
379
+ function geoip_open($filename, $flags) {
380
+ $gi = new GeoIP;
381
+ $gi->flags = $flags;
382
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
383
+ $gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
384
+ } else {
385
+ $gi->filehandle = fopen($filename,"rb") or die( "Can not open $filename\n" );
386
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
387
+ $s_array = fstat($gi->filehandle);
388
+ $gi->memory_buffer = fread($gi->filehandle, $s_array['size']);
389
+ }
390
+ }
391
+
392
+ $gi = _setup_segments($gi);
393
+ return $gi;
394
+ }
395
+
396
+ function geoip_close($gi) {
397
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
398
+ return true;
399
+ }
400
+
401
+ return fclose($gi->filehandle);
402
+ }
403
+
404
+ function geoip_country_id_by_name_v6($gi, $name) {
405
+ $rec = dns_get_record($name, DNS_AAAA);
406
+ if ( !$rec ) {
407
+ return false;
408
+ }
409
+ $addr = $rec[0]["ipv6"];
410
+ if (!$addr || $addr == $name) {
411
+ return false;
412
+ }
413
+ return geoip_country_id_by_addr_v6($gi, $addr);
414
+ }
415
+
416
+ function geoip_country_id_by_name($gi, $name) {
417
+ $addr = gethostbyname($name);
418
+ if (!$addr || $addr == $name) {
419
+ return false;
420
+ }
421
+ return geoip_country_id_by_addr($gi, $addr);
422
+ }
423
+
424
+ function geoip_country_code_by_name_v6($gi, $name) {
425
+ $country_id = geoip_country_id_by_name_v6($gi,$name);
426
+ if ($country_id !== false) {
427
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
428
+ }
429
+ return false;
430
+ }
431
+
432
+ function geoip_country_code_by_name($gi, $name) {
433
+ $country_id = geoip_country_id_by_name($gi,$name);
434
+ if ($country_id !== false) {
435
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
436
+ }
437
+ return false;
438
+ }
439
+
440
+ function geoip_country_name_by_name_v6($gi, $name) {
441
+ $country_id = geoip_country_id_by_name_v6($gi,$name);
442
+ if ($country_id !== false) {
443
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
444
+ }
445
+ return false;
446
+ }
447
+
448
+ function geoip_country_name_by_name($gi, $name) {
449
+ $country_id = geoip_country_id_by_name($gi,$name);
450
+ if ($country_id !== false) {
451
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
452
+ }
453
+ return false;
454
+ }
455
+
456
+ function geoip_country_id_by_addr_v6($gi, $addr) {
457
+ $ipnum = inet_pton($addr);
458
+ return _geoip_seek_country_v6($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
459
+ }
460
+
461
+ function geoip_country_id_by_addr($gi, $addr) {
462
+ $ipnum = ip2long($addr);
463
+ return _geoip_seek_country($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
464
+ }
465
+
466
+ function geoip_country_code_by_addr_v6($gi, $addr) {
467
+ $country_id = geoip_country_id_by_addr_v6($gi,$addr);
468
+ if ($country_id !== false) {
469
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
470
+ }
471
+ return false;
472
+ }
473
+
474
+ function geoip_country_code_by_addr($gi, $addr) {
475
+ if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
476
+ $record = geoip_record_by_addr($gi,$addr);
477
+ if ( $record !== false ) {
478
+ return $record->country_code;
479
+ }
480
+ } else {
481
+ $country_id = geoip_country_id_by_addr($gi,$addr);
482
+ if ($country_id !== false) {
483
+ return $gi->GEOIP_COUNTRY_CODES[$country_id];
484
+ }
485
+ }
486
+ return false;
487
+ }
488
+
489
+ function geoip_country_name_by_addr_v6($gi, $addr) {
490
+ $country_id = geoip_country_id_by_addr_v6($gi,$addr);
491
+ if ($country_id !== false) {
492
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
493
+ }
494
+ return false;
495
+ }
496
+
497
+ function geoip_country_name_by_addr($gi, $addr) {
498
+ if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
499
+ $record = geoip_record_by_addr($gi,$addr);
500
+ return $record->country_name;
501
+ } else {
502
+ $country_id = geoip_country_id_by_addr($gi,$addr);
503
+ if ($country_id !== false) {
504
+ return $gi->GEOIP_COUNTRY_NAMES[$country_id];
505
+ }
506
+ }
507
+ return false;
508
+ }
509
+
510
+ function _geoip_seek_country_v6($gi, $ipnum) {
511
+
512
+ # arrays from unpack start with offset 1
513
+ # yet another php mystery. array_merge work around
514
+ # this broken behaviour
515
+ $v6vec = array_merge(unpack( "C16", $ipnum));
516
+
517
+ $offset = 0;
518
+ for ($depth = 127; $depth >= 0; --$depth) {
519
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
520
+ // workaround php's broken substr, strpos, etc handling with
521
+ // mbstring.func_overload and mbstring.internal_encoding
522
+ $enc = mb_internal_encoding();
523
+ mb_internal_encoding('ISO-8859-1');
524
+
525
+ $buf = substr($gi->memory_buffer,
526
+ 2 * $gi->record_length * $offset,
527
+ 2 * $gi->record_length);
528
+
529
+ mb_internal_encoding($enc);
530
+ } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
531
+ $buf = @shmop_read ($gi->shmid,
532
+ 2 * $gi->record_length * $offset,
533
+ 2 * $gi->record_length );
534
+ } else {
535
+ fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
536
+ or die("fseek failed");
537
+ $buf = fread($gi->filehandle, 2 * $gi->record_length);
538
+ }
539
+ $x = array(0,0);
540
+ for ($i = 0; $i < 2; ++$i) {
541
+ for ($j = 0; $j < $gi->record_length; ++$j) {
542
+ $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
543
+ }
544
+ }
545
+
546
+ $bnum = 127 - $depth;
547
+ $idx = $bnum >> 3;
548
+ $b_mask = 1 << ( $bnum & 7 ^ 7 );
549
+ if (($v6vec[$idx] & $b_mask) > 0) {
550
+ if ($x[1] >= $gi->databaseSegments) {
551
+ return $x[1];
552
+ }
553
+ $offset = $x[1];
554
+ } else {
555
+ if ($x[0] >= $gi->databaseSegments) {
556
+ return $x[0];
557
+ }
558
+ $offset = $x[0];
559
+ }
560
+ }
561
+ trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
562
+ return false;
563
+ }
564
+
565
+ function _geoip_seek_country($gi, $ipnum) {
566
+ $offset = 0;
567
+ for ($depth = 31; $depth >= 0; --$depth) {
568
+ if ($gi->flags & GEOIP_MEMORY_CACHE) {
569
+ // workaround php's broken substr, strpos, etc handling with
570
+ // mbstring.func_overload and mbstring.internal_encoding
571
+ $enc = mb_internal_encoding();
572
+ mb_internal_encoding('ISO-8859-1');
573
+
574
+ $buf = substr($gi->memory_buffer,
575
+ 2 * $gi->record_length * $offset,
576
+ 2 * $gi->record_length);
577
+
578
+ mb_internal_encoding($enc);
579
+ } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
580
+ $buf = @shmop_read ($gi->shmid,
581
+ 2 * $gi->record_length * $offset,
582
+ 2 * $gi->record_length );
583
+ } else {
584
+ fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
585
+ or die("fseek failed");
586
+ $buf = fread($gi->filehandle, 2 * $gi->record_length);
587
+ }
588
+ $x = array(0,0);
589
+ for ($i = 0; $i < 2; ++$i) {
590
+ for ($j = 0; $j < $gi->record_length; ++$j) {
591
+ $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
592
+ }
593
+ }
594
+ if ($ipnum & (1 << $depth)) {
595
+ if ($x[1] >= $gi->databaseSegments) {
596
+ return $x[1];
597
+ }
598
+ $offset = $x[1];
599
+ } else {
600
+ if ($x[0] >= $gi->databaseSegments) {
601
+ return $x[0];
602
+ }
603
+ $offset = $x[0];
604
+ }
605
+ }
606
+ trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
607
+ return false;
608
+ }
609
+
610
+ function _common_get_org($gi, $seek_org){
611
+ $record_pointer = $seek_org + (2 * $gi->record_length - 1) * $gi->databaseSegments;
612
+ if ($gi->flags & GEOIP_SHARED_MEMORY) {
613
+ $org_buf = @shmop_read ($gi->shmid, $record_pointer, MAX_ORG_RECORD_LENGTH);
614
+ } else {
615
+ fseek($gi->filehandle, $record_pointer, SEEK_SET);
616
+ $org_buf = fread($gi->filehandle,MAX_ORG_RECORD_LENGTH);
617
+ }
618
+ // workaround php's broken substr, strpos, etc handling with
619
+ // mbstring.func_overload and mbstring.internal_encoding
620
+ $enc = mb_internal_encoding();
621
+ mb_internal_encoding('ISO-8859-1');
622
+ $org_buf = substr($org_buf, 0, strpos($org_buf, "\0"));
623
+ mb_internal_encoding($enc);
624
+ return $org_buf;
625
+ }
626
+
627
+ function _get_org_v6($gi,$ipnum){
628
+ $seek_org = _geoip_seek_country_v6($gi,$ipnum);
629
+ if ($seek_org == $gi->databaseSegments) {
630
+ return NULL;
631
+ }
632
+ return _common_get_org($gi, $seek_org);
633
+ }
634
+
635
+ function _get_org($gi,$ipnum){
636
+ $seek_org = _geoip_seek_country($gi,$ipnum);
637
+ if ($seek_org == $gi->databaseSegments) {
638
+ return NULL;
639
+ }
640
+ return _common_get_org($gi, $seek_org);
641
+ }
642
+
643
+
644
+
645
+ function geoip_name_by_addr_v6 ($gi,$addr) {
646
+ if ($addr == NULL) {
647
+ return 0;
648
+ }
649
+ $ipnum = inet_pton($addr);
650
+ return _get_org_v6($gi, $ipnum);
651
+ }
652
+
653
+ function geoip_name_by_addr ($gi,$addr) {
654
+ if ($addr == NULL) {
655
+ return 0;
656
+ }
657
+ $ipnum = ip2long($addr);
658
+ return _get_org($gi, $ipnum);
659
+ }
660
+
661
+ function geoip_org_by_addr ($gi,$addr) {
662
+ return geoip_name_by_addr($gi, $addr);
663
+ }
664
+
665
+ function _get_region($gi,$ipnum){
666
+ if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
667
+ $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV0;
668
+ if ($seek_region >= 1000){
669
+ $country_code = "US";
670
+ $region = chr(($seek_region - 1000)/26 + 65) . chr(($seek_region - 1000)%26 + 65);
671
+ } else {
672
+ $country_code = $gi->GEOIP_COUNTRY_CODES[$seek_region];
673
+ $region = "";
674
+ }
675
+ return array ($country_code,$region);
676
+ } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1) {
677
+ $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV1;
678
+ //print $seek_region;
679
+ if ($seek_region < US_OFFSET){
680
+ $country_code = "";
681
+ $region = "";
682
+ } else if ($seek_region < CANADA_OFFSET) {
683
+ $country_code = "US";
684
+ $region = chr(($seek_region - US_OFFSET)/26 + 65) . chr(($seek_region - US_OFFSET)%26 + 65);
685
+ } else if ($seek_region < WORLD_OFFSET) {
686
+ $country_code = "CA";
687
+ $region = chr(($seek_region - CANADA_OFFSET)/26 + 65) . chr(($seek_region - CANADA_OFFSET)%26 + 65);
688
+ } else {
689
+ $country_code = $gi->GEOIP_COUNTRY_CODES[($seek_region - WORLD_OFFSET) / FIPS_RANGE];
690
+ $region = "";
691
+ }
692
+ return array ($country_code,$region);
693
+ }
694
+ }
695
+
696
+ function geoip_region_by_addr ($gi,$addr) {
697
+ if ($addr == NULL) {
698
+ return 0;
699
+ }
700
+ $ipnum = ip2long($addr);
701
+ return _get_region($gi, $ipnum);
702
+ }
703
+
704
+ function getdnsattributes ($l,$ip){
705
+ $r = new Net_DNS_Resolver();
706
+ $r->nameservers = array("ws1.maxmind.com");
707
+ $p = $r->search($l."." . $ip .".s.maxmind.com","TXT","IN");
708
+ $str = is_object($p->answer[0])?$p->answer[0]->string():'';
709
+ $str = substr( $str, 1, -1 );
710
+ return $str;
711
+ }
712
+
713
+ ?>
lib/wfLog.php CHANGED
@@ -233,7 +233,7 @@ class wfLog {
233
  return $results;
234
  }
235
  public function getBlockedIPs(){
236
- $res = $this->getDB()->query("select IP, unix_timestamp() - blockedTime as createdAgo, reason, unix_timestamp() - lastAttempt as lastAttemptAgo, lastAttempt, blockedHits, (blockedTime + %s) - unix_timestamp() as blockedFor, permanent from " . $this->blocksTable . " where blockedTime + %s > unix_timestamp() order by blockedTime desc", wfConfig::get('blockedTime'), wfConfig::get('blockedTime'));
237
  $results = array();
238
  while($elem = mysql_fetch_assoc($res)){
239
  $lastHitAgo = 0;
@@ -482,6 +482,39 @@ class wfLog {
482
  return $this->db;
483
  }
484
  public function firewallBadIPs(){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  $IP = wfUtils::inet_aton(wfUtils::getIP());
486
  if($rec = $this->getDB()->querySingleRec("select blockedTime, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR (blockedTime + %s > unix_timestamp()))", wfConfig::get('blockedTime'), $IP, wfConfig::get('blockedTime'))){
487
  $this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
@@ -526,6 +559,10 @@ class wfLog {
526
  require_once('wf503.php');
527
  exit();
528
  }
 
 
 
 
529
  private function googleSafetyCheckOK(){ //returns true if OK to block. Returns false if we must not block.
530
  $cacheKey = md5($_SERVER['HTTP_USER_AGENT'] . ' ' . wfUtils::getIP());
531
  //Cache so we can call this multiple times in one request
233
  return $results;
234
  }
235
  public function getBlockedIPs(){
236
+ $res = $this->getDB()->query("select IP, unix_timestamp() - blockedTime as createdAgo, reason, unix_timestamp() - lastAttempt as lastAttemptAgo, lastAttempt, blockedHits, (blockedTime + %s) - unix_timestamp() as blockedFor, permanent from " . $this->blocksTable . " where (permanent=1 OR (blockedTime + %s > unix_timestamp())) order by blockedTime desc", wfConfig::get('blockedTime'), wfConfig::get('blockedTime'));
237
  $results = array();
238
  while($elem = mysql_fetch_assoc($res)){
239
  $lastHitAgo = 0;
482
  return $this->db;
483
  }
484
  public function firewallBadIPs(){
485
+ $blockedCountries = wfConfig::get('cbl_countries', false);
486
+ if($blockedCountries && wfConfig::get('isPaid')){
487
+ if(is_user_logged_in() && (! wfConfig::get('cbl_loggedInBlocked', false)) ){ //User is logged in and we're allowing logins
488
+ //Do nothing
489
+ } else if(strpos($_SERVER['REQUEST_URI'], '/wp-login.php') !== false && (! wfConfig::get('cbl_loginFormBlocked', false)) ){ //It's the login form and we're allowing that
490
+ //Do nothing
491
+ } else {
492
+ if($country = wfUtils::IP2Country(wfUtils::getIP()) ){
493
+ foreach(explode(',', $blockedCountries) as $blocked){
494
+ if(strtoupper($blocked) == strtoupper($country)){
495
+ if(wfConfig::get('cbl_action') == 'redir'){
496
+ $redirURL = wfConfig::get('cbl_redirURL');
497
+ if(wfUtils::extractBareURI($redirURL) == wfUtils::extractBareURI($_SERVER['REQUEST_URI'])){ //Is this the URI we want to redirect to, then don't block it
498
+ //Do nothing
499
+ /* Uncomment the following if page components aren't loading for the page we redirect to.
500
+ Uncommenting is not recommended because it means that anyone from a blocked country
501
+ can crawl your site by sending the page blocked users are redirected to as the referer for every request.
502
+ But it's your call.
503
+ } else if(wfUtils::extractBareURI($_SERVER['HTTP_REFERER']) == $redirURL){ //If the referer the page we want to redirect to? Then this might be loading as a component so don't block.
504
+ //Do nothing
505
+ */
506
+ } else {
507
+ $this->redirect(wfConfig::get('cbl_redirURL'));
508
+ }
509
+ } else {
510
+ $this->do503(3600, "Access from your area has been temporarily limited for security reasons");
511
+ }
512
+ }
513
+ }
514
+ }
515
+ }
516
+ }
517
+
518
  $IP = wfUtils::inet_aton(wfUtils::getIP());
519
  if($rec = $this->getDB()->querySingleRec("select blockedTime, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR (blockedTime + %s > unix_timestamp()))", wfConfig::get('blockedTime'), $IP, wfConfig::get('blockedTime'))){
520
  $this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
559
  require_once('wf503.php');
560
  exit();
561
  }
562
+ private function redirect($URL){
563
+ wp_redirect($URL, 302);
564
+ exit();
565
+ }
566
  private function googleSafetyCheckOK(){ //returns true if OK to block. Returns false if we must not block.
567
  $cacheKey = md5($_SERVER['HTTP_USER_AGENT'] . ' ' . wfUtils::getIP());
568
  //Cache so we can call this multiple times in one request
lib/wfScanEngine.php CHANGED
@@ -7,6 +7,7 @@ require_once('wfIssues.php');
7
  require_once('wfDB.php');
8
  require_once('wfUtils.php');
9
  class wfScanEngine {
 
10
  private $api = false;
11
  private $dictWords = array();
12
  private $forkRequested = false;
@@ -79,10 +80,8 @@ class wfScanEngine {
79
  $this->i->setScanTimeNow();
80
  //scan ID only incremented at end of scan to make UI load new results
81
  $this->emailNewIssues();
82
- wordfence::scheduleNextScan(true);
83
  } catch(Exception $e){
84
  wfConfig::set('lastScanCompleted', $e->getMessage());
85
- wordfence::scheduleNextScan(true);
86
  throw $e;
87
  }
88
  }
@@ -432,6 +431,10 @@ class wfScanEngine {
432
  private function scan_comments_main(){
433
  $wfdb = new wfDB();
434
  while($elem = array_shift($this->scanQueue)){
 
 
 
 
435
  $blog = $elem[0];
436
  $commentID = $elem[1];
437
  $row = $wfdb->querySingleRec("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from " . $blog['table'] . " where comment_ID=%d", $commentID);
@@ -913,11 +916,15 @@ class wfScanEngine {
913
  $host = self::getOwnHostname();
914
  $opts['headers'] = array( 'Host' => $host);
915
  }
916
- wordfence::status(4, 'info', "Starting HTTP connection to test if we can kick off a scan");
917
- $result = wp_remote_post($URL . '?test=1', $opts);
918
- wordfence::status(4, 'info', "Done test HTTP connection");
919
  if( is_array($result) && isset($result['body']) && preg_match('/WFCRONTESTOK:' . wfConfig::get('cronTestID') . '/', $result['body'])){
 
920
  return true;
 
 
 
921
  }
922
  return false;
923
  }
@@ -959,7 +966,13 @@ class wfScanEngine {
959
  return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
960
  }
961
  if(! self::detectCronURL()){
962
- return "We could not determine how this WordPress server connects to itself. You can try asking your WordPress host to edit their hosts file and add the hostname for this machine to the file. This machine's hostname is: " . self::getOwnHostname();
 
 
 
 
 
 
963
  }
964
  }
965
 
7
  require_once('wfDB.php');
8
  require_once('wfUtils.php');
9
  class wfScanEngine {
10
+ private static $cronTestFailedURLs = array();
11
  private $api = false;
12
  private $dictWords = array();
13
  private $forkRequested = false;
80
  $this->i->setScanTimeNow();
81
  //scan ID only incremented at end of scan to make UI load new results
82
  $this->emailNewIssues();
 
83
  } catch(Exception $e){
84
  wfConfig::set('lastScanCompleted', $e->getMessage());
 
85
  throw $e;
86
  }
87
  }
431
  private function scan_comments_main(){
432
  $wfdb = new wfDB();
433
  while($elem = array_shift($this->scanQueue)){
434
+ $queueSize = sizeof($this->scanQueue);
435
+ if($queueSize > 0 && $queueSize % 1000 == 0){
436
+ wordfence::status(2, 'info', "Scanning comments with $queueSize left to scan.");
437
+ }
438
  $blog = $elem[0];
439
  $commentID = $elem[1];
440
  $row = $wfdb->querySingleRec("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from " . $blog['table'] . " where comment_ID=%d", $commentID);
916
  $host = self::getOwnHostname();
917
  $opts['headers'] = array( 'Host' => $host);
918
  }
919
+ $testURL = $URL . '?test=1';
920
+ wordfence::status(4, 'info', "Testing cron URL: $testURL");
921
+ $result = wp_remote_post($testURL, $opts);
922
  if( is_array($result) && isset($result['body']) && preg_match('/WFCRONTESTOK:' . wfConfig::get('cronTestID') . '/', $result['body'])){
923
+ wordfence::status(4, 'info', "Cron URL test success with: $testURL");
924
  return true;
925
+ } else {
926
+ wordfence::status(4, 'info', "Cron URL test fail with: $testURL");
927
+ self::$cronTestFailedURLs[] = $testURL;
928
  }
929
  return false;
930
  }
966
  return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
967
  }
968
  if(! self::detectCronURL()){
969
+ $msg = 'We could not determine how this WordPress server connects to itself. Please read <a href="http://www.wordfence.com/docs/wordfence-server-cant-connect-to-itself-error/" target="_blank">the documentation we provide on this page</a> which may help with this error. For your info, this machine\'s hostname is: ' . self::getOwnHostname();
970
+ $msg .= "<br /><br />We tried the following URLs:<ul>";
971
+ foreach(self::$cronTestFailedURLs as $URL){
972
+ $msg .= '<li><a href="' . $URL . '" target="_blank">' . $URL . '</a></li>';
973
+ }
974
+ $msg .= '</ul>';
975
+ return $msg;
976
  }
977
  }
978
 
lib/wfUtils.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
  require_once('wfConfig.php');
 
3
  class wfUtils {
4
  private static $isWindows = false;
5
  public static $scanLockFH = false;
@@ -419,6 +420,39 @@ class wfUtils {
419
  fclose($fh);
420
  return $tooBig;
421
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
  }
423
 
424
 
1
  <?php
2
  require_once('wfConfig.php');
3
+ require_once('wfCountryMap.php');
4
  class wfUtils {
5
  private static $isWindows = false;
6
  public static $scanLockFH = false;
420
  fclose($fh);
421
  return $tooBig;
422
  }
423
+ public static function countryCode2Name($code){
424
+ if(isset(wfCountryMap::$map[$code])){
425
+ return wfCountryMap::$map[$code];
426
+ } else {
427
+ return '';
428
+ }
429
+ }
430
+ public static function extractBareURI($URL){
431
+ $URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); //strip of method and host
432
+ $URL = preg_replace('/\#.*$/', '', $URL); //strip off fragment
433
+ $URL = preg_replace('/\?.*$/', '', $URL); //strip off query string
434
+ return $URL;
435
+ }
436
+ public static function IP2Country($IP){
437
+ if(! (function_exists('geoip_open') && function_exists('geoip_country_code_by_addr'))){
438
+ require_once('wfGeoIP.php');
439
+ }
440
+ $gi = geoip_open(dirname(__FILE__) . "/GeoIP.dat",GEOIP_STANDARD);
441
+ $country = geoip_country_code_by_addr($gi, $IP);
442
+ geoip_close($gi);
443
+ return $country ? $country : '';
444
+ }
445
+ public static function siteURLRelative(){
446
+ if(is_multisite()){
447
+ $URL = network_site_url();
448
+ } else {
449
+ $URL = site_url();
450
+ }
451
+ $URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL);
452
+ $URL = rtrim($URL, '/') . '/';
453
+ return $URL;
454
+ }
455
+
456
  }
457
 
458
 
lib/wordfenceClass.php CHANGED
@@ -25,10 +25,6 @@ class wordfence {
25
  private static $statusStartMsgs = array();
26
  private static $debugOn = null;
27
  public static function installPlugin(){
28
- if(wfUtils::isWindows()){
29
- die("You are running Windows. Unfortunately Wordfence is not supported on Windows at this time. We may add Windows support in future, but have no ETA at present.");
30
- }
31
-
32
  self::runInstall();
33
  //Used by MU code below
34
  update_option('wordfenceActivated', 1);
@@ -38,7 +34,13 @@ class wordfence {
38
  update_option('wordfenceActivated', 0);
39
  wp_clear_scheduled_hook('wordfence_daily_cron');
40
  wp_clear_scheduled_hook('wordfence_hourly_cron');
 
 
41
  wp_clear_scheduled_hook('wordfence_scheduled_scan');
 
 
 
 
42
  if(wfConfig::get('deleteTablesOnDeact')){
43
  $schema = new wfSchema();
44
  $schema->dropAll();
@@ -160,6 +162,13 @@ class wordfence {
160
  public static function runInstall(){
161
  update_option('wordfence_version', WORDFENCE_VERSION); //In case we have a fatal error we don't want to keep running install.
162
  //EVERYTHING HERE MUST BE IDEMPOTENT
 
 
 
 
 
 
 
163
  $schema = new wfSchema();
164
  $schema->createAll(); //if not exists
165
  wfConfig::setDefaults(); //If not set
@@ -227,11 +236,10 @@ class wordfence {
227
  global $blog_id;
228
  if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
229
  }
230
-
231
  add_action('wordfence_daily_cron', 'wordfence::dailyCron');
232
  add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
233
  add_action('plugins_loaded', 'wordfence::veryFirstAction');
234
- add_action('wordfence_scheduled_scan','wordfence::startScan');
235
  add_action('init', 'wordfence::initAction');
236
  add_action('template_redirect', 'wordfence::templateRedir');
237
  add_action('shutdown', 'wordfence::shutdownAction');
@@ -393,6 +401,7 @@ class wordfence {
393
  wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's via disabling firewall rules.");
394
  $wfLog->unblockAllIPs();
395
  $wfLog->unlockAllIPs();
 
396
  header('Location: ' . wp_login_url());
397
  exit();
398
  } else {
@@ -511,6 +520,92 @@ class wordfence {
511
  return array('errorMsg' => $e->getMessage());
512
  }
513
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  public static function ajax_sendActivityLog_callback(){
515
  $content = "SITE: " . site_url() . "\nPLUGIN VERSION: " . WORDFENCE_VERSION . "\nWP VERSION: " . wfUtils::getWPVersion() . "\nAPI KEY: " . wfConfig::get('apiKey') . "\nADMIN EMAIL: " . get_option('admin_email') . "\nLOG:\n\n";
516
  $wfdb = new wfDB();
@@ -577,10 +672,6 @@ class wordfence {
577
  } else {
578
  $opts['whitelisted'] = '';
579
  }
580
- $opts['apiKey'] = trim($opts['apiKey']);
581
- if(! preg_match('/^[a-fA-F0-9]+$/', $opts['apiKey'])){
582
- return array('errorMsg' => "Please enter a valid API key for Wordfence before saving your options.");
583
- }
584
  $validUsers = array();
585
  $invalidUsers = array();
586
  foreach(explode(',', preg_replace('/[\r\n\s\t]+/', '', $opts['liveTraf_ignoreUsers'])) as $val){
@@ -592,6 +683,11 @@ class wordfence {
592
  }
593
  }
594
  }
 
 
 
 
 
595
  if(sizeof($invalidUsers) > 0){
596
  return array('errorMsg' => "The following users you selected to ignore in live traffic reports are not valid on this system: " . implode(', ', $invalidUsers));
597
  }
@@ -618,9 +714,43 @@ class wordfence {
618
  if(sizeof($validIPs) > 0){
619
  $opts['liveTraf_ignoreIPs'] = implode(',', $validIPs);
620
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  $reload = '';
622
  $paidKeyMsg = false;
623
- if($opts['apiKey'] != wfConfig::get('apiKey')){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
  $api = new wfAPI($opts['apiKey'], wfUtils::getWPVersion());
625
  try {
626
  $res = $api->call('check_api_key', array(), array());
@@ -635,27 +765,13 @@ class wordfence {
635
  throw new Exception("We could not understand the Wordfence API server reply when updating your API key.");
636
  }
637
  } catch (Exception $e){
638
- return array('errorMsg' => $e->getMessage());
639
  }
640
  }
641
-
642
- if(preg_match('/[a-zA-Z0-9\d]+/', $opts['liveTraf_ignoreUA'])){
643
- $opts['liveTraf_ignoreUA'] = trim($opts['liveTraf_ignoreUA']);
644
- } else {
645
- $opts['liveTraf_ignoreUA'] = '';
646
- }
647
- if(! $opts['other_WFNet']){
648
- $wfdb = new wfDB();
649
- global $wpdb;
650
- $p = $wpdb->base_prefix;
651
- $wfdb->query("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
652
- }
653
- foreach($opts as $key => $val){
654
- wfConfig::set($key, $val);
655
- }
656
-
657
  //Clears next scan if scans are disabled. Schedules next scan if enabled.
658
- $err = self::scheduleNextScan();
659
  if($err){
660
  return array('errorMsg' => $err);
661
  } else {
@@ -1108,7 +1224,7 @@ class wordfence {
1108
  }
1109
  public static function admin_init(){
1110
  if(! wfUtils::isAdmin()){ return; }
1111
- foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan') as $func){
1112
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1113
  }
1114
 
@@ -1144,7 +1260,7 @@ class wordfence {
1144
  }
1145
  }
1146
  public static function noKeyError(){
1147
- echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>Wordfence is not configured correctly.</strong> Go to your plugins menu and disable and re-enable Wordfence and this should fix the problem.</p></div>';
1148
  }
1149
  public static function admin_menus(){
1150
  if(! wfUtils::isAdmin()){ return; }
@@ -1168,6 +1284,8 @@ class wordfence {
1168
  add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
1169
  }
1170
  add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
 
 
1171
  add_submenu_page("Wordfence", "Options", "Options", "activate_plugins", "WordfenceSecOpt", 'wordfence::menu_options');
1172
  }
1173
  public static function menu_options(){
@@ -1176,6 +1294,12 @@ class wordfence {
1176
  public static function menu_blockedIPs(){
1177
  require 'menu_blockedIPs.php';
1178
  }
 
 
 
 
 
 
1179
  public static function menu_activity(){
1180
  require 'menu_activity.php';
1181
  }
@@ -1265,29 +1389,6 @@ class wordfence {
1265
  $subject = "[Wordfence Alert] $shortSiteURL " . $subject;
1266
  wp_mail(implode(',', $emails), $subject, $content);
1267
  }
1268
- public static function scheduleNextScan($force = false){
1269
- if(wfConfig::get('scheduledScansEnabled')){
1270
- $nextScan = wp_next_scheduled('wordfence_scheduled_scan');
1271
- if((! $force) && $nextScan && $nextScan - time() > 0){
1272
- //scan is already scheduled for the future
1273
- return;
1274
- }
1275
- $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
1276
- try {
1277
- $result = $api->call('get_next_scan_time', array(), array());
1278
- $secsToGo = 3600 * 6; //In case we can't contact the API, schedule next scan 6 hours from now.
1279
- if(is_array($result) && $result['secsToGo'] > 1800){
1280
- $secsToGo = $result['secsToGo'];
1281
- }
1282
- wp_clear_scheduled_hook('wordfence_scheduled_scan');
1283
- wp_schedule_single_event(time() + $secsToGo, 'wordfence_scheduled_scan');
1284
- } catch (Exception $e){
1285
- return $e->getMessage();
1286
- }
1287
- } else {
1288
- wp_clear_scheduled_hook('wordfence_scheduled_scan');
1289
- }
1290
- }
1291
  private static function getLog(){
1292
  if(! self::$wfLog){
1293
  $wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
25
  private static $statusStartMsgs = array();
26
  private static $debugOn = null;
27
  public static function installPlugin(){
 
 
 
 
28
  self::runInstall();
29
  //Used by MU code below
30
  update_option('wordfenceActivated', 1);
34
  update_option('wordfenceActivated', 0);
35
  wp_clear_scheduled_hook('wordfence_daily_cron');
36
  wp_clear_scheduled_hook('wordfence_hourly_cron');
37
+
38
+ //Remove old legacy cron job if it exists
39
  wp_clear_scheduled_hook('wordfence_scheduled_scan');
40
+
41
+ //Remove all scheduled scans.
42
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Clear all scheduled scans.
43
+
44
  if(wfConfig::get('deleteTablesOnDeact')){
45
  $schema = new wfSchema();
46
  $schema->dropAll();
162
  public static function runInstall(){
163
  update_option('wordfence_version', WORDFENCE_VERSION); //In case we have a fatal error we don't want to keep running install.
164
  //EVERYTHING HERE MUST BE IDEMPOTENT
165
+
166
+ //Remove old legacy cron job if exists
167
+ wp_clear_scheduled_hook('wordfence_scheduled_scan');
168
+
169
+ //Install new schedule. If schedule config is blank it will install the default 'auto' schedule.
170
+ wordfence::scheduleScans();
171
+
172
  $schema = new wfSchema();
173
  $schema->createAll(); //if not exists
174
  wfConfig::setDefaults(); //If not set
236
  global $blog_id;
237
  if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
238
  }
239
+ add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
240
  add_action('wordfence_daily_cron', 'wordfence::dailyCron');
241
  add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
242
  add_action('plugins_loaded', 'wordfence::veryFirstAction');
 
243
  add_action('init', 'wordfence::initAction');
244
  add_action('template_redirect', 'wordfence::templateRedir');
245
  add_action('shutdown', 'wordfence::shutdownAction');
401
  wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's via disabling firewall rules.");
402
  $wfLog->unblockAllIPs();
403
  $wfLog->unlockAllIPs();
404
+ wfConfig::set('cbl_countries', ''); //unblock all countries
405
  header('Location: ' . wp_login_url());
406
  exit();
407
  } else {
520
  return array('errorMsg' => $e->getMessage());
521
  }
522
  }
523
+ public static function ajax_saveScanSchedule_callback(){
524
+ if(! wfConfig::get('isPaid')){
525
+ return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
526
+ }
527
+ $schedDays = explode('|', $_POST['schedTxt']);
528
+ $schedule = array();
529
+ for($day = 0; $day <= 6; $day++){
530
+ $schedule[$day] = explode(',', $schedDays[$day]);
531
+ }
532
+ $schedMode = $_POST['schedMode'];
533
+ wfConfig::set_ser('scanSched', $schedule);
534
+ wfConfig::set('schedMode', $schedMode);
535
+ wordfence::scheduleScans();
536
+ return array('ok' => 1);
537
+ }
538
+ public static function wordfenceStartScheduledScan(){
539
+ //This prevents scheduled scans from piling up on low traffic blogs and all being run at once.
540
+ //Only one scheduled scan runs within a given 60 min window. Won't run if another scan has run within 30 mins.
541
+ $lastScanStart = wfConfig::get('lastScheduledScanStart', 0);
542
+ if($lastScanStart && (time() - $lastScanStart) < 1800){
543
+ //A scheduled scan was started in the last 30 mins, so skip this one.
544
+ return;
545
+ }
546
+ wfConfig::set('lastScheduledScanStart', time());
547
+ wordfence::status(1, 'info', "Scheduled Wordfence scan starting at " . date('l jS \of F Y h:i:s A', current_time('timestamp')) );
548
+
549
+ //We call this before the scan actually starts to advance the schedule for the next week.
550
+ //This ensures that if the scan crashes for some reason, the schedule will hold.
551
+ wordfence::scheduleScans();
552
+
553
+ wfScanEngine::startScan();
554
+ }
555
+ public static function scheduleScans(){ //Idempotent. Deschedules everything and schedules the following week.
556
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Clear all scheduled scans.
557
+ $sched = wfConfig::get_ser('scanSched', array());
558
+ $mode = wfConfig::get('schedMode');
559
+ if($mode == 'manual' && is_array($sched) && is_array($sched[0]) ){
560
+ //Use sched as it is
561
+ } else { //Default to setting scans to run once a day at a randomly selected time.
562
+ $sched = array();
563
+ $runAt = rand(0,23);
564
+ for($day = 0; $day <= 6; $day++){
565
+ $sched[$day] = array();
566
+ for($hour = 0; $hour <= 23; $hour++){
567
+ if($hour == $runAt){
568
+ $sched[$day][$hour] = 1;
569
+ } else {
570
+ $sched[$day][$hour] = 0;
571
+ }
572
+ }
573
+ }
574
+ }
575
+ for($scheduledDay = 0; $scheduledDay <= 6; $scheduledDay++){
576
+ //0 is sunday
577
+ //6 is Saturday
578
+ for($scheduledHour = 0; $scheduledHour <= 23; $scheduledHour++){
579
+ if($sched[$scheduledDay][$scheduledHour]){
580
+ $wpTime = current_time('timestamp');
581
+ $currentDayOfWeek = date('w', $wpTime);
582
+ $daysInFuture = $scheduledDay - $currentDayOfWeek; //It's monday and scheduledDay is Wed (3) then result is 2 days in future. It's Wed and sched day is monday, then result is 3 - 1 = -2
583
+ if($daysInFuture < 0){ $daysInFuture -= 7; } //Turns -2 into 5 days in future
584
+ $currentHour = date('G', $wpTime);
585
+ $secsOffset = ($scheduledHour - $currentHour) * 3600; //Offset from current hour, can be negative
586
+ $secondsInFuture = ($daysInFuture * 86400) + $secsOffset; //Can be negative, so we schedule those 1 week ahead
587
+ if($secondsInFuture < 1){
588
+ $secondsInFuture += (86400 * 7); //Add a week
589
+ }
590
+ $wpTimeRoundDownHour = strtotime(date("D, d M y H:00:00 O", $wpTime));
591
+ $futureTime = $wpTimeRoundDownHour + $secondsInFuture;
592
+ wordfence::status(4, 'info', "Scheduled time for day $scheduledDay hour $scheduledHour is: " . date('l jS \of F Y h:i:s A', $futureTime));
593
+ wp_schedule_single_event($futureTime, 'wordfence_start_scheduled_scan');
594
+ }
595
+ }
596
+ }
597
+ }
598
+ public static function ajax_saveCountryBlocking_callback(){
599
+ if(! wfConfig::get('isPaid')){
600
+ return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
601
+ }
602
+ wfConfig::set('cbl_action', $_POST['blockAction']);
603
+ wfConfig::set('cbl_countries', $_POST['codes']);
604
+ wfConfig::set('cbl_redirURL', $_POST['redirURL']);
605
+ wfConfig::set('cbl_loggedInBlocked', $_POST['loggedInBlocked']);
606
+ wfConfig::set('cbl_loginFormBlocked', $_POST['loginFormBlocked']);
607
+ return array('ok' => 1);
608
+ }
609
  public static function ajax_sendActivityLog_callback(){
610
  $content = "SITE: " . site_url() . "\nPLUGIN VERSION: " . WORDFENCE_VERSION . "\nWP VERSION: " . wfUtils::getWPVersion() . "\nAPI KEY: " . wfConfig::get('apiKey') . "\nADMIN EMAIL: " . get_option('admin_email') . "\nLOG:\n\n";
611
  $wfdb = new wfDB();
672
  } else {
673
  $opts['whitelisted'] = '';
674
  }
 
 
 
 
675
  $validUsers = array();
676
  $invalidUsers = array();
677
  foreach(explode(',', preg_replace('/[\r\n\s\t]+/', '', $opts['liveTraf_ignoreUsers'])) as $val){
683
  }
684
  }
685
  }
686
+ $opts['apiKey'] = trim($opts['apiKey']);
687
+ if($opts['apiKey'] && (! preg_match('/^[a-fA-F0-9]+$/', $opts['apiKey'])) ){ //User entered something but it's garbage.
688
+ return array('errorMsg' => "You entered an API key but it is not in a valid format. It must consist only of characters A to F and 0 to 9.");
689
+ }
690
+
691
  if(sizeof($invalidUsers) > 0){
692
  return array('errorMsg' => "The following users you selected to ignore in live traffic reports are not valid on this system: " . implode(', ', $invalidUsers));
693
  }
714
  if(sizeof($validIPs) > 0){
715
  $opts['liveTraf_ignoreIPs'] = implode(',', $validIPs);
716
  }
717
+
718
+ if(preg_match('/[a-zA-Z0-9\d]+/', $opts['liveTraf_ignoreUA'])){
719
+ $opts['liveTraf_ignoreUA'] = trim($opts['liveTraf_ignoreUA']);
720
+ } else {
721
+ $opts['liveTraf_ignoreUA'] = '';
722
+ }
723
+ if(! $opts['other_WFNet']){
724
+ $wfdb = new wfDB();
725
+ global $wpdb;
726
+ $p = $wpdb->base_prefix;
727
+ $wfdb->query("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
728
+ }
729
+ foreach($opts as $key => $val){
730
+ if($key != 'apiKey'){ //Don't save API key yet
731
+ wfConfig::set($key, $val);
732
+ }
733
+ }
734
+
735
  $reload = '';
736
  $paidKeyMsg = false;
737
+
738
+
739
+ if(! $opts['apiKey']){ //Empty API key (after trim above), then try to get one.
740
+ $api = new wfAPI('', wfUtils::getWPVersion());
741
+ try {
742
+ $keyData = $api->call('get_anon_api_key');
743
+ if($keyData['ok'] && $keyData['apiKey']){
744
+ wfConfig::set('apiKey', $keyData['apiKey']);
745
+ wfConfig::set('isPaid', 0);
746
+ $reload = 'reload';
747
+ } else {
748
+ throw new Exception("We could not understand the Wordfence server's response because it did not contain an 'ok' and 'apiKey' element.");
749
+ }
750
+ } catch(Exception $e){
751
+ return array('errorMsg' => "Your options have been saved, but we encountered a problem. You left your API key blank, so we tried to get you a free API key from the Wordfence servers. However we encountered a problem fetching the free key: " . $e->getMessage());
752
+ }
753
+ } else if($opts['apiKey'] != wfConfig::get('apiKey')){
754
  $api = new wfAPI($opts['apiKey'], wfUtils::getWPVersion());
755
  try {
756
  $res = $api->call('check_api_key', array(), array());
765
  throw new Exception("We could not understand the Wordfence API server reply when updating your API key.");
766
  }
767
  } catch (Exception $e){
768
+ return array('errorMsg' => "Your options have been saved. However we noticed you changed your API key and we tried to verify it with the Wordfence servers and received an error: " . $e->getMessage());
769
  }
770
  }
771
+
772
+
773
+
 
 
 
 
 
 
 
 
 
 
 
 
 
774
  //Clears next scan if scans are disabled. Schedules next scan if enabled.
 
775
  if($err){
776
  return array('errorMsg' => $err);
777
  } else {
1224
  }
1225
  public static function admin_init(){
1226
  if(! wfUtils::isAdmin()){ return; }
1227
+ foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule') as $func){
1228
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1229
  }
1230
 
1260
  }
1261
  }
1262
  public static function noKeyError(){
1263
+ echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>Wordfence could not get an API key from the Wordfence scanning servers when it activated.</strong> You can try to fix this by going to the Wordfence "options" page and hitting "Save Changes". This will cause Wordfence to retry fetching an API key for you. If you keep seeing this error it usually means your WordPress server can\'t connect to our scanning servers. You can try asking your WordPress host to allow your WordPress server to connect to noc1.wordfence.com.</p></div>';
1264
  }
1265
  public static function admin_menus(){
1266
  if(! wfUtils::isAdmin()){ return; }
1284
  add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
1285
  }
1286
  add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
1287
+ add_submenu_page("Wordfence", "Country Blocking", "Country Blocking", "activate_plugins", "WordfenceCountryBlocking", 'wordfence::menu_countryBlocking');
1288
+ add_submenu_page("Wordfence", "Scan Schedule", "Scan Schedule", "activate_plugins", "WordfenceScanSchedule", 'wordfence::menu_scanSchedule');
1289
  add_submenu_page("Wordfence", "Options", "Options", "activate_plugins", "WordfenceSecOpt", 'wordfence::menu_options');
1290
  }
1291
  public static function menu_options(){
1294
  public static function menu_blockedIPs(){
1295
  require 'menu_blockedIPs.php';
1296
  }
1297
+ public static function menu_scanSchedule(){
1298
+ require 'menu_scanSchedule.php';
1299
+ }
1300
+ public static function menu_countryBlocking(){
1301
+ require 'menu_countryBlocking.php';
1302
+ }
1303
  public static function menu_activity(){
1304
  require 'menu_activity.php';
1305
  }
1389
  $subject = "[Wordfence Alert] $shortSiteURL " . $subject;
1390
  wp_mail(implode(',', $emails), $subject, $content);
1391
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1392
  private static function getLog(){
1393
  if(! self::$wfLog){
1394
  $wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
- Stable tag: 3.1.1
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
@@ -152,6 +152,20 @@ or a theme, because often these have been updated to fix a security hole.
152
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
153
 
154
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  = 3.1.1 =
156
  * Added another fix for "mysql server has gone away" error. Wordfence now makes sure the DB is still connected and reconnects if not.
157
  * Added new detection for encoded malicious code in files.
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
+ Stable tag: 3.1.2
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
152
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
153
 
154
  == Changelog ==
155
+ = 3.1.2 =
156
+ * Fixed permanent IP blocking bug which caused permanently blocked IP's to no longer display in the list after some time, even though there were still blocked. (Incorrect SQL query)
157
+ * Fixed "Can't get admin ID" on scan starts for both MU and single site installs.
158
+ * Improved status messages for sites with very large numbers of comments.
159
+ * Fixed bug that caused sites in subdirectories to not be able to view site config or run the memory test on the Wordfence "options" page.
160
+ * Fixed database disconnect bug (mysql server has gone away). An additional fix was required to finally squash this bug.
161
+ * Removed the code that prevented you from installing Wordfence on Windows. Sorry Windows customers!
162
+ * Improved scheduling so that it is now more reliable.
163
+ * Fixed bug that caused a loop for customers who could not contact the Wordfence servers on install.
164
+ * Added helpful message if you get the "can't connect to itself" error message with some additional documentation to help solve this issue.
165
+ * Improved error reporting when Wordfence can't connect to the scanning servers. Now features a helpful explanation rather than a generic message.
166
+ * Added Country Geo-Blocking feature for paid customers.
167
+ * Added Scan Scheduling feature for paid customers.
168
+
169
  = 3.1.1 =
170
  * Added another fix for "mysql server has gone away" error. Wordfence now makes sure the DB is still connected and reconnects if not.
171
  * Added new detection for encoded malicious code in files.
wfscan.php CHANGED
@@ -155,12 +155,40 @@ class wfScan {
155
  $userSource = '';
156
  if(is_multisite()){
157
  $users = get_users('role=super&fields=ID');
158
- $userSource = 'multisite get_users() function';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  } else {
160
  $users = get_users('role=administrator&fields=ID');
161
- $userSource = 'singlesite get_users() function';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
- if(sizeof($users) > 1){
164
  sort($users, SORT_NUMERIC);
165
  $adminUserID = $users[0];
166
  } else {
155
  $userSource = '';
156
  if(is_multisite()){
157
  $users = get_users('role=super&fields=ID');
158
+ if(sizeof($users) < 1){
159
+ $supers = get_super_admins();
160
+ if(sizeof($supers) > 0){
161
+ foreach($supers as $superLogin){
162
+ $superDat = get_user_by('login', $superLogin);
163
+ if($superDat){
164
+ $users = array($superDat->ID);
165
+ $userSource = 'multisite get_super_admins() function';
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ } else {
171
+ $userSource = 'multisite get_users() function';
172
+ }
173
  } else {
174
  $users = get_users('role=administrator&fields=ID');
175
+ if(sizeof($users) < 1){
176
+ $supers = get_super_admins();
177
+ if(sizeof($supers) > 0){
178
+ foreach($supers as $superLogin){
179
+ $superDat = get_user_by('login', $superLogin);
180
+ if($superDat){
181
+ $users = array($superDat->ID);
182
+ $userSource = 'singlesite get_super_admins() function';
183
+ break;
184
+ }
185
+ }
186
+ }
187
+ } else {
188
+ $userSource = 'singlesite get_users() function';
189
+ }
190
  }
191
+ if(sizeof($users) > 0){
192
  sort($users, SORT_NUMERIC);
193
  $adminUserID = $users[0];
194
  } else {
wordfence.php CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
- Version: 3.1.1
8
  Author URI: http://wordfence.com/
9
  */
10
- define('WORDFENCE_VERSION', '3.1.1');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
+ Version: 3.1.2
8
  Author URI: http://wordfence.com/
9
  */
10
+ define('WORDFENCE_VERSION', '3.1.2');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.