Version Description
- Fixed bug that caused WF to not work when certain DB caching plugins are used and override wpdb object.
- Fixed Wordfence so activity log only shows our own errors unless in debug mode.
- Wordfence now deletes all it's tables and deletes all saved options when you deactivate the plugin.
- Removed all exit() on error statements. Critical errors are handled more gracefully by writing to the log instead.
- Fixed a bug that would cause a database loop until running out of memory under certain error conditions.
- Suppressed useless warnings that occur in environments with basedir set or where functions are disabled for security reasons.
- Removed redundant check that executed on every request and put it in activation instead.
- If serialization during scan breaks, exit gracefully instead of looping.
- Disk space in log is now shown as Gigabytes and formatted nicely.
- Removed wdie() function which is a little obnoxious. Writing to WF error log instead.
- Fixed bug where a non-empty but useless HTTP header can break getIP() function.
- Added useful data to error output if getIP() tells you it can't work on your system.
- Removed option to start scan in debug because it's no longer possible with a forked scan.
- Removed option to test process running time on a system because it breaks on most systems and confuses customers.
- Database connection errors no longer call die() but log an error instead in a way that removes the risk of a logging loop.
- Removed dropAll.php script because we now clean up tables on deactivate and it's not needed.
- Updated readme to show that we support 3.4.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 2.1.5 |
Comparing to | |
See all releases |
Code changes from version 2.1.4 to 2.1.5
- lib/dropAll.php +0 -8
- lib/menu_options.php +0 -2
- lib/viewFullActivityLog.php +4 -1
- lib/wfConfig.php +11 -9
- lib/wfDB.php +54 -33
- lib/wfLog.php +8 -4
- lib/wfScanEngine.php +9 -6
- lib/wfSchema.php +2 -2
- lib/wfUtils.php +45 -22
- lib/wordfenceClass.php +6 -7
- lib/wordfenceHash.php +1 -1
- readme.txt +21 -2
- wfscan.php +9 -1
- wordfence.php +2 -2
lib/dropAll.php
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
require_once('wfSchema.php');
|
3 |
-
if((! isset($_SERVER)) || isset($_SERVER['REQUEST_URI'])){ echo "Running under web interface. Exiting.\n"; exit(0); }
|
4 |
-
if(! (isset($argv[1]) && isset($argv[2]) && isset($argv[3]) && isset($argv[4])) ){ echo "Usage: {$argv[0]} <DB username> <DB password> <DB name> <prefix>\n"; exit(); } $s = new wfSchema('localhost', $argv[1], $argv[2], $argv[3]);
|
5 |
-
|
6 |
-
$s->dropAll($argv[4]);
|
7 |
-
|
8 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/menu_options.php
CHANGED
@@ -208,9 +208,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
208 |
<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>
|
209 |
<tr><th>Enable debugging mode</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></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="<?php echo wfUtils::getBaseURL(); ?>wfscan.php?debugMode=1&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Start a scan in debug mode (advanced users only)</a></th></tr>
|
212 |
<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>
|
213 |
-
<tr><th colspan="2"><a href="/?_wfsf=testtime&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Test your WordPress host's process running time (you may see a blank screen for up to 3 minutes)</a></th></tr>
|
214 |
</table>
|
215 |
<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"> Your changes have been saved!</span></td></tr></table></p>
|
216 |
</div>
|
208 |
<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>
|
209 |
<tr><th>Enable debugging mode</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></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"> Your changes have been saved!</span></td></tr></table></p>
|
214 |
</div>
|
lib/viewFullActivityLog.php
CHANGED
@@ -11,10 +11,13 @@
|
|
11 |
<?php
|
12 |
$db = new wfDB();
|
13 |
global $wpdb;
|
|
|
14 |
$table = $wpdb->base_prefix . 'wfStatus';
|
15 |
$q = $db->query("select ctime, level, type, msg from $table order by ctime desc");
|
16 |
while($r = mysql_fetch_assoc($q)){
|
17 |
-
|
|
|
|
|
18 |
}
|
19 |
?>
|
20 |
</body>
|
11 |
<?php
|
12 |
$db = new wfDB();
|
13 |
global $wpdb;
|
14 |
+
$debugOn = wfConfig::get('debugOn', 0);
|
15 |
$table = $wpdb->base_prefix . 'wfStatus';
|
16 |
$q = $db->query("select ctime, level, type, msg from $table order by ctime desc");
|
17 |
while($r = mysql_fetch_assoc($q)){
|
18 |
+
if($r['level'] < 4 || $debugOn){
|
19 |
+
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', $r['ctime']) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . '] ' . htmlspecialchars($r['msg']) . "</div>\n";
|
20 |
+
}
|
21 |
}
|
22 |
?>
|
23 |
</body>
|
lib/wfConfig.php
CHANGED
@@ -376,7 +376,7 @@ class wfConfig {
|
|
376 |
$msg = "wfConfig::set() got an array as second param with key: $key - Please report this bug. Exiting.";
|
377 |
wfstatus(1, 'error', $msg);
|
378 |
error_log($msg);
|
379 |
-
|
380 |
}
|
381 |
|
382 |
self::getDB()->query("insert into " . self::table() . " (name, val) values ('%s', '%s') ON DUPLICATE KEY UPDATE val='%s'", $key, $val, $val);
|
@@ -450,7 +450,7 @@ class wfConfig {
|
|
450 |
wordfence::status(4, 'info', "Serialized data for $key is " . strlen($serialized) . " bytes and is greater than max_allowed packet so writing it to disk file: " . $fullFile);
|
451 |
} else {
|
452 |
wordfence::status(1, 'error', "Your database doesn't allow big packets so we have to use files to store temporary data and Wordfence can't find a place to write them. Either ask your admin to increase max_allowed_packet on your MySQL database, or make one of the following directories writable by your web server: " . implode(', ', $dirs));
|
453 |
-
|
454 |
}
|
455 |
fwrite($fh, self::$tmpFileHeader);
|
456 |
fwrite($fh, $serialized);
|
@@ -458,12 +458,12 @@ class wfConfig {
|
|
458 |
return true;
|
459 |
} else {
|
460 |
wordfence::status(1, 'error', "Wordfence tried to save a variable with name '$key' and your database max_allowed_packet is set to be too small. We then tried to save it to disk, but you don't have a temporary directory that is writable. You can fix this by making the /wp-content/plugins/wordfence/tmp/ directory writable by your web server. Or by increasing your max_allowed_packet configuration variable in your mysql database.");
|
461 |
-
|
462 |
}
|
463 |
|
464 |
} else {
|
465 |
wordfence::status(1, 'error', "Wordfence tried to save a variable with name '$key' and your database max_allowed_packet is set to be too small. This particular variable can't be saved to disk. Please ask your administrator to increase max_allowed_packet and also report this in the Wordfence forums because it may be a bug. Thanks.");
|
466 |
-
|
467 |
}
|
468 |
} else {
|
469 |
//Delete temp files on disk or else the DB will be written to but get_ser will see files on disk and read them instead
|
@@ -496,17 +496,19 @@ class wfConfig {
|
|
496 |
if(! self::$tmpDirCache){
|
497 |
$dirs = array(wfUtils::getPluginBaseDir() . 'wordfence/tmp/', sys_get_temp_dir(), ABSPATH . 'wp-content/uploads/');
|
498 |
$finalDir = 'notmp';
|
|
|
499 |
foreach($dirs as $dir){
|
500 |
$dir = rtrim($dir, '/') . '/';
|
501 |
-
$fh = fopen($dir . 'wftmptest.txt', 'w');
|
502 |
if(! $fh){ continue; }
|
503 |
-
$bytes = fwrite($fh, 'test');
|
504 |
-
if($bytes != 4){ fclose($fh); continue; }
|
505 |
-
fclose($fh);
|
506 |
-
if(! unlink($dir . 'wftmptest.txt')){ continue; }
|
507 |
$finalDir = $dir;
|
508 |
break;
|
509 |
}
|
|
|
510 |
self::$tmpDirCache = $finalDir;
|
511 |
}
|
512 |
if(self::$tmpDirCache == 'notmp'){
|
376 |
$msg = "wfConfig::set() got an array as second param with key: $key - Please report this bug. Exiting.";
|
377 |
wfstatus(1, 'error', $msg);
|
378 |
error_log($msg);
|
379 |
+
return;
|
380 |
}
|
381 |
|
382 |
self::getDB()->query("insert into " . self::table() . " (name, val) values ('%s', '%s') ON DUPLICATE KEY UPDATE val='%s'", $key, $val, $val);
|
450 |
wordfence::status(4, 'info', "Serialized data for $key is " . strlen($serialized) . " bytes and is greater than max_allowed packet so writing it to disk file: " . $fullFile);
|
451 |
} else {
|
452 |
wordfence::status(1, 'error', "Your database doesn't allow big packets so we have to use files to store temporary data and Wordfence can't find a place to write them. Either ask your admin to increase max_allowed_packet on your MySQL database, or make one of the following directories writable by your web server: " . implode(', ', $dirs));
|
453 |
+
return false;
|
454 |
}
|
455 |
fwrite($fh, self::$tmpFileHeader);
|
456 |
fwrite($fh, $serialized);
|
458 |
return true;
|
459 |
} else {
|
460 |
wordfence::status(1, 'error', "Wordfence tried to save a variable with name '$key' and your database max_allowed_packet is set to be too small. We then tried to save it to disk, but you don't have a temporary directory that is writable. You can fix this by making the /wp-content/plugins/wordfence/tmp/ directory writable by your web server. Or by increasing your max_allowed_packet configuration variable in your mysql database.");
|
461 |
+
return false;
|
462 |
}
|
463 |
|
464 |
} else {
|
465 |
wordfence::status(1, 'error', "Wordfence tried to save a variable with name '$key' and your database max_allowed_packet is set to be too small. This particular variable can't be saved to disk. Please ask your administrator to increase max_allowed_packet and also report this in the Wordfence forums because it may be a bug. Thanks.");
|
466 |
+
return false;
|
467 |
}
|
468 |
} else {
|
469 |
//Delete temp files on disk or else the DB will be written to but get_ser will see files on disk and read them instead
|
496 |
if(! self::$tmpDirCache){
|
497 |
$dirs = array(wfUtils::getPluginBaseDir() . 'wordfence/tmp/', sys_get_temp_dir(), ABSPATH . 'wp-content/uploads/');
|
498 |
$finalDir = 'notmp';
|
499 |
+
wfUtils::errorsOff();
|
500 |
foreach($dirs as $dir){
|
501 |
$dir = rtrim($dir, '/') . '/';
|
502 |
+
$fh = @fopen($dir . 'wftmptest.txt', 'w');
|
503 |
if(! $fh){ continue; }
|
504 |
+
$bytes = @fwrite($fh, 'test');
|
505 |
+
if($bytes != 4){ @fclose($fh); continue; }
|
506 |
+
@fclose($fh);
|
507 |
+
if(! @unlink($dir . 'wftmptest.txt')){ continue; }
|
508 |
$finalDir = $dir;
|
509 |
break;
|
510 |
}
|
511 |
+
wfUtils::errorsOn();
|
512 |
self::$tmpDirCache = $finalDir;
|
513 |
}
|
514 |
if(self::$tmpDirCache == 'notmp'){
|
lib/wfDB.php
CHANGED
@@ -16,21 +16,32 @@ class wfDB {
|
|
16 |
} else {
|
17 |
global $wpdb;
|
18 |
if(! $wpdb){
|
19 |
-
self::
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
}
|
21 |
-
if(! $wpdb->dbhost ){ self::wfdie("The WordPress variable from wpdb dbhost is not defined."); }
|
22 |
-
if(! $wpdb->dbuser ){ self::wfdie("The WordPress variable from wpdb dbuser is not defined."); }
|
23 |
-
if(! isset($wpdb->dbpassword) ){ self::wfdie("The WordPress variable from wpdb dbpassword is not defined."); }
|
24 |
-
if(! $wpdb->dbname ){ self::wfdie("The WordPress variable from wpdb dbname is not defined."); }
|
25 |
-
$this->dbhost = $wpdb->dbhost;
|
26 |
-
$this->dbuser = $wpdb->dbuser;
|
27 |
-
$this->dbpassword = $wpdb->dbpassword;
|
28 |
-
$this->dbname = $wpdb->dbname;
|
29 |
}
|
30 |
if($createNewHandle){
|
31 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
32 |
if($dbh === false){
|
33 |
-
self::
|
|
|
34 |
}
|
35 |
mysql_select_db($this->dbname, $dbh);
|
36 |
$this->dbh = $dbh;
|
@@ -45,7 +56,8 @@ class wfDB {
|
|
45 |
} else {
|
46 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
47 |
if($dbh === false){
|
48 |
-
self::
|
|
|
49 |
}
|
50 |
|
51 |
mysql_select_db($this->dbname, $dbh);
|
@@ -66,16 +78,32 @@ class wfDB {
|
|
66 |
} else if(sizeof($args) > 1){
|
67 |
$query = call_user_func_array('sprintf', $args);
|
68 |
} else {
|
69 |
-
|
70 |
}
|
71 |
$res = mysql_query($query, $this->dbh);
|
72 |
-
$
|
73 |
-
if( (! preg_match('/Wordfence DB error/i', $query)) && $err){ //prevent loops
|
74 |
-
$this->errorMsg = $err;
|
75 |
-
$trace=debug_backtrace(); $caller=array_shift($trace); wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
76 |
-
}
|
77 |
return mysql_fetch_assoc($res); //returns false if no rows found
|
78 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
public function querySingle(){
|
80 |
$this->errorMsg = false;
|
81 |
$args = func_get_args();
|
@@ -87,14 +115,10 @@ class wfDB {
|
|
87 |
}
|
88 |
$query = call_user_func_array('sprintf', $args);
|
89 |
} else {
|
90 |
-
|
91 |
}
|
92 |
$res = mysql_query($query, $this->dbh);
|
93 |
-
$
|
94 |
-
if( (! preg_match('/Wordfence DB error/i', $query)) && $err){
|
95 |
-
$this->errorMsg = $err;
|
96 |
-
$trace=debug_backtrace(); $caller=array_shift($trace); wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
97 |
-
}
|
98 |
if(! $res){
|
99 |
return false;
|
100 |
}
|
@@ -120,13 +144,9 @@ class wfDB {
|
|
120 |
}
|
121 |
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
122 |
} else {
|
123 |
-
|
124 |
-
}
|
125 |
-
$err = mysql_error();
|
126 |
-
if( (! $isStatusQuery) && $err){ //isStatusQuery prevents loops if status itself is causing error
|
127 |
-
$this->errorMsg = $err;
|
128 |
-
$trace=debug_backtrace(); $caller=array_shift($trace); wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
129 |
}
|
|
|
130 |
return $res;
|
131 |
}
|
132 |
public function queryIgnoreError(){ //sprintfString, arguments
|
@@ -140,14 +160,15 @@ class wfDB {
|
|
140 |
}
|
141 |
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
142 |
} else {
|
143 |
-
|
144 |
}
|
145 |
return $res;
|
146 |
}
|
147 |
|
148 |
-
private function
|
149 |
-
|
150 |
-
|
|
|
151 |
}
|
152 |
public function createKeyIfNotExists($table, $col, $keyName){
|
153 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
16 |
} else {
|
17 |
global $wpdb;
|
18 |
if(! $wpdb){
|
19 |
+
self::criticalError("The WordPress variable wpdb is not defined. Wordfence can't function without this being defined as it is in all standard WordPress installs.");
|
20 |
+
return;
|
21 |
+
}
|
22 |
+
$sources = array(
|
23 |
+
array('dbhost', 'DB_HOST'),
|
24 |
+
array('dbuser', 'DB_USER'),
|
25 |
+
array('dbpassword', 'DB_PASSWORD'),
|
26 |
+
array('dbname', 'DB_NAME')
|
27 |
+
);
|
28 |
+
foreach($sources as $src){
|
29 |
+
$prop = $src[0];
|
30 |
+
if(isset($wpdb->$prop)){
|
31 |
+
$this->$prop = $wpdb->$prop;
|
32 |
+
} else if(defined($src[1])){
|
33 |
+
$this->$prop = constant($src[1]);
|
34 |
+
} else {
|
35 |
+
self::criticalError("Wordfence DB connect error. wpdb.$prop is not set and " . $src[1] . " is not defined.");
|
36 |
+
return;
|
37 |
+
}
|
38 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
if($createNewHandle){
|
41 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
42 |
if($dbh === false){
|
43 |
+
self::criticalError("Wordfence could not connect to your database. Error was: " . mysql_error());
|
44 |
+
return;
|
45 |
}
|
46 |
mysql_select_db($this->dbname, $dbh);
|
47 |
$this->dbh = $dbh;
|
56 |
} else {
|
57 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
58 |
if($dbh === false){
|
59 |
+
self::criticalError("Wordfence could not connect to your database. The error was: " . mysql_error());
|
60 |
+
return;
|
61 |
}
|
62 |
|
63 |
mysql_select_db($this->dbname, $dbh);
|
78 |
} else if(sizeof($args) > 1){
|
79 |
$query = call_user_func_array('sprintf', $args);
|
80 |
} else {
|
81 |
+
$this->handleError("No arguments passed to querySingle()");
|
82 |
}
|
83 |
$res = mysql_query($query, $this->dbh);
|
84 |
+
$this->handleError();
|
|
|
|
|
|
|
|
|
85 |
return mysql_fetch_assoc($res); //returns false if no rows found
|
86 |
}
|
87 |
+
public function handleError($err = false){
|
88 |
+
if(! $err){
|
89 |
+
$err = mysql_error();
|
90 |
+
}
|
91 |
+
if($err){
|
92 |
+
$trace=debug_backtrace();
|
93 |
+
$first=array_shift($trace);
|
94 |
+
$caller=array_shift($trace);
|
95 |
+
$msg = "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err";
|
96 |
+
global $wpdb;
|
97 |
+
$statusTable = $wpdb->base_prefix . 'wfStatus';
|
98 |
+
mysql_query(sprintf("insert into " . $statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')",
|
99 |
+
mysql_real_escape_string(sprintf('%.6f', microtime(true))),
|
100 |
+
mysql_real_escape_string(1),
|
101 |
+
mysql_real_escape_string('error'),
|
102 |
+
mysql_real_escape_string($msg)), $this->dbh);
|
103 |
+
error_log($msg);
|
104 |
+
return;
|
105 |
+
}
|
106 |
+
}
|
107 |
public function querySingle(){
|
108 |
$this->errorMsg = false;
|
109 |
$args = func_get_args();
|
115 |
}
|
116 |
$query = call_user_func_array('sprintf', $args);
|
117 |
} else {
|
118 |
+
$this->handleError("No arguments passed to querySingle()");
|
119 |
}
|
120 |
$res = mysql_query($query, $this->dbh);
|
121 |
+
$this->handleError();
|
|
|
|
|
|
|
|
|
122 |
if(! $res){
|
123 |
return false;
|
124 |
}
|
144 |
}
|
145 |
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
146 |
} else {
|
147 |
+
$this->handleError("No arguments passed to query()");
|
|
|
|
|
|
|
|
|
|
|
148 |
}
|
149 |
+
$this->handleError();
|
150 |
return $res;
|
151 |
}
|
152 |
public function queryIgnoreError(){ //sprintfString, arguments
|
160 |
}
|
161 |
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
162 |
} else {
|
163 |
+
$this->handleError("No arguments passed to query()");
|
164 |
}
|
165 |
return $res;
|
166 |
}
|
167 |
|
168 |
+
private static function criticalError($msg){
|
169 |
+
$msg = "Wordfence critical database error: $msg";
|
170 |
+
error_log($msg);
|
171 |
+
return;
|
172 |
}
|
173 |
public function createKeyIfNotExists($table, $col, $keyName){
|
174 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
lib/wfLog.php
CHANGED
@@ -55,7 +55,8 @@ class wfLog {
|
|
55 |
} else if($type == 'hit'){
|
56 |
$table = $this->leechTable;
|
57 |
} else {
|
58 |
-
|
|
|
59 |
}
|
60 |
$IP = wfUtils::getIP();
|
61 |
$this->getDB()->query("insert into $table (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfcurrenthits := hits + 1, hits + 1, hits + 1)", wfUtils::inet_aton($IP));
|
@@ -254,7 +255,8 @@ class wfLog {
|
|
254 |
} else if($type == 'topLeechers'){
|
255 |
$table = $this->leechTable;
|
256 |
} else {
|
257 |
-
|
|
|
258 |
}
|
259 |
$res = $this->getDB()->query("select IP, sum(hits) as totalHits from $table where eMin > ((unix_timestamp() - 86400) / 60) group by IP order by totalHits desc limit 20");
|
260 |
$results = array();
|
@@ -313,7 +315,8 @@ class wfLog {
|
|
313 |
} else if($type == 'ruser'){
|
314 |
$typeSQL = " and userID > 0 ";
|
315 |
} else {
|
316 |
-
|
|
|
317 |
}
|
318 |
|
319 |
$r1 = $this->getDB()->query("select * from " . $this->hitsTable . " where ctime > %f $IPSQL $typeSQL order by ctime desc limit %s",
|
@@ -328,7 +331,8 @@ class wfLog {
|
|
328 |
);
|
329 |
|
330 |
} else {
|
331 |
-
|
|
|
332 |
}
|
333 |
$results = array();
|
334 |
while($res = mysql_fetch_assoc($r1)){
|
55 |
} else if($type == 'hit'){
|
56 |
$table = $this->leechTable;
|
57 |
} else {
|
58 |
+
wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
|
59 |
+
return;
|
60 |
}
|
61 |
$IP = wfUtils::getIP();
|
62 |
$this->getDB()->query("insert into $table (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfcurrenthits := hits + 1, hits + 1, hits + 1)", wfUtils::inet_aton($IP));
|
255 |
} else if($type == 'topLeechers'){
|
256 |
$table = $this->leechTable;
|
257 |
} else {
|
258 |
+
wordfence::status(1, 'error', "Invalid type to getLeechers(): $type");
|
259 |
+
return false;
|
260 |
}
|
261 |
$res = $this->getDB()->query("select IP, sum(hits) as totalHits from $table where eMin > ((unix_timestamp() - 86400) / 60) group by IP order by totalHits desc limit 20");
|
262 |
$results = array();
|
315 |
} else if($type == 'ruser'){
|
316 |
$typeSQL = " and userID > 0 ";
|
317 |
} else {
|
318 |
+
wordfence::status(1, 'error', "Invalid log type to wfLog: $type");
|
319 |
+
return false;
|
320 |
}
|
321 |
|
322 |
$r1 = $this->getDB()->query("select * from " . $this->hitsTable . " where ctime > %f $IPSQL $typeSQL order by ctime desc limit %s",
|
331 |
);
|
332 |
|
333 |
} else {
|
334 |
+
wordfence::status(1, 'error', "getHits got invalid hitType: $hitType");
|
335 |
+
return false;
|
336 |
}
|
337 |
$results = array();
|
338 |
while($res = mysql_fetch_assoc($r1)){
|
lib/wfScanEngine.php
CHANGED
@@ -89,9 +89,10 @@ class wfScanEngine {
|
|
89 |
}
|
90 |
}
|
91 |
public function fork(){
|
92 |
-
wfConfig::set_ser('wfsd_engine', $this, true)
|
93 |
-
|
94 |
-
|
|
|
95 |
exit(0);
|
96 |
}
|
97 |
public function emailNewIssues(){
|
@@ -625,13 +626,15 @@ class wfScanEngine {
|
|
625 |
}
|
626 |
private function scan_diskSpace(){
|
627 |
$this->statusIDX['diskSpace'] = wordfence::statusStart("Scanning to check available disk space");
|
628 |
-
|
629 |
-
$
|
630 |
-
$
|
|
|
631 |
if( (! $total) || (! $free )){ //If we get zeros it's probably not reading right. If free is zero then we're out of space and already in trouble.
|
632 |
wordfence::statusEnd($this->statusIDX['diskSpace'], false);
|
633 |
return;
|
634 |
}
|
|
|
635 |
$level = false;
|
636 |
$spaceLeft = sprintf('%.2f', ($free / $total * 100));
|
637 |
$this->status(2, 'info', "The disk has $spaceLeft percent space available");
|
89 |
}
|
90 |
}
|
91 |
public function fork(){
|
92 |
+
if(wfConfig::set_ser('wfsd_engine', $this, true)){
|
93 |
+
wfUtils::clearScanLock();
|
94 |
+
self::startScan(true);
|
95 |
+
} //Otherwise there was an error so don't start another scan.
|
96 |
exit(0);
|
97 |
}
|
98 |
public function emailNewIssues(){
|
626 |
}
|
627 |
private function scan_diskSpace(){
|
628 |
$this->statusIDX['diskSpace'] = wordfence::statusStart("Scanning to check available disk space");
|
629 |
+
wfUtils::errorsOff();
|
630 |
+
$total = @disk_total_space('.');
|
631 |
+
$free = @disk_free_space('.');
|
632 |
+
wfUtils::errorsOn();
|
633 |
if( (! $total) || (! $free )){ //If we get zeros it's probably not reading right. If free is zero then we're out of space and already in trouble.
|
634 |
wordfence::statusEnd($this->statusIDX['diskSpace'], false);
|
635 |
return;
|
636 |
}
|
637 |
+
$this->status(2, 'info', "Total disk space: " . sprintf('%.4f', ($total / 1024 / 1024 / 1024)) . "GB -- Free disk space: " . sprintf('%.4f', ($free / 1024 / 1024 / 1024)) . "GB");
|
638 |
$level = false;
|
639 |
$spaceLeft = sprintf('%.2f', ($free / $total * 100));
|
640 |
$this->status(2, 'info', "The disk has $spaceLeft percent space available");
|
lib/wfSchema.php
CHANGED
@@ -157,9 +157,9 @@ class wfSchema {
|
|
157 |
$this->prefix = $wpdb->base_prefix;
|
158 |
}
|
159 |
}
|
160 |
-
public function dropAll(
|
161 |
foreach($this->tables as $table => $def){
|
162 |
-
$this->db->query("drop table if exists " . $prefix . $table);
|
163 |
}
|
164 |
}
|
165 |
public function createAll(){
|
157 |
$this->prefix = $wpdb->base_prefix;
|
158 |
}
|
159 |
}
|
160 |
+
public function dropAll(){
|
161 |
foreach($this->tables as $table => $def){
|
162 |
+
$this->db->query("drop table if exists " . $this->prefix . $table);
|
163 |
}
|
164 |
}
|
165 |
public function createAll(){
|
lib/wfUtils.php
CHANGED
@@ -3,6 +3,8 @@ require_once('wfConfig.php');
|
|
3 |
class wfUtils {
|
4 |
private static $isWindows = false;
|
5 |
public static $scanLockFH = false;
|
|
|
|
|
6 |
public static function makeTimeAgo($secs, $noSeconds = false) {
|
7 |
if($secs < 1){
|
8 |
return "a moment";
|
@@ -72,27 +74,41 @@ class wfUtils {
|
|
72 |
//return ABSPATH . 'wp-content/plugins/';
|
73 |
}
|
74 |
public static function getIP(){
|
75 |
-
$
|
76 |
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
|
77 |
-
$
|
78 |
}
|
79 |
-
if((! $
|
80 |
-
$
|
81 |
}
|
82 |
-
if(preg_match('/,/', $
|
83 |
-
$parts = explode(',', $
|
84 |
-
$
|
85 |
}
|
86 |
-
if(preg_match('/:\d+$/', $
|
87 |
-
$
|
88 |
}
|
89 |
-
if(self::isValidIP($
|
90 |
-
return $
|
91 |
} else {
|
92 |
-
$msg = "Wordfence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
wordfence::status(1, 'error', $msg);
|
94 |
error_log($msg);
|
95 |
-
|
96 |
}
|
97 |
}
|
98 |
public static function isValidIP($IP){
|
@@ -115,11 +131,6 @@ class wfUtils {
|
|
115 |
public static function editUserLink($userID){
|
116 |
return get_admin_url() . 'user-edit.php?user_id=' . $userID;
|
117 |
}
|
118 |
-
public static function wdie($err){
|
119 |
-
$trace=debug_backtrace(); $caller=array_shift($trace);
|
120 |
-
error_log("Wordfence error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
121 |
-
exit();
|
122 |
-
}
|
123 |
public static function tmpl($file, $data){
|
124 |
extract($data);
|
125 |
ob_start();
|
@@ -132,8 +143,8 @@ class wfUtils {
|
|
132 |
public static function encrypt($str){
|
133 |
$key = wfConfig::get('encKey');
|
134 |
if(! $key){
|
135 |
-
|
136 |
-
|
137 |
}
|
138 |
$db = new wfDB();
|
139 |
return $db->querySingle("select HEX(AES_ENCRYPT('%s', '%s')) as val", $str, $key);
|
@@ -141,8 +152,8 @@ class wfUtils {
|
|
141 |
public static function decrypt($str){
|
142 |
$key = wfConfig::get('encKey');
|
143 |
if(! $key){
|
144 |
-
|
145 |
-
|
146 |
}
|
147 |
$db = new wfDB();
|
148 |
return $db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val", $str, $key);
|
@@ -362,6 +373,18 @@ class wfUtils {
|
|
362 |
return $host;
|
363 |
}
|
364 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
}
|
366 |
|
367 |
|
3 |
class wfUtils {
|
4 |
private static $isWindows = false;
|
5 |
public static $scanLockFH = false;
|
6 |
+
private static $lastErrorReporting = false;
|
7 |
+
private static $lastDisplayErrors = false;
|
8 |
public static function makeTimeAgo($secs, $noSeconds = false) {
|
9 |
if($secs < 1){
|
10 |
return "a moment";
|
74 |
//return ABSPATH . 'wp-content/plugins/';
|
75 |
}
|
76 |
public static function getIP(){
|
77 |
+
$IP = 0;
|
78 |
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
|
79 |
+
$IP = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
80 |
}
|
81 |
+
if((! preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $IP)) && isset($_SERVER['REMOTE_ADDR'])){
|
82 |
+
$IP = $_SERVER['REMOTE_ADDR'];
|
83 |
}
|
84 |
+
if(preg_match('/,/', $IP)){
|
85 |
+
$parts = explode(',', $IP);
|
86 |
+
$IP = trim($parts[0]);
|
87 |
}
|
88 |
+
if(preg_match('/:\d+$/', $IP)){
|
89 |
+
$IP = preg_replace('/:\d+$/', '', $IP);
|
90 |
}
|
91 |
+
if(self::isValidIP($IP)){
|
92 |
+
return $IP;
|
93 |
} else {
|
94 |
+
$msg = "Wordfence can't get the IP of clients and therefore can't operate. We received IP: $IP. X-Forwarded-For was: " . $_SERVER['HTTP_X_FORWARDED_FOR'] . " REMOTE_ADDR was: " . $_SERVER['REMOTE_ADDR'];
|
95 |
+
$possible = array();
|
96 |
+
foreach($_SERVER as $key => $val){
|
97 |
+
if(preg_match('/^\d+\.\d+\.\d+\.\d+/', $val) && strlen($val) < 255){
|
98 |
+
if($val != '127.0.0.1'){
|
99 |
+
$possible[$key] = $val;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
}
|
103 |
+
if(sizeof($possible) > 0){
|
104 |
+
$msg .= " Report the following on the Wordfence forums and they may be able to help. Headers that may contain the client IP: ";
|
105 |
+
foreach($possible as $key => $val){
|
106 |
+
$msg .= "$key => $val ";
|
107 |
+
}
|
108 |
+
}
|
109 |
wordfence::status(1, 'error', $msg);
|
110 |
error_log($msg);
|
111 |
+
return false;
|
112 |
}
|
113 |
}
|
114 |
public static function isValidIP($IP){
|
131 |
public static function editUserLink($userID){
|
132 |
return get_admin_url() . 'user-edit.php?user_id=' . $userID;
|
133 |
}
|
|
|
|
|
|
|
|
|
|
|
134 |
public static function tmpl($file, $data){
|
135 |
extract($data);
|
136 |
ob_start();
|
143 |
public static function encrypt($str){
|
144 |
$key = wfConfig::get('encKey');
|
145 |
if(! $key){
|
146 |
+
wordfence::status(1, 'error', "Wordfence error: No encryption key found!");
|
147 |
+
return false;
|
148 |
}
|
149 |
$db = new wfDB();
|
150 |
return $db->querySingle("select HEX(AES_ENCRYPT('%s', '%s')) as val", $str, $key);
|
152 |
public static function decrypt($str){
|
153 |
$key = wfConfig::get('encKey');
|
154 |
if(! $key){
|
155 |
+
wordfence::status(1, 'error', "Wordfence error: No encryption key found!");
|
156 |
+
return false;
|
157 |
}
|
158 |
$db = new wfDB();
|
159 |
return $db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val", $str, $key);
|
373 |
return $host;
|
374 |
}
|
375 |
}
|
376 |
+
public static function errorsOff(){
|
377 |
+
self::$lastErrorReporting = @ini_get('error_reporting');
|
378 |
+
@error_reporting(0);
|
379 |
+
self::$lastDisplayErrors = @ini_get('display_errors');
|
380 |
+
@ini_set('display_errors', 0);
|
381 |
+
if(class_exists('wfScan')){ wfScan::$errorHandlingOn = false; }
|
382 |
+
}
|
383 |
+
public static function errorsOn(){
|
384 |
+
@error_reporting(self::$lastErrorReporting);
|
385 |
+
@ini_set('display_errors', self::$lastDisplayErrors);
|
386 |
+
if(class_exists('wfScan')){ wfScan::$errorHandlingOn = true; }
|
387 |
+
}
|
388 |
}
|
389 |
|
390 |
|
lib/wordfenceClass.php
CHANGED
@@ -34,6 +34,11 @@ class wordfence {
|
|
34 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
35 |
wp_clear_scheduled_hook('wordfence_hourly_cron');
|
36 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
|
|
|
|
|
|
|
|
|
|
37 |
}
|
38 |
public static function hourlyCron(){
|
39 |
global $wpdb; $p = $wpdb->base_prefix;
|
@@ -187,7 +192,7 @@ class wordfence {
|
|
187 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
188 |
$db->queryIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
|
189 |
$db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
|
190 |
-
|
191 |
//Must be the final line
|
192 |
update_option('wordfence_version', WORDFENCE_VERSION);
|
193 |
}
|
@@ -202,12 +207,6 @@ class wordfence {
|
|
202 |
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?!)
|
203 |
}
|
204 |
|
205 |
-
//Upgrading from 2.0.3 we changed isPaid from 'free' or 'paid' to true and false
|
206 |
-
if(wfConfig::get('isPaid') == 'free'){
|
207 |
-
wfConfig::set('isPaid', '');
|
208 |
-
}
|
209 |
-
//end
|
210 |
-
|
211 |
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
|
212 |
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
|
213 |
add_action('plugins_loaded', 'wordfence::veryFirstAction');
|
34 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
35 |
wp_clear_scheduled_hook('wordfence_hourly_cron');
|
36 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
37 |
+
$schema = new wfSchema();
|
38 |
+
$schema->dropAll();
|
39 |
+
foreach(array('wordfence_version', 'wordfenceActivated') as $opt){
|
40 |
+
delete_option($opt);
|
41 |
+
}
|
42 |
}
|
43 |
public static function hourlyCron(){
|
44 |
global $wpdb; $p = $wpdb->base_prefix;
|
192 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
193 |
$db->queryIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
|
194 |
$db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
|
195 |
+
|
196 |
//Must be the final line
|
197 |
update_option('wordfence_version', WORDFENCE_VERSION);
|
198 |
}
|
207 |
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?!)
|
208 |
}
|
209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
|
211 |
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
|
212 |
add_action('plugins_loaded', 'wordfence::veryFirstAction');
|
lib/wordfenceHash.php
CHANGED
@@ -26,7 +26,7 @@ class wordfenceHash {
|
|
26 |
$path .= '/';
|
27 |
}
|
28 |
if(! is_readable($path)){
|
29 |
-
wordfence::status(1, 'error', "Could not read directory $path to do
|
30 |
exit();
|
31 |
}
|
32 |
$files = scandir($path);
|
26 |
$path .= '/';
|
27 |
}
|
28 |
if(! is_readable($path)){
|
29 |
+
wordfence::status(1, 'error', "Could not read directory $path to do scan.");
|
30 |
exit();
|
31 |
}
|
32 |
$files = scandir($path);
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
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.
|
6 |
-
Stable tag: 2.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,25 @@ 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 |
= 2.1.4 =
|
156 |
* Fixed registered users not appearing in live traffic.
|
157 |
* Fixed temp file deletion bug that caused warnings and loops.
|
2 |
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
|
6 |
+
Stable tag: 2.1.5
|
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 |
+
= 2.1.5 =
|
156 |
+
* Fixed bug that caused WF to not work when certain DB caching plugins are used and override wpdb object.
|
157 |
+
* Fixed Wordfence so activity log only shows our own errors unless in debug mode.
|
158 |
+
* Wordfence now deletes all it's tables and deletes all saved options when you deactivate the plugin.
|
159 |
+
* Removed all exit() on error statements. Critical errors are handled more gracefully by writing to the log instead.
|
160 |
+
* Fixed a bug that would cause a database loop until running out of memory under certain error conditions.
|
161 |
+
* Suppressed useless warnings that occur in environments with basedir set or where functions are disabled for security reasons.
|
162 |
+
* Removed redundant check that executed on every request and put it in activation instead.
|
163 |
+
* If serialization during scan breaks, exit gracefully instead of looping.
|
164 |
+
* Disk space in log is now shown as Gigabytes and formatted nicely.
|
165 |
+
* Removed wdie() function which is a little obnoxious. Writing to WF error log instead.
|
166 |
+
* Fixed bug where a non-empty but useless HTTP header can break getIP() function.
|
167 |
+
* Added useful data to error output if getIP() tells you it can't work on your system.
|
168 |
+
* Removed option to start scan in debug because it's no longer possible with a forked scan.
|
169 |
+
* Removed option to test process running time on a system because it breaks on most systems and confuses customers.
|
170 |
+
* Database connection errors no longer call die() but log an error instead in a way that removes the risk of a logging loop.
|
171 |
+
* Removed dropAll.php script because we now clean up tables on deactivate and it's not needed.
|
172 |
+
* Updated readme to show that we support 3.4.
|
173 |
+
|
174 |
= 2.1.4 =
|
175 |
* Fixed registered users not appearing in live traffic.
|
176 |
* Fixed temp file deletion bug that caused warnings and loops.
|
wfscan.php
CHANGED
@@ -23,6 +23,7 @@ require_once('lib/wfScanEngine.php');
|
|
23 |
|
24 |
class wfScan {
|
25 |
public static $debugMode = false;
|
|
|
26 |
public static function wfScanMain(){
|
27 |
$db = new wfDB();
|
28 |
if($db->errorMsg){
|
@@ -112,7 +113,14 @@ class wfScan {
|
|
112 |
}
|
113 |
}
|
114 |
public static function error_handler($errno, $errstr, $errfile, $errline){
|
115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
}
|
117 |
public static function shutdown(){
|
118 |
wfUtils::clearScanLock();
|
23 |
|
24 |
class wfScan {
|
25 |
public static $debugMode = false;
|
26 |
+
public static $errorHandlingOn = true;
|
27 |
public static function wfScanMain(){
|
28 |
$db = new wfDB();
|
29 |
if($db->errorMsg){
|
113 |
}
|
114 |
}
|
115 |
public static function error_handler($errno, $errstr, $errfile, $errline){
|
116 |
+
if(self::$errorHandlingOn){
|
117 |
+
if(preg_match('/wordfence\//', $errfile)){
|
118 |
+
$level = 1; //It's one of our files, so level 1
|
119 |
+
} else {
|
120 |
+
$level = 4; //It's someone elses plugin so only show if debug is enabled
|
121 |
+
}
|
122 |
+
wordfence::status($level, 'error', "$errstr ($errno) File: $errfile Line: $errline");
|
123 |
+
}
|
124 |
}
|
125 |
public static function shutdown(){
|
126 |
wfUtils::clearScanLock();
|
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: 2.1.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '2.1.
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
require_once('lib/wordfenceConstants.php');
|
13 |
require_once('lib/wordfenceClass.php');
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 2.1.5
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '2.1.5');
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
require_once('lib/wordfenceConstants.php');
|
13 |
require_once('lib/wordfenceClass.php');
|