Wordfence Security – Firewall & Malware Scan - Version 1.3.2

Version Description

  • Reduced the number of database connections that Wordfence makes to one.
  • Modified the memory efficient unbuffered queries we use to only use a single DB connection.
  • Removed status updates during post and comment scans which prevents interference with unbuffered queries and makes the scans even faster.
Download this release

Release Info

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

Code changes from version 1.3.1 to 1.3.2

Files changed (5) hide show
  1. lib/wfDB.php +21 -16
  2. lib/wfScanEngine.php +2 -3
  3. lib/wfSchema.php +1 -1
  4. readme.txt +6 -1
  5. wordfence.php +1 -1
lib/wfDB.php CHANGED
@@ -1,11 +1,12 @@
1
<?php
2
class wfDB {
3
private $dbh = false;
4
private $dbhost = false;
5
private $dbpassword = false;
6
private $dbname = false;
7
private $dbuser = false;
8
- public function __construct($dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
9
if($dbhost && $dbuser && $dbpassword && $dbname){
10
$this->dbhost = $dbhost;
11
$this->dbuser = $dbuser;
@@ -19,7 +20,20 @@ class wfDB {
19
$this->dbpassword = $wpdb->dbpassword;
20
$this->dbname = $wpdb->dbname;
21
}
22
- $this->getDBH(); //or mysql_real_escape_string won't work
23
}
24
public function querySingleRec(){
25
$args = func_get_args();
@@ -30,7 +44,7 @@ class wfDB {
30
} else {
31
wfdie("No arguments passed to querySingle()");
32
}
33
- $res = mysql_query($query, $this->getDBH());
34
$err = mysql_error();
35
if($err){
36
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
@@ -49,7 +63,7 @@ class wfDB {
49
} else {
50
wfdie("No arguments passed to querySingle()");
51
}
52
- $res = mysql_query($query, $this->getDBH());
53
$err = mysql_error();
54
if($err){
55
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
@@ -73,14 +87,14 @@ class wfDB {
73
} else {
74
wfdie("No arguments passed to query()");
75
}
76
- $res = mysql_query($query, $this->getDBH());
77
$err = mysql_error();
78
if($err){
79
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
80
}
81
return $res;
82
}
83
- public function uQuery(){ //sprintfString, arguments
84
$args = func_get_args();
85
if(sizeof($args) == 1){
86
$query = $args[0];
@@ -92,22 +106,13 @@ class wfDB {
92
} else {
93
wfdie("No arguments passed to query()");
94
}
95
- $res = mysql_unbuffered_query($query, $this->getDBH());
96
$err = mysql_error();
97
if($err){
98
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
99
}
100
return $res;
101
}
102
- private function getDBH(){
103
- if($this->dbh){
104
- return $this->dbh;
105
- }
106
- $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
107
- mysql_select_db($this->dbname, $dbh);
108
- $this->dbh = $dbh;
109
- return $dbh;
110
- }
111
private function wfdie($msg){
112
error_log($msg);
113
exit(1);
1
<?php
2
class wfDB {
3
private $dbh = false;
4
+ private static $dbhCache = false;
5
private $dbhost = false;
6
private $dbpassword = false;
7
private $dbname = false;
8
private $dbuser = false;
9
+ public function __construct($createNewHandle = false, $dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
10
if($dbhost && $dbuser && $dbpassword && $dbname){
11
$this->dbhost = $dbhost;
12
$this->dbuser = $dbuser;
20
$this->dbpassword = $wpdb->dbpassword;
21
$this->dbname = $wpdb->dbname;
22
}
23
+ if($createNewHandle){
24
+ $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
25
+ mysql_select_db($this->dbname, $dbh);
26
+ $this->dbh = $dbh;
27
+ } else {
28
+ if(self::$dbhCache){
29
+ $this->dbh = self::$dbhCache;
30
+ } else {
31
+ $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
32
+ mysql_select_db($this->dbname, $dbh);
33
+ self::$dbhCache = $dbh;
34
+ $this->dbh = self::$dbhCache;
35
+ }
36
+ }
37
}
38
public function querySingleRec(){
39
$args = func_get_args();
44
} else {
45
wfdie("No arguments passed to querySingle()");
46
}
47
+ $res = mysql_query($query, $this->dbh);
48
$err = mysql_error();
49
if($err){
50
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
63
} else {
64
wfdie("No arguments passed to querySingle()");
65
}
66
+ $res = mysql_query($query, $this->dbh);
67
$err = mysql_error();
68
if($err){
69
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
87
} else {
88
wfdie("No arguments passed to query()");
89
}
90
+ $res = mysql_query($query, $this->dbh);
91
$err = mysql_error();
92
if($err){
93
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
94
}
95
return $res;
96
}
97
+ public function uQuery(){ //sprintfString, arguments NOTE: Very important that there is no other DB activity between uQuery and when you call mysql_free_result on the return value of uQuery.
98
$args = func_get_args();
99
if(sizeof($args) == 1){
100
$query = $args[0];
106
} else {
107
wfdie("No arguments passed to query()");
108
}
109
+ $res = mysql_unbuffered_query($query, $this->dbh);
110
$err = mysql_error();
111
if($err){
112
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
113
}
114
return $res;
115
}
116
private function wfdie($msg){
117
error_log($msg);
118
exit(1);
lib/wfScanEngine.php CHANGED
@@ -282,13 +282,12 @@ class wfScanEngine {
282
$this->status(1, 'info', "Starting posts scan");
283
global $wpdb;
284
$wfdb = new wfDB();
285
$q1 = $wfdb->uQuery("select ID, post_title, post_type, post_date, post_content from $wpdb->posts where post_type IN ('page', 'post') and post_status = 'publish'");
286
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
287
$postDat = array();
288
while($row = mysql_fetch_assoc($q1)){
289
- $this->status(2, 'info', "Scanning " . $row['post_type'] . ": \"" . $row['post_title'] . "\"");
290
$h->hoover($row['ID'], $row['post_title'] . ' ' . $row['post_content']);
291
-
292
$postDat[$row['ID']] = array(
293
'contentMD5' => md5($row['post_content']),
294
'title' => $row['post_title'],
@@ -372,6 +371,7 @@ class wfScanEngine {
372
private function scanComments(){
373
global $wpdb;
374
$wfdb = new wfDB();
375
$q1 = $wfdb->uQuery("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_approved=1");
376
if( ! $q1){
377
return;
@@ -381,7 +381,6 @@ class wfScanEngine {
381
$gotRow = false;
382
while($row = mysql_fetch_assoc($q1)){
383
$gotRow = true; //because we can't use mysql_num_rows on unbuffered queries
384
- $this->status(2, 'info', "Scanning comment ID " . $row['comment_ID'] . " with author " . $row['comment_author']);
385
$h->hoover($row['comment_ID'], $row['comment_author_url'] . ' ' . $row['comment_author'] . ' ' . $row['comment_content']);
386
$commentDat[$row['comment_ID']] = array(
387
'contentMD5' => md5($row['comment_content'] . $row['comment_author'] . $row['comment_author_url']),
282
$this->status(1, 'info', "Starting posts scan");
283
global $wpdb;
284
$wfdb = new wfDB();
285
+ //NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
286
$q1 = $wfdb->uQuery("select ID, post_title, post_type, post_date, post_content from $wpdb->posts where post_type IN ('page', 'post') and post_status = 'publish'");
287
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
288
$postDat = array();
289
while($row = mysql_fetch_assoc($q1)){
290
$h->hoover($row['ID'], $row['post_title'] . ' ' . $row['post_content']);
291
$postDat[$row['ID']] = array(
292
'contentMD5' => md5($row['post_content']),
293
'title' => $row['post_title'],
371
private function scanComments(){
372
global $wpdb;
373
$wfdb = new wfDB();
374
+ //NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
375
$q1 = $wfdb->uQuery("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_approved=1");
376
if( ! $q1){
377
return;
381
$gotRow = false;
382
while($row = mysql_fetch_assoc($q1)){
383
$gotRow = true; //because we can't use mysql_num_rows on unbuffered queries
384
$h->hoover($row['comment_ID'], $row['comment_author_url'] . ' ' . $row['comment_author'] . ' ' . $row['comment_content']);
385
$commentDat[$row['comment_ID']] = array(
386
'contentMD5' => md5($row['comment_content'] . $row['comment_author'] . $row['comment_author_url']),
lib/wfSchema.php CHANGED
@@ -139,7 +139,7 @@ class wfSchema {
139
private $prefix = 'wp_';
140
public function __construct($dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
141
if($dbhost){ //for testing
142
- $this->db = new wfDB($dbhost, $dbuser, $dbpassword, $dbname);
143
$this->prefix = 'wp_';
144
} else {
145
global $wpdb;
139
private $prefix = 'wp_';
140
public function __construct($dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
141
if($dbhost){ //for testing
142
+ $this->db = new wfDB(false, $dbhost, $dbuser, $dbpassword, $dbname);
143
$this->prefix = 'wp_';
144
} else {
145
global $wpdb;
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
Tags: anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence
4
Requires at least: 3.3.1
5
Tested up to: 3.3.2
6
- Stable tag: 1.3.1
7
8
Wordfence is an enterprise firewall and anti-virus plugin for WordPress.
9
@@ -89,6 +89,11 @@ Yes! Simply visit the Options page, click on advanced options and enable or disa
89
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
90
91
== Changelog ==
92
= 1.3.1 =
93
* Fixed a bug where if you have the plugin "secure-wordpress" installed, you can't do a Wordfence scan because it says you have the wrong version. This is because secure-wordpress trashes the $wp_version global variable to hide your version rather than using the filters provided by WordPress. So coded a workaround so that your Wordfence scans will work with that plugin installed.
94
3
Tags: anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence
4
Requires at least: 3.3.1
5
Tested up to: 3.3.2
6
+ Stable tag: 1.3.2
7
8
Wordfence is an enterprise firewall and anti-virus plugin for WordPress.
9
89
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
90
91
== Changelog ==
92
+ = 1.3.2 =
93
+ * Reduced the number of database connections that Wordfence makes to one.
94
+ * Modified the memory efficient unbuffered queries we use to only use a single DB connection.
95
+ * Removed status updates during post and comment scans which prevents interference with unbuffered queries and makes the scans even faster.
96
+
97
= 1.3.1 =
98
* Fixed a bug where if you have the plugin "secure-wordpress" installed, you can't do a Wordfence scan because it says you have the wrong version. This is because secure-wordpress trashes the $wp_version global variable to hide your version rather than using the filters provided by WordPress. So coded a workaround so that your Wordfence scans will work with that plugin installed.
99
wordfence.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Wordfence
4
Plugin URI: http://wordfence.com/
5
Description: Anti-virus and Firewall for WordPress
6
Author: Mark Maunder
7
- Version: 1.3.1
8
Author URI: http://wordfence.com/
9
*/
10
require_once('lib/wordfenceConstants.php');
4
Plugin URI: http://wordfence.com/
5
Description: Anti-virus and Firewall for WordPress
6
Author: Mark Maunder
7
+ Version: 1.3.2
8
Author URI: http://wordfence.com/
9
*/
10
require_once('lib/wordfenceConstants.php');