Wordfence Security – Firewall & Malware Scan - Version 3.3.4

Version Description

  • Fixed bug that caused malformed URLs to be sent to scanning server which caused errors on some installations.
  • Fixed issue that caused scans to "hang" or stall on larger sites during "Analyzing" phase when we hash files. Sites of arbitrary size can now be scanned.
  • Fixed issue that caused "plugin generated X characters of unexpected output" error during install or upgrade.
Download this release

Release Info

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

Code changes from version 3.3.3 to 3.3.4

lib/wfAPI.php CHANGED
@@ -17,7 +17,7 @@ class wfAPI {
17
  return $this->getURL($this->getAPIURL() . $url);
18
  }
19
  public function call($action, $getParams = array(), $postParams = array()){
20
- $json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
21
  array_merge(
22
  array('action' => $action),
23
  $getParams
@@ -157,12 +157,19 @@ class wfAPI {
157
  if(function_exists('get_bloginfo')){
158
  $siteurl = get_bloginfo('siteurl');
159
  }
160
- return http_build_query(array(
161
  'v' => $this->wordpressVersion,
162
  's' => $siteurl,
163
  'k' => $this->APIKey
164
  ));
165
  }
 
 
 
 
 
 
 
166
  private function getAPIURL(){
167
  $ssl_supported = false;
168
  if(defined('CURL_VERSION_SSL') && function_exists('curl_version')){
17
  return $this->getURL($this->getAPIURL() . $url);
18
  }
19
  public function call($action, $getParams = array(), $postParams = array()){
20
+ $json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . self::buildQuery(
21
  array_merge(
22
  array('action' => $action),
23
  $getParams
157
  if(function_exists('get_bloginfo')){
158
  $siteurl = get_bloginfo('siteurl');
159
  }
160
+ return self::buildQuery(array(
161
  'v' => $this->wordpressVersion,
162
  's' => $siteurl,
163
  'k' => $this->APIKey
164
  ));
165
  }
166
+ private function buildQuery($data){
167
+ if(version_compare(phpversion(), '5.1.2', '>=')){
168
+ return http_build_query($data, '', '&'); //arg_separator parameter was only added in PHP 5.1.2. We do this because some PHP.ini's have arg_separator.output set to '&'
169
+ } else {
170
+ return http_build_query($data);
171
+ }
172
+ }
173
  private function getAPIURL(){
174
  $ssl_supported = false;
175
  if(defined('CURL_VERSION_SSL') && function_exists('curl_version')){
lib/wfScanEngine.php CHANGED
@@ -21,7 +21,7 @@ class wfScanEngine {
21
  private $apiKey = false;
22
  private $startTime = 0;
23
  private $scanStep = 0;
24
- private $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
  private $publicScanEnabled = false;
26
  private $fileContentsResults = false;
27
  private $scanner = false;
@@ -50,8 +50,10 @@ class wfScanEngine {
50
  include('wfDict.php'); //$dictWords
51
  $this->dictWords = $dictWords;
52
  $this->jobList[] = 'publicSite';
53
- $this->jobList[] = 'knownFiles';
54
- foreach(array('fileContents', 'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions') as $scanType){
 
 
55
  if(wfConfig::get('scansEnabled_' . $scanType)){
56
  if(method_exists($this, 'scan_' . $scanType . '_init')){
57
  foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
@@ -148,10 +150,9 @@ class wfScanEngine {
148
  sleep(2); //enough time to read the message before it scrolls off.
149
  }
150
  }
151
- private function scan_knownFiles(){
152
  $this->status(1, 'info', "Contacting Wordfence to initiate scan");
153
  $this->api->call('log_scan', array(), array());
154
- $this->hasher = new wordfenceHash(strlen(ABSPATH));
155
  $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');
156
  $baseContents = scandir(ABSPATH);
157
  if(! is_array($baseContents)){
@@ -161,12 +162,13 @@ class wfScanEngine {
161
  if($scanOutside){
162
  wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
163
  }
 
164
  foreach($baseContents as $file){ //Only include base files less than a meg that are files.
165
  $fullFile = rtrim(ABSPATH, '/') . '/' . $file;
166
  if($scanOutside){
167
- $includeInScan[] = $file;
168
  } else if(in_array($file, $baseWPStuff) || (@is_file($fullFile) && @is_readable($fullFile) && (! wfUtils::fileTooBig($fullFile)) ) ){
169
- $includeInScan[] = $file;
170
  }
171
  }
172
 
@@ -175,12 +177,12 @@ class wfScanEngine {
175
  }
176
  $this->status(2, 'info', "Getting plugin list from WordPress");
177
  $pluginData = get_plugins();
178
- $plugins = array();
179
  foreach($pluginData as $key => $data){
180
  if(preg_match('/^([^\/]+)\//', $key, $matches)){
181
  $pluginDir = $matches[1];
182
  $pluginFullDir = "wp-content/plugins/" . $pluginDir;
183
- $plugins[$key] = array(
184
  'Name' => $data['Name'],
185
  'Version' => $data['Version'],
186
  'ShortDir' => $pluginDir,
@@ -189,20 +191,20 @@ class wfScanEngine {
189
  }
190
  }
191
 
192
- $this->status(2, 'info', "Found " . sizeof($plugins) . " plugins");
193
- $this->i->updateSummaryItem('totalPlugins', sizeof($plugins));
194
 
195
  if(! function_exists( 'get_themes')){
196
  require_once ABSPATH . '/wp-includes/theme.php';
197
  }
198
  $this->status(2, 'info', "Getting theme list from WordPress");
199
  $themeData = get_themes();
200
- $themes = array();
201
  foreach($themeData as $themeName => $themeData){
202
  if(preg_match('/\/([^\/]+)$/', $themeData['Stylesheet Dir'], $matches)){
203
  $shortDir = $matches[1]; //e.g. evo4cms
204
  $fullDir = substr($themeData['Stylesheet Dir'], strlen(ABSPATH)); //e.g. wp-content/themes/evo4cms
205
- $themes[$themeName] = array(
206
  'Name' => $themeData['Name'],
207
  'Version' => $themeData['Version'],
208
  'ShortDir' => $shortDir,
@@ -210,15 +212,21 @@ class wfScanEngine {
210
  );
211
  }
212
  }
213
- $this->status(2, 'info', "Found " . sizeof($themes) . " themes");
214
- $this->i->updateSummaryItem('totalThemes', sizeof($themes));
215
 
216
- $this->hasher->run(ABSPATH, $includeInScan, $themes, $plugins, $this); //Include this so we can call addIssue and ->api->
 
 
 
217
  $this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
218
  $this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
219
  $this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
220
  $this->i->updateSummaryItem('linesOfPHP', $this->hasher->linesOfPHP);
221
  $this->i->updateSummaryItem('linesOfJCH', $this->hasher->linesOfJCH);
 
 
 
222
  }
223
  private function scan_fileContents_init(){
224
  $this->statusIDX['infect'] = wordfence::statusStart('Scanning file contents for infections and vulnerabilities');
21
  private $apiKey = false;
22
  private $startTime = 0;
23
  private $scanStep = 0;
24
+ public $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
  private $publicScanEnabled = false;
26
  private $fileContentsResults = false;
27
  private $scanner = false;
50
  include('wfDict.php'); //$dictWords
51
  $this->dictWords = $dictWords;
52
  $this->jobList[] = 'publicSite';
53
+ $this->jobList[] = 'knownFiles_init';
54
+ $this->jobList[] = 'knownFiles_main';
55
+ $this->jobList[] = 'knownFiles_finish';
56
+ foreach(array('knownFiles', 'fileContents', 'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions') as $scanType){
57
  if(wfConfig::get('scansEnabled_' . $scanType)){
58
  if(method_exists($this, 'scan_' . $scanType . '_init')){
59
  foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
150
  sleep(2); //enough time to read the message before it scrolls off.
151
  }
152
  }
153
+ private function scan_knownFiles_init(){
154
  $this->status(1, 'info', "Contacting Wordfence to initiate scan");
155
  $this->api->call('log_scan', array(), array());
 
156
  $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');
157
  $baseContents = scandir(ABSPATH);
158
  if(! is_array($baseContents)){
162
  if($scanOutside){
163
  wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
164
  }
165
+ $includeInKnownFilesScan = array();
166
  foreach($baseContents as $file){ //Only include base files less than a meg that are files.
167
  $fullFile = rtrim(ABSPATH, '/') . '/' . $file;
168
  if($scanOutside){
169
+ $includeInKnownFilesScan[] = $file;
170
  } else if(in_array($file, $baseWPStuff) || (@is_file($fullFile) && @is_readable($fullFile) && (! wfUtils::fileTooBig($fullFile)) ) ){
171
+ $includeInKnownFilesScan[] = $file;
172
  }
173
  }
174
 
177
  }
178
  $this->status(2, 'info', "Getting plugin list from WordPress");
179
  $pluginData = get_plugins();
180
+ $knownFilesPlugins = array();
181
  foreach($pluginData as $key => $data){
182
  if(preg_match('/^([^\/]+)\//', $key, $matches)){
183
  $pluginDir = $matches[1];
184
  $pluginFullDir = "wp-content/plugins/" . $pluginDir;
185
+ $knownFilesPlugins[$key] = array(
186
  'Name' => $data['Name'],
187
  'Version' => $data['Version'],
188
  'ShortDir' => $pluginDir,
191
  }
192
  }
193
 
194
+ $this->status(2, 'info', "Found " . sizeof($knownFilesPlugins) . " plugins");
195
+ $this->i->updateSummaryItem('totalPlugins', sizeof($knownFilesPlugins));
196
 
197
  if(! function_exists( 'get_themes')){
198
  require_once ABSPATH . '/wp-includes/theme.php';
199
  }
200
  $this->status(2, 'info', "Getting theme list from WordPress");
201
  $themeData = get_themes();
202
+ $knownFilesThemes = array();
203
  foreach($themeData as $themeName => $themeData){
204
  if(preg_match('/\/([^\/]+)$/', $themeData['Stylesheet Dir'], $matches)){
205
  $shortDir = $matches[1]; //e.g. evo4cms
206
  $fullDir = substr($themeData['Stylesheet Dir'], strlen(ABSPATH)); //e.g. wp-content/themes/evo4cms
207
+ $knownFilesThemes[$themeName] = array(
208
  'Name' => $themeData['Name'],
209
  'Version' => $themeData['Version'],
210
  'ShortDir' => $shortDir,
212
  );
213
  }
214
  }
215
+ $this->status(2, 'info', "Found " . sizeof($knownFilesThemes) . " themes");
216
+ $this->i->updateSummaryItem('totalThemes', sizeof($knownFilesThemes));
217
 
218
+ $this->hasher = new wordfenceHash(strlen(ABSPATH), ABSPATH, $includeInKnownFilesScan, $knownFilesThemes, $knownFilesPlugins, $this);
219
+ }
220
+ private function scan_knownFiles_main(){
221
+ $this->hasher->run($this); //Include this so we can call addIssue and ->api->
222
  $this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
223
  $this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
224
  $this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
225
  $this->i->updateSummaryItem('linesOfPHP', $this->hasher->linesOfPHP);
226
  $this->i->updateSummaryItem('linesOfJCH', $this->hasher->linesOfJCH);
227
+ $this->hasher = false;
228
+ }
229
+ private function scan_knownFiles_finish(){
230
  }
231
  private function scan_fileContents_init(){
232
  $this->statusIDX['infect'] = wordfence::statusStart('Scanning file contents for infections and vulnerabilities');
lib/wordfenceClass.php CHANGED
@@ -639,8 +639,10 @@ class wordfence {
639
  wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Unschedule legacy scans without args
640
 
641
  $schedArgs = wfConfig::get_ser('schedScanArgs', array());
642
- foreach($schedArgs as $futureTime){
643
- wp_clear_scheduled_hook('wordfence_start_scheduled_scan', array($futureTime));
 
 
644
  }
645
  wfConfig::set_ser('schedScanArgs', array());
646
  }
639
  wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Unschedule legacy scans without args
640
 
641
  $schedArgs = wfConfig::get_ser('schedScanArgs', array());
642
+ if(is_array($schedArgs)){
643
+ foreach($schedArgs as $futureTime){
644
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan', array($futureTime));
645
+ }
646
  }
647
  wfConfig::set_ser('schedScanArgs', array());
648
  }
lib/wordfenceHash.php CHANGED
@@ -1,29 +1,39 @@
1
  <?php
2
  require_once('wordfenceClass.php');
3
  class wordfenceHash {
4
- //Begin serialized vars
5
  private $whitespace = array("\n","\r","\t"," ");
6
- public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
 
 
 
 
 
7
  public $totalFiles = 0;
8
  public $totalDirs = 0;
 
9
  public $linesOfPHP = 0;
10
  public $linesOfJCH = 0; //lines of HTML, CSS and javascript
11
- public $striplen = 0;
12
- private $engine = false;
13
- private $db = false;
14
  private $coreEnabled = false;
15
- private $themesEnabled = false;
16
  private $pluginsEnabled = false;
 
17
  private $malwareEnabled = false;
 
18
  private $malwareData = "";
19
- private $possibleMalware = array();
20
- private $status = array();
21
  private $haveIssues = array();
22
- public function __construct($striplen){
 
 
 
 
 
 
23
  $this->striplen = $striplen;
24
- }
25
- public function run($path, $only, $themes, $plugins, $engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
26
- $this->engine = $engine;
 
 
27
  if(wfConfig::get('scansEnabled_core')){
28
  $this->coreEnabled = true;
29
  }
@@ -39,7 +49,7 @@ class wordfenceHash {
39
  $this->db = new wfDB();
40
 
41
  //Doing a delete for now. Later we can optimize this to only scan modified files.
42
- //$this->db->query("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
43
  $this->db->query("delete from " . $this->db->prefix() . "wfFileMods");
44
  $fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
45
  $dataArr = $engine->api->binCall('get_known_files', json_encode(array(
@@ -75,14 +85,13 @@ class wordfenceHash {
75
  wordfence::statusEnd($malwarePrefixStatus, false, true);
76
  }
77
 
78
- if($path[strlen($path) - 1] != '/'){
79
- $path .= '/';
80
  }
81
  if(! is_readable($path)){
82
- throw new Exception("Could not read directory $path to do scan.");
83
  exit();
84
  }
85
- $files = scandir($path);
86
  $this->haveIssues = array(
87
  'core' => false,
88
  'themes' => false,
@@ -93,11 +102,26 @@ class wordfenceHash {
93
  if($this->themesEnabled){ $this->status['themes'] = wordfence::statusStart("Comparing open source themes against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping theme scan"); }
94
  if($this->pluginsEnabled){ $this->status['plugins'] = wordfence::statusStart("Comparing plugins against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping plugin scan"); }
95
  if($this->malwareEnabled){ $this->status['malware'] = wordfence::statusStart("Scanning for known malware files"); } else { wordfence::statusDisabled("Skipping malware scan"); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  foreach($files as $file){
97
- if(sizeof($only) > 0 && (! in_array($file, $only))){
98
  continue;
99
  }
100
- $file = $path . $file;
101
  wordfence::status(4, 'info', "Hashing item in base dir: $file");
102
  $this->_dirHash($file);
103
  }
@@ -121,7 +145,7 @@ class wordfenceHash {
121
  $this->engine->addIssue(
122
  'file',
123
  1,
124
- $path . $file,
125
  $md5,
126
  'This file is suspected malware: ' . $file,
127
  "This file's signature matches a known malware file. The title of the malware is '" . $name . "'. Immediately inspect this file using the 'View' option below and consider deleting it from your server.",
@@ -166,6 +190,19 @@ class wordfenceHash {
166
  }
167
  private function processFile($realFile){
168
  $file = substr($realFile, $this->striplen);
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  if(wfUtils::fileTooBig($realFile)){
170
  wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
171
  return;
1
  <?php
2
  require_once('wordfenceClass.php');
3
  class wordfenceHash {
 
4
  private $whitespace = array("\n","\r","\t"," ");
5
+ private $engine = false;
6
+ private $db = false;
7
+ private $startTime = false;
8
+
9
+ //Begin serialized vars
10
+ public $striplen = 0;
11
  public $totalFiles = 0;
12
  public $totalDirs = 0;
13
+ public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
14
  public $linesOfPHP = 0;
15
  public $linesOfJCH = 0; //lines of HTML, CSS and javascript
16
+ public $stoppedOnFile = false;
 
 
17
  private $coreEnabled = false;
 
18
  private $pluginsEnabled = false;
19
+ private $themesEnabled = false;
20
  private $malwareEnabled = false;
21
+ private $knownFiles = false;
22
  private $malwareData = "";
 
 
23
  private $haveIssues = array();
24
+ private $status = array();
25
+ private $possibleMalware = array();
26
+ private $path = false;
27
+ private $only = false;
28
+ private $totalForks = 0;
29
+
30
+ public function __construct($striplen, $path, $only, $themes, $plugins, $engine){
31
  $this->striplen = $striplen;
32
+ $this->path = $path;
33
+ $this->only = $only;
34
+
35
+ $this->startTime = microtime(true);
36
+
37
  if(wfConfig::get('scansEnabled_core')){
38
  $this->coreEnabled = true;
39
  }
49
  $this->db = new wfDB();
50
 
51
  //Doing a delete for now. Later we can optimize this to only scan modified files.
52
+ //$this->db->query("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
53
  $this->db->query("delete from " . $this->db->prefix() . "wfFileMods");
54
  $fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
55
  $dataArr = $engine->api->binCall('get_known_files', json_encode(array(
85
  wordfence::statusEnd($malwarePrefixStatus, false, true);
86
  }
87
 
88
+ if($this->path[strlen($this->path) - 1] != '/'){
89
+ $this->path .= '/';
90
  }
91
  if(! is_readable($path)){
92
+ throw new Exception("Could not read directory " . $this->path . " to do scan.");
93
  exit();
94
  }
 
95
  $this->haveIssues = array(
96
  'core' => false,
97
  'themes' => false,
102
  if($this->themesEnabled){ $this->status['themes'] = wordfence::statusStart("Comparing open source themes against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping theme scan"); }
103
  if($this->pluginsEnabled){ $this->status['plugins'] = wordfence::statusStart("Comparing plugins against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping plugin scan"); }
104
  if($this->malwareEnabled){ $this->status['malware'] = wordfence::statusStart("Scanning for known malware files"); } else { wordfence::statusDisabled("Skipping malware scan"); }
105
+ }
106
+ public function __sleep(){
107
+ return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'linesOfPHP', 'linesOfJCH', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks');
108
+ }
109
+ public function __wakeup(){
110
+ $this->db = new wfDB();
111
+ $this->startTime = microtime(true);
112
+ $this->totalForks++;
113
+ }
114
+ public function run($engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
115
+ if($this->totalForks > 1000){
116
+ throw new Exception("Wordfence file scanner detected a possible infinite loop. Exiting on file: " . $this->stoppedOnFile);
117
+ }
118
+ $this->engine = $engine;
119
+ $files = scandir($this->path);
120
  foreach($files as $file){
121
+ if(sizeof($this->only) > 0 && (! in_array($file, $this->only))){
122
  continue;
123
  }
124
+ $file = $this->path . $file;
125
  wordfence::status(4, 'info', "Hashing item in base dir: $file");
126
  $this->_dirHash($file);
127
  }
145
  $this->engine->addIssue(
146
  'file',
147
  1,
148
+ $this->path . $file,
149
  $md5,
150
  'This file is suspected malware: ' . $file,
151
  "This file's signature matches a known malware file. The title of the malware is '" . $name . "'. Immediately inspect this file using the 'View' option below and consider deleting it from your server.",
190
  }
191
  private function processFile($realFile){
192
  $file = substr($realFile, $this->striplen);
193
+ if( (! $this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime){ //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
194
+ $this->stoppedOnFile = $file;
195
+ $this->engine->fork();
196
+ //exits
197
+ }
198
+
199
+ //Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
200
+ if($this->stoppedOnFile && $file != $this->stoppedOnFile){
201
+ return;
202
+ } else if($this->stoppedOnFile && $file == $this->stoppedOnFile){
203
+ $this->stoppedOnFile = false; //Continue scanning
204
+ }
205
+
206
  if(wfUtils::fileTooBig($realFile)){
207
  wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
208
  return;
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.2
6
- Stable tag: 3.3.3
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
 
@@ -153,6 +153,11 @@ or a theme, because often these have been updated to fix a security hole.
153
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
154
 
155
  == Changelog ==
 
 
 
 
 
156
  = 3.3.3 =
157
  * Fixed errors caused by ini_set being disabled on certain servers.
158
  * Removed error logging messages in certain cases because some badly configured hosts write these errors to the web browser.
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.2
6
+ Stable tag: 3.3.4
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
 
153
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
154
 
155
  == Changelog ==
156
+ = 3.3.4 =
157
+ * Fixed bug that caused malformed URLs to be sent to scanning server which caused errors on some installations.
158
+ * Fixed issue that caused scans to "hang" or stall on larger sites during "Analyzing" phase when we hash files. Sites of arbitrary size can now be scanned.
159
+ * Fixed issue that caused "plugin generated X characters of unexpected output" error during install or upgrade.
160
+
161
  = 3.3.3 =
162
  * Fixed errors caused by ini_set being disabled on certain servers.
163
  * Removed error logging messages in certain cases because some badly configured hosts write these errors to the web browser.
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.3.3
8
  Author URI: http://wordfence.com/
9
  */
10
- define('WORDFENCE_VERSION', '3.3.3');
11
  add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
12
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
13
  if((int) @ini_get('memory_limit') < 64){
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.3.4
8
  Author URI: http://wordfence.com/
9
  */
10
+ define('WORDFENCE_VERSION', '3.3.4');
11
  add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
12
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
13
  if((int) @ini_get('memory_limit') < 64){