WordPress Zero Spam - Version 4.9.3

Version Description

  • Added a confidence threshold for Stop Form Spam checks. See #202;
  • Added an API timeout field to adjust how long a response is allowed to take.
  • Restructred several functions which fixed some interment bugs users were experiencing.
  • Added ability to delete all entries from a table.
  • This update will delete all exisiting blacklisted IPs to ensure visitors aren't getting blocked when that shouldn't be.
Download this release

Release Info

Developer bmarshall511
Plugin Icon 128x128 WordPress Zero Spam
Version 4.9.3
Comparing to
See all releases

Code changes from version 4.9.2 to 4.9.3

classes/class-wpzerospam-blacklisted-table.php CHANGED
@@ -32,6 +32,7 @@ class WPZeroSpam_Blacklisted_Table extends WP_List_Table {
32
  'last_updated' => __( 'Last Updated', 'wpzerospam' ),
33
  'user_ip' => __( 'IP Address', 'wpzerospam' ),
34
  'service' => __( 'Service', 'wpzerospam' ),
 
35
  'details' => __( 'Details', 'wpzerospam' )
36
  ];
37
 
@@ -44,6 +45,7 @@ class WPZeroSpam_Blacklisted_Table extends WP_List_Table {
44
  'last_updated' => [ 'last_updated', false ],
45
  'user_ip' => [ 'user_ip', false ],
46
  'service' => [ 'service', false ],
 
47
  ];
48
 
49
  return $sortable_columns;
@@ -101,6 +103,9 @@ class WPZeroSpam_Blacklisted_Table extends WP_List_Table {
101
  return $item->blacklist_service;
102
  }
103
  break;
 
 
 
104
  case 'user_ip':
105
  return '<a href="https://whatismyipaddress.com/ip/' . $item->user_ip .'" target="_blank" rel="noopener noreferrer">' . $item->user_ip . '</a>';
106
  break;
@@ -199,7 +204,10 @@ class WPZeroSpam_Blacklisted_Table extends WP_List_Table {
199
 
200
  // Register bulk actions
201
  function get_bulk_actions() {
202
- $actions = [ 'delete' => __( 'Delete', 'wpzerospam' ) ];
 
 
 
203
 
204
  return $actions;
205
  }
@@ -289,6 +297,9 @@ class WPZeroSpam_Blacklisted_Table extends WP_List_Table {
289
  }
290
  }
291
  break;
 
 
 
292
  }
293
  }
294
  }
32
  'last_updated' => __( 'Last Updated', 'wpzerospam' ),
33
  'user_ip' => __( 'IP Address', 'wpzerospam' ),
34
  'service' => __( 'Service', 'wpzerospam' ),
35
+ 'attempts' => __( 'Attempts', 'wpzerospam' ),
36
  'details' => __( 'Details', 'wpzerospam' )
37
  ];
38
 
45
  'last_updated' => [ 'last_updated', false ],
46
  'user_ip' => [ 'user_ip', false ],
47
  'service' => [ 'service', false ],
48
+ 'attempts' => [ 'attempts', false ],
49
  ];
50
 
51
  return $sortable_columns;
103
  return $item->blacklist_service;
104
  }
105
  break;
106
+ case 'attempts':
107
+ return number_format( $item->attempts, 0 );
108
+ break;
109
  case 'user_ip':
110
  return '<a href="https://whatismyipaddress.com/ip/' . $item->user_ip .'" target="_blank" rel="noopener noreferrer">' . $item->user_ip . '</a>';
111
  break;
204
 
205
  // Register bulk actions
206
  function get_bulk_actions() {
207
+ $actions = [
208
+ 'delete' => __( 'Delete', 'wpzerospam' ),
209
+ 'delete_all' => __( 'Delete All Entries', 'wpzerospam' )
210
+ ];
211
 
212
  return $actions;
213
  }
297
  }
298
  }
299
  break;
300
+ case 'delete_all':
301
+ $wpdb->query( "TRUNCATE TABLE " . wpzerospam_tables( 'blacklist' ) );
302
+ break;
303
  }
304
  }
305
  }
classes/class-wpzerospam-blocked-ip-table.php CHANGED
@@ -150,7 +150,10 @@ class WPZeroSpam_Blocked_IP_Table extends WP_List_Table {
150
 
151
  // Register bulk actions
152
  function get_bulk_actions() {
153
- $actions = [ 'delete' => __( 'Delete', 'wpzerospam' ) ];
 
 
 
154
 
155
  return $actions;
156
  }
@@ -239,6 +242,9 @@ class WPZeroSpam_Blocked_IP_Table extends WP_List_Table {
239
  }
240
  }
241
  break;
 
 
 
242
  }
243
  }
244
  }
150
 
151
  // Register bulk actions
152
  function get_bulk_actions() {
153
+ $actions = [
154
+ 'delete' => __( 'Delete', 'wpzerospam' ),
155
+ 'delete_all' => __( 'Delete All Entries', 'wpzerospam' )
156
+ ];
157
 
158
  return $actions;
159
  }
242
  }
243
  }
244
  break;
245
+ case 'delete_all':
246
+ $wpdb->query( "TRUNCATE TABLE " . wpzerospam_tables( 'blocked' ) );
247
+ break;
248
  }
249
  }
250
  }
classes/class-wpzerospam-log-table.php CHANGED
@@ -95,8 +95,7 @@ class WPZeroSpam_Log_Table extends WP_List_Table {
95
  function column_default( $item, $column_name ) {
96
  switch( $column_name ) {
97
  case 'actions':
98
- $blocked_status = wpzerospam_get_blocked_ips( $item->user_ip );
99
- if ( $blocked_status && wpzerospam_is_blocked( $blocked_status ) ) {
100
  return '<span class="wpzerospam-blocked">' . __( 'Blocked', 'wpzerospam' ) . '</span>';
101
  } else {
102
  return '<a class="button" href="' . admin_url( 'admin.php?page=wordpress-zero-spam-blocked-ips&ip=' . $item->user_ip ) . '">' . __( 'Block IP', 'wpzerospam' ) . '</a>';
@@ -421,7 +420,10 @@ class WPZeroSpam_Log_Table extends WP_List_Table {
421
 
422
  // Register bulk actions
423
  function get_bulk_actions() {
424
- $actions = [ 'delete' => __( 'Delete', 'wpzerospam' ) ];
 
 
 
425
 
426
  return $actions;
427
  }
@@ -511,6 +513,9 @@ class WPZeroSpam_Log_Table extends WP_List_Table {
511
  }
512
  }
513
  break;
 
 
 
514
  }
515
  }
516
  }
95
  function column_default( $item, $column_name ) {
96
  switch( $column_name ) {
97
  case 'actions':
98
+ if ( wpzerospam_is_blocked( $item->user_ip ) ) {
 
99
  return '<span class="wpzerospam-blocked">' . __( 'Blocked', 'wpzerospam' ) . '</span>';
100
  } else {
101
  return '<a class="button" href="' . admin_url( 'admin.php?page=wordpress-zero-spam-blocked-ips&ip=' . $item->user_ip ) . '">' . __( 'Block IP', 'wpzerospam' ) . '</a>';
420
 
421
  // Register bulk actions
422
  function get_bulk_actions() {
423
+ $actions = [
424
+ 'delete' => __( 'Delete Selected', 'wpzerospam' ) ,
425
+ 'delete_all' => __( 'Delete All Entries', 'wpzerospam' )
426
+ ];
427
 
428
  return $actions;
429
  }
513
  }
514
  }
515
  break;
516
+ case 'delete_all':
517
+ $wpdb->query( "TRUNCATE TABLE " . wpzerospam_tables( 'log' ) );
518
+ break;
519
  }
520
  }
521
  }
inc/admin.php CHANGED
@@ -326,6 +326,8 @@ function wpzerospam_validate_options( $input ) {
326
  if ( empty( $input['auto_block_period'] ) ) { $input['auto_block_period'] = 0; }
327
  if ( empty( $input['botscout_api'] ) ) { $input['botscout'] = false; }
328
  if ( empty( $input['auto_block_permanently'] ) ) { $input['auto_block_permanently'] = 3; }
 
 
329
 
330
  if ( empty( $input['ip_whitelist'] ) ) {
331
  $input['ip_whitelist'] = '';
@@ -485,6 +487,16 @@ function wpzerospam_admin_init() {
485
  ]
486
  ]);
487
 
 
 
 
 
 
 
 
 
 
 
488
  if ( 'enabled' == $options['log_spam'] ) {
489
  // Redirect URL for spam detections
490
  add_settings_field( 'ipstack_api', __( 'ipstack API Key', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
@@ -516,6 +528,16 @@ function wpzerospam_admin_init() {
516
  ]
517
  ]);
518
 
 
 
 
 
 
 
 
 
 
 
519
  // How to handle blocks
520
  add_settings_field( 'block_handler', __( 'Blocked IPs', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
521
  'label_for' => 'block_handler',
326
  if ( empty( $input['auto_block_period'] ) ) { $input['auto_block_period'] = 0; }
327
  if ( empty( $input['botscout_api'] ) ) { $input['botscout'] = false; }
328
  if ( empty( $input['auto_block_permanently'] ) ) { $input['auto_block_permanently'] = 3; }
329
+ if ( empty( $input['api_timeout'] ) ) { $input['api_timeout'] = 5; }
330
+ if ( empty( $input['stopforumspam_confidence_min'] ) ) { $input['stopforumspam_confidence_min'] = 20; }
331
 
332
  if ( empty( $input['ip_whitelist'] ) ) {
333
  $input['ip_whitelist'] = '';
487
  ]
488
  ]);
489
 
490
+ // API timeout
491
+ add_settings_field( 'api_timeout', __( 'API Timeout', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
492
+ 'label_for' => 'api_timeout',
493
+ 'type' => 'number',
494
+ 'desc' => 'Number of seconds to allow an API to return a response.<br /><strong>WARNING:</strong> Setting this too high could cause your site to load slowly. Setting too low may not allow an API enough time to respond with a result. <strong>Recommended is 5 seconds.</strong>',
495
+ 'class' => 'small-text',
496
+ 'placeholder' => '30',
497
+ 'suffix' => __( 'seconds', 'wpzerospam' )
498
+ ]);
499
+
500
  if ( 'enabled' == $options['log_spam'] ) {
501
  // Redirect URL for spam detections
502
  add_settings_field( 'ipstack_api', __( 'ipstack API Key', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
528
  ]
529
  ]);
530
 
531
+ // StopForumSpam confidence minimum
532
+ add_settings_field( 'stopforumspam_confidence_min', __( 'Stop Forum Spam Confidence Minimum', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
533
+ 'label_for' => 'stopforumspam_confidence_min',
534
+ 'type' => 'number',
535
+ 'desc' => 'Minimum <a href="https://www.stopforumspam.com/usage" target="_blank" rel="noopener noreferrer">confidence score</a> an IP must meet before being marked as spam/malicious.<br /><strong>WARNING:</strong> Setting this too low could cause users to be blocked that shouldn\'t be, <strong>recommended is 20%</strong>.',
536
+ 'class' => 'small-text',
537
+ 'placeholder' => '20',
538
+ 'suffix' => __( '%', 'wpzerospam' )
539
+ ]);
540
+
541
  // How to handle blocks
542
  add_settings_field( 'block_handler', __( 'Blocked IPs', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
543
  'label_for' => 'block_handler',
inc/helpers.php CHANGED
@@ -8,140 +8,183 @@
8
  */
9
 
10
  /**
11
- * Locations helper
12
- */
13
- require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/inc/locations.php';
14
-
15
- /**
16
- * Returns the human-readable spam type or an array of available spam types.
17
  *
18
- * @param string $type_key The key of the type that should be returned.
19
- * @return string/array The human-readable type name or an array of all the
20
- * available types.
21
  */
22
- if ( ! function_exists( 'wpzerospam_types' ) ) {
23
- function wpzerospam_types( $type_key = false ) {
24
- $types = apply_filters( 'wpzerospam_types', [ 'blocked' => __( 'Access Blocked', 'wpzerospam' ) ] );
 
 
25
 
26
- if ( $type_key ) {
27
- if ( ! empty( $types[ $type_key ] ) ) {
28
- return $types[ $type_key ];
29
- }
30
 
31
- return $type_key;
 
 
32
  }
33
 
34
- return $types;
35
- }
36
- }
 
 
 
 
 
 
 
 
 
 
37
 
38
- /**
39
- * Returns the geolocation information for a specified IP address.
40
- *
41
- * @param string $ip IP address.
42
- * @return array/false An array with the IP address location information or
43
- * false if not found.
44
- */
45
- if ( ! function_exists( 'wpzerospam_get_ip_info' ) ) {
46
- function wpzerospam_get_ip_info( $ip ) {
47
  $options = wpzerospam_options();
48
 
49
- if ( empty( $options['ipstack_api'] ) ) { return false; }
50
-
51
- $base_url = 'http://api.ipstack.com/';
52
- $remote_url = $base_url . $ip . '?access_key=' . $options['ipstack_api'];
53
- $response = wp_remote_get( $remote_url );
54
-
55
- if ( is_array( $response ) && ! is_wp_error( $response ) ) {
56
- $info = json_decode( $response['body'], true );
57
-
58
- return [
59
- 'type' => ! empty( $info['type'] ) ? sanitize_text_field( $info['type'] ) : false,
60
- 'continent_code' => ! empty( $info['continent_code'] ) ? sanitize_text_field( $info['continent_code'] ) : false,
61
- 'continent_name' => ! empty( $info['continent_name'] ) ? sanitize_text_field( $info['continent_name'] ) : false,
62
- 'country_code' => ! empty( $info['country_code'] ) ? sanitize_text_field( $info['country_code'] ) : false,
63
- 'country_name' => ! empty( $info['country_name'] ) ? sanitize_text_field( $info['country_name'] ) : false,
64
- 'region_code' => ! empty( $info['region_code'] ) ? sanitize_text_field( $info['region_code'] ) : false,
65
- 'region_name' => ! empty( $info['region_name'] ) ? sanitize_text_field( $info['region_name'] ) : false,
66
- 'city' => ! empty( $info['city'] ) ? sanitize_text_field( $info['city'] ) : false,
67
- 'zip' => ! empty( $info['zip'] ) ? sanitize_text_field( $info['zip'] ) : false,
68
- 'latitude' => ! empty( $info['latitude'] ) ? sanitize_text_field( $info['latitude'] ) : false,
69
- 'longitude' => ! empty( $info['longitude'] ) ? sanitize_text_field( $info['longitude'] ) : false,
70
- 'flag' => ! empty( $info['location']['country_flag'] ) ? sanitize_text_field( $info['location']['country_flag'] ) : false,
71
- ];
72
  }
73
 
74
- return false;
75
- }
76
- }
77
-
78
- /**
79
- * Query the database tables
80
- *
81
- * @return false/array False if not found, otherwise the blocked IP info.
82
- */
83
- if ( ! function_exists( 'wpzerospam_query_table' ) ) {
84
- function wpzerospam_query_table( $table, $args = [] ) {
85
- global $wpdb;
86
 
87
- // Select
88
- $sql = 'SELECT ';
89
- if ( ! empty( $args['select'] ) ) {
90
- $sql .= implode( ',', $args['select'] );
91
- } else {
92
- $sql .= '*';
93
  }
94
 
95
- // From
96
- $sql .= " from " . wpzerospam_tables( $table );
 
 
 
 
 
 
 
 
 
 
97
 
98
- // Where
99
- if ( ! empty( $args['where'] ) ) {
100
- $sql .= ' WHERE ';
101
- foreach( $args['where'] as $key => $value ) {
102
- if ( is_int( $value ) ) {
103
- $sql .= $key . ' = ' . $value . ' ';
104
- } else {
105
- $sql .= $key . ' = "' . $value . '" ';
106
- }
107
  }
108
  }
109
 
110
- // Limit
111
- if ( ! empty( $args['limit'] ) ) {
112
- $sql .= 'LIMIT ' . $args['limit'];
 
 
113
 
114
- // Offset
115
- if ( ! empty( $args['offset'] ) ) {
116
- $sql .= ', ' . $args['offset'];
117
- }
118
  }
119
 
120
- if ( ! empty( $args['limit'] ) && 1 == $args['limit'] ) {
121
- return $wpdb->get_row( $sql, ARRAY_A );
122
- } else {
123
- return $wpdb->get_results( $sql, ARRAY_A );
124
- }
125
  }
126
  }
127
 
128
  /**
129
- * Whitelisted IPs
130
  *
131
- * @return array An array of whitelisted IP addresses.
 
 
 
132
  */
133
- if ( ! function_exists( 'wpzerospam_get_whitelist' ) ) {
134
- function wpzerospam_get_whitelist() {
 
 
135
  $options = wpzerospam_options();
136
- if ( $options['ip_whitelist'] ) {
137
- $whitelist = explode( PHP_EOL, $options['ip_whitelist'] );
138
- if ( $whitelist ) {
139
- $whitelisted = [];
140
- foreach( $whitelist as $k => $whitelisted_ip ) {
141
- $whitelisted[ $whitelisted_ip ] = $whitelisted_ip;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
 
144
- return $whitelisted;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
146
  }
147
 
@@ -150,117 +193,131 @@ if ( ! function_exists( 'wpzerospam_get_whitelist' ) ) {
150
  }
151
 
152
  /**
153
- * Check access
154
- *
155
- * Determines if the current user IP should have access to the site.
156
  *
157
- * @return array Includes info about the access check.
158
  */
159
- if ( ! function_exists( 'wpzerospam_check_access' ) ) {
160
- function wpzerospam_check_access() {
161
- // Innocent until proven guilty...
162
- $access = [ 'access' => true ];
163
 
164
- // Always allow authenticated users & users trying to log in access
165
- if ( is_user_logged_in() || wpzerospam_is_login() ) {
166
- return $access;
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
 
169
- /**
170
- * Only check access for actual page vists. Some resource requests like
171
- * favicons fire this function which causes duplicate entries in the DB.
172
- *
173
- * @TODO - Find a way to avoid these checks & ensure this function only gets
174
- * fired on page requests vs. resources.
175
- */
176
- if (
177
- ! is_singular() && ! is_page() && ! is_single() && ! is_archive() &&
178
- ! is_home() && ! is_front_page()
179
- ) {
180
- return $access;
181
  }
182
 
183
- // Get the user's IP address then begin the checks
184
- $options = wpzerospam_options();
185
- $ip = wpzerospam_ip();
186
 
187
- // 1. Check whitelisted IP addresses
188
- $whitelist = wpzerospam_get_whitelist();
189
- if ( $whitelist && array_key_exists( $ip, $whitelist ) ) {
190
- return $access;
 
 
191
  }
 
 
192
 
193
- // 2. Check if the user's IP address has been blocked
194
- $blocked_ip = wpzerospam_query_table( 'blocked', [
195
- 'select' => [
196
- 'blocked_type',
197
- 'start_block',
198
- 'end_block',
199
- 'reason',
200
- 'attempts'
201
- ],
202
- 'where' => [ 'user_ip' => $ip ],
203
- 'limit' => 1
204
- ]);
205
 
206
- if ( $blocked_ip ) {
207
- if ( 'permanent' == $blocked_ip['blocked_type'] ) {
208
- $access['access'] = false;
209
- $access['reason'] = $blocked_ip['reason'];
210
 
211
- return $access;
212
- } else {
213
- $current_datetime = current_time( 'timestamp' );
214
- $start_block = strtotime( $blocked_ip['start_block'] );
215
- $end_block = strtotime( $blocked_ip['end_block'] );
216
- if (
217
- $current_datetime >= $start_block &&
218
- $current_datetime < $end_block
219
- ) {
220
- $access['access'] = false;
221
- $access['reason'] = $blocked_ip['reason'];
222
-
223
- return $access;
224
- }
225
- }
226
- }
227
 
228
- // 3. Check the blacklist
229
- $blacklist_ip = wpzerospam_query_table( 'blacklist', [
230
- 'select' => [ 'blacklist_service' ],
231
- 'where' => [ 'user_ip' => $ip ],
232
- 'limit' => 1
233
- ]);
234
- if ( $blacklist_ip ) {
235
- $access['access'] = false;
236
- $access['reason'] = $blacklist_ip['blacklist_service'];
237
 
238
- return $access;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  }
240
 
241
- // 4. Check the Stop Forum Spam blacklist
242
- if ( 'enabled' == $options['stop_forum_spam'] ) {
243
- $stop_forum_spam_is_spam = wpzerospam_stopforumspam_is_spam( $ip );
244
- if ( $stop_forum_spam_is_spam ) {
245
- $access['access'] = false;
246
- $access['reason'] = 'Stop Forum Spam';
 
247
 
248
- return $access;
249
- }
 
 
 
 
 
250
  }
251
 
252
- // 5. Check the BotScout blacklist
253
- if ( ! empty( $options['botscout'] ) ) {
254
- $botscout_request = wpzerospam_botscout_is_spam( $ip );
255
- if ( $botscout_request ) {
256
- $access['access'] = false;
257
- $access['reason'] = 'BotScout';
258
 
259
- return $access;
260
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  }
262
 
263
- return $access;
264
  }
265
  }
266
 
@@ -281,8 +338,6 @@ if ( ! function_exists( 'wpzerospam_check_access' ) ) {
281
 
282
 
283
 
284
-
285
-
286
 
287
 
288
 
@@ -554,86 +609,6 @@ if ( ! function_exists( 'wpzerospam_update_blocked_ip' ) ) {
554
  }
555
  }
556
 
557
- /**
558
- * Create a log entry if logging is enabled
559
- */
560
- if ( ! function_exists( 'wpzerospam_log_spam' ) ) {
561
- function wpzerospam_log_spam( $type, $data = [] ) {
562
- global $wpdb;
563
-
564
- $options = wpzerospam_options();
565
-
566
- if ( ! empty( $data['ip'] ) ) {
567
- $ip_address = $data['ip'];
568
- unset( $data['ip'] );
569
- } else {
570
- $ip_address = wpzerospam_ip();
571
- }
572
-
573
- // Check is the spam detection should be shared
574
- if ( 'enabled' == $options['share_detections'] ) {
575
- wpzerospam_send_detection([
576
- 'ip' => $ip_address,
577
- 'type' => $type
578
- ]);
579
- }
580
-
581
- // Check if spam logging is enabled, also check if type is 'denied'
582
- // (blocked IP address) & logging of blocked IPs is enabled.
583
- if ( 'enabled' != $options['log_spam'] ||
584
- ( 'blocked' == $type && 'enabled' != $options['log_blocked_ips'] )
585
- ) {
586
- // Logging disabled
587
- return false;
588
- }
589
-
590
- $current_url = wpzerospam_current_url();
591
- $location_info = wpzerospam_get_ip_info( $ip_address );
592
-
593
- // Add record to the database
594
- $record = [
595
- 'log_type' => $type,
596
- 'user_ip' => wpzerospam_ip(),
597
- 'date_recorded' => current_time( 'mysql' ),
598
- 'page_url' => $current_url['full'],
599
- 'submission_data' => json_encode( $data )
600
- ];
601
-
602
- if ( $location_info ) {
603
- $record['country'] = $location_info['country_code'];
604
- $record['region'] = $location_info['region_code'];
605
- $record['city'] = $location_info['city'];
606
- $record['latitude'] = $location_info['latitude'];
607
- $record['longitude'] = $location_info['longitude'];
608
- }
609
-
610
- $wpdb->insert( wpzerospam_tables( 'log' ), $record );
611
- }
612
- }
613
-
614
- /**
615
- * Returns an array of tables the plugin uses
616
- */
617
- if ( ! function_exists( 'wpzerospam_tables' ) ) {
618
- function wpzerospam_tables( $key = false ) {
619
- global $wpdb;
620
-
621
- $tables = [
622
- 'log' => $wpdb->prefix . 'wpzerospam_log',
623
- 'blocked' => $wpdb->prefix . 'wpzerospam_blocked',
624
- 'blacklist' => $wpdb->prefix . 'wpzerospam_blacklist'
625
- ];
626
-
627
- if ( ! $key ) {
628
- return $tables;
629
- } elseif( ! empty( $tables[ $key ] ) ) {
630
- return $tables[ $key ];
631
- }
632
-
633
- return false;
634
- }
635
- }
636
-
637
  /**
638
  * Returns the generated key for checking submissions
639
  */
@@ -680,41 +655,6 @@ if ( ! function_exists( 'wpzerospam_get_blocked_ips' ) ) {
680
  }
681
  }
682
 
683
- /**
684
- * Adds a access attempt from a blocked user
685
- */
686
- if ( ! function_exists( 'wpzerospam_attempt_blocked' ) ) {
687
- function wpzerospam_attempt_blocked( $reason ) {
688
- global $wpdb;
689
-
690
- $options = wpzerospam_options();
691
- $ip_address = wpzerospam_ip();
692
-
693
- $is_blocked = wpzerospam_get_blocked_ips( $ip_address );
694
- if ( $is_blocked ) {
695
- // IP already exists in the database
696
- $attempts = $is_blocked->attempts;
697
- $attempts++;
698
-
699
- $wpdb->update( wpzerospam_tables( 'blocked' ), [
700
- 'attempts' => $attempts
701
- ], [
702
- 'blocked_id' => $is_blocked->blocked_id
703
- ]);
704
- }
705
-
706
- wpzerospam_log_spam( 'blocked' );
707
-
708
- if ( 'redirect' == $options['block_handler'] ) {
709
- wp_redirect( esc_url( $options['blocked_redirect_url'] ) );
710
- exit();
711
- } else {
712
- status_header( 403 );
713
- die( $options['blocked_message'] );
714
- }
715
- }
716
- }
717
-
718
  /**
719
  * Checks if a specific plugin integration is turned on & plugin active.
720
  */
@@ -771,141 +711,6 @@ if ( ! function_exists( 'wpzerospam_plugin_integration_enabled' ) ) {
771
  }
772
  }
773
 
774
- /**
775
- * Returns the plugin settings.
776
- */
777
- if ( ! function_exists( 'wpzerospam_options' ) ) {
778
- function wpzerospam_options() {
779
- $options = get_option( 'wpzerospam' );
780
-
781
- if ( empty( $options['share_data'] ) ) { $options['share_data'] = 'enabled'; }
782
- if ( empty( $options['auto_block_ips'] ) ) { $options['auto_block_ips'] = 'disabled'; }
783
- if ( empty( $options['auto_block_period'] ) ) { $options['auto_block_period'] = 30; }
784
- if ( empty( $options['blocked_redirect_url'] ) ) { $options['blocked_redirect_url'] = 'https://www.google.com'; }
785
- if ( empty( $options['spam_handler'] ) ) { $options['spam_handler'] = '403'; }
786
- if ( empty( $options['block_handler'] ) ) { $options['block_handler'] = '403'; }
787
- if ( empty( $options['spam_redirect_url'] ) ) { $options['spam_redirect_url'] = 'https://www.google.com'; }
788
- if ( empty( $options['spam_message'] ) ) { $options['spam_message'] = __( 'There was a problem with your submission. Please go back and try again.', 'wpzerospam' ); }
789
- if ( empty( $options['blocked_message'] ) ) { $options['blocked_message'] = __( 'You have been blocked from visiting this site by WordPress Zero Spam due to detected spam activity.', 'wpzerospam' ); }
790
- if ( empty( $options['log_spam'] ) ) { $options['log_spam'] = 'disabled'; }
791
- if ( empty( $options['verify_comments'] ) ) { $options['verify_comments'] = 'enabled'; }
792
- if ( empty( $options['verify_registrations'] ) ) { $options['verify_registrations'] = 'enabled'; }
793
- if ( empty( $options['log_blocked_ips'] ) ) { $options['log_blocked_ips'] = 'disabled'; }
794
- if ( empty( $options['auto_block_permanently'] ) ) { $options['auto_block_permanently'] = 3; }
795
- if ( empty( $options['botscout_api'] ) ) { $options['botscout_api'] = false; }
796
- if ( empty( $options['ip_whitelist'] ) ) { $options['ip_whitelist'] = false; }
797
-
798
- if ( empty( $options['verify_cf7'] ) ) {
799
- $options['verify_cf7'] = 'enabled';
800
- }
801
-
802
- if ( empty( $options['share_detections'] ) ) {
803
- $options['share_detections'] = 'enabled';
804
- }
805
-
806
- if ( empty( $options['verify_gform'] ) ) {
807
- $options['verify_gform'] = 'enabled';
808
- }
809
-
810
- if ( empty( $options['verify_bp_registrations'] ) ) {
811
- $options['verify_bp_registrations'] = 'enabled';
812
- }
813
-
814
- if ( empty( $options['verify_wpforms'] ) ) {
815
- $options['verify_wpforms'] = 'enabled';
816
- }
817
-
818
- if ( empty( $options['verify_fluentform'] ) ) {
819
- $options['verify_fluentform'] = 'enabled';
820
- }
821
-
822
- if ( empty( $options['verify_formidable'] ) ) {
823
- $options['verify_formidable'] = 'enabled';
824
- }
825
-
826
- if ( empty( $options['stop_forum_spam'] ) ) {
827
- $options['stop_forum_spam'] = 'enabled';
828
- }
829
-
830
- if ( empty( $options['strip_comment_links'] ) ) {
831
- $options['strip_comment_links'] = 'disabled';
832
- }
833
-
834
- if ( empty( $options['strip_comment_author_links'] ) ) {
835
- $options['strip_comment_author_links'] = 'disabled';
836
- }
837
-
838
- return $options;
839
- }
840
- }
841
-
842
- /**
843
- * Returns the current user's IP address
844
- */
845
- if ( ! function_exists( 'wpzerospam_ip' ) ) {
846
- function wpzerospam_ip() {
847
- if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
848
- $ip = $_SERVER['HTTP_CLIENT_IP'];
849
- } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
850
- $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
851
- } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED'])) {
852
- $ip = $_SERVER['HTTP_X_FORWARDED'];
853
- } elseif ( ! empty($_SERVER['HTTP_FORWARDED_FOR'])) {
854
- $ip = $_SERVER['HTTP_FORWARDED_FOR'];
855
- } elseif ( ! empty($_SERVER['HTTP_FORWARDED'])) {
856
- $ip = $_SERVER['HTTP_FORWARDED'];
857
- } else {
858
- $ip = $_SERVER['REMOTE_ADDR'];
859
- }
860
-
861
- $ip = explode( ',', $ip );
862
- $ip = trim( $ip[0] );
863
-
864
- if ( ! rest_is_ip_address( $ip ) ) { return false; }
865
-
866
- return $ip;
867
- }
868
- }
869
-
870
- /**
871
- * Return true/false if the IP is currently blocked
872
- */
873
- if ( ! function_exists( 'wpzerospam_is_blocked' ) ) {
874
- function wpzerospam_is_blocked( $blocked_ip_entry ) {
875
- if ( 'permanent' == $blocked_ip_entry->blocked_type ) {
876
- return true;
877
- }
878
-
879
- $todays_date = new DateTime( current_time( 'mysql' ) );
880
-
881
- if ( ! empty( $blocked_ip_entry->start_block ) || ! empty( $blocked_ip_entry->end_block ) ) {
882
- $start_block = ! empty( $blocked_ip_entry->start_block ) ? new DateTime( $blocked_ip_entry->start_block ): false;
883
- $end_block = ! empty( $is_blocked->end_block ) ? new DateTime( $is_blocked->end_block ): false;
884
-
885
- // @TODO - I'm sure there's a better way to handle this
886
- if (
887
- (
888
- $start_block && $end_block &&
889
- $todays_date->getTimestamp() >= $start_block->getTimestamp() &&
890
- $todays_date->getTimestamp() <= $end_block->getTimestamp()
891
- ) || (
892
- $start_block && ! $end_block &&
893
- $todays_date->getTimestamp() >= $start_block->getTimestamp()
894
- ) || (
895
- ! $start_block && $end_block &&
896
- $todays_date->getTimestamp() <= $end_block->getTimestamp()
897
- )
898
- ) {
899
- return true;
900
- }
901
- } else {
902
- return true;
903
- }
904
-
905
- return false;
906
- }
907
- }
908
-
909
  /**
910
  * Determines if the current page is the login page
911
  */
@@ -922,282 +727,6 @@ if ( ! function_exists( 'wpzerospam_is_login' ) ) {
922
  }
923
  }
924
 
925
- /**
926
- * Get the user's current URL
927
- */
928
- if ( ! function_exists( 'wpzerospam_current_url' ) ) {
929
- function wpzerospam_current_url() {
930
- $url = [];
931
-
932
- $url['full'] = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
933
- $url = array_merge( $url, parse_url( $url['full'] ) );
934
-
935
- // Parse the URL query string
936
- if ( ! empty( $url['query'] ) ) {
937
- parse_str( $url['query'], $url['query'] );
938
- }
939
-
940
- return $url;
941
- }
942
- }
943
-
944
- /**
945
- * Queries the BotScout API
946
- *
947
- * @link http://botscout.com/api.htm
948
- *
949
- * @since 4.6.0
950
- */
951
- if ( ! function_exists( 'wpzerospam_botscout_request' ) ) {
952
- function wpzerospam_botscout_request( $ip ) {
953
- $options = wpzerospam_options();
954
-
955
- if ( empty( $options['botscout_api'] ) ) { return false; }
956
-
957
- $api_url = 'https://botscout.com/test/?';
958
- $params = [ 'ip' => $ip, 'key' => $options['botscout_api'] ];
959
- $endpoint = $api_url . http_build_query( $params );
960
- $response = wp_remote_get( $endpoint );
961
-
962
- if ( is_array( $response ) && ! is_wp_error( $response ) ) {
963
- $data = wp_remote_retrieve_body( $response );
964
-
965
- // Check if there's an error
966
- if ( strpos( $data, '!' ) === false ) {
967
- // Valid request
968
- list( $matched, $type, $count ) = explode( "|", $data );
969
- return [
970
- 'matched' => ( $matched == 'Y' ) ? true : false,
971
- 'count' => $count
972
- ];
973
- }
974
- }
975
-
976
- return false;
977
- }
978
- }
979
-
980
- /**
981
- * Checks the post submission for a valid key
982
- *
983
- * @since 4.5.0
984
- */
985
- if ( ! function_exists( 'wpzerospam_botscout_is_spam' ) ) {
986
- function wpzerospam_botscout_is_spam( $ip ) {
987
- // First check if the IP is already in the blacklist table
988
- $in_blacklist = wpzerospam_in_blacklist( $ip );
989
- if ( $in_blacklist ) {
990
- // Check if the record should be updated
991
- $last_updated = strtotime( $in_blacklist->last_updated );
992
- $current_time = current_time( 'timestamp' );
993
- $expiration = $last_updated + MONTH_IN_SECONDS;
994
-
995
- if ( $current_time > $expiration ) {
996
- // Expired, update the record
997
- $botscout_request = wpzerospam_botscout_request( $ip );
998
- if ( $botscout_request && ! empty( $botscout['matched'] ) ) {
999
- $botscout_request['blacklist_service'] = 'botscout';
1000
- $botscout_request['blacklist_id'] = $in_blacklist->blacklist_id;
1001
- wpzerospam_update_blacklist( $botscout_request );
1002
-
1003
- return $botscout_request;
1004
- }
1005
- }
1006
-
1007
- return $in_blacklist;
1008
- }
1009
-
1010
- // Not in the blacklist, query the BotScout API now
1011
- $botscout_request = wpzerospam_botscout_request( $ip );
1012
- if (
1013
- $botscout_request &&
1014
- ! empty( $botscout_request['matched'] )
1015
- ) {
1016
- $new_record = $botscout_request;
1017
- $new_record['ip'] = $ip;
1018
- $new_record['blacklist_service'] = 'botscout';
1019
-
1020
- wpzerospam_update_blacklist( $new_record );
1021
-
1022
- return $new_record;
1023
- }
1024
-
1025
- return false;
1026
- }
1027
- }
1028
-
1029
- /**
1030
- * Queries the Stop Forum Spam API
1031
- *
1032
- * @since 4.5.0
1033
- */
1034
- if ( ! function_exists( 'wpzerospam_stopforumspam_request' ) ) {
1035
- function wpzerospam_stopforumspam_request( $ip ) {
1036
- $api_url = 'https://api.stopforumspam.org/api?';
1037
- $params = [ 'ip' => $ip, 'json' => '' ];
1038
- $endpoint = $api_url . http_build_query( $params );
1039
- $response = wp_remote_get( $endpoint );
1040
-
1041
- if ( is_array( $response ) && ! is_wp_error( $response ) ) {
1042
- $data = wp_remote_retrieve_body( $response );
1043
- $data = json_decode( $data, true );
1044
- if ( ! empty( $data['success'] ) && ! empty( $data['ip'] ) ) {
1045
- return $data['ip'];
1046
- }
1047
- }
1048
-
1049
- return false;
1050
- }
1051
- }
1052
-
1053
- /**
1054
- * Add/update blacklisted IP
1055
- *
1056
- * @since 4.5.0
1057
- */
1058
- if ( ! function_exists( 'wpzerospam_update_blacklist' ) ) {
1059
- function wpzerospam_update_blacklist( $data ) {
1060
- global $wpdb;
1061
-
1062
- $update = [
1063
- 'last_updated' => current_time( 'mysql' ),
1064
- 'blacklist_data' => []
1065
- ];
1066
-
1067
- if ( ! empty( $data['ip'] ) ) {
1068
- $update['user_ip'] = $data['ip'];
1069
- }
1070
-
1071
- if ( ! empty( $data['blacklist_service'] ) ) {
1072
- $update['blacklist_service'] = $data['blacklist_service'];
1073
- }
1074
-
1075
- if ( ! empty( $data['count'] ) ) {
1076
- $update['blacklist_data']['count'] = intval( $data['count'] );
1077
- }
1078
-
1079
- if ( ! empty( $data['appears'] ) ) {
1080
- $update['blacklist_data']['appears'] = intval( $data['appears'] );
1081
- }
1082
-
1083
- if ( ! empty( $data['confidence'] ) ) {
1084
- $update['blacklist_data']['confidence'] = floatval( $data['confidence'] );
1085
- }
1086
-
1087
- if ( ! empty( $data['frequency'] ) ) {
1088
- $update['blacklist_data']['frequency'] = floatval( $data['frequency'] );
1089
- }
1090
-
1091
- if ( ! empty( $data['lastseen'] ) ) {
1092
- $update['blacklist_data']['lastseen'] = floatval( $data['lastseen'] );
1093
- }
1094
-
1095
- if ( ! empty( $data['delegated'] ) ) {
1096
- $update['blacklist_data']['delegated'] = floatval( $data['delegated'] );
1097
- }
1098
-
1099
- if ( ! empty( $data['asn'] ) ) {
1100
- $update['blacklist_data']['asn'] = floatval( $data['asn'] );
1101
- }
1102
-
1103
- if ( ! empty( $data['country'] ) ) {
1104
- $update['blacklist_data']['country'] = floatval( $data['country'] );
1105
- }
1106
-
1107
- if ( ! empty( $update['blacklist_data'] ) ) {
1108
- $update['blacklist_data'] = json_encode( $update['blacklist_data'] );
1109
- }
1110
-
1111
- if ( ! empty( $data['blacklist_id'] ) ) {
1112
- // Update
1113
- $wpdb->update( wpzerospam_tables( 'blacklist' ), $update, [
1114
- 'blacklist_id' => $data['blacklist_id']
1115
- ]);
1116
- return true;
1117
- }
1118
-
1119
- // Insert
1120
- $wpdb->insert( wpzerospam_tables( 'blacklist' ), $update );
1121
- return true;
1122
- }
1123
- }
1124
-
1125
- /**
1126
- * Checks the post submission for a valid key
1127
- *
1128
- * @since 4.5.0
1129
- */
1130
- if ( ! function_exists( 'wpzerospam_stopforumspam_is_spam' ) ) {
1131
- function wpzerospam_stopforumspam_is_spam( $ip ) {
1132
- // First check if the IP is already in the blacklist table
1133
- $in_blacklist = wpzerospam_in_blacklist( $ip );
1134
- if ( $in_blacklist ) {
1135
- // Check if the record should be updated
1136
- $last_updated = strtotime( $in_blacklist->last_updated );
1137
- $current_time = current_time( 'timestamp' );
1138
- $expiration = $last_updated + MONTH_IN_SECONDS;
1139
-
1140
- if ( $current_time > $expiration ) {
1141
- // Expired, update the record
1142
- $stopforumspam_request = wpzerospam_stopforumspam_request( $ip );
1143
- if ( $stopforumspam_request ) {
1144
- $stopforumspam_request['blacklist_id'] = $in_blacklist->blacklist_id;
1145
- wpzerospam_update_blacklist( $stopforumspam_request );
1146
-
1147
- return $stopforumspam_request;
1148
- }
1149
- }
1150
-
1151
- return $in_blacklist;
1152
- }
1153
-
1154
- // Not in the blacklist, query the Stop Forum Spam API now
1155
- $stopforumspam_request = wpzerospam_stopforumspam_request( $ip );
1156
- if (
1157
- $stopforumspam_request &&
1158
- ! empty( $stopforumspam_request['appears'] ) &&
1159
- 'no' != $stopforumspam_request['appears']
1160
- ) {
1161
- $new_record = $stopforumspam_request;
1162
- $new_record['ip'] = $ip;
1163
- $new_record['blacklist_service'] = 'stopforumspam';
1164
-
1165
- wpzerospam_update_blacklist( $new_record );
1166
-
1167
- return $new_record;
1168
- }
1169
-
1170
- return false;
1171
- }
1172
- }
1173
-
1174
- /**
1175
- * Returns a record from the blacklist table if one exists
1176
- *
1177
- * @since 4.5.0
1178
- */
1179
- if ( ! function_exists( 'wpzerospam_in_blacklist' ) ) {
1180
- function wpzerospam_in_blacklist( $ip ) {
1181
- global $wpdb;
1182
-
1183
- return $wpdb->get_row($wpdb->prepare(
1184
- 'SELECT * FROM ' . wpzerospam_tables( 'blacklist' ) . ' WHERE user_ip = %s',
1185
- $ip
1186
- ));
1187
- }
1188
- }
1189
-
1190
- /**
1191
- * Return all blacklisted IPs in the DB
1192
- */
1193
- if ( ! function_exists( 'wpzerospam_get_blacklist' ) ) {
1194
- function wpzerospam_get_blacklist( $args = [] ) {
1195
- global $wpdb;
1196
-
1197
- return $wpdb->get_results( 'SELECT * FROM ' . wpzerospam_tables( 'blacklist' ) );
1198
- }
1199
- }
1200
-
1201
  /**
1202
  * Sends a spam detection to the WordPress Zero Spam database
1203
  */
8
  */
9
 
10
  /**
11
+ * Check access
 
 
 
 
 
12
  *
13
+ * Determines if the current user IP should have access to the site.
14
+ *
15
+ * @return array Includes info about the access check.
16
  */
17
+ if ( ! function_exists( 'wpzerospam_check_access' ) ) {
18
+ function wpzerospam_check_access() {
19
+ $ip = wpzerospam_ip();
20
+ //$ip = '46.229.168.150'; // StopForumSpam testing IP
21
+ //$ip = '120.40.130.70'; // BotScout testing IP
22
 
23
+ // Innocent until proven guilty...
24
+ $access = [ 'access' => true, 'ip' => $ip ];
 
 
25
 
26
+ // Always allow authenticated users & users trying to log in access
27
+ if ( is_user_logged_in() || wpzerospam_is_login() ) {
28
+ return $access;
29
  }
30
 
31
+ /**
32
+ * Only check access for actual page vists. Some resource requests like
33
+ * favicons fire this function which causes duplicate entries in the DB.
34
+ *
35
+ * @TODO - Find a way to avoid these checks & ensure this function only gets
36
+ * fired on page requests vs. resources.
37
+ */
38
+ if (
39
+ ! is_singular() && ! is_page() && ! is_single() && ! is_archive() &&
40
+ ! is_home() && ! is_front_page()
41
+ ) {
42
+ return $access;
43
+ }
44
 
 
 
 
 
 
 
 
 
 
45
  $options = wpzerospam_options();
46
 
47
+ // 1. Check whitelisted IP addresses
48
+ $whitelist = wpzerospam_get_whitelist();
49
+ if ( $whitelist && array_key_exists( $ip, $whitelist ) ) {
50
+ return $access;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
 
53
+ // 2. Check if the user's IP address has been blocked
54
+ $blocked = wpzerospam_is_blocked( $ip );
55
+ if ( $blocked ) {
56
+ $access['access'] = false;
57
+ $access['reason'] = $blocked['reason'];
 
 
 
 
 
 
 
58
 
59
+ return $access;
 
 
 
 
 
60
  }
61
 
62
+ // 3. Check the blacklist
63
+ $blacklisted = wpzerospam_is_blacklisted( $ip );
64
+ if ( $blacklisted ) {
65
+ /**
66
+ * IP found in the blacklist, check to see if the record needs to be
67
+ * updated.
68
+ */
69
+ $api_blacklisted = wpzerospam_is_api_blacklisted( $ip, $blacklisted );
70
+ if ( $api_blacklisted ) {
71
+ // IP address blacklisted record found & updated
72
+ $access['access'] = false;
73
+ $access['reason'] = $api_blacklisted['blacklist_service'];
74
 
75
+ return $access;
 
 
 
 
 
 
 
 
76
  }
77
  }
78
 
79
+ // 4. Check the API blacklists
80
+ $api_blacklisted = wpzerospam_is_api_blacklisted( $ip );
81
+ if ( $api_blacklisted ) {
82
+ $access['access'] = false;
83
+ $access['reason'] = $api_blacklisted['blacklist_service'];
84
 
85
+ return $access;
 
 
 
86
  }
87
 
88
+ return $access;
 
 
 
 
89
  }
90
  }
91
 
92
  /**
93
+ * Checks & updates blacklist records from APIs
94
  *
95
+ * @param string $ip IP address to check.
96
+ * @param array $blacklisted_record IP blacklist record from the DB
97
+ * @return boolean/array False is not blacklisted, otherwise an array with the
98
+ * blacklisted IP information.
99
  */
100
+ if ( ! function_exists( 'wpzerospam_is_api_blacklisted' ) ) {
101
+ function wpzerospam_is_api_blacklisted( $ip, $blacklisted_record = false ) {
102
+ global $wpdb;
103
+
104
  $options = wpzerospam_options();
105
+
106
+ if ( $blacklisted_record ) {
107
+ // Check/update existing blacklist record
108
+
109
+ $last_updated = strtotime( $blacklisted_record['last_updated'] );
110
+ $current_time = current_time( 'timestamp' );
111
+ $expiration = $last_updated + MONTH_IN_SECONDS;
112
+
113
+ if ( $current_time > $expiration ) {
114
+ // Expired, update the blacklist record in the DB
115
+ $query = wpzerospam_query_blacklist_api(
116
+ $ip,
117
+ $blacklisted_record['blacklist_service']
118
+ );
119
+
120
+ if ( $query ) {
121
+ if ( ! empty( $query['confidence'] ) && $query['confidence'] < $options['stopforumspam_confidence_min'] ) {
122
+ // Does not meet the stopforumspam confidence minimum, delete record
123
+ $wpdb->delete( wpzerospam_tables( 'blacklist' ), [
124
+ 'blacklist_id' => $blacklisted_record['blacklist_id']
125
+ ]);
126
+
127
+ return false;
128
+ } else {
129
+ // Blacklist API found a matching record, update the DB one
130
+ $blacklisted_record['last_updated'] = current_time( 'mysql' );
131
+ $blacklisted_record['blacklist_data'] = json_encode( $query );
132
+
133
+ $wpdb->update( wpzerospam_tables( 'blacklist' ), $blacklisted_record, [
134
+ 'blacklist_id' => $blacklisted_record['blacklist_id']
135
+ ]);
136
+
137
+ return $blacklisted_record;
138
+ }
139
+ } else {
140
+ // Blacklist API didn't find a matching record, delete the DB one
141
+ $wpdb->delete( wpzerospam_tables( 'blacklist' ), [
142
+ 'blacklist_id' => $blacklisted_record['blacklist_id']
143
+ ]);
144
+
145
+ return false;
146
+ }
147
+ } else {
148
+ // Not expired
149
+ return $blacklisted_record;
150
+ }
151
+ } else {
152
+ // Check all available blacklist APIs
153
+ $stopforumspam = wpzerospam_query_blacklist_api( $ip, 'stopforumspam' );
154
+ if ( $stopforumspam ) {
155
+ if ( ! empty( $stopforumspam['confidence'] ) && $stopforumspam['confidence'] < $options['stopforumspam_confidence_min'] ) {
156
+ // Does not meet the stopforumspam confidence minimum, delete record
157
+ $wpdb->delete( wpzerospam_tables( 'blacklist' ), [
158
+ 'user_ip' => $ip
159
+ ]);
160
+
161
+ return false;
162
  }
163
 
164
+ $blacklisted_record = [
165
+ 'blacklist_service' => 'stopforumspam',
166
+ 'user_ip' => $ip,
167
+ 'last_updated' => current_time( 'mysql' ),
168
+ 'blacklist_data' => json_encode( $stopforumspam )
169
+ ];
170
+
171
+ $wpdb->replace( wpzerospam_tables( 'blacklist' ), $blacklisted_record );
172
+
173
+ return $blacklisted_record;
174
+ }
175
+
176
+ $botscout = wpzerospam_query_blacklist_api( $ip, 'botscout' );
177
+ if ( $botscout ) {
178
+ $blacklisted_record = [
179
+ 'blacklist_service' => 'botscout',
180
+ 'user_ip' => $ip,
181
+ 'last_updated' => current_time( 'mysql' ),
182
+ 'blacklist_data' => json_encode( $botscout )
183
+ ];
184
+
185
+ $wpdb->replace( wpzerospam_tables( 'blacklist' ), $blacklisted_record );
186
+
187
+ return $blacklisted_record;
188
  }
189
  }
190
 
193
  }
194
 
195
  /**
196
+ * Adds a access attempt from a blocked user
 
 
197
  *
198
+ * @param string $reason The reason for the block
199
  */
200
+ if ( ! function_exists( 'wpzerospam_attempt_blocked' ) ) {
201
+ function wpzerospam_attempt_blocked( $ip, $reason ) {
202
+ global $wpdb;
 
203
 
204
+ $options = wpzerospam_options();
205
+
206
+ // Check blocked tables
207
+ $blocked = wpzerospam_is_blocked( $ip );
208
+ if ( $blocked ) {
209
+ // IP already exists in the blocked IP table, increment attempt
210
+ $attempts = $blocked['attempts'];
211
+ $attempts++;
212
+
213
+ $wpdb->update( wpzerospam_tables( 'blocked' ), [
214
+ 'attempts' => $attempts
215
+ ], [
216
+ 'blocked_id' => $blocked['blocked_id']
217
+ ]);
218
  }
219
 
220
+ // Check $blacklisted table
221
+ $blacklisted = wpzerospam_is_blacklisted( $ip );
222
+ if ( $blacklisted ) {
223
+ // IP already exists in the blacklisted IP table, increment attempt
224
+ $attempts = $blacklisted['attempts'];
225
+ $attempts++;
226
+
227
+ $wpdb->update( wpzerospam_tables( 'blacklist' ), [
228
+ 'attempts' => $attempts
229
+ ], [
230
+ 'blacklist_id' => $blacklisted['blacklist_id']
231
+ ]);
232
  }
233
 
234
+ wpzerospam_log_spam( 'blocked', [ 'reason' => $reason ] );
 
 
235
 
236
+ if ( 'redirect' == $options['block_handler'] ) {
237
+ wp_redirect( esc_url( $options['blocked_redirect_url'] ) );
238
+ exit();
239
+ } else {
240
+ status_header( 403 );
241
+ die( $options['blocked_message'] );
242
  }
243
+ }
244
+ }
245
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
 
 
 
 
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
 
 
 
 
 
 
 
 
 
249
 
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
+
265
+
266
+
267
+ /**
268
+ * Create a log entry if logging is enabled
269
+ */
270
+ if ( ! function_exists( 'wpzerospam_log_spam' ) ) {
271
+ function wpzerospam_log_spam( $type, $data = [] ) {
272
+ global $wpdb;
273
+
274
+ $options = wpzerospam_options();
275
+
276
+ if ( ! empty( $data['ip'] ) ) {
277
+ $ip_address = $data['ip'];
278
+ unset( $data['ip'] );
279
+ } else {
280
+ $ip_address = wpzerospam_ip();
281
  }
282
 
283
+ // Check is the spam detection should be shared
284
+ if ( 'enabled' == $options['share_detections'] ) {
285
+ wpzerospam_send_detection([
286
+ 'ip' => $ip_address,
287
+ 'type' => $type
288
+ ]);
289
+ }
290
 
291
+ // Check if spam logging is enabled, also check if type is 'denied'
292
+ // (blocked IP address) & logging of blocked IPs is enabled.
293
+ if ( 'enabled' != $options['log_spam'] ||
294
+ ( 'blocked' == $type && 'enabled' != $options['log_blocked_ips'] )
295
+ ) {
296
+ // Logging disabled
297
+ return false;
298
  }
299
 
300
+ $current_url = wpzerospam_current_url();
301
+ $location_info = wpzerospam_get_ip_info( $ip_address );
 
 
 
 
302
 
303
+ // Add record to the database
304
+ $record = [
305
+ 'log_type' => $type,
306
+ 'user_ip' => wpzerospam_ip(),
307
+ 'date_recorded' => current_time( 'mysql' ),
308
+ 'page_url' => $current_url['full'],
309
+ 'submission_data' => json_encode( $data )
310
+ ];
311
+
312
+ if ( $location_info ) {
313
+ $record['country'] = $location_info['country_code'];
314
+ $record['region'] = $location_info['region_code'];
315
+ $record['city'] = $location_info['city'];
316
+ $record['latitude'] = $location_info['latitude'];
317
+ $record['longitude'] = $location_info['longitude'];
318
  }
319
 
320
+ $wpdb->insert( wpzerospam_tables( 'log' ), $record );
321
  }
322
  }
323
 
338
 
339
 
340
 
 
 
341
 
342
 
343
 
609
  }
610
  }
611
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  /**
613
  * Returns the generated key for checking submissions
614
  */
655
  }
656
  }
657
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
658
  /**
659
  * Checks if a specific plugin integration is turned on & plugin active.
660
  */
711
  }
712
  }
713
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  /**
715
  * Determines if the current page is the login page
716
  */
727
  }
728
  }
729
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
730
  /**
731
  * Sends a spam detection to the WordPress Zero Spam database
732
  */
inc/updates.php CHANGED
@@ -6,16 +6,27 @@
6
  * @since 4.0.0
7
  */
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  /**
11
- * Transfers the blocked IPs that used to exist in options to the dedicated
12
- * table.
13
  *
14
  * @since 4.2.0
15
  */
16
  add_action( 'admin_init', function() {
17
- $options = wpzerospam_options();
18
-
19
  if( ! function_exists( 'is_plugin_active' ) ) {
20
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
21
  }
@@ -34,18 +45,4 @@ add_action( 'admin_init', function() {
34
  ) {
35
  activate_plugin( 'zero-spam/wordpress-zero-spam.php', '', true );
36
  }
37
-
38
- if ( ! empty( $options['blocked_ips'] ) ) {
39
- // IPs found, transfer them to the database
40
- foreach( $options['blocked_ips'] as $key => $ip ) {
41
- if ( ! empty( $ips ) ) {
42
- wpzerospam_update_blocked_ip( $ip['ip_address'], [
43
- 'reason' => $ip['reason']
44
- ]);
45
- }
46
- }
47
-
48
- unset( $options['blocked_ips'] );
49
- update_option( 'wpzerospam', $options );
50
- }
51
  });
6
  * @since 4.0.0
7
  */
8
 
9
+ /**
10
+ * Check if any updates should be preformed
11
+ */
12
+ add_action( 'init', function() {
13
+ global $wpdb;
14
+ $update_version = get_option( 'wpzerospam_update_version' );
15
+
16
+ if ( ! $update_version ) {
17
+ // Clear the blacklist.
18
+ $wpdb->query( "TRUNCATE TABLE " . wpzerospam_tables( 'blacklist' ) );
19
+ update_option( 'wpzerospam_update_version', '1' );
20
+ }
21
+ });
22
+
23
 
24
  /**
25
+ * Fixes issue with upgrade from 3 to 4
 
26
  *
27
  * @since 4.2.0
28
  */
29
  add_action( 'admin_init', function() {
 
 
30
  if( ! function_exists( 'is_plugin_active' ) ) {
31
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
32
  }
45
  ) {
46
  activate_plugin( 'zero-spam/wordpress-zero-spam.php', '', true );
47
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  });
inc/utilities.php ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Utility helpers
4
+ *
5
+ * Helpers functions to return data vs. altering it or doing anything with it.
6
+ *
7
+ * @package WordPressZeroSpam
8
+ * @since 4.9.3
9
+ * @link https://benmarshall.me/wordpress-zero-spam/
10
+ */
11
+
12
+ /**
13
+ * Locations helper
14
+ */
15
+ require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/inc/locations.php';
16
+
17
+ /**
18
+ * Get the user's current URL
19
+ */
20
+ if ( ! function_exists( 'wpzerospam_current_url' ) ) {
21
+ function wpzerospam_current_url() {
22
+ $url = [];
23
+
24
+ $url['full'] = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
25
+ $url = array_merge( $url, parse_url( $url['full'] ) );
26
+
27
+ // Parse the URL query string
28
+ if ( ! empty( $url['query'] ) ) {
29
+ parse_str( $url['query'], $url['query'] );
30
+ }
31
+
32
+ return $url;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Returns the current user's IP address
38
+ */
39
+ if ( ! function_exists( 'wpzerospam_ip' ) ) {
40
+ function wpzerospam_ip() {
41
+ if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
42
+ $ip = $_SERVER['HTTP_CLIENT_IP'];
43
+ } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
44
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
45
+ } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED'])) {
46
+ $ip = $_SERVER['HTTP_X_FORWARDED'];
47
+ } elseif ( ! empty($_SERVER['HTTP_FORWARDED_FOR'])) {
48
+ $ip = $_SERVER['HTTP_FORWARDED_FOR'];
49
+ } elseif ( ! empty($_SERVER['HTTP_FORWARDED'])) {
50
+ $ip = $_SERVER['HTTP_FORWARDED'];
51
+ } else {
52
+ $ip = $_SERVER['REMOTE_ADDR'];
53
+ }
54
+
55
+ $ip = explode( ',', $ip );
56
+ $ip = trim( $ip[0] );
57
+
58
+ if ( ! rest_is_ip_address( $ip ) ) { return false; }
59
+
60
+ return $ip;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Returns an array of tables the plugin uses
66
+ */
67
+ if ( ! function_exists( 'wpzerospam_tables' ) ) {
68
+ function wpzerospam_tables( $key = false ) {
69
+ global $wpdb;
70
+
71
+ $tables = [
72
+ 'log' => $wpdb->prefix . 'wpzerospam_log',
73
+ 'blocked' => $wpdb->prefix . 'wpzerospam_blocked',
74
+ 'blacklist' => $wpdb->prefix . 'wpzerospam_blacklist'
75
+ ];
76
+
77
+ if ( ! $key ) {
78
+ return $tables;
79
+ } elseif( ! empty( $tables[ $key ] ) ) {
80
+ return $tables[ $key ];
81
+ }
82
+
83
+ return false;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Returns the plugin settings.
89
+ */
90
+ if ( ! function_exists( 'wpzerospam_options' ) ) {
91
+ function wpzerospam_options() {
92
+ $options = get_option( 'wpzerospam' );
93
+
94
+ if ( empty( $options['share_data'] ) ) { $options['share_data'] = 'enabled'; }
95
+ if ( empty( $options['auto_block_ips'] ) ) { $options['auto_block_ips'] = 'disabled'; }
96
+ if ( empty( $options['auto_block_period'] ) ) { $options['auto_block_period'] = 30; }
97
+ if ( empty( $options['blocked_redirect_url'] ) ) { $options['blocked_redirect_url'] = 'https://www.google.com'; }
98
+ if ( empty( $options['spam_handler'] ) ) { $options['spam_handler'] = '403'; }
99
+ if ( empty( $options['block_handler'] ) ) { $options['block_handler'] = '403'; }
100
+ if ( empty( $options['spam_redirect_url'] ) ) { $options['spam_redirect_url'] = 'https://www.google.com'; }
101
+ if ( empty( $options['spam_message'] ) ) { $options['spam_message'] = __( 'There was a problem with your submission. Please go back and try again.', 'wpzerospam' ); }
102
+ if ( empty( $options['blocked_message'] ) ) { $options['blocked_message'] = __( 'You have been blocked from visiting this site by WordPress Zero Spam due to detected spam activity.', 'wpzerospam' ); }
103
+ if ( empty( $options['log_spam'] ) ) { $options['log_spam'] = 'disabled'; }
104
+ if ( empty( $options['verify_comments'] ) ) { $options['verify_comments'] = 'enabled'; }
105
+ if ( empty( $options['verify_registrations'] ) ) { $options['verify_registrations'] = 'enabled'; }
106
+ if ( empty( $options['log_blocked_ips'] ) ) { $options['log_blocked_ips'] = 'disabled'; }
107
+ if ( empty( $options['auto_block_permanently'] ) ) { $options['auto_block_permanently'] = 3; }
108
+ if ( empty( $options['botscout_api'] ) ) { $options['botscout_api'] = false; }
109
+ if ( empty( $options['ip_whitelist'] ) ) { $options['ip_whitelist'] = false; }
110
+ if ( empty( $options['api_timeout'] ) ) { $options['api_timeout'] = 5; }
111
+ if ( empty( $options['stopforumspam_confidence_min'] ) ) { $options['stopforumspam_confidence_min'] = 20; }
112
+
113
+ if ( empty( $options['verify_cf7'] ) ) {
114
+ $options['verify_cf7'] = 'enabled';
115
+ }
116
+
117
+ if ( empty( $options['share_detections'] ) ) {
118
+ $options['share_detections'] = 'enabled';
119
+ }
120
+
121
+ if ( empty( $options['verify_gform'] ) ) {
122
+ $options['verify_gform'] = 'enabled';
123
+ }
124
+
125
+ if ( empty( $options['verify_bp_registrations'] ) ) {
126
+ $options['verify_bp_registrations'] = 'enabled';
127
+ }
128
+
129
+ if ( empty( $options['verify_wpforms'] ) ) {
130
+ $options['verify_wpforms'] = 'enabled';
131
+ }
132
+
133
+ if ( empty( $options['verify_fluentform'] ) ) {
134
+ $options['verify_fluentform'] = 'enabled';
135
+ }
136
+
137
+ if ( empty( $options['verify_formidable'] ) ) {
138
+ $options['verify_formidable'] = 'enabled';
139
+ }
140
+
141
+ if ( empty( $options['stop_forum_spam'] ) ) {
142
+ $options['stop_forum_spam'] = 'enabled';
143
+ }
144
+
145
+ if ( empty( $options['strip_comment_links'] ) ) {
146
+ $options['strip_comment_links'] = 'disabled';
147
+ }
148
+
149
+ if ( empty( $options['strip_comment_author_links'] ) ) {
150
+ $options['strip_comment_author_links'] = 'disabled';
151
+ }
152
+
153
+ return $options;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Queries a blacklist API
159
+ *
160
+ * @param string $ip The IP address to query
161
+ * @param string $service The API service to query
162
+ * @return false/array False if not found, otherwise the IP info.
163
+ */
164
+ if ( ! function_exists( 'wpzerospam_query_blacklist_api' ) ) {
165
+ function wpzerospam_query_blacklist_api( $ip, $service ) {
166
+ $options = wpzerospam_options();
167
+
168
+ switch( $service ) {
169
+ case 'stopforumspam':
170
+ if ( 'enabled' != $options['stop_forum_spam'] ) { return false; }
171
+
172
+ $api_url = 'https://api.stopforumspam.org/api?';
173
+ $params = [ 'ip' => $ip, 'json' => '' ];
174
+ $endpoint = $api_url . http_build_query( $params );
175
+ break;
176
+ case 'botscout':
177
+ if ( empty( $options['botscout_api'] ) ) { return false; }
178
+
179
+ $api_url = 'https://botscout.com/test/?';
180
+ $params = [ 'ip' => $ip, 'key' => $options['botscout_api'] ];
181
+ $endpoint = $api_url . http_build_query( $params );
182
+ break;
183
+ }
184
+
185
+ if ( ! empty( $endpoint ) ) {
186
+ $response = wp_remote_get( $endpoint, [ 'timeout' => $options['api_timeout'] ] );
187
+ if ( is_array( $response ) && ! is_wp_error( $response ) ) {
188
+ $data = wp_remote_retrieve_body( $response );
189
+
190
+ switch( $service ) {
191
+ case 'stopforumspam':
192
+ $data = json_decode( $data, true );
193
+ if (
194
+ ! empty( $data['success'] ) &&
195
+ $data['success'] &&
196
+ ! empty( $data['ip'] ) &&
197
+ ! empty( $data['ip']['appears'] )
198
+ ) {
199
+ return $data['ip'];
200
+ }
201
+ break;
202
+ case 'botscout':
203
+ if ( strpos( $data, '!' ) === false ) {
204
+ list( $matched, $type, $count ) = explode( "|", $data );
205
+ if ( 'Y' == $matched ) {
206
+ return [
207
+ 'type' => $type,
208
+ 'count' => $count
209
+ ];
210
+ }
211
+ }
212
+ break;
213
+ }
214
+ }
215
+ }
216
+
217
+ return false;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Query the database tables
223
+ *
224
+ * @return false/array False if not found, otherwise the blocked IP info.
225
+ */
226
+ if ( ! function_exists( 'wpzerospam_query_table' ) ) {
227
+ function wpzerospam_query_table( $table, $args = [] ) {
228
+ global $wpdb;
229
+
230
+ // Select
231
+ $sql = 'SELECT ';
232
+ if ( ! empty( $args['select'] ) ) {
233
+ $sql .= implode( ',', $args['select'] );
234
+ } else {
235
+ $sql .= '*';
236
+ }
237
+
238
+ // From
239
+ $sql .= " from " . wpzerospam_tables( $table );
240
+
241
+ // Where
242
+ if ( ! empty( $args['where'] ) ) {
243
+ $sql .= ' WHERE ';
244
+ foreach( $args['where'] as $key => $value ) {
245
+ if ( is_int( $value ) ) {
246
+ $sql .= $key . ' = ' . $value . ' ';
247
+ } else {
248
+ $sql .= $key . ' = "' . $value . '" ';
249
+ }
250
+ }
251
+ }
252
+
253
+ // Limit
254
+ if ( ! empty( $args['limit'] ) ) {
255
+ $sql .= 'LIMIT ' . $args['limit'];
256
+
257
+ // Offset
258
+ if ( ! empty( $args['offset'] ) ) {
259
+ $sql .= ', ' . $args['offset'];
260
+ }
261
+ }
262
+
263
+ if ( ! empty( $args['limit'] ) && 1 == $args['limit'] ) {
264
+ return $wpdb->get_row( $sql, ARRAY_A );
265
+ } else {
266
+ return $wpdb->get_results( $sql, ARRAY_A );
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Returns the geolocation information for a specified IP address.
273
+ *
274
+ * @param string $ip IP address.
275
+ * @return array/false An array with the IP address location information or
276
+ * false if not found.
277
+ */
278
+ if ( ! function_exists( 'wpzerospam_get_ip_info' ) ) {
279
+ function wpzerospam_get_ip_info( $ip ) {
280
+ $options = wpzerospam_options();
281
+
282
+ if ( empty( $options['ipstack_api'] ) ) { return false; }
283
+
284
+ $base_url = 'http://api.ipstack.com/';
285
+ $remote_url = $base_url . $ip . '?access_key=' . $options['ipstack_api'];
286
+ $response = wp_remote_get( $remote_url, [ 'timeout' => $options['api_timeout'] ] );
287
+
288
+ if ( is_array( $response ) && ! is_wp_error( $response ) ) {
289
+ $info = json_decode( $response['body'], true );
290
+
291
+ return [
292
+ 'type' => ! empty( $info['type'] ) ? sanitize_text_field( $info['type'] ) : false,
293
+ 'continent_code' => ! empty( $info['continent_code'] ) ? sanitize_text_field( $info['continent_code'] ) : false,
294
+ 'continent_name' => ! empty( $info['continent_name'] ) ? sanitize_text_field( $info['continent_name'] ) : false,
295
+ 'country_code' => ! empty( $info['country_code'] ) ? sanitize_text_field( $info['country_code'] ) : false,
296
+ 'country_name' => ! empty( $info['country_name'] ) ? sanitize_text_field( $info['country_name'] ) : false,
297
+ 'region_code' => ! empty( $info['region_code'] ) ? sanitize_text_field( $info['region_code'] ) : false,
298
+ 'region_name' => ! empty( $info['region_name'] ) ? sanitize_text_field( $info['region_name'] ) : false,
299
+ 'city' => ! empty( $info['city'] ) ? sanitize_text_field( $info['city'] ) : false,
300
+ 'zip' => ! empty( $info['zip'] ) ? sanitize_text_field( $info['zip'] ) : false,
301
+ 'latitude' => ! empty( $info['latitude'] ) ? sanitize_text_field( $info['latitude'] ) : false,
302
+ 'longitude' => ! empty( $info['longitude'] ) ? sanitize_text_field( $info['longitude'] ) : false,
303
+ 'flag' => ! empty( $info['location']['country_flag'] ) ? sanitize_text_field( $info['location']['country_flag'] ) : false,
304
+ ];
305
+ }
306
+
307
+ return false;
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Returns the human-readable spam type or an array of available spam types.
313
+ *
314
+ * @param string $type_key The key of the type that should be returned.
315
+ * @return string/array The human-readable type name or an array of all the
316
+ * available types.
317
+ */
318
+ if ( ! function_exists( 'wpzerospam_types' ) ) {
319
+ function wpzerospam_types( $type_key = false ) {
320
+ $types = apply_filters( 'wpzerospam_types', [ 'blocked' => __( 'Access Blocked', 'wpzerospam' ) ] );
321
+
322
+ if ( $type_key ) {
323
+ if ( ! empty( $types[ $type_key ] ) ) {
324
+ return $types[ $type_key ];
325
+ }
326
+
327
+ return $type_key;
328
+ }
329
+
330
+ return $types;
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Whitelisted IPs
336
+ *
337
+ * @return array An array of whitelisted IP addresses.
338
+ */
339
+ if ( ! function_exists( 'wpzerospam_get_whitelist' ) ) {
340
+ function wpzerospam_get_whitelist() {
341
+ $options = wpzerospam_options();
342
+ if ( $options['ip_whitelist'] ) {
343
+ $whitelist = explode( PHP_EOL, $options['ip_whitelist'] );
344
+ if ( $whitelist ) {
345
+ $whitelisted = [];
346
+ foreach( $whitelist as $k => $whitelisted_ip ) {
347
+ $whitelisted[ $whitelisted_ip ] = $whitelisted_ip;
348
+ }
349
+
350
+ return $whitelisted;
351
+ }
352
+ }
353
+
354
+ return false;
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Checks if an IP is blocked
360
+ *
361
+ * @param string IP address to check.
362
+ * @return boolean/array False is not blocked, otherwise an array with the
363
+ * blocked IP information.
364
+ */
365
+ if ( ! function_exists( 'wpzerospam_is_blocked' ) ) {
366
+ function wpzerospam_is_blocked( $ip ) {
367
+ $blocked_ip = wpzerospam_query_table( 'blocked', [
368
+ 'select' => [
369
+ 'blocked_type',
370
+ 'start_block',
371
+ 'end_block',
372
+ 'reason',
373
+ 'attempts'
374
+ ],
375
+ 'where' => [ 'user_ip' => $ip ],
376
+ 'limit' => 1
377
+ ]);
378
+
379
+ if ( $blocked_ip ) {
380
+ if ( 'permanent' == $blocked_ip['blocked_type'] ) {
381
+ // Permanently blocked
382
+ return $blocked_ip;
383
+ } else {
384
+ // Temporarily blocked
385
+ $current_datetime = current_time( 'timestamp' );
386
+ $start_block = strtotime( $blocked_ip['start_block'] );
387
+ $end_block = strtotime( $blocked_ip['end_block'] );
388
+ if (
389
+ $current_datetime >= $start_block &&
390
+ $current_datetime < $end_block
391
+ ) {
392
+ return $blocked_ip;
393
+ }
394
+ }
395
+ }
396
+
397
+ return false;
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Checks if an IP is blacklisted
403
+ *
404
+ * @param string IP address to check.
405
+ * @return boolean/array False is not blacklisted, otherwise an array with the
406
+ * blacklisted IP information.
407
+ */
408
+ if ( ! function_exists( 'wpzerospam_is_blacklisted' ) ) {
409
+ function wpzerospam_is_blacklisted( $ip ) {
410
+ $blacklist_ip = wpzerospam_query_table( 'blacklist', [
411
+ 'select' => [
412
+ 'blacklist_service', 'blacklist_id', 'last_updated', 'attempts'
413
+ ],
414
+ 'where' => [ 'user_ip' => $ip ],
415
+ 'limit' => 1
416
+ ]);
417
+
418
+ return $blacklist_ip;
419
+ }
420
+ }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Donate link: https://benmarshall.me/donate/?utm_source=wordpress_zero_spam&utm_m
5
  Requires at least: 5.2
6
  Tested up to: 5.4.2
7
  Requires PHP: 7.1
8
- Stable tag: 4.9.2
9
  License: GNU GPLv3
10
  License URI: https://choosealicense.com/licenses/gpl-3.0/
11
 
@@ -13,9 +13,11 @@ WordPress Zero Spam makes blocking spam & malicious visitors a cinch. Just insta
13
 
14
  == Description ==
15
 
16
- Quit forcing users to answer silly questions, read confusing captchas, or take additional steps just to prove they're not spam. Stop malicious bots & hackers in their tracks before they ever have a chance to infiltrate your site &mdash; introducing WordPress Zero Spam.
17
 
18
- [WordPress Zero Spam](https://benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) uses AI in combination with proven spam detection techniques and a database of known malicious IPs from around the world to detect and block unwanted visitors. In addition, it integrates with other popular plugins to provide all around protection. Just install, activate, and enjoy a spam-free site.
 
 
19
 
20
  = WordPress Zero Spam features =
21
 
@@ -23,7 +25,7 @@ Quit forcing users to answer silly questions, read confusing captchas, or take a
23
  * **No moderation queues**, spam isn't a administrators' problem
24
  * **Blocks 99.9% of spam** submissions
25
  * **Blocks malicious IPs** from ever seeing your site
26
- * **Check IPs against spam blacklists** ([Zero Spam](https://zerospam.org), [Stop Forum Spam](https://www.stopforumspam.com/), [BotScout](https://botscout.com/))
27
  * **Auto-block IPs** when a spam detection is triggered
28
  * **Manually block IPs** either temporarily or permanently
29
  * **Developer-friendly**, integrate with any theme, plugin or form
@@ -56,7 +58,7 @@ WordPress Zero Spam is great at blocking spam &mdash; as a site owner there's mo
56
 
57
  = Show Your Support =
58
 
59
- WordPress Zero Spam is free &mdash; completely free & always will be. No premium versions or addons you've gotta buy to access additional features. Help support it's development by [donating](https://benmarshall.me/donate/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) today.
60
 
61
  == Installation ==
62
 
@@ -70,7 +72,7 @@ For more information & developer documentation, see the [plugin’s website](htt
70
 
71
  = Does WordPress Zero Spam check Ninja Forms submissions? =
72
 
73
- No. As of v4.10.0, WordPress Zero Spam no longer checks Ninja Form submissions. Support was dropped due its [required of JavaScript](https://developer.ninjaforms.com/codex/loading-the-form-via-ajax/) and how it submits forms. JavaScript is one of the techniques WordPress Zero Spam uses to determine if a submission is spam. Ninja Forms employs a similar method and has its own [spam detection](https://ninjaforms.com/blog/spam-wordpress-form/) feature.
74
 
75
  = Does WordPress Zero Spam check Jetpack comments? =
76
 
@@ -112,6 +114,14 @@ Yes. One of the many techniques WordPress Zero Spam employs requires JavaScript
112
 
113
  == Changelog ==
114
 
 
 
 
 
 
 
 
 
115
  = 4.9.2 =
116
 
117
  * Removed Ninja Form submission support. See FAQs for more details.
5
  Requires at least: 5.2
6
  Tested up to: 5.4.2
7
  Requires PHP: 7.1
8
+ Stable tag: 4.9.3
9
  License: GNU GPLv3
10
  License URI: https://choosealicense.com/licenses/gpl-3.0/
11
 
13
 
14
  == Description ==
15
 
16
+ Quit forcing users to answer silly questions, read confusing captchas, or take additional steps just to prove they're not spam. Stop malicious bots & hackers in their tracks before they ever have a chance to infiltrate your site &mdash; **introducing WordPress Zero Spam**.
17
 
18
+ [WordPress Zero Spam](https://benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) uses AI in combination with proven spam detection techniques and a database of known malicious IPs from around the world to detect and block unwanted visitors.
19
+
20
+ In addition, it integrates with other popular plugins to provide all around protection. Just install, activate, and enjoy a spam-free site.
21
 
22
  = WordPress Zero Spam features =
23
 
25
  * **No moderation queues**, spam isn't a administrators' problem
26
  * **Blocks 99.9% of spam** submissions
27
  * **Blocks malicious IPs** from ever seeing your site
28
+ * **IP blacklist spam checks** ([Zero Spam](https://zerospam.org), [Stop Forum Spam](https://www.stopforumspam.com/), [BotScout](https://botscout.com/))
29
  * **Auto-block IPs** when a spam detection is triggered
30
  * **Manually block IPs** either temporarily or permanently
31
  * **Developer-friendly**, integrate with any theme, plugin or form
58
 
59
  = Show Your Support =
60
 
61
+ **WordPress Zero Spam is free &mdash; completely free & always will be.** No premium versions or addons you've gotta buy to access additional features. Help support it's development by [donating](https://benmarshall.me/donate/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) today.
62
 
63
  == Installation ==
64
 
72
 
73
  = Does WordPress Zero Spam check Ninja Forms submissions? =
74
 
75
+ No. As of v4.10.0, WordPress Zero Spam no longer checks Ninja Form submissions. Support was dropped due its [requirement of JavaScript](https://developer.ninjaforms.com/codex/loading-the-form-via-ajax/) and how it submits forms. JavaScript is one of the techniques WordPress Zero Spam uses to determine if a submission is spam. Ninja Forms employs a similar method and has its own [spam detection](https://ninjaforms.com/blog/spam-wordpress-form/) feature.
76
 
77
  = Does WordPress Zero Spam check Jetpack comments? =
78
 
114
 
115
  == Changelog ==
116
 
117
+ = 4.9.3 =
118
+
119
+ * Added a confidence threshold for Stop Form Spam checks. See [#202](https://github.com/bmarshall511/wordpress-zero-spam/issues/202);
120
+ * Added an API timeout field to adjust how long a response is allowed to take.
121
+ * Restructred several functions which fixed some interment bugs users were experiencing.
122
+ * Added ability to delete all entries from a table.
123
+ * This update **will delete all exisiting blacklisted IPs** to ensure visitors aren't getting blocked when that shouldn't be.
124
+
125
  = 4.9.2 =
126
 
127
  * Removed Ninja Form submission support. See FAQs for more details.
templates/ip-list.php CHANGED
@@ -56,10 +56,7 @@ $chart_limit = 20;
56
  <?php echo number_format( $ary['count'], 0 ); ?>
57
  </span>
58
  <span class="wpzerospam-list-cell wpzerospam-list-cell-action">
59
- <?php
60
- $blocked_status = wpzerospam_get_blocked_ips( $ip );
61
- if ( $blocked_status && wpzerospam_is_blocked( $blocked_status ) ):
62
- ?>
63
  <span class="wpzerospam-blocked"><?php _e( 'Blocked', 'wpzerospam' ); ?></span>
64
  <?php else: ?>
65
  <a href="<?php echo admin_url( 'admin.php?page=wordpress-zero-spam-blocked-ips&ip=' . $ip ); ?>">
56
  <?php echo number_format( $ary['count'], 0 ); ?>
57
  </span>
58
  <span class="wpzerospam-list-cell wpzerospam-list-cell-action">
59
+ <?php if ( wpzerospam_is_blocked( $ip ) ): ?>
 
 
 
60
  <span class="wpzerospam-blocked"><?php _e( 'Blocked', 'wpzerospam' ); ?></span>
61
  <?php else: ?>
62
  <a href="<?php echo admin_url( 'admin.php?page=wordpress-zero-spam-blocked-ips&ip=' . $ip ); ?>">
wordpress-zero-spam.php CHANGED
@@ -13,7 +13,7 @@
13
  * Plugin Name: WordPress Zero Spam
14
  * Plugin URI: https://benmarshall.me/wordpress-zero-spam
15
  * Description: Tired of all the useless and bloated WordPress spam plugins? The WordPress Zero Spam plugin makes blocking spam a cinch. <strong>Just install, activate and say goodbye to spam.</strong> Based on work by <a href="http://davidwalsh.name/wordpress-comment-spam" target="_blank">David Walsh</a>.
16
- * Version: 4.9.2
17
  * Requires at least: 5.2
18
  * Requires PHP: 7.2
19
  * Author: Ben Marshall
@@ -30,8 +30,13 @@ defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
30
 
31
  // Define plugin constants
32
  define( 'WORDPRESS_ZERO_SPAM', __FILE__ );
33
- define( 'WORDPRESS_ZERO_SPAM_DB_VERSION', '0.2' );
34
- define( 'WORDPRESS_ZERO_SPAM_VERSION', '4.9.2' );
 
 
 
 
 
35
 
36
  /**
37
  * Helpers
@@ -87,6 +92,7 @@ function wpzerospam_install() {
87
  user_ip VARCHAR(39) NOT NULL,
88
  last_updated DATETIME NOT NULL,
89
  blacklist_service VARCHAR(255) NULL DEFAULT NULL,
 
90
  blacklist_data LONGTEXT NULL DEFAULT NULL,
91
  PRIMARY KEY (`blacklist_id`)) $charset_collate;";
92
 
@@ -95,14 +101,10 @@ function wpzerospam_install() {
95
 
96
  if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $blocked_table ) ) === $blocked_table ) {
97
  $wpdb->query( "DELETE t1 FROM $blocked_table AS t1 JOIN $blocked_table AS t2 ON t2.blocked_id = t1.blocked_id WHERE t1.blocked_id < t2.blocked_id AND t1.user_ip = t2.user_ip" );
98
-
99
- $wpdb->query( "ALTER TABLE $blocked_table ADD UNIQUE `user_ip` (`user_ip`(39));" );
100
  }
101
 
102
  if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $blacklist_table ) ) === $blacklist_table ) {
103
  $wpdb->query( "DELETE t1 FROM $blacklist_table AS t1 JOIN $blacklist_table AS t2 ON t2.blacklist_id = t1.blacklist_id WHERE t1.blacklist_id < t2.blacklist_id AND t1.user_ip = t2.user_ip" );
104
-
105
- $wpdb->query( "ALTER TABLE $blacklist_table ADD UNIQUE `user_ip` (`user_ip`(39));" );
106
  }
107
 
108
  update_option( 'wpzerospam_db_version', WORDPRESS_ZERO_SPAM_DB_VERSION );
@@ -176,7 +178,7 @@ if ( ! function_exists( 'wpzerospam_template_redirect' ) ) {
176
  $access = wpzerospam_check_access();
177
 
178
  if ( ! $access['access'] ) {
179
- wpzerospam_attempt_blocked( $access['reason'] );
180
  }
181
  }
182
  }
@@ -199,6 +201,7 @@ if ( ! function_exists( 'wpzerospam_uninstall' ) ) {
199
  delete_option( 'wpzerospam' );
200
  delete_option( 'wpzerospam_key' );
201
  delete_option( 'wpzerospam_db_version' );
 
202
 
203
  $tables = wpzerospam_tables();
204
  foreach( $tables as $key => $table ) {
@@ -211,6 +214,7 @@ if ( ! function_exists( 'wpzerospam_uninstall' ) ) {
211
  delete_option( 'wpzerospam' );
212
  delete_option( 'wpzerospam_key' );
213
  delete_option( 'wpzerospam_db_version' );
 
214
 
215
  $tables = wpzerospam_tables();
216
  foreach( $tables as $key => $table ) {
13
  * Plugin Name: WordPress Zero Spam
14
  * Plugin URI: https://benmarshall.me/wordpress-zero-spam
15
  * Description: Tired of all the useless and bloated WordPress spam plugins? The WordPress Zero Spam plugin makes blocking spam a cinch. <strong>Just install, activate and say goodbye to spam.</strong> Based on work by <a href="http://davidwalsh.name/wordpress-comment-spam" target="_blank">David Walsh</a>.
16
+ * Version: 4.9.3
17
  * Requires at least: 5.2
18
  * Requires PHP: 7.2
19
  * Author: Ben Marshall
30
 
31
  // Define plugin constants
32
  define( 'WORDPRESS_ZERO_SPAM', __FILE__ );
33
+ define( 'WORDPRESS_ZERO_SPAM_DB_VERSION', '0.5' );
34
+ define( 'WORDPRESS_ZERO_SPAM_VERSION', '4.9.3' );
35
+
36
+ /**
37
+ * Utility helper functions
38
+ */
39
+ require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/inc/utilities.php';
40
 
41
  /**
42
  * Helpers
92
  user_ip VARCHAR(39) NOT NULL,
93
  last_updated DATETIME NOT NULL,
94
  blacklist_service VARCHAR(255) NULL DEFAULT NULL,
95
+ attempts BIGINT UNSIGNED NOT NULL,
96
  blacklist_data LONGTEXT NULL DEFAULT NULL,
97
  PRIMARY KEY (`blacklist_id`)) $charset_collate;";
98
 
101
 
102
  if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $blocked_table ) ) === $blocked_table ) {
103
  $wpdb->query( "DELETE t1 FROM $blocked_table AS t1 JOIN $blocked_table AS t2 ON t2.blocked_id = t1.blocked_id WHERE t1.blocked_id < t2.blocked_id AND t1.user_ip = t2.user_ip" );
 
 
104
  }
105
 
106
  if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $blacklist_table ) ) === $blacklist_table ) {
107
  $wpdb->query( "DELETE t1 FROM $blacklist_table AS t1 JOIN $blacklist_table AS t2 ON t2.blacklist_id = t1.blacklist_id WHERE t1.blacklist_id < t2.blacklist_id AND t1.user_ip = t2.user_ip" );
 
 
108
  }
109
 
110
  update_option( 'wpzerospam_db_version', WORDPRESS_ZERO_SPAM_DB_VERSION );
178
  $access = wpzerospam_check_access();
179
 
180
  if ( ! $access['access'] ) {
181
+ wpzerospam_attempt_blocked( $access['ip'], $access['reason'] );
182
  }
183
  }
184
  }
201
  delete_option( 'wpzerospam' );
202
  delete_option( 'wpzerospam_key' );
203
  delete_option( 'wpzerospam_db_version' );
204
+ delete_option( 'wpzerospam_update_version' );
205
 
206
  $tables = wpzerospam_tables();
207
  foreach( $tables as $key => $table ) {
214
  delete_option( 'wpzerospam' );
215
  delete_option( 'wpzerospam_key' );
216
  delete_option( 'wpzerospam_db_version' );
217
+ delete_option( 'wpzerospam_update_version' );
218
 
219
  $tables = wpzerospam_tables();
220
  foreach( $tables as $key => $table ) {