WordPress Zero Spam - Version 4.2.0

Version Description

  • Re-implemented logging & added admin pages to prepare for charts & statistics. See #181
Download this release

Release Info

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

Code changes from version 4.1.3 to 4.2.0

addons/buddypress.php CHANGED
@@ -23,7 +23,6 @@ if ( ! function_exists( 'wpzerospam_bp_signup_validate' ) ) {
23
 
24
  do_action( 'wpzerospam_bp_registration_spam' );
25
 
26
- wpzerospam_log_spam( 'bp_registration' );
27
  wpzerospam_spam_detected( 'bp_registration' );
28
  }
29
  }
23
 
24
  do_action( 'wpzerospam_bp_registration_spam' );
25
 
 
26
  wpzerospam_spam_detected( 'bp_registration' );
27
  }
28
  }
addons/comments.php CHANGED
@@ -25,7 +25,6 @@ if ( ! function_exists( 'wpzerospam_preprocess_comment' ) ) {
25
  // Spam comment detected
26
  do_action( 'wpzerospam_comment_spam', $commentdata );
27
 
28
- wpzerospam_log_spam( 'comment', $commentdata );
29
  wpzerospam_spam_detected( 'comment', $commentdata );
30
  }
31
  }
25
  // Spam comment detected
26
  do_action( 'wpzerospam_comment_spam', $commentdata );
27
 
 
28
  wpzerospam_spam_detected( 'comment', $commentdata );
29
  }
30
  }
addons/contact-form-7.php CHANGED
@@ -23,7 +23,6 @@ if ( ! function_exists( 'wpzerospam_wpcf7_validate' ) ) {
23
 
24
  do_action( 'wpzerospam_cf7_spam' );
25
 
26
- wpzerospam_log_spam( 'cf7', $result );
27
  wpzerospam_spam_detected( 'cf7', $result );
28
  }
29
  }
23
 
24
  do_action( 'wpzerospam_cf7_spam' );
25
 
 
26
  wpzerospam_spam_detected( 'cf7', $result );
27
  }
28
  }
addons/gravity-forms.php CHANGED
@@ -23,7 +23,6 @@ if ( ! function_exists( 'wpzerospam_wpcf7_validate' ) ) {
23
 
24
  do_action( 'wpzerospam_gform_spam' );
25
 
26
- wpzerospam_log_spam( 'gform', $form );
27
  wpzerospam_spam_detected( 'gform', $form );
28
  }
29
  }
23
 
24
  do_action( 'wpzerospam_gform_spam' );
25
 
 
26
  wpzerospam_spam_detected( 'gform', $form );
27
  }
28
  }
addons/ninja-forms.php CHANGED
@@ -23,7 +23,6 @@ if ( ! function_exists( 'wpzerospam_ninja_forms_validate' ) ) {
23
 
24
  do_action( 'wpzerospam_ninja_forms_spam' );
25
 
26
- wpzerospam_log_spam( 'ninja_forms' );
27
  wpzerospam_spam_detected( 'ninja_forms' );
28
  }
29
  }
23
 
24
  do_action( 'wpzerospam_ninja_forms_spam' );
25
 
 
26
  wpzerospam_spam_detected( 'ninja_forms' );
27
  }
28
  }
addons/registration.php CHANGED
@@ -21,7 +21,6 @@ if ( ! function_exists( 'wpzerospam_preprocess_registration' ) ) {
21
  'user_email' => $user_email
22
  ];
23
 
24
- wpzerospam_log_spam( 'registration', $data );
25
  wpzerospam_spam_detected( 'registration', $data );
26
  }
27
 
21
  'user_email' => $user_email
22
  ];
23
 
 
24
  wpzerospam_spam_detected( 'registration', $data );
25
  }
26
 
addons/wpforms.php CHANGED
@@ -29,7 +29,6 @@ if ( ! function_exists( 'wpzerospam_wpforms_process_honeypot' ) ) {
29
  'entry' => $entry,
30
  'form_data' => $form_data
31
  ];
32
- wpzerospam_log_spam( 'wpform', $data );
33
  wpzerospam_spam_detected( 'wpform', $data );
34
  }
35
  }
29
  'entry' => $entry,
30
  'form_data' => $form_data
31
  ];
 
32
  wpzerospam_spam_detected( 'wpform', $data );
33
  }
34
  }
classes/class-wpzerospam-blocked-ip-table.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress Zero Spam blocked IP table
4
+ *
5
+ * @package WordPressZeroSpam
6
+ * @since 4.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
10
+
11
+ if ( ! class_exists( 'WP_List_Table' ) ) {
12
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
13
+ }
14
+
15
+ class WPZeroSpam_Blocked_IP_Table extends WP_List_Table {
16
+ function __construct() {
17
+ global $status, $page;
18
+
19
+ $args = [
20
+ 'singular' => __( 'Blocked IP', 'wpzerospam' ),
21
+ 'plural' => __( 'Blocked IPs', 'wpzerospam' ),
22
+ 'ajax' => true
23
+ ];
24
+ parent::__construct( $args );
25
+ }
26
+
27
+ // Register columns
28
+ function get_columns() {
29
+ // Render a checkbox instead of text
30
+ $columns = [
31
+ 'cb' => '<input type="checkbox" />',
32
+ 'user_ip' => __( 'IP Address', 'wpzerospam' ),
33
+ 'blocked_type' => __( 'Type', 'wpzerospam' ),
34
+ 'date_added' => __( 'Date Added', 'wpzerospam' ),
35
+ 'start_block' => __( 'Start Date', 'wpzerospam' ),
36
+ 'end_block' => __( 'End Date', 'wpzerospam' ),
37
+ 'reason' => __( 'Reason', 'wpzerospam' ),
38
+ 'attempts' => __( 'Attempts', 'wpzerospam' ),
39
+ ];
40
+
41
+ return $columns;
42
+ }
43
+
44
+ // Sortable columns
45
+ function get_sortable_columns() {
46
+ $sortable_columns = [
47
+ 'user_ip' => [ 'user_ip', false ],
48
+ 'blocked_type' => [ 'blocked_type', false ],
49
+ 'date_added' => [ 'date_added', false ],
50
+ 'start_block' => [ 'start_block', false ],
51
+ 'end_block' => [ 'end_block', false ],
52
+ 'attempts' => [ 'attempts', false ],
53
+ ];
54
+
55
+ return $sortable_columns;
56
+ }
57
+
58
+ // Checkbox column
59
+ function column_cb( $item ){
60
+ return sprintf(
61
+ '<input type="checkbox" name="%1$s[]" value="%2$s" />',
62
+ /*$1%s*/ 'ids',
63
+ /*$2%s*/ $item->blocked_id
64
+ );
65
+ }
66
+
67
+ // Render column
68
+ function column_default( $item, $column_name ) {
69
+ switch( $column_name ) {
70
+ case 'user_ip':
71
+ return '<a href="https://whatismyipaddress.com/ip/' . $item->user_ip .'" target="_blank" rel="noopener noreferrer">' . $item->user_ip . '</a>';
72
+ break;
73
+ case 'blocked_id':
74
+ return $item->blocked_id;
75
+ break;
76
+ case 'blocked_type':
77
+ return $item->blocked_type;
78
+ break;
79
+ case 'date_added':
80
+ return date( 'M j, Y g:ia' , strtotime( $item->date_added ) );
81
+ break;
82
+ case 'start_block':
83
+ if ( '0000-00-00 00:00:00' == $item->start_block ) {
84
+ $item->start_block = 'N/A';
85
+ }
86
+
87
+ return $item->start_block;
88
+ break;
89
+ case 'end_block':
90
+ if ( '0000-00-00 00:00:00' == $item->end_block ) {
91
+ $item->end_block = 'N/A';
92
+ }
93
+
94
+ return $item->end_block;
95
+ break;
96
+ case 'reason':
97
+ return $item->reason;
98
+ break;
99
+ case 'attempts':
100
+ return $item->attempts;
101
+ break;
102
+ }
103
+ }
104
+
105
+ // Register bulk actions
106
+ function get_bulk_actions() {
107
+ $actions = [ 'delete' => __( 'Delete', 'wpzerospam' ) ];
108
+
109
+ return $actions;
110
+ }
111
+
112
+ /**
113
+ * Define which columns are hidden
114
+ *
115
+ * @return Array
116
+ */
117
+ public function get_hidden_columns() {
118
+ return [];
119
+ }
120
+
121
+ /**
122
+ * Allows you to sort the data by the variables set in the $_GET
123
+ *
124
+ * @return Mixed
125
+ */
126
+ private function sort_data( $a, $b ) {
127
+ // Set defaults
128
+ $orderby = 'date_added';
129
+ $order = 'desc';
130
+
131
+ // If orderby is set, use this as the sort column
132
+ if( ! empty( $_GET['orderby'] ) ) {
133
+ $orderby = $_GET['orderby'];
134
+ }
135
+
136
+ // If order is set use this as the order
137
+ if ( ! empty($_GET['order'] ) ) {
138
+ $order = $_GET['order'];
139
+ }
140
+
141
+ $result = strcmp( $a->$orderby, $b->$orderby );
142
+
143
+ if ( $order === 'asc' ) {
144
+ return $result;
145
+ }
146
+
147
+ return -$result;
148
+ }
149
+
150
+ // Get results
151
+ function prepare_items($args = []) {
152
+ $this->process_bulk_action();
153
+
154
+ $columns = $this->get_columns();
155
+ $hidden = $this->get_hidden_columns();
156
+ $sortable = $this->get_sortable_columns();
157
+
158
+ $data = wpzerospam_get_blocked_ips();
159
+ usort( $data, [ &$this, 'sort_data' ] );
160
+
161
+ $per_page = 50;
162
+ $current_page = $this->get_pagenum();
163
+ $total_items = count( $data );
164
+
165
+ $this->set_pagination_args([
166
+ 'total_items' => $total_items,
167
+ 'per_page' => $per_page
168
+ ]);
169
+
170
+ $data = array_slice ( $data, ( ( $current_page - 1 ) * $per_page ), $per_page );
171
+
172
+ $this->_column_headers = [ $columns, $hidden, $sortable ];
173
+ $this->items = $data;
174
+ }
175
+
176
+ // Process bulk actions
177
+ function process_bulk_action() {
178
+ global $wpdb;
179
+
180
+ $ids = ( isset( $_REQUEST['ids'] ) ) ? $_REQUEST['ids'] : '';
181
+
182
+ switch( $this->current_action() ) {
183
+ // Delete
184
+ case 'delete':
185
+ $nonce = ( isset( $_POST['wpzerospam_nonce'] ) ) ? $_POST['wpzerospam_nonce'] : '';
186
+ if ( ! wp_verify_nonce( $nonce, 'wpzerospam_nonce' ) ) return false;
187
+
188
+ if ( ! empty ( $ids ) && is_array( $ids ) ) {
189
+ // Delete query
190
+ foreach( $ids as $k => $blocked_id ) {
191
+ $wpdb->delete( wpzerospam_tables( 'blocked' ), [ 'blocked_id' => $blocked_id ] );
192
+ }
193
+ }
194
+ break;
195
+ }
196
+ }
197
+ }
classes/class-wpzerospam-log-table.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress Zero Spam log table
4
+ *
5
+ * @package WordPressZeroSpam
6
+ * @since 4.0.0
7
+ */
8
+
9
+ defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
10
+
11
+ if ( ! class_exists( 'WP_List_Table' ) ) {
12
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
13
+ }
14
+
15
+ class WPZeroSpam_Log_Table extends WP_List_Table {
16
+ function __construct() {
17
+ global $status, $page;
18
+
19
+ $args = [
20
+ 'singular' => __( 'Spam Detection', 'wpzerospam' ),
21
+ 'plural' => __( 'Spam Detections', 'wpzerospam' ),
22
+ 'ajax' => true
23
+ ];
24
+ parent::__construct( $args );
25
+ }
26
+
27
+ // Register columns
28
+ function get_columns() {
29
+ // Render a checkbox instead of text
30
+ $columns = [
31
+ 'cb' => '<input type="checkbox" />',
32
+ 'date_recorded' => __( 'Date', 'wpzerospam' ),
33
+ 'log_type' => __( 'Type', 'wpzerospam' ),
34
+ 'user_ip' => __( 'IP Address', 'wpzerospam' ),
35
+ 'page_url' => __( 'Page URL', 'wpzerospam' ),
36
+ 'country' => __( 'Country', 'wpzerospam' ),
37
+ 'region' => __( 'Region', 'wpzerospam' ),
38
+ 'city' => __( 'City', 'wpzerospam' ),
39
+ ];
40
+
41
+ return $columns;
42
+ }
43
+
44
+ // Sortable columns
45
+ function get_sortable_columns() {
46
+ $sortable_columns = [
47
+ 'date_recorded' => [ 'date_recorded', false ],
48
+ 'log_type' => [ 'log_type', false ],
49
+ 'user_ip' => [ 'user_ip', false ],
50
+ 'page_url' => [ 'page_url', false ],
51
+ 'country' => [ 'country', false ],
52
+ 'region' => [ 'region', false ],
53
+ 'city' => [ 'city', false ],
54
+ ];
55
+
56
+ return $sortable_columns;
57
+ }
58
+
59
+ // Checkbox column
60
+ function column_cb( $item ){
61
+ return sprintf(
62
+ '<input type="checkbox" name="%1$s[]" value="%2$s" />',
63
+ /*$1%s*/ 'ids',
64
+ /*$2%s*/ $item->log_id
65
+ );
66
+ }
67
+
68
+ // Render column
69
+ function column_default( $item, $column_name ) {
70
+ switch( $column_name ) {
71
+ case 'log_id':
72
+ return $item->log_id;
73
+ break;
74
+ case 'log_type':
75
+ return $item->log_type;
76
+ break;
77
+ case 'user_ip':
78
+ return '<a href="https://whatismyipaddress.com/ip/' . $item->user_ip .'" target="_blank" rel="noopener noreferrer">' . $item->user_ip . '</a>';
79
+ break;
80
+ case 'date_recorded':
81
+ return date( 'M j, Y g:ia' , strtotime( $item->date_recorded ) );
82
+ break;
83
+ case 'page_url':
84
+ return $item->page_url;
85
+ break;
86
+ case 'country':
87
+ if ( ! $item->country ) {
88
+ return 'N/A';
89
+ }
90
+ return $item->country;
91
+ break;
92
+ case 'region':
93
+ if ( ! $item->region ) {
94
+ return 'N/A';
95
+ }
96
+ return $item->region;
97
+ break;
98
+ case 'city':
99
+ if ( ! $item->city ) {
100
+ return 'N/A';
101
+ }
102
+ return $item->city;
103
+ break;
104
+ }
105
+ }
106
+
107
+ // Register bulk actions
108
+ function get_bulk_actions() {
109
+ $actions = [ 'delete' => __( 'Delete', 'wpzerospam' ) ];
110
+
111
+ return $actions;
112
+ }
113
+
114
+ /**
115
+ * Define which columns are hidden
116
+ *
117
+ * @return Array
118
+ */
119
+ public function get_hidden_columns() {
120
+ return [];
121
+ }
122
+
123
+ /**
124
+ * Allows you to sort the data by the variables set in the $_GET
125
+ *
126
+ * @return Mixed
127
+ */
128
+ private function sort_data( $a, $b ) {
129
+ // Set defaults
130
+ $orderby = 'date_recorded';
131
+ $order = 'desc';
132
+
133
+ // If orderby is set, use this as the sort column
134
+ if( ! empty( $_GET['orderby'] ) ) {
135
+ $orderby = $_GET['orderby'];
136
+ }
137
+
138
+ // If order is set use this as the order
139
+ if ( ! empty($_GET['order'] ) ) {
140
+ $order = $_GET['order'];
141
+ }
142
+
143
+ $result = strcmp( $a->$orderby, $b->$orderby );
144
+
145
+ if ( $order === 'asc' ) {
146
+ return $result;
147
+ }
148
+
149
+ return -$result;
150
+ }
151
+
152
+ // Get results
153
+ function prepare_items($args = []) {
154
+ $this->process_bulk_action();
155
+
156
+ $columns = $this->get_columns();
157
+ $hidden = $this->get_hidden_columns();
158
+ $sortable = $this->get_sortable_columns();
159
+
160
+ $data = wpzerospam_get_log();
161
+ usort( $data, [ &$this, 'sort_data' ] );
162
+
163
+ $per_page = 50;
164
+ $current_page = $this->get_pagenum();
165
+ $total_items = count( $data );
166
+
167
+ $this->set_pagination_args([
168
+ 'total_items' => $total_items,
169
+ 'per_page' => $per_page
170
+ ]);
171
+
172
+ $data = array_slice ( $data, ( ( $current_page - 1 ) * $per_page ), $per_page );
173
+
174
+ $this->_column_headers = [ $columns, $hidden, $sortable ];
175
+ $this->items = $data;
176
+ }
177
+
178
+ // Process bulk actions
179
+ function process_bulk_action() {
180
+ global $wpdb;
181
+
182
+ $ids = ( isset( $_REQUEST['ids'] ) ) ? $_REQUEST['ids'] : '';
183
+
184
+ switch( $this->current_action() ) {
185
+ // Delete
186
+ case 'delete':
187
+ // Delete query
188
+ $nonce = ( isset( $_POST['wpzerospam_nonce'] ) ) ? $_POST['wpzerospam_nonce'] : '';
189
+ if ( ! wp_verify_nonce( $nonce, 'wpzerospam_nonce' ) ) return false;
190
+
191
+ if ( ! empty ( $ids ) && is_array( $ids ) ) {
192
+ // Delete query
193
+ foreach( $ids as $k => $log_id ) {
194
+ $wpdb->delete( wpzerospam_tables( 'log' ), [ 'log_id' => $log_id ] );
195
+ }
196
+ }
197
+ break;
198
+ }
199
+ }
200
+ }
inc/admin.php CHANGED
@@ -7,10 +7,108 @@
7
  */
8
 
9
  function wpzerospam_admin_menu() {
10
- add_submenu_page( 'options-general.php', __( 'WordPress Zero Spam Settings', 'wpzerospam' ), __( 'WP Zero Spam', 'wpzerospam' ), 'manage_options', 'wordpress-zero-spam', 'wpzerospam_options_page' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  }
12
  add_action( 'admin_menu', 'wpzerospam_admin_menu' );
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  function wpzerospam_options_page() {
15
  if ( ! current_user_can( 'manage_options' ) ) { return; }
16
  ?>
@@ -53,18 +151,50 @@ function wpzerospam_admin_init() {
53
 
54
  add_settings_section( 'wpzerospam_general_settings', __( 'General Settings', 'wpzerospam' ), 'wpzerospam_general_settings_cb', 'wpzerospam' );
55
  add_settings_section( 'wpzerospam_spam_checks', __( 'Spam Checks', 'wpzerospam' ), 'wpzerospam_spam_checks_cb', 'wpzerospam' );
56
- add_settings_section( 'wpzerospam_ip_blocks', __( 'Blocked IP Address', 'wpzerospam' ), 'wpzerospam_ip_blocks_cb', 'wpzerospam' );
57
-
58
- // Redirect URL for blocked users
59
- add_settings_field( 'blocked_redirect_url', __( 'Redirect for Blocked Users', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
60
- 'label_for' => 'blocked_redirect_url',
61
- 'type' => 'url',
62
- 'class' => 'regular-text',
63
- 'desc' => 'URL blocked users will be taken to.',
64
- 'placeholder' => 'e.g. https://google.com'
 
65
  ]);
66
 
67
- // Log spam detections
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  add_settings_field( 'spam_handler', __( 'Spam Detections', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
69
  'label_for' => 'spam_handler',
70
  'type' => 'radio',
@@ -85,7 +215,7 @@ function wpzerospam_admin_init() {
85
  'placeholder' => 'e.g. https://google.com'
86
  ]);
87
  } else {
88
- // Redirect URL for spam detections
89
  add_settings_field( 'spam_message', __( 'Spam Detection Message', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
90
  'label_for' => 'spam_message',
91
  'type' => 'text',
@@ -106,6 +236,16 @@ function wpzerospam_admin_init() {
106
  ]
107
  ]);
108
 
 
 
 
 
 
 
 
 
 
 
109
  // Comment spam check
110
  add_settings_field( 'verify_comments', __( 'Verify Comments', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
111
  'label_for' => 'verify_comments',
@@ -192,26 +332,9 @@ function wpzerospam_admin_init() {
192
  ]
193
  ]);
194
  }
195
-
196
- // Toggle logging of blocked IPs
197
- add_settings_field( 'log_blocked_ips', __( 'Log Blocked IPs', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_ip_blocks', [
198
- 'label_for' => 'log_blocked_ips',
199
- 'type' => 'checkbox',
200
- 'multi' => false,
201
- 'desc' => 'Enables logging of when IPs are blocked from accessing the site.',
202
- 'options' => [
203
- 'enabled' => __( 'Enabled', 'wpzerospam' )
204
- ]
205
- ]);
206
-
207
- // Blocked IP address
208
- add_settings_field( 'blocked_ips', __( 'Blocked IP Address', 'wpzerospam' ), 'wpzerospam_blocked_ip_cb', 'wpzerospam', 'wpzerospam_ip_blocks' );
209
  }
210
  add_action( 'admin_init', 'wpzerospam_admin_init' );
211
 
212
- function wpzerospam_ip_blocks_cb() {
213
- }
214
-
215
  function wpzerospam_general_settings_cb() {
216
  }
217
 
@@ -282,65 +405,3 @@ function wpzerospam_field_cb( $args ) {
282
  ?>
283
  <?php
284
  }
285
-
286
- function wpzerospam_blocked_ip_cb( $args ) {
287
- $options = wpzerospam_options();
288
- $key = 0;
289
- ?>
290
- <div class="wpzerospam-setting-header">
291
- <div>
292
- <label><?php _e( 'IP Address', 'wpzerospam' ); ?></label>
293
- <small><?php _e( 'The IP address to block.', 'wpzerospam' ); ?></small>
294
- </div>
295
- <div>
296
- <label><?php _e( 'Reason', 'wpzerospam' ); ?></label>
297
- <small><?php _e( 'Reason the IP address is being blocked.', 'wpzerospam' ); ?></small>
298
- </div>
299
- </div>
300
- <?php
301
- $cnt = 0;
302
- if ( $options['blocked_ips'] ):
303
- foreach( $options['blocked_ips'] as $key => $ip ):
304
- if ( empty( $ip['ip_address'] )) { continue; }
305
- ?>
306
- <div class="wpzerospam-blocked-ip-option">
307
- <input
308
- type="text"
309
- name="wpzerospam[blocked_ips][<?php echo $cnt; ?>][ip_address]"
310
- value="<?php echo trim( $ip['ip_address'] ); ?>"
311
- placeholder="<?php _e( 'Blocked IP Address (i.e. XXX.XXX.X.X)', 'wpzerospam' ); ?>"
312
- class="wpzerospam-input"
313
- />
314
-
315
- <input
316
- type="text"
317
- name="wpzerospam[blocked_ips][<?php echo $cnt; ?>][reason]"
318
- value="<?php echo trim( $ip['reason'] ); ?>"
319
- placeholder="<?php _e( 'Reason (i.e. spam)', 'wpzerospam' ); ?>"
320
- class="wpzerospam-input"
321
- />
322
- </div>
323
- <?php
324
- $cnt++;
325
- endforeach;
326
- endif;
327
- ?>
328
- <div class="wpzerospam-blocked-ip-option">
329
- <input
330
- type="text"
331
- name="wpzerospam[blocked_ips][<?php echo $cnt; ?>][ip_address]"
332
- value=""
333
- placeholder="<?php _e( 'Blocked IP Address (i.e. XXX.XXX.X.X)', 'wpzerospam' ); ?>"
334
- class="wpzerospam-input"
335
- />
336
-
337
- <input
338
- type="text"
339
- name="wpzerospam[blocked_ips][<?php echo $cnt; ?>][reason]"
340
- value=""
341
- placeholder="<?php _e( 'Reason (i.e. spam)', 'wpzerospam' ); ?>"
342
- class="wpzerospam-input"
343
- />
344
- </div>
345
- <?php
346
- }
7
  */
8
 
9
  function wpzerospam_admin_menu() {
10
+ $main_page = add_menu_page(
11
+ __( 'WordPress Zero Spam Dashboard', 'wpzerospam' ),
12
+ __( 'WP Zero Spam', 'wpzerospam' ),
13
+ 'manage_options',
14
+ 'wordpress-zero-spam',
15
+ 'wpzerospam_dashboard',
16
+ 'dashicons-shield'
17
+ );
18
+
19
+ add_submenu_page(
20
+ 'wordpress-zero-spam',
21
+ __( 'Blocked IP Addresses', 'wpzerospam' ),
22
+ __( 'Blocked IPs', 'wpzerospam' ),
23
+ 'manage_options',
24
+ 'wordpress-zero-spam-blocked-ips',
25
+ 'wpzerospam_blocked_ips_page'
26
+ );
27
+
28
+ add_submenu_page(
29
+ 'wordpress-zero-spam',
30
+ __( 'WordPress Zero Spam Settings', 'wpzerospam' ),
31
+ __( 'Settings', 'wpzerospam' ),
32
+ 'manage_options',
33
+ 'wordpress-zero-spam-settings',
34
+ 'wpzerospam_options_page'
35
+ );
36
  }
37
  add_action( 'admin_menu', 'wpzerospam_admin_menu' );
38
 
39
+ function wpzerospam_blocked_ips_page() {
40
+ if ( ! current_user_can( 'manage_options' ) ) { return; }
41
+ ?>
42
+ <div class="wrap">
43
+ <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
44
+ <?php
45
+ /**
46
+ * Blocked IP table
47
+ */
48
+ require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/classes/class-wpzerospam-blocked-ip-table.php';
49
+
50
+ $table_data = new WPZeroSpam_Blocked_IP_Table();
51
+
52
+ // Setup page parameters
53
+ $current_page = $table_data->get_pagenum();
54
+ $current_page = ( isset( $current_page ) ) ? $current_page : 1;
55
+ $paged = ( isset( $_GET['page'] ) ) ? absint( $_GET['page'] ) : $current_page;
56
+ $paged = ( isset( $_GET['paged'] ) ) ? absint( $_GET['paged'] ) : $current_page;
57
+ $paged = ( isset( $args['paged'] ) ) ? $args['paged'] : $paged;
58
+
59
+ // Fetch, prepare, sort, and filter our data...
60
+ $table_data->prepare_items();
61
+ ?>
62
+ <form id="log-table" method="post">
63
+ <?php wp_nonce_field( 'wpzerospam_nonce', 'wpzerospam_nonce' ); ?>
64
+
65
+ <?php # Current page ?>
66
+ <input type="hidden" name="paged" value="<?php echo $paged; ?>" />
67
+
68
+ <?php $table_data->display(); ?>
69
+ </form>
70
+ </div>
71
+ <?php
72
+ }
73
+
74
+ function wpzerospam_dashboard() {
75
+ if ( ! current_user_can( 'manage_options' ) ) { return; }
76
+ ?>
77
+ <div class="wrap">
78
+ <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
79
+
80
+ <h2><?php _e( 'Spam Detections Log', 'wpzerospam' ); ?></h2>
81
+ <p><?php _e( 'Charts, graphs, etc. coming soon!', 'wpzerospam' ); ?></p>
82
+ <?php
83
+ /**
84
+ * Log table
85
+ */
86
+ require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/classes/class-wpzerospam-log-table.php';
87
+
88
+ $table_data = new WPZeroSpam_Log_Table();
89
+
90
+ // Setup page parameters
91
+ $current_page = $table_data->get_pagenum();
92
+ $current_page = (isset($current_page)) ? $current_page : 1;
93
+ $paged = ( isset( $_GET['page'] ) ) ? absint( $_GET['page'] ) : $current_page;
94
+ $paged = ( isset( $_GET['paged'] ) ) ? absint( $_GET['paged'] ) : $current_page;
95
+ $paged = ( isset( $args['paged'] ) ) ? $args['paged'] : $paged;
96
+
97
+ // Fetch, prepare, sort, and filter our data...
98
+ $table_data->prepare_items();
99
+ ?>
100
+ <form id="log-table" method="post">
101
+ <?php wp_nonce_field( 'wpzerospam_nonce', 'wpzerospam_nonce' ); ?>
102
+
103
+ <?php # Current page ?>
104
+ <input type="hidden" name="paged" value="<?php echo $paged; ?>" />
105
+
106
+ <?php $table_data->display(); ?>
107
+ </form>
108
+ </div>
109
+ <?php
110
+ }
111
+
112
  function wpzerospam_options_page() {
113
  if ( ! current_user_can( 'manage_options' ) ) { return; }
114
  ?>
151
 
152
  add_settings_section( 'wpzerospam_general_settings', __( 'General Settings', 'wpzerospam' ), 'wpzerospam_general_settings_cb', 'wpzerospam' );
153
  add_settings_section( 'wpzerospam_spam_checks', __( 'Spam Checks', 'wpzerospam' ), 'wpzerospam_spam_checks_cb', 'wpzerospam' );
154
+
155
+ // Toggle logging of blocked IPs
156
+ add_settings_field( 'log_blocked_ips', __( 'Log Blocked IPs', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
157
+ 'label_for' => 'log_blocked_ips',
158
+ 'type' => 'checkbox',
159
+ 'multi' => false,
160
+ 'desc' => 'Enables logging of when IPs are blocked from accessing the site.',
161
+ 'options' => [
162
+ 'enabled' => __( 'Enabled', 'wpzerospam' )
163
+ ]
164
  ]);
165
 
166
+ // How to handle blocks
167
+ add_settings_field( 'block_handler', __( 'Blocked IPs', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
168
+ 'label_for' => 'block_handler',
169
+ 'type' => 'radio',
170
+ 'desc' => 'Determines how blocked IPs are handled when they attempt to visit the site.',
171
+ 'options' => [
172
+ 'redirect' => __( 'Redirect user', 'wpzerospam' ),
173
+ '403' => __( 'Display a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403" target="_blank"><code>403 Forbidden</code></a> error', 'wpzerospam' )
174
+ ]
175
+ ]);
176
+
177
+ if ( 'redirect' == $options['block_handler'] ) {
178
+ // Redirect URL for blocked users
179
+ add_settings_field( 'blocked_redirect_url', __( 'Redirect for Blocked Users', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
180
+ 'label_for' => 'blocked_redirect_url',
181
+ 'type' => 'url',
182
+ 'class' => 'regular-text',
183
+ 'desc' => 'URL blocked users will be taken to.',
184
+ 'placeholder' => 'e.g. https://google.com'
185
+ ]);
186
+ } else {
187
+ // Blocked message
188
+ add_settings_field( 'blocked_message', __( 'Blocked Message', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
189
+ 'label_for' => 'blocked_message',
190
+ 'type' => 'text',
191
+ 'class' => 'large-text',
192
+ 'desc' => 'The message that will be displayed to a blocked user.',
193
+ 'placeholder' => __( 'You have been blocked from visiting this site.', 'wpzerospam' )
194
+ ]);
195
+ }
196
+
197
+ // How to handle spam detections
198
  add_settings_field( 'spam_handler', __( 'Spam Detections', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
199
  'label_for' => 'spam_handler',
200
  'type' => 'radio',
215
  'placeholder' => 'e.g. https://google.com'
216
  ]);
217
  } else {
218
+ // Spam message
219
  add_settings_field( 'spam_message', __( 'Spam Detection Message', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
220
  'label_for' => 'spam_message',
221
  'type' => 'text',
236
  ]
237
  ]);
238
 
239
+ if ( 'enabled' == $options['log_spam'] ) {
240
+ // Redirect URL for spam detections
241
+ add_settings_field( 'ipstack_api', __( 'ipstack API Key', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_general_settings', [
242
+ 'label_for' => 'ipstack_api',
243
+ 'type' => 'text',
244
+ 'class' => 'regular-text',
245
+ 'desc' => 'Enter your <a href="https://ipstack.com/" target="_blank">ipstack API key</a> to enable location-based statistics.',
246
+ ]);
247
+ }
248
+
249
  // Comment spam check
250
  add_settings_field( 'verify_comments', __( 'Verify Comments', 'wpzerospam' ), 'wpzerospam_field_cb', 'wpzerospam', 'wpzerospam_spam_checks', [
251
  'label_for' => 'verify_comments',
332
  ]
333
  ]);
334
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  }
336
  add_action( 'admin_init', 'wpzerospam_admin_init' );
337
 
 
 
 
338
  function wpzerospam_general_settings_cb() {
339
  }
340
 
405
  ?>
406
  <?php
407
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/helpers.php CHANGED
@@ -6,6 +6,53 @@
6
  * @since 4.0.0
7
  */
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  /**
10
  * Handles what happens when spam is detected
11
  */
@@ -13,6 +60,8 @@ if ( ! function_exists( 'wpzerospam_spam_detected' ) ) {
13
  function wpzerospam_spam_detected( $type, $data = [] ) {
14
  $options = wpzerospam_options();
15
 
 
 
16
  if ( 'redirect' == $options['spam_handler'] ) {
17
  wp_redirect( esc_url( $options['spam_redirect_url'] ) );
18
  exit();
@@ -20,11 +69,10 @@ if ( ! function_exists( 'wpzerospam_spam_detected' ) ) {
20
  status_header( 403 );
21
  die( $options['spam_message'] );
22
  }
23
-
24
  }
25
  }
26
 
27
- /**
28
  * Checks the post submission for a valid key
29
  */
30
  if ( ! function_exists( 'wpzerospam_key_check' ) ) {
@@ -37,11 +85,37 @@ if ( ! function_exists( 'wpzerospam_key_check' ) ) {
37
  }
38
  }
39
 
40
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  * Create a log entry if logging is enabled
42
  */
43
  if ( ! function_exists( 'wpzerospam_log_spam' ) ) {
44
  function wpzerospam_log_spam( $type, $data = [] ) {
 
 
45
  $options = wpzerospam_options();
46
 
47
  if ( 'enabled' != $options['log_spam'] ) {
@@ -49,7 +123,56 @@ if ( ! function_exists( 'wpzerospam_log_spam' ) ) {
49
  return false;
50
  }
51
 
52
- // Logging enabled
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
54
  }
55
 
@@ -81,6 +204,63 @@ if ( ! function_exists( 'wpzerospam_validate_submission' ) ) {
81
  }
82
  }
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  /**
85
  * Returns the plugin settings.
86
  */
@@ -92,8 +272,10 @@ if ( ! function_exists( 'wpzerospam_options' ) ) {
92
 
93
  if ( empty( $options['blocked_redirect_url'] ) ) { $options['blocked_redirect_url'] = 'https://www.google.com'; }
94
  if ( empty( $options['spam_handler'] ) ) { $options['spam_handler'] = '403'; }
 
95
  if ( empty( $options['spam_redirect_url'] ) ) { $options['spam_redirect_url'] = 'https://www.google.com'; }
96
  if ( empty( $options['spam_message'] ) ) { $options['spam_message'] = __( 'There was a problem with your submission. Please go back and try again.', 'wpzerospam' ); }
 
97
  if ( empty( $options['log_spam'] ) ) { $options['log_spam'] = 'disabled'; }
98
  if ( empty( $options['verify_comments'] ) ) { $options['verify_comments'] = 'enabled'; }
99
  if ( empty( $options['verify_registrations'] ) ) { $options['verify_registrations'] = 'enabled'; }
@@ -118,8 +300,6 @@ if ( ! function_exists( 'wpzerospam_options' ) ) {
118
  $options['verify_wpforms'] = 'enabled';
119
  }
120
 
121
- if ( empty( $options['blocked_ips'] ) ) { $options['blocked_ips'] = []; }
122
-
123
  return $options;
124
  }
125
  }
@@ -130,14 +310,25 @@ if ( ! function_exists( 'wpzerospam_options' ) ) {
130
  if ( ! function_exists( 'wpzerospam_ip' ) ) {
131
  function wpzerospam_ip() {
132
  if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
133
- return $_SERVER['HTTP_CLIENT_IP'];
134
- } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
135
- return $_SERVER['HTTP_X_FORWARDED_FOR'];
 
 
 
 
 
 
136
  } else {
137
- return $_SERVER['REMOTE_ADDR'];
138
  }
139
 
140
- return false;
 
 
 
 
 
141
  }
142
  }
143
 
@@ -161,15 +352,17 @@ if ( ! function_exists( 'wpzerospam_check_access' ) ) {
161
  $options = wpzerospam_options();
162
 
163
  // Check if the current user's IP address has been blocked
164
- $ip = wpzerospam_ip();
165
- $block_ip_key = array_search( $ip, array_column( $options['blocked_ips'], 'ip_address' ) );
166
- if ( $block_ip_key ) {
167
- $access['access'] = false;
168
- $access['type'] = 'blocked_ips';
169
- $access['ip'] = $ip;
170
- $access['reason'] = ! empty( $options['blocked_ips'][ $block_ip_key ]['reason'] ) ? $options['blocked_ips'][ $block_ip_key ]['reason'] : false;
171
  }
172
 
 
 
 
 
173
  return $access;
174
  }
175
  }
@@ -208,57 +401,3 @@ if ( ! function_exists( 'wpzerospam_current_url' ) ) {
208
  return $url;
209
  }
210
  }
211
-
212
- /**
213
- * Returns the location of a log file
214
- */
215
- if ( ! function_exists( 'wpzerospam_log_file' ) ) {
216
- function wpzerospam_log_file( $type ) {
217
- $wp_upload_dir = wp_upload_dir();
218
- $wp_upload_dir = $wp_upload_dir['basedir'];
219
- $file = $wp_upload_dir . '/wpzerospam-' . $type . '.log';
220
-
221
- return $file;
222
- }
223
- }
224
-
225
- /**
226
- * Creates a log entry & reads a log file
227
- */
228
- if ( ! function_exists( 'wpzerospam_log' ) ) {
229
- function wpzerospam_log( $type, $data = false, $mode = 'a' ) {
230
- $options = wpzerospam_options();
231
- $location = wpzerospam_log_file( $type );
232
-
233
- if ( $data ) {
234
- // Only log if the type is enabled
235
- if ( empty( $options['log_' . $type ] ) || 'enabled' != $options['log_' . $type ] ) { return false; }
236
-
237
- $data = [ 'date' => current_time( 'mysql' ) ] + $data;
238
-
239
- // Write a log entry
240
- $file = fopen( $location, $mode );
241
- fwrite( $file, json_encode( $data ) . "\n" );
242
- fclose( $file );
243
-
244
- return true;
245
- }
246
-
247
- // Return a log
248
- if ( file_exists( $location ) ) {
249
- $log = [];
250
- $entries = file_get_entries( $location );
251
- $entries = explode( "\n", $entries );
252
-
253
- foreach( $entries as $key => $entry ) {
254
- if ( ! $entry ) { continue; }
255
-
256
- $log[] = json_decode( $entry, true );
257
- }
258
-
259
- return $log;
260
- }
261
-
262
- return false;
263
- }
264
- }
6
  * @since 4.0.0
7
  */
8
 
9
+ /**
10
+ * Handles what happens when spam is detected
11
+ */
12
+ if ( ! function_exists( 'wpzerospam_get_ip_info' ) ) {
13
+ function wpzerospam_get_ip_info( $ip ) {
14
+ $options = wpzerospam_options();
15
+
16
+ if ( empty( $options['ipstack_api'] ) ) { return false; }
17
+
18
+ $base_url = 'http://api.ipstack.com/';
19
+ $remote_url = $base_url . $ip . '?access_key=' . $options['ipstack_api'];
20
+ $response = wp_remote_get( $remote_url );
21
+
22
+ if ( is_array( $response ) && ! is_wp_error( $response ) ) {
23
+ $info = json_decode( $response['body'], true );
24
+
25
+ return [
26
+ 'type' => ! empty( $info['type'] ) ? sanitize_text_field( $info['type'] ) : false,
27
+ 'continent_code' => ! empty( $info['continent_code'] ) ? sanitize_text_field( $info['continent_code'] ) : false,
28
+ 'continent_name' => ! empty( $info['continent_name'] ) ? sanitize_text_field( $info['continent_name'] ) : false,
29
+ 'country_code' => ! empty( $info['country_code'] ) ? sanitize_text_field( $info['country_code'] ) : false,
30
+ 'country_name' => ! empty( $info['country_name'] ) ? sanitize_text_field( $info['country_name'] ) : false,
31
+ 'region_code' => ! empty( $info['region_code'] ) ? sanitize_text_field( $info['region_code'] ) : false,
32
+ 'region_name' => ! empty( $info['region_name'] ) ? sanitize_text_field( $info['region_name'] ) : false,
33
+ 'city' => ! empty( $info['city'] ) ? sanitize_text_field( $info['city'] ) : false,
34
+ 'zip' => ! empty( $info['zip'] ) ? sanitize_text_field( $info['zip'] ) : false,
35
+ 'latitude' => ! empty( $info['latitude'] ) ? sanitize_text_field( $info['latitude'] ) : false,
36
+ 'longitude' => ! empty( $info['longitude'] ) ? sanitize_text_field( $info['longitude'] ) : false,
37
+ 'flag' => ! empty( $info['location']['country_flag'] ) ? sanitize_text_field( $info['location']['country_flag'] ) : false,
38
+ ];
39
+ }
40
+
41
+ return false;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Handles what happens when spam is detected
47
+ */
48
+ if ( ! function_exists( 'wpzerospam_get_log' ) ) {
49
+ function wpzerospam_get_log( $args = [] ) {
50
+ global $wpdb;
51
+
52
+ return $wpdb->get_results( 'SELECT * FROM ' . wpzerospam_tables( 'log' ) );
53
+ }
54
+ }
55
+
56
  /**
57
  * Handles what happens when spam is detected
58
  */
60
  function wpzerospam_spam_detected( $type, $data = [] ) {
61
  $options = wpzerospam_options();
62
 
63
+ wpzerospam_log_spam( $type, $data );
64
+
65
  if ( 'redirect' == $options['spam_handler'] ) {
66
  wp_redirect( esc_url( $options['spam_redirect_url'] ) );
67
  exit();
69
  status_header( 403 );
70
  die( $options['spam_message'] );
71
  }
 
72
  }
73
  }
74
 
75
+ /**
76
  * Checks the post submission for a valid key
77
  */
78
  if ( ! function_exists( 'wpzerospam_key_check' ) ) {
85
  }
86
  }
87
 
88
+ /**
89
+ * Create a log entry if logging is enabled
90
+ */
91
+ if ( ! function_exists( 'wpzerospam_add_blocked_ip' ) ) {
92
+ function wpzerospam_add_blocked_ip( $ip, $args = [] ) {
93
+ global $wpdb;
94
+
95
+ $options = wpzerospam_options();
96
+
97
+ $record = wp_parse_args( $args, [
98
+ 'blocked_type' => 'permanent',
99
+ 'date_added' => current_time( 'mysql' ),
100
+ 'start_block' => false,
101
+ 'end_block' => false,
102
+ 'reason' => false,
103
+ 'attempts' => 0
104
+ ]);
105
+
106
+ $record['user_ip'] = $ip;
107
+
108
+ $wpdb->insert( wpzerospam_tables( 'blocked' ), $record );
109
+ }
110
+ }
111
+
112
+ /**
113
  * Create a log entry if logging is enabled
114
  */
115
  if ( ! function_exists( 'wpzerospam_log_spam' ) ) {
116
  function wpzerospam_log_spam( $type, $data = [] ) {
117
+ global $wpdb;
118
+
119
  $options = wpzerospam_options();
120
 
121
  if ( 'enabled' != $options['log_spam'] ) {
123
  return false;
124
  }
125
 
126
+ if ( ! empty( $data['ip'] ) ) {
127
+ $ip_address = $data['ip'];
128
+ unset( $data['ip'] );
129
+ } else {
130
+ $ip_address = wpzerospam_ip();
131
+ }
132
+
133
+ $current_url = wpzerospam_current_url();
134
+ $location_info = wpzerospam_get_ip_info( $ip_address );
135
+
136
+ // Add record to the database
137
+ $record = [
138
+ 'log_type' => $type,
139
+ 'user_ip' => wpzerospam_ip(),
140
+ 'date_recorded' => current_time( 'mysql' ),
141
+ 'page_url' => $current_url['full'],
142
+ 'submission_data' => json_encode( $data )
143
+ ];
144
+
145
+ if ( $location_info ) {
146
+ $record['country'] = $location_info['country_code'];
147
+ $record['region'] = $location_info['region_code'];
148
+ $record['city'] = $location_info['city'];
149
+ $record['latitude'] = $location_info['latitude'];
150
+ $record['longitude'] = $location_info['longitude'];
151
+ }
152
+
153
+ $wpdb->insert( wpzerospam_tables( 'log' ), $record );
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Returns an array of tables the plugin uses
159
+ */
160
+ if ( ! function_exists( 'wpzerospam_tables' ) ) {
161
+ function wpzerospam_tables( $key = false ) {
162
+ global $wpdb;
163
+
164
+ $tables = [
165
+ 'log' => $wpdb->prefix . 'wpzerospam_log',
166
+ 'blocked' => $wpdb->prefix . 'wpzerospam_blocked'
167
+ ];
168
+
169
+ if ( ! $key ) {
170
+ return $tables;
171
+ } elseif( ! empty( $tables[ $key ] ) ) {
172
+ return $tables[ $key ];
173
+ }
174
+
175
+ return false;
176
  }
177
  }
178
 
204
  }
205
  }
206
 
207
+ /**
208
+ * Returns an array of blocked IPs or an individual IP's details
209
+ */
210
+ if ( ! function_exists( 'wpzerospam_get_blocked_ips' ) ) {
211
+ function wpzerospam_get_blocked_ips( $ip = false ) {
212
+ global $wpdb;
213
+
214
+ if ( ! $ip ) {
215
+ return $wpdb->get_results( 'SELECT * FROM ' . wpzerospam_tables( 'blocked' ) );
216
+ }
217
+
218
+ return $wpdb->get_row($wpdb->prepare(
219
+ 'SELECT * FROM ' . wpzerospam_tables( 'blocked' ) . ' WHERE user_ip = %s',
220
+ $ip
221
+ ));
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Adds a access attempt from a blocked user
227
+ */
228
+ if ( ! function_exists( 'wpzerospam_attempt_blocked' ) ) {
229
+ function wpzerospam_attempt_blocked( $data ) {
230
+ global $wpdb;
231
+
232
+ $options = wpzerospam_options();
233
+
234
+ if ( ! empty( $data['ip'] ) ) {
235
+ $ip_address = $data['ip'];
236
+ } else {
237
+ $ip_address = wpzerospam_ip();
238
+ }
239
+
240
+ $blocked = wpzerospam_get_blocked_ips( $ip_address );
241
+ if ( $blocked ) {
242
+ $attempts = $blocked->attempts;
243
+ $attempts++;
244
+
245
+ $wpdb->update( wpzerospam_tables( 'blocked' ), [
246
+ 'attempts' => $attempts
247
+ ], [
248
+ 'blocked_id' => $blocked->blocked_id
249
+ ]);
250
+ }
251
+
252
+ wpzerospam_log_spam( 'denied', $data );
253
+
254
+ if ( 'redirect' == $options['block_handler'] ) {
255
+ wp_redirect( esc_url( $options['blocked_redirect_url'] ) );
256
+ exit();
257
+ } else {
258
+ status_header( 403 );
259
+ die( $options['blocked_message'] );
260
+ }
261
+ }
262
+ }
263
+
264
  /**
265
  * Returns the plugin settings.
266
  */
272
 
273
  if ( empty( $options['blocked_redirect_url'] ) ) { $options['blocked_redirect_url'] = 'https://www.google.com'; }
274
  if ( empty( $options['spam_handler'] ) ) { $options['spam_handler'] = '403'; }
275
+ if ( empty( $options['block_handler'] ) ) { $options['block_handler'] = '403'; }
276
  if ( empty( $options['spam_redirect_url'] ) ) { $options['spam_redirect_url'] = 'https://www.google.com'; }
277
  if ( empty( $options['spam_message'] ) ) { $options['spam_message'] = __( 'There was a problem with your submission. Please go back and try again.', 'wpzerospam' ); }
278
+ if ( empty( $options['blocked_message'] ) ) { $options['blocked_message'] = __( 'You have been blocked from visiting this site.', 'wpzerospam' ); }
279
  if ( empty( $options['log_spam'] ) ) { $options['log_spam'] = 'disabled'; }
280
  if ( empty( $options['verify_comments'] ) ) { $options['verify_comments'] = 'enabled'; }
281
  if ( empty( $options['verify_registrations'] ) ) { $options['verify_registrations'] = 'enabled'; }
300
  $options['verify_wpforms'] = 'enabled';
301
  }
302
 
 
 
303
  return $options;
304
  }
305
  }
310
  if ( ! function_exists( 'wpzerospam_ip' ) ) {
311
  function wpzerospam_ip() {
312
  if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
313
+ $ip = $_SERVER['HTTP_CLIENT_IP'];
314
+ } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
315
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
316
+ } elseif ( ! empty($_SERVER['HTTP_X_FORWARDED'])) {
317
+ $ip = $_SERVER['HTTP_X_FORWARDED'];
318
+ } elseif ( ! empty($_SERVER['HTTP_FORWARDED_FOR'])) {
319
+ $ip = $_SERVER['HTTP_FORWARDED_FOR'];
320
+ } elseif ( ! empty($_SERVER['HTTP_FORWARDED'])) {
321
+ $ip = $_SERVER['HTTP_FORWARDED'];
322
  } else {
323
+ $ip = $_SERVER['REMOTE_ADDR'];
324
  }
325
 
326
+ $ip = explode( ',', $ip );
327
+ $ip = trim( $ip[0] );
328
+
329
+ if ( false === WP_Http::is_ip_address( $ip ) ) { return false; }
330
+
331
+ return $ip;
332
  }
333
  }
334
 
352
  $options = wpzerospam_options();
353
 
354
  // Check if the current user's IP address has been blocked
355
+ $ip = wpzerospam_ip();
356
+ $is_blocked = wpzerospam_get_blocked_ips( $ip );
357
+
358
+ if ( ! $is_blocked ) {
359
+ return $access;
 
 
360
  }
361
 
362
+ $access['access'] = false;
363
+ $access['ip'] = $ip;
364
+ $access['reason'] = $is_blocked->reason;
365
+
366
  return $access;
367
  }
368
  }
401
  return $url;
402
  }
403
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/updates.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Contains plugin updates
4
+ *
5
+ * @package WordPressZeroSpam
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 ( ! empty( $options['blocked_ips'] ) ) {
20
+ // IPs found, transfer them to the database
21
+ foreach( $options['blocked_ips'] as $key => $ip ) {
22
+ if ( ! empty( $ips ) ) {
23
+ wpzerospam_add_blocked_ip( $ip['ip_address'], [
24
+ 'reason' => $ip['reason']
25
+ ]);
26
+ }
27
+ }
28
+
29
+ unset( $options['blocked_ips'] );
30
+ update_option( 'wpzerospam', $options );
31
+ }
32
+ });
readme.txt CHANGED
@@ -5,7 +5,7 @@ Donate link: https://benmarshall.me
5
  Requires at least: 5.2
6
  Tested up to: 5.4.2
7
  Requires PHP: 7.1
8
- Stable tag: 4.1.3
9
  License: GNU GPLv3
10
  License URI: https://choosealicense.com/licenses/gpl-3.0/
11
 
@@ -69,6 +69,10 @@ Yes, that's what does the magic and keeps spam bots out.
69
 
70
  == Changelog ==
71
 
 
 
 
 
72
  = 4.1.3 =
73
 
74
  * Fixed JS errors for some 3rd-party plugins. See [#178](https://github.com/bmarshall511/wordpress-zero-spam/issues/178)
5
  Requires at least: 5.2
6
  Tested up to: 5.4.2
7
  Requires PHP: 7.1
8
+ Stable tag: 4.2.0
9
  License: GNU GPLv3
10
  License URI: https://choosealicense.com/licenses/gpl-3.0/
11
 
69
 
70
  == Changelog ==
71
 
72
+ = 4.2.0 =
73
+
74
+ * Re-implemented logging & added admin pages to prepare for charts & statistics. See [#181](https://github.com/bmarshall511/wordpress-zero-spam/issues/181)
75
+
76
  = 4.1.3 =
77
 
78
  * Fixed JS errors for some 3rd-party plugins. See [#178](https://github.com/bmarshall511/wordpress-zero-spam/issues/178)
wordpress-zero-spam.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * @package WordPressZeroSpam
6
  * @subpackage WordPress
7
- * @since 4.1.3
8
  * @author Ben Marshall
9
  * @copyright 2020 Ben Marshall
10
  * @license GPL-2.0-or-later
@@ -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.1.3
17
  * Requires at least: 5.2
18
  * Requires PHP: 7.2
19
  * Author: Ben Marshall
@@ -30,6 +30,68 @@ defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
30
 
31
  // Define plugin constants
32
  define( 'WORDPRESS_ZERO_SPAM', __FILE__ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  /**
35
  * Plugin scripts
@@ -66,16 +128,12 @@ if ( ! function_exists( 'wpzerospam_template_redirect' ) ) {
66
 
67
  // Check if the current user has access to the site
68
  $access = wpzerospam_check_access();
69
- if ( ! $access['access'] ) {
70
-
71
- // Log the blocked entry
72
- wpzerospam_log( $access['type'], [
73
- 'ip' => $access['ip'],
74
- 'reason' => $access['reason']
75
- ] );
76
 
77
- wp_redirect( $options['blocked_redirect_url'] );
78
- exit();
 
 
 
79
  }
80
  }
81
  }
@@ -86,8 +144,16 @@ add_action( 'template_redirect', 'wpzerospam_template_redirect' );
86
  */
87
  if ( ! function_exists( 'wpzerospam_uninstall' ) ) {
88
  function wpzerospam_uninstall() {
 
 
89
  delete_option( 'wpzerospam_key' );
90
  delete_option( 'wpzerospam' );
 
 
 
 
 
 
91
  }
92
  }
93
  register_uninstall_hook( WORDPRESS_ZERO_SPAM, 'wpzerospam_uninstall' );
4
  *
5
  * @package WordPressZeroSpam
6
  * @subpackage WordPress
7
+ * @since 4.0.0
8
  * @author Ben Marshall
9
  * @copyright 2020 Ben Marshall
10
  * @license GPL-2.0-or-later
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.2.0
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.1' );
34
+
35
+ /**
36
+ * Install plugin tables
37
+ */
38
+ function wpzerospam_install() {
39
+ global $wpdb;
40
+
41
+ $charset_collate = $wpdb->get_charset_collate();
42
+ $installed_db_version = get_option( 'wpzerospam_db_version' );
43
+
44
+ if ( $installed_db_version != WORDPRESS_ZERO_SPAM_DB_VERSION ) {
45
+ $log_table = wpzerospam_tables( 'log' );
46
+ $blocked_table = wpzerospam_tables( 'blocked' );
47
+
48
+ $sql = "CREATE TABLE $log_table (
49
+ log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
50
+ log_type VARCHAR(255) NOT NULL,
51
+ user_ip VARCHAR(255) NOT NULL,
52
+ date_recorded DATETIME NOT NULL,
53
+ page_url VARCHAR(255) NULL DEFAULT NULL,
54
+ submission_data LONGTEXT NULL DEFAULT NULL,
55
+ country VARCHAR(2) NULL DEFAULT NULL,
56
+ region VARCHAR(255) NULL DEFAULT NULL,
57
+ city VARCHAR(255) NULL DEFAULT NULL,
58
+ latitude VARCHAR(255) NULL DEFAULT NULL,
59
+ longitude VARCHAR(255) NULL DEFAULT NULL,
60
+ PRIMARY KEY (`log_id`)) $charset_collate;";
61
+
62
+ $sql .= "CREATE TABLE $blocked_table (
63
+ blocked_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
64
+ blocked_type ENUM('permanent','temporary') NOT NULL DEFAULT 'temporary',
65
+ user_ip VARCHAR(255) NOT NULL,
66
+ date_added DATETIME NOT NULL,
67
+ start_block DATETIME NULL DEFAULT NULL,
68
+ end_block DATETIME NULL DEFAULT NULL,
69
+ reason VARCHAR(255) NULL DEFAULT NULL,
70
+ attempts BIGINT UNSIGNED NOT NULL,
71
+ PRIMARY KEY (`blocked_id`)) $charset_collate;";
72
+
73
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
74
+ dbDelta( $sql );
75
+
76
+ update_option( 'wpzerospam_db_version', WORDPRESS_ZERO_SPAM_DB_VERSION );
77
+ }
78
+ }
79
+ register_activation_hook( WORDPRESS_ZERO_SPAM, 'wpzerospam_install' );
80
+
81
+ /**
82
+ * Check to ensure the database tables have been installed
83
+ */
84
+ function wpzerospam_db_check() {
85
+ if ( get_site_option( 'wpzerospam_db_version' ) != WORDPRESS_ZERO_SPAM_DB_VERSION ) {
86
+ wpzerospam_install();
87
+ }
88
+ }
89
+ add_action( 'plugins_loaded', 'wpzerospam_db_check' );
90
+
91
+ /**
92
+ * Plugin updates
93
+ */
94
+ require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . '/inc/updates.php';
95
 
96
  /**
97
  * Plugin scripts
128
 
129
  // Check if the current user has access to the site
130
  $access = wpzerospam_check_access();
 
 
 
 
 
 
 
131
 
132
+ if ( ! $access['access'] ) {
133
+ wpzerospam_attempt_blocked([
134
+ 'reason' => $access['reason'],
135
+ 'ip' => $access['ip']
136
+ ]);
137
  }
138
  }
139
  }
144
  */
145
  if ( ! function_exists( 'wpzerospam_uninstall' ) ) {
146
  function wpzerospam_uninstall() {
147
+ global $wpdb;
148
+
149
  delete_option( 'wpzerospam_key' );
150
  delete_option( 'wpzerospam' );
151
+ delete_option( 'wpzerospam_db_version' );
152
+
153
+ $tables = wpzerospam_tables();
154
+ foreach( $tables as $key => $table ) {
155
+ $wpdb->query( "DROP TABLE IF EXISTS $table" );
156
+ }
157
  }
158
  }
159
  register_uninstall_hook( WORDPRESS_ZERO_SPAM, 'wpzerospam_uninstall' );