Wordfence Security – Firewall & Malware Scan - Version 3.1.1

Version Description

  • Added another fix for "mysql server has gone away" error. Wordfence now makes sure the DB is still connected and reconnects if not.
  • Added new detection for encoded malicious code in files.
  • Fixed bug introduced yesterday that prevented permanent blocking of IP's.
  • Improved ability to detect if we're running on Windows (but we don't support Windows yet).
  • Issue intelligent warning if Wordfence can't read base WordPress directory.
  • Don't activate Wordfence if user is running Windows.
  • Cleaned up errors if a file can't be scanned due to permission restrictions.
  • Improved reporting of which user scan is running as and how we determined who the admin user is.
Download this release

Release Info

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

Code changes from version 3.1.0 to 3.1.1

lib/wfDB.php CHANGED
@@ -6,8 +6,10 @@ class wfDB {
6
private $dbpassword = false;
7
private $dbname = false;
8
private $dbuser = false;
9
public $errorMsg = false;
10
public function __construct($createNewHandle = false, $dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
11
if($dbhost && $dbuser && $dbpassword && $dbname){
12
$this->dbhost = $dbhost;
13
$this->dbuser = $dbuser;
@@ -37,14 +39,23 @@ class wfDB {
37
}
38
}
39
}
40
//We tried reusing wpdb but got disconnection errors from many users.
41
- $handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
42
- if( (! $createNewHandle) && isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey]) ){
43
$this->dbh = self::$dbhCache[$handleKey];
44
} else {
45
- $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
46
mysql_select_db($this->dbname, $dbh);
47
- if($createNewHandle){
48
$this->dbh = $dbh;
49
} else {
50
self::$dbhCache[$handleKey] = $dbh;
@@ -56,7 +67,13 @@ class wfDB {
56
$this->queryIgnoreError("SET @@wait_timeout=30800"); //Changing to session setting bc user may not have super privilege
57
}
58
}
59
public function querySingleRec(){
60
$this->errorMsg = false;
61
$args = func_get_args();
62
if(sizeof($args) == 1){
@@ -81,6 +98,7 @@ class wfDB {
81
$msg = "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err";
82
global $wpdb;
83
$statusTable = $wpdb->base_prefix . 'wfStatus';
84
mysql_query(sprintf("insert into " . $statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')",
85
mysql_real_escape_string(sprintf('%.6f', microtime(true))),
86
mysql_real_escape_string(1),
@@ -91,6 +109,7 @@ class wfDB {
91
}
92
}
93
public function querySingle(){
94
$this->errorMsg = false;
95
$args = func_get_args();
96
if(sizeof($args) == 1){
@@ -113,6 +132,7 @@ class wfDB {
113
return $row[0];
114
}
115
public function query(){ //sprintfString, arguments
116
$this->errorMsg = false;
117
$args = func_get_args();
118
$isStatusQuery = false;
@@ -136,6 +156,7 @@ class wfDB {
136
return $res;
137
}
138
public function queryIgnoreError(){ //sprintfString, arguments
139
$this->errorMsg = false;
140
$args = func_get_args();
141
if(sizeof($args) == 1){
6
private $dbpassword = false;
7
private $dbname = false;
8
private $dbuser = false;
9
+ private $createNewHandle = false;
10
public $errorMsg = false;
11
public function __construct($createNewHandle = false, $dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
12
+ $this->createNewHandle = $createNewHandle;
13
if($dbhost && $dbuser && $dbpassword && $dbname){
14
$this->dbhost = $dbhost;
15
$this->dbuser = $dbuser;
39
}
40
}
41
}
42
+ $this->connectHandle();
43
+ }
44
+ private function connectHandle(){
45
//We tried reusing wpdb but got disconnection errors from many users.
46
+ $handleKey = md5($this->dbhost . $this->dbuser . $this->dbpassword . $this->dbname);
47
+ //Use a cached handle if it exists and is still connected
48
+ if( (! $this->createNewHandle) && isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey]) ){
49
$this->dbh = self::$dbhCache[$handleKey];
50
} else {
51
+ //This close call is to deal with versions of mysql prior to 5.0.3 which auto-recommend when callig ping. So the conditional above may have reconnected this handle, so we disconnect it before reconnecting, if it's connected.
52
+ if(isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey])){
53
+ mysql_close(self::$dbhCache[$handleKey]);
54
+ unset(self::$dbhCache[$handleKey]);
55
+ }
56
+ $dbh = mysql_connect($this->dbhost, $this->dbuser, $this->dbpassword, true );
57
mysql_select_db($this->dbname, $dbh);
58
+ if($this->createNewHandle){
59
$this->dbh = $dbh;
60
} else {
61
self::$dbhCache[$handleKey] = $dbh;
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
+ }
74
+ }
75
public function querySingleRec(){
76
+ $this->reconnect();
77
$this->errorMsg = false;
78
$args = func_get_args();
79
if(sizeof($args) == 1){
98
$msg = "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err";
99
global $wpdb;
100
$statusTable = $wpdb->base_prefix . 'wfStatus';
101
+ $this->reconnect(); //Putting reconnect here so it doesn't mess with the mysql_error() call
102
mysql_query(sprintf("insert into " . $statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')",
103
mysql_real_escape_string(sprintf('%.6f', microtime(true))),
104
mysql_real_escape_string(1),
109
}
110
}
111
public function querySingle(){
112
+ $this->reconnect();
113
$this->errorMsg = false;
114
$args = func_get_args();
115
if(sizeof($args) == 1){
132
return $row[0];
133
}
134
public function query(){ //sprintfString, arguments
135
+ $this->reconnect();
136
$this->errorMsg = false;
137
$args = func_get_args();
138
$isStatusQuery = false;
156
return $res;
157
}
158
public function queryIgnoreError(){ //sprintfString, arguments
159
+ $this->reconnect();
160
$this->errorMsg = false;
161
$args = func_get_args();
162
if(sizeof($args) == 1){
lib/wfLog.php CHANGED
@@ -160,15 +160,28 @@ class wfLog {
160
public function blockIP($IP, $reason, $wfsn = false, $permanent = false){ //wfsn indicates it comes from Wordfence secure network
161
if($this->isWhitelisted($IP)){ return false; }
162
$wfsn = $wfsn ? 1 : 0;
163
- $permanent = $permanent ? 1 : 0;
164
- $this->getDB()->query("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, unix_timestamp(), '%s', %d, %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d",
165
- wfUtils::inet_aton($IP),
166
- $reason,
167
- $wfsn,
168
- $permanent,
169
- $reason,
170
- $wfsn
171
- );
172
return true;
173
}
174
public function lockOutIP($IP, $reason){
160
public function blockIP($IP, $reason, $wfsn = false, $permanent = false){ //wfsn indicates it comes from Wordfence secure network
161
if($this->isWhitelisted($IP)){ return false; }
162
$wfsn = $wfsn ? 1 : 0;
163
+ if($permanent){
164
+ //Insert permanent=1 or update existing perm or non-per block to be permanent
165
+ $this->getDB()->query("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, unix_timestamp(), '%s', %d, %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d, permanent=%d",
166
+ wfUtils::inet_aton($IP),
167
+ $reason,
168
+ $wfsn,
169
+ 1,
170
+ $reason,
171
+ $wfsn,
172
+ 1
173
+ );
174
+ } else {
175
+ //insert perm=0 but don't update and make perm blocks non-perm.
176
+ $this->getDB()->query("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, unix_timestamp(), '%s', %d, %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d",
177
+ wfUtils::inet_aton($IP),
178
+ $reason,
179
+ $wfsn,
180
+ 0,
181
+ $reason,
182
+ $wfsn
183
+ );
184
+ }
185
return true;
186
}
187
public function lockOutIP($IP, $reason){
lib/wfScanEngine.php CHANGED
@@ -176,6 +176,9 @@ class wfScanEngine {
176
$this->hasher = new wordfenceHash(strlen(ABSPATH));
177
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
178
$baseContents = scandir(ABSPATH);
179
$scanOutside = wfConfig::get('other_scanOutside');
180
if($scanOutside){
181
wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
176
$this->hasher = new wordfenceHash(strlen(ABSPATH));
177
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
178
$baseContents = scandir(ABSPATH);
179
+ if(! is_array($baseContents)){
180
+ throw new Exception("Wordfence could not read the contents of your base WordPress directory. This usually indicates your permissions are so strict that your web server can't read your WordPress directory.");
181
+ }
182
$scanOutside = wfConfig::get('other_scanOutside');
183
if($scanOutside){
184
wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
lib/wfUtils.php CHANGED
@@ -246,7 +246,7 @@ class wfUtils {
246
}
247
public static function isWindows(){
248
if(! self::$isWindows){
249
- if(preg_match('/^win/', PHP_OS)){
250
self::$isWindows = 'yes';
251
} else {
252
self::$isWindows = 'no';
@@ -392,7 +392,9 @@ class wfUtils {
392
if(class_exists('wfScan')){ wfScan::$errorHandlingOn = true; }
393
}
394
public static function fileTooBig($file){
395
$fh = @fopen($file, 'r');
396
if(! $fh){ return false; }
397
$offset = WORDFENCE_MAX_FILE_SIZE_TO_PROCESS + 1;
398
$tooBig = false;
246
}
247
public static function isWindows(){
248
if(! self::$isWindows){
249
+ if(preg_match('/^win/i', PHP_OS)){
250
self::$isWindows = 'yes';
251
} else {
252
self::$isWindows = 'no';
392
if(class_exists('wfScan')){ wfScan::$errorHandlingOn = true; }
393
}
394
public static function fileTooBig($file){
395
+ wfUtils::errorsOff();
396
$fh = @fopen($file, 'r');
397
+ wfUtils::errorsOn();
398
if(! $fh){ return false; }
399
$offset = WORDFENCE_MAX_FILE_SIZE_TO_PROCESS + 1;
400
$tooBig = false;
lib/wordfenceClass.php CHANGED
@@ -25,6 +25,10 @@ class wordfence {
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);
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);
lib/wordfenceHash.php CHANGED
@@ -169,7 +169,7 @@ class wordfenceHash {
169
$this->writeHashingStatus();
170
}
171
} else {
172
- wordfence::status(2, 'error', "Could not gen hash for file: $file");
173
}
174
}
175
private function sendHashPacket(){
@@ -199,7 +199,10 @@ class wordfenceHash {
199
return $this->hashStorageID;
200
}
201
public function wfHash($file){
202
$md5 = @md5_file($file, false);
203
if(! $md5){ return false; }
204
$fp = @fopen($file, "rb");
205
if(! $fp){
169
$this->writeHashingStatus();
170
}
171
} else {
172
+ wordfence::status(2, 'error', "Could not gen hash for file (probably because we don't have permission to access the file): $file");
173
}
174
}
175
private function sendHashPacket(){
199
return $this->hashStorageID;
200
}
201
public function wfHash($file){
202
+ wfUtils::errorsOff();
203
$md5 = @md5_file($file, false);
204
+ wfUtils::errorsOn();
205
+
206
if(! $md5){ return false; }
207
$fp = @fopen($file, "rb");
208
if(! $fp){
lib/wordfenceScanner.php CHANGED
@@ -135,7 +135,23 @@ class wordfenceScanner {
135
));
136
break;
137
}
138
-
139
$this->urlHoover->hoover($file, $data);
140
} else {
141
$this->urlHoover->hoover($file, $data);
@@ -170,7 +186,7 @@ class wordfenceScanner {
170
'ignoreP' => $this->path . $file,
171
'ignoreC' => md5_file($this->path . $file),
172
'shortMsg' => "File contains suspected malware URL: " . $this->path . $file,
173
- 'longMsg' => "This file contains a suspected malware URL listed on Google's list of malware sites. Wordfence decodes base64 when scanning files so the URL may not be visible if you view this file. The URL is: " . $result['URL'] . " - More info available at <a href=\"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=" . urlencode($result['URL']) . "&client=googlechrome&hl=en-US\" target=\"_blank\">Google Safe Browsing diagnostic page</a>.",
174
'data' => array(
175
'file' => $file,
176
'badURL' => $result['URL'],
@@ -225,7 +241,7 @@ class wordfenceScanner {
225
}
226
public static function containsCode($arr){
227
foreach($arr as $elem){
228
- if(preg_match('/(?:base64_decode|base64_encode|eval|if|exists|isset|close|file|implode|fopen|while|feof|fread|fclose|fsockopen|fwrite|explode|chr|gethostbyname|strstr|filemtime|time|count|trim|rand|stristr|dir|mkdir|urlencode|ord|substr|unpack|strpos|sprintf)[\r\n\s\t]*\(/i', $elem)){
229
return true;
230
}
231
}
135
));
136
break;
137
}
138
+ if(preg_match('/eval.*base'.'64_decode/i', $data)){
139
+ $this->addResult(array(
140
+ 'type' => 'file',
141
+ 'severity' => 1,
142
+ 'ignoreP' => $this->path . $file,
143
+ 'ignoreC' => $fileSum,
144
+ 'shortMsg' => "This file may contain malicious executable code",
145
+ 'longMsg' => "This file is a PHP executable file and contains an evaluation function and base"."64 decoding function on the same line. This is a common technique used by hackers to hide and execute code. If you know about this file you can choose to ignore it to exclude it from future scans.",
146
+ 'data' => array(
147
+ 'file' => $file,
148
+ 'canDiff' => false,
149
+ 'canFix' => false,
150
+ 'canDelete' => true
151
+ )
152
+ ));
153
+ break;
154
+ }
155
$this->urlHoover->hoover($file, $data);
156
} else {
157
$this->urlHoover->hoover($file, $data);
186
'ignoreP' => $this->path . $file,
187
'ignoreC' => md5_file($this->path . $file),
188
'shortMsg' => "File contains suspected malware URL: " . $this->path . $file,
189
+ 'longMsg' => "This file contains a suspected malware URL listed on Google's list of malware sites. Wordfence decodes base"."64 when scanning files so the URL may not be visible if you view this file. The URL is: " . $result['URL'] . " - More info available at <a href=\"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=" . urlencode($result['URL']) . "&client=googlechrome&hl=en-US\" target=\"_blank\">Google Safe Browsing diagnostic page</a>.",
190
'data' => array(
191
'file' => $file,
192
'badURL' => $result['URL'],
241
}
242
public static function containsCode($arr){
243
foreach($arr as $elem){
244
+ if(preg_match('/(?:base'.'64_decode|base'.'64_encode|eval|if|exists|isset|close|file|implode|fopen|while|feof|fread|fclose|fsockopen|fwrite|explode|chr|gethostbyname|strstr|filemtime|time|count|trim|rand|stristr|dir|mkdir|urlencode|ord|substr|unpack|strpos|sprintf)[\r\n\s\t]*\(/i', $elem)){
245
return true;
246
}
247
}
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.0
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,16 @@ 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.0 =
156
* Changed the way we monitor disk space from % to warning on 20 megs and critical on 5 megs remaining. This deals with very large disks in a more rational way. (Thanks Yael M. and Ola A.)
157
* We now deal with cases where the $_SERVER variable contains an array instead of string for IP address. It seems that some installations modify the value into an array. (Thanks S.S.)
@@ -468,6 +478,9 @@ or a theme, because often these have been updated to fix a security hole.
468
* Initial public release of Wordfence.
469
470
== Upgrade Notice ==
471
= 3.0.9 =
472
Upgrade immediately. Fixes two critical bugs: Could not get admin ID bug and permanent IP blocks not staying permanent.
473
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
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.
158
+ * Fixed bug introduced yesterday that prevented permanent blocking of IP's.
159
+ * Improved ability to detect if we're running on Windows (but we don't support Windows yet).
160
+ * Issue intelligent warning if Wordfence can't read base WordPress directory.
161
+ * Don't activate Wordfence if user is running Windows.
162
+ * Cleaned up errors if a file can't be scanned due to permission restrictions.
163
+ * Improved reporting of which user scan is running as and how we determined who the admin user is.
164
+
165
= 3.1.0 =
166
* Changed the way we monitor disk space from % to warning on 20 megs and critical on 5 megs remaining. This deals with very large disks in a more rational way. (Thanks Yael M. and Ola A.)
167
* We now deal with cases where the $_SERVER variable contains an array instead of string for IP address. It seems that some installations modify the value into an array. (Thanks S.S.)
478
* Initial public release of Wordfence.
479
480
== Upgrade Notice ==
481
+ = 3.1.1 =
482
+ Upgrade immediately. Fixes bug introduced in last release that broke permenent IP blocking.
483
+
484
= 3.0.9 =
485
Upgrade immediately. Fixes two critical bugs: Could not get admin ID bug and permanent IP blocks not staying permanent.
486
wfscan.php CHANGED
@@ -152,10 +152,13 @@ class wfScan {
152
$db = new wfDB();
153
global $wpdb;
154
$adminUserID = false;
155
if(is_multisite()){
156
$users = get_users('role=super&fields=ID');
157
} else {
158
$users = get_users('role=administrator&fields=ID');
159
}
160
if(sizeof($users) > 1){
161
sort($users, SORT_NUMERIC);
@@ -167,12 +170,13 @@ class wfScan {
167
self::status(1, 'error', "Could not get the administrator's user ID. Scan can't continue.");
168
exit();
169
}
170
}
171
- $adminUsername = $db->querySingle("select user_nicename from " . $wpdb->users . " where ID=%d", $adminUserID);
172
- self::status(4, 'info', "Scan will run as admin user '$adminUsername' with ID '$adminUserID'");
173
wp_set_current_user($adminUserID);
174
if(! is_user_logged_in()){
175
- self::status(1, 'error', "Scan could not sign in as user '$adminUsername' with ID '$adminUserID'. Scan can't continue.");
176
exit();
177
}
178
self::status(4, 'info', "Scan authentication complete.");
152
$db = new wfDB();
153
global $wpdb;
154
$adminUserID = false;
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);
170
self::status(1, 'error', "Could not get the administrator's user ID. Scan can't continue.");
171
exit();
172
}
173
+ $userSource = 'manual DB query';
174
}
175
+ $adminUsername = $db->querySingle("select user_login from " . $wpdb->users . " where ID=%d", $adminUserID);
176
+ self::status(4, 'info', "Scan will run as admin user '$adminUsername' with ID '$adminUserID' sourced from: $userSource");
177
wp_set_current_user($adminUserID);
178
if(! is_user_logged_in()){
179
+ self::status(1, 'error', "Scan could not sign in as user '$adminUsername' with ID '$adminUserID' from source '$userSource'. Scan can't continue.");
180
exit();
181
}
182
self::status(4, 'info', "Scan authentication complete.");
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.0
8
Author URI: http://wordfence.com/
9
*/
10
- define('WORDFENCE_VERSION', '3.1.0');
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.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.