Version Description
- Enhancement - Various performance improvements & caching added.
- Enhancement - Easier to use class methods for integrating Zero Spam into any plugin or theme.
- Enhancement - New
WordPress_Zero_Spam
class added. - Enhancement - IPs are now checked against known, safe hosts and user agents (i.e. search engine crawlers).
- Enhancement - Added advanced debugging functionality.
Download this release
Release Info
Developer | bmarshall511 |
Plugin | WordPress Zero Spam |
Version | 4.10.0 |
Comparing to | |
See all releases |
Code changes from version 4.9.13 to 4.10.0
- assets/css/debug.css +25 -0
- classes/class-wordpress-zero-spam.php +931 -0
- inc/helpers.php +0 -279
- inc/utilities.php +0 -109
- readme.txt +30 -25
- wordpress-zero-spam.php +22 -29
assets/css/debug.css
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.wpzerospam-debug-overlay {
|
2 |
+
background: rgba(255, 255, 255, 0.9);
|
3 |
+
bottom: 0;
|
4 |
+
font-size: 13px;
|
5 |
+
left: 0;
|
6 |
+
max-height: 95%;
|
7 |
+
max-width: 800px;
|
8 |
+
overflow: auto;
|
9 |
+
padding: 2em;
|
10 |
+
position: fixed;
|
11 |
+
width: 100%;
|
12 |
+
}
|
13 |
+
|
14 |
+
.wpzerospam-debug-item {
|
15 |
+
display: flex;
|
16 |
+
}
|
17 |
+
|
18 |
+
.wpzerospam-debug-item-label {
|
19 |
+
flex-shrink: 0;
|
20 |
+
width: 16em;
|
21 |
+
}
|
22 |
+
|
23 |
+
.wpzerospam-debug-item-value {
|
24 |
+
flex-grow: 1;
|
25 |
+
}
|
classes/class-wordpress-zero-spam.php
ADDED
@@ -0,0 +1,931 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WordPress Zero Spam class.
|
4 |
+
*
|
5 |
+
* @package WordPressZeroSpam
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Security Note: Blocks direct access to the plugin PHP files.
|
9 |
+
defined( 'ABSPATH' ) || die();
|
10 |
+
|
11 |
+
/**
|
12 |
+
* WordPress Zero Spam class.
|
13 |
+
*/
|
14 |
+
class WordPress_Zero_Spam {
|
15 |
+
/**
|
16 |
+
* Contains all plugin options.
|
17 |
+
*
|
18 |
+
* @var array Array of plugin options.
|
19 |
+
*/
|
20 |
+
public $options;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* The default core plugin options.
|
24 |
+
*
|
25 |
+
* @var array Array of core plugin options.
|
26 |
+
*/
|
27 |
+
public $default_options = array(
|
28 |
+
'debug' => 'disabled',
|
29 |
+
'ip_whitelist' => '',
|
30 |
+
'cookie_expiration' => 7,
|
31 |
+
'log_spam' => false,
|
32 |
+
'log_blocked_ips' => false,
|
33 |
+
'share_detections' => true,
|
34 |
+
'stopforumspam_confidence_min' => 20,
|
35 |
+
'botscout_count_min' => 5,
|
36 |
+
'botscout_api' => false,
|
37 |
+
'api_timeout' => 5,
|
38 |
+
'block_handler' => 403,
|
39 |
+
'blocked_redirect_url' => 'https://google.com',
|
40 |
+
'blocked_message' => false,
|
41 |
+
'ipstack_api' => false,
|
42 |
+
);
|
43 |
+
|
44 |
+
/**
|
45 |
+
* The current user's IP address.
|
46 |
+
*
|
47 |
+
* @var string The current user's IP address.
|
48 |
+
*/
|
49 |
+
public $current_user_ip;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* The current user's IP address access.
|
53 |
+
*
|
54 |
+
* @var array IP address access details.
|
55 |
+
*/
|
56 |
+
public $current_user_ip_access;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Database tables.
|
60 |
+
*
|
61 |
+
* @var array Array of plugin database tables.
|
62 |
+
*/
|
63 |
+
public $tables;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Class constructor.
|
67 |
+
*/
|
68 |
+
public function __construct() {
|
69 |
+
// Triggered on the WP init action.
|
70 |
+
add_action( 'init', array( $this, 'wp_init' ) );
|
71 |
+
|
72 |
+
// Triggered on the WP wp_footer action.
|
73 |
+
add_action( 'wp_footer', array( $this, 'wp_footer' ) );
|
74 |
+
|
75 |
+
// Handles IPs that have been denied access.
|
76 |
+
add_action( 'template_redirect', array( $this, 'access_check' ) );
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Checks is an IP is safe (i.e. from a known bot or crawler)
|
81 |
+
*/
|
82 |
+
public function is_known_safe_ip() {
|
83 |
+
$safe_hosts = array(
|
84 |
+
'googlebot.com',
|
85 |
+
'google.com',
|
86 |
+
'search.msn.com',
|
87 |
+
'bing.com',
|
88 |
+
'yahoo.com',
|
89 |
+
'duckduckgo.com',
|
90 |
+
'baidu.com',
|
91 |
+
'yandex.com',
|
92 |
+
'exabot.com',
|
93 |
+
'facebook.com',
|
94 |
+
'alexa.com',
|
95 |
+
);
|
96 |
+
|
97 |
+
$safe_user_agents = array(
|
98 |
+
'Googlebot',
|
99 |
+
'Bingbot',
|
100 |
+
'Slurp',
|
101 |
+
'DuckDuckBot',
|
102 |
+
'Baiduspider',
|
103 |
+
'YandexBot',
|
104 |
+
'facebot',
|
105 |
+
'ia_archiver',
|
106 |
+
);
|
107 |
+
|
108 |
+
$ip_host = gethostbyaddr( $this->current_user_ip );
|
109 |
+
$user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? esc_html( $_SERVER['HTTP_USER_AGENT'] ) : false;
|
110 |
+
|
111 |
+
if ( ! $ip_host || ! $user_agent ) {
|
112 |
+
return false;
|
113 |
+
}
|
114 |
+
|
115 |
+
// 1. Check hostnames.
|
116 |
+
foreach ( $safe_hosts as $key => $host ) {
|
117 |
+
if ( stripos( $ip_host, $host ) !== false ) {
|
118 |
+
return true;
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
// 2. Check user agents.
|
123 |
+
foreach ( $safe_user_agents as $key => $agent ) {
|
124 |
+
if ( stripos( $user_agent, $agent ) !== false ) {
|
125 |
+
return true;
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Checks an IP access.
|
134 |
+
*
|
135 |
+
* @param string $ip The IP address to check.
|
136 |
+
*/
|
137 |
+
public function get_access( $ip ) {
|
138 |
+
$access = array(
|
139 |
+
'ip_checked' => $ip,
|
140 |
+
'has_access' => true,
|
141 |
+
'access_checked' => false,
|
142 |
+
'cached' => false,
|
143 |
+
'blacklist_api' => false,
|
144 |
+
'attempts' => false,
|
145 |
+
);
|
146 |
+
|
147 |
+
// Ignore logged in users.
|
148 |
+
if ( is_user_logged_in() ) {
|
149 |
+
$access['access_checked'] = 'authenticated';
|
150 |
+
return $this->set_access_cookies( $access );
|
151 |
+
}
|
152 |
+
|
153 |
+
// 1. Check if an access check has already been ran for this IP.
|
154 |
+
if ( $this->get_cookie( 'access_checked' ) && $this->get_cookie( 'ip_checked' ) === $ip ) {
|
155 |
+
// IP has already been checked, return the saved access.
|
156 |
+
foreach ( $access as $key => $value ) {
|
157 |
+
$access[ $key ] = $this->get_cookie( $key );
|
158 |
+
}
|
159 |
+
|
160 |
+
$access['cached'] = 'cookie';
|
161 |
+
|
162 |
+
return $this->set_access_cookies( $access );
|
163 |
+
}
|
164 |
+
|
165 |
+
// 2. Check known/safe hosts (i.e. Google crawlers, etc.)
|
166 |
+
if ( $this->is_known_safe_ip( $ip ) ) {
|
167 |
+
$access['access_checked'] = 'safe_ip';
|
168 |
+
|
169 |
+
return $this->set_access_cookies( $access );
|
170 |
+
}
|
171 |
+
|
172 |
+
// 3. Check the whitelisted IP addresses.
|
173 |
+
$whitelisted_ips = $this->get_whitelisted_ips();
|
174 |
+
|
175 |
+
if ( array_key_exists( $ip, $whitelisted_ips ) ) {
|
176 |
+
// IP address found in the whitelist.
|
177 |
+
$access['access_checked'] = 'whitelisted';
|
178 |
+
|
179 |
+
return $this->set_access_cookies( $access );
|
180 |
+
}
|
181 |
+
|
182 |
+
// 4. Check if IP has been blocked.
|
183 |
+
$blocked_ip = $this->get_blocked_ip( $ip );
|
184 |
+
if ( $blocked_ip ) {
|
185 |
+
$access['attempts'] = $blocked_ip['attempts'];
|
186 |
+
|
187 |
+
// IP has been blocked, check the type.
|
188 |
+
if ( 'permanent' === $blocked_ip['blocked_type'] ) {
|
189 |
+
// Permanent block.
|
190 |
+
$access['access_checked'] = 'permanent_block';
|
191 |
+
$access['has_access'] = false;
|
192 |
+
return $this->set_access_cookies( $access );
|
193 |
+
} else {
|
194 |
+
// Temporary block, check if still valid.
|
195 |
+
if ( $this->is_blocked_ip_active( $blocked_ip ) ) {
|
196 |
+
$access['access_checked'] = 'temporary_block';
|
197 |
+
$access['has_access'] = false;
|
198 |
+
return $this->set_access_cookies( $access );
|
199 |
+
}
|
200 |
+
}
|
201 |
+
}
|
202 |
+
|
203 |
+
// 5. Check if the IP appears on the blacklist.
|
204 |
+
$blacklisted_ip = $this->get_blacklisted_ip( $ip );
|
205 |
+
if ( $blacklisted_ip ) {
|
206 |
+
// IP has been blacklisted, check if it needs updated.
|
207 |
+
$current_datetime = strtotime( current_time( 'mysql' ) );
|
208 |
+
$last_updated = strtotime( $blacklisted_ip['last_updated'] );
|
209 |
+
if ( $current_datetime >= ( $last_updated + MONTH_IN_SECONDS ) ) {
|
210 |
+
// Expired, update the record.
|
211 |
+
$blacklisted_api_ip = $this->get_ip_from_api( $ip, $blacklisted_ip['blacklist_service'] );
|
212 |
+
if ( ! $blacklisted_api_ip ) {
|
213 |
+
// IP not found, delete.
|
214 |
+
$this->delete_blacklisted_ip( $ip );
|
215 |
+
} else {
|
216 |
+
// IP found, update (or delete depending on plugin settings) it.
|
217 |
+
if ( $this->update_blacklisted_ip( $blacklisted_api_ip, 'update' ) ) {
|
218 |
+
$access['has_access'] = false;
|
219 |
+
$access['access_checked'] = 'blacklist';
|
220 |
+
$access['blacklist_api'] = $blacklisted_ip['blacklist_service'];
|
221 |
+
$access['attempts'] = $blacklisted_ip['attempts'];
|
222 |
+
|
223 |
+
return $this->set_access_cookies( $access );
|
224 |
+
}
|
225 |
+
}
|
226 |
+
} else {
|
227 |
+
// Not expired.
|
228 |
+
$access['has_access'] = false;
|
229 |
+
$access['access_checked'] = 'blacklist';
|
230 |
+
$access['blacklist_api'] = $blacklisted_ip['blacklist_service'];
|
231 |
+
$access['attempts'] = $blacklisted_ip['attempts'];
|
232 |
+
|
233 |
+
return $this->set_access_cookies( $access );
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
// 6. Check the IP against the StopForumSpam API.
|
238 |
+
$blacklisted_api_ip = $this->get_ip_from_api( $ip, 'stopforumspam' );
|
239 |
+
if ( $blacklisted_api_ip && $this->update_blacklisted_ip( $blacklisted_api_ip, 'insert' ) ) {
|
240 |
+
$access['has_access'] = false;
|
241 |
+
$access['access_checked'] = 'blacklist';
|
242 |
+
$access['blacklist_api'] = 'stopforumspam';
|
243 |
+
$access['attempts'] = $blacklisted_api_ip['attempts'];
|
244 |
+
|
245 |
+
return $this->set_access_cookies( $access );
|
246 |
+
}
|
247 |
+
|
248 |
+
// 7. Check the IP against the BotScout API.
|
249 |
+
$blacklisted_api_ip = $this->get_ip_from_api( $ip, 'botscout' );
|
250 |
+
if ( $blacklisted_api_ip && $this->update_blacklisted_ip( $blacklisted_api_ip, 'insert' ) ) {
|
251 |
+
$access['has_access'] = false;
|
252 |
+
$access['access_checked'] = 'blacklist';
|
253 |
+
$access['blacklist_api'] = 'botscout';
|
254 |
+
$access['attempts'] = $blacklisted_api_ip['attempts'];
|
255 |
+
|
256 |
+
return $this->set_access_cookies( $access );
|
257 |
+
}
|
258 |
+
|
259 |
+
return $this->set_access_cookies( $access );
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Handles IPs that have been denied access.
|
264 |
+
*/
|
265 |
+
public function access_check() {
|
266 |
+
global $wpdb;
|
267 |
+
|
268 |
+
if ( ! $this->current_user_ip_access['has_access'] ) {
|
269 |
+
$block_type = $this->current_user_ip_access['access_checked'];
|
270 |
+
$log_data = array();
|
271 |
+
|
272 |
+
// IP doesn't have access, update attempts.
|
273 |
+
switch ( $block_type ) {
|
274 |
+
case 'temporary_block':
|
275 |
+
case 'permanent_block':
|
276 |
+
case 'blacklist':
|
277 |
+
$log_data['reason'] = $block_type;
|
278 |
+
|
279 |
+
switch ( $block_type ) {
|
280 |
+
case 'temporary_block':
|
281 |
+
case 'permanent_block':
|
282 |
+
$table = 'blocked';
|
283 |
+
break;
|
284 |
+
case 'blacklist':
|
285 |
+
$table = 'blacklist';
|
286 |
+
break;
|
287 |
+
}
|
288 |
+
|
289 |
+
if ( ! $this->current_user_ip_access[ 'attempts' ] ) {
|
290 |
+
$this->current_user_ip_access[ 'attempts' ] = 1;
|
291 |
+
} else {
|
292 |
+
$this->current_user_ip_access[ 'attempts' ]++;
|
293 |
+
}
|
294 |
+
|
295 |
+
$wpdb->update(
|
296 |
+
$this->tables[ $table ],
|
297 |
+
array(
|
298 |
+
'attempts' => $this->current_user_ip_access[ 'attempts' ],
|
299 |
+
),
|
300 |
+
array(
|
301 |
+
'user_ip' => $this->current_user_ip,
|
302 |
+
)
|
303 |
+
);
|
304 |
+
|
305 |
+
$this->set_cookie( 'attempts', $this->current_user_ip_access[ 'attempts' ], 0 );
|
306 |
+
break;
|
307 |
+
}
|
308 |
+
|
309 |
+
// Log the detection.
|
310 |
+
$this->log_detection( 'blocked', $log_data );
|
311 |
+
|
312 |
+
if ( 'redirect' === $this->options['block_handler'] ) {
|
313 |
+
wp_redirect( esc_url( $this->options['blocked_redirect_url'] ) );
|
314 |
+
exit();
|
315 |
+
} else {
|
316 |
+
status_header( 403 );
|
317 |
+
die( $this->options['blocked_message'] );
|
318 |
+
}
|
319 |
+
}
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Logs a IP detections.
|
324 |
+
*/
|
325 |
+
public function log_detection( $type, $data ) {
|
326 |
+
global $wpdb;
|
327 |
+
|
328 |
+
$record = array(
|
329 |
+
'user_ip' => $this->current_user_ip,
|
330 |
+
'log_type' => $type,
|
331 |
+
'date_recorded' => current_time( 'mysql' ),
|
332 |
+
);
|
333 |
+
|
334 |
+
|
335 |
+
// If sharing detections is enabled, send the detection to Zero Spam.
|
336 |
+
if ( 'enabled' === $this->options['share_detections'] ) {
|
337 |
+
$this->share_detection( $record['user_ip'], $record['log_type'] );
|
338 |
+
}
|
339 |
+
|
340 |
+
// Check if logging detections & 'blocks' are enabled.
|
341 |
+
if (
|
342 |
+
'enabled' !== $this->options['log_spam'] ||
|
343 |
+
( 'blocked' === $record['log_type'] && 'enabled' !== $this->options['log_blocked_ips'] )
|
344 |
+
) {
|
345 |
+
// Logging disabled.
|
346 |
+
return false;
|
347 |
+
}
|
348 |
+
|
349 |
+
// Logging enabled, get the current URL & IP location information.
|
350 |
+
$location = $this->get_ip_geolocation( $record['user_ip'] );
|
351 |
+
$current_url = $this->get_current_url();
|
352 |
+
|
353 |
+
// Add additional information to the detection record.
|
354 |
+
$record['page_url'] = $current_url;
|
355 |
+
$record['submission_data'] = wp_json_encode( $data );
|
356 |
+
|
357 |
+
if ( $location ) {
|
358 |
+
$record['country'] = ! empty( $location['country_code'] ) ? $location['country_code'] : false;
|
359 |
+
$record['region'] = ! empty( $location['region_code'] ) ? $location['region_code'] : false;
|
360 |
+
$record['city'] = ! empty( $location['city'] ) ? $location['city'] : false;
|
361 |
+
$record['latitude'] = ! empty( $location['latitude'] ) ? $location['latitude'] : false;
|
362 |
+
$record['longitude'] = ! empty( $location['longitude'] ) ? $location['longitude'] : false;
|
363 |
+
}
|
364 |
+
|
365 |
+
return $wpdb->insert( $this->tables['log'], $record );
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* Returns the current URL.
|
370 |
+
*/
|
371 |
+
public function get_current_url() {
|
372 |
+
global $wp;
|
373 |
+
|
374 |
+
return home_url( add_query_arg( array(), $wp->request ) );
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* Retreives an IP geolocation.
|
379 |
+
*/
|
380 |
+
public function get_ip_geolocation( $ip ) {
|
381 |
+
if ( empty( $this->options['ipstack_api'] ) ) {
|
382 |
+
return false;
|
383 |
+
}
|
384 |
+
|
385 |
+
$base_url = 'http://api.ipstack.com/';
|
386 |
+
$remote_url = $base_url . $ip . '?access_key=' . $this->options['ipstack_api'];
|
387 |
+
$response = wp_remote_get( $remote_url, array( 'timeout' => $this->options['api_timeout'] ) );
|
388 |
+
|
389 |
+
if ( is_array( $response ) && ! is_wp_error( $response ) ) {
|
390 |
+
$info = json_decode( $response['body'], true );
|
391 |
+
|
392 |
+
return array(
|
393 |
+
'type' => ! empty( $info['type'] ) ? sanitize_text_field( $info['type'] ) : false,
|
394 |
+
'continent_code' => ! empty( $info['continent_code'] ) ? sanitize_text_field( $info['continent_code'] ) : false,
|
395 |
+
'continent_name' => ! empty( $info['continent_name'] ) ? sanitize_text_field( $info['continent_name'] ) : false,
|
396 |
+
'country_code' => ! empty( $info['country_code'] ) ? sanitize_text_field( $info['country_code'] ) : false,
|
397 |
+
'country_name' => ! empty( $info['country_name'] ) ? sanitize_text_field( $info['country_name'] ) : false,
|
398 |
+
'region_code' => ! empty( $info['region_code'] ) ? sanitize_text_field( $info['region_code'] ) : false,
|
399 |
+
'region_name' => ! empty( $info['region_name'] ) ? sanitize_text_field( $info['region_name'] ) : false,
|
400 |
+
'city' => ! empty( $info['city'] ) ? sanitize_text_field( $info['city'] ) : false,
|
401 |
+
'zip' => ! empty( $info['zip'] ) ? sanitize_text_field( $info['zip'] ) : false,
|
402 |
+
'latitude' => ! empty( $info['latitude'] ) ? sanitize_text_field( $info['latitude'] ) : false,
|
403 |
+
'longitude' => ! empty( $info['longitude'] ) ? sanitize_text_field( $info['longitude'] ) : false,
|
404 |
+
'flag' => ! empty( $info['location']['country_flag'] ) ? sanitize_text_field( $info['location']['country_flag'] ) : false,
|
405 |
+
);
|
406 |
+
}
|
407 |
+
|
408 |
+
return false;
|
409 |
+
}
|
410 |
+
|
411 |
+
/**
|
412 |
+
* Share a detection with Zero Spam.
|
413 |
+
*/
|
414 |
+
public function share_detection( $ip, $type ) {
|
415 |
+
// The Zero Spam API endpoint for sharing detections.
|
416 |
+
$api_url = 'https://zerospam.org/wp-json/wpzerospamapi/v1/detection/';
|
417 |
+
|
418 |
+
// Setup the request parameters.
|
419 |
+
$request_args = array(
|
420 |
+
'method' => 'POST',
|
421 |
+
'body' => array(
|
422 |
+
'ip' => $ip,
|
423 |
+
'type' => $type,
|
424 |
+
'site' => site_url(),
|
425 |
+
'email' => get_bloginfo( 'admin_email' ),
|
426 |
+
'wpversion' => get_bloginfo( 'version' ),
|
427 |
+
'name' => get_bloginfo( 'name' ),
|
428 |
+
'desc' => get_bloginfo( 'description' ),
|
429 |
+
'language' => get_bloginfo( 'language' ),
|
430 |
+
'version' => WORDPRESS_ZERO_SPAM_VERSION,
|
431 |
+
),
|
432 |
+
'sslverify' => true,
|
433 |
+
);
|
434 |
+
|
435 |
+
// For debugging purposes only.
|
436 |
+
if ( WP_DEBUG ) {
|
437 |
+
$request_args['sslverify'] = false;
|
438 |
+
}
|
439 |
+
|
440 |
+
// Send the request.
|
441 |
+
$request = wp_remote_post( $api_url, $request_args );
|
442 |
+
if ( is_wp_error( $request ) ) {
|
443 |
+
// Request failed.
|
444 |
+
return false;
|
445 |
+
}
|
446 |
+
|
447 |
+
// Request succeeded, return the result.
|
448 |
+
return wp_remote_retrieve_body( $request );
|
449 |
+
}
|
450 |
+
|
451 |
+
/**
|
452 |
+
* Triggered on the WP init action.
|
453 |
+
*/
|
454 |
+
public function wp_footer() {
|
455 |
+
// Display debug info if enabled.
|
456 |
+
if ( 'enabled' === $this->options['debug'] ) {
|
457 |
+
wp_enqueue_style(
|
458 |
+
'wpzerospam-debug',
|
459 |
+
plugin_dir_url( WORDPRESS_ZERO_SPAM ) .
|
460 |
+
'assets/css/debug.css',
|
461 |
+
false,
|
462 |
+
WORDPRESS_ZERO_SPAM_VERSION
|
463 |
+
);
|
464 |
+
?>
|
465 |
+
<div class="wpzerospam-debug-overlay">
|
466 |
+
<div class="wpzerospam-debug-item">
|
467 |
+
<div class="wpzerospam-debug-item-label"><strong><?php esc_html_e( 'Options', 'wpzerospam' ); ?>:</strong></div>
|
468 |
+
<div class="wpzerospam-debug-item-value">
|
469 |
+
<?php foreach ( $this->options as $key => $value ): ?>
|
470 |
+
<div class="wpzerospam-debug-item">
|
471 |
+
<div class="wpzerospam-debug-item-label"><?php esc_html_e( $key ); ?></div>
|
472 |
+
<div class="wpzerospam-debug-item-value"><?php esc_html_e( $value ); ?></div>
|
473 |
+
</div>
|
474 |
+
<?php endforeach; ?>
|
475 |
+
</div>
|
476 |
+
</div>
|
477 |
+
<div class="wpzerospam-debug-item">
|
478 |
+
<div class="wpzerospam-debug-item-label"><strong><?php esc_html_e( 'Current User IP', 'wpzerospam' ); ?>:</strong></div>
|
479 |
+
<div class="wpzerospam-debug-item-value"><?php echo esc_html( $this->current_user_ip ); ?></div>
|
480 |
+
</div>
|
481 |
+
<div class="wpzerospam-debug-item">
|
482 |
+
<div class="wpzerospam-debug-item-label"><strong><?php esc_html_e( 'Current User IP Access', 'wpzerospam' ); ?>:</strong></div>
|
483 |
+
<div class="wpzerospam-debug-item-value">
|
484 |
+
<?php foreach ( $this->current_user_ip_access as $key => $value ): ?>
|
485 |
+
<div class="wpzerospam-debug-item">
|
486 |
+
<div class="wpzerospam-debug-item-label"><?php esc_html_e( $key ); ?></div>
|
487 |
+
<div class="wpzerospam-debug-item-value"><?php esc_html_e( $value ); ?></div>
|
488 |
+
</div>
|
489 |
+
<?php endforeach; ?>
|
490 |
+
</div>
|
491 |
+
</div>
|
492 |
+
</div>
|
493 |
+
<?php
|
494 |
+
}
|
495 |
+
}
|
496 |
+
|
497 |
+
/**
|
498 |
+
* Triggered on the WP init action.
|
499 |
+
*/
|
500 |
+
public function wp_init() {
|
501 |
+
global $wpdb;
|
502 |
+
|
503 |
+
// Set the database tables.
|
504 |
+
$this->tables = array(
|
505 |
+
'log' => $wpdb->prefix . 'wpzerospam_log',
|
506 |
+
'blocked' => $wpdb->prefix . 'wpzerospam_blocked',
|
507 |
+
'blacklist' => $wpdb->prefix . 'wpzerospam_blacklist',
|
508 |
+
);
|
509 |
+
|
510 |
+
// Set the plugin options.
|
511 |
+
$this->options = $this->get_options();
|
512 |
+
if ( empty( $this->options['blocked_message'] ) ) {
|
513 |
+
$this->options['blocked_message'] = __( 'You have been blocked from visiting this site by WordPress Zero Spam due to detected spam activity.', 'wpzerospam' );
|
514 |
+
}
|
515 |
+
|
516 |
+
// Set the current user's IP address.
|
517 |
+
if ( 'enabled' === $this->options['debug'] && ! empty( $_REQUEST['wpzerospamip'] ) ) {
|
518 |
+
$this->current_user_ip = $_REQUEST['wpzerospamip'];
|
519 |
+
} else {
|
520 |
+
$this->current_user_ip = $this->get_user_ip();
|
521 |
+
}
|
522 |
+
|
523 |
+
// Set the current user's IP address access.
|
524 |
+
$this->current_user_ip_access = $this->get_access( $this->current_user_ip );
|
525 |
+
}
|
526 |
+
|
527 |
+
/**
|
528 |
+
* Returns the saved plugin options.
|
529 |
+
*/
|
530 |
+
public function get_options() {
|
531 |
+
$options = $this->default_options;
|
532 |
+
$options = array_merge( $options, get_option( 'wpzerospam' ) );
|
533 |
+
$options = apply_filters( 'wpzerospam_options', $options );
|
534 |
+
|
535 |
+
return $options;
|
536 |
+
}
|
537 |
+
|
538 |
+
/**
|
539 |
+
* Sets access cookies.
|
540 |
+
*
|
541 |
+
* @param array $access Access details.
|
542 |
+
*/
|
543 |
+
public function set_access_cookies( $access ) {
|
544 |
+
foreach ( $access as $key => $value ) {
|
545 |
+
$this->set_cookie( $key, $value, 0 );
|
546 |
+
}
|
547 |
+
|
548 |
+
return $access;
|
549 |
+
}
|
550 |
+
|
551 |
+
/**
|
552 |
+
* Updates a blacklisted IP.
|
553 |
+
*
|
554 |
+
* @param array $api_data The returned IP data from the API.
|
555 |
+
*/
|
556 |
+
public function update_blacklisted_ip( $api_data, $type ) {
|
557 |
+
global $wpdb;
|
558 |
+
|
559 |
+
if ( ! $api_data ) {
|
560 |
+
return false;
|
561 |
+
}
|
562 |
+
|
563 |
+
switch ( $api_data['api'] ) {
|
564 |
+
case 'stopforumspam':
|
565 |
+
if ( ! empty( $api_data['confidence'] ) && $api_data['confidence'] < $this->options['stopforumspam_confidence_min'] ) {
|
566 |
+
// Doesn't meet the threshold, delete the IP from the database.
|
567 |
+
$this->delete_blacklisted_ip( $api_data['ip_address'] );
|
568 |
+
return false;
|
569 |
+
}
|
570 |
+
break;
|
571 |
+
case 'botscout':
|
572 |
+
if ( ! empty( $api_data['count'] ) && $api_data['count'] < $this->options['botscout_count_min'] ) {
|
573 |
+
// Doesn't meet the threshold, delete the IP from the database.
|
574 |
+
$this->delete_blacklisted_ip( $api_data['ip_address'] );
|
575 |
+
return false;
|
576 |
+
}
|
577 |
+
break;
|
578 |
+
}
|
579 |
+
|
580 |
+
// Update the record.
|
581 |
+
if ( 'update' === $type ) {
|
582 |
+
$wpdb->update(
|
583 |
+
$this->tables['blacklist'],
|
584 |
+
array(
|
585 |
+
'last_updated' => current_time( 'mysql' ),
|
586 |
+
'blacklist_data' => wp_json_encode( $api_data ),
|
587 |
+
),
|
588 |
+
array(
|
589 |
+
'user_ip' => $api_data['ip_address'],
|
590 |
+
)
|
591 |
+
);
|
592 |
+
} else {
|
593 |
+
$wpdb->insert(
|
594 |
+
$this->tables['blacklist'],
|
595 |
+
array(
|
596 |
+
'user_ip' => $api_data['ip_address'],
|
597 |
+
'last_updated' => current_time( 'mysql' ),
|
598 |
+
'blacklist_service' => $api_data['api'],
|
599 |
+
'blacklist_data' => wp_json_encode( $api_data ),
|
600 |
+
)
|
601 |
+
);
|
602 |
+
}
|
603 |
+
|
604 |
+
return true;
|
605 |
+
}
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Deletes an IP from the blacklist.
|
609 |
+
*
|
610 |
+
* @param string $ip The IP address to delete.
|
611 |
+
*/
|
612 |
+
public function delete_blacklisted_ip( $ip ) {
|
613 |
+
global $wpdb;
|
614 |
+
|
615 |
+
$wpdb->delete(
|
616 |
+
$this->tables['blacklist'],
|
617 |
+
array(
|
618 |
+
'user_ip' => $ip
|
619 |
+
)
|
620 |
+
);
|
621 |
+
}
|
622 |
+
|
623 |
+
/**
|
624 |
+
* Gets an IP from an API.
|
625 |
+
*
|
626 |
+
* @param string $ip IP address to query.
|
627 |
+
* @param string $api The API to query.
|
628 |
+
*/
|
629 |
+
public function get_ip_from_api( $ip, $api ) {
|
630 |
+
$cache_key = sanitize_title( $api . '_' . $ip );
|
631 |
+
$data = wp_cache_get( $cache_key );
|
632 |
+
|
633 |
+
if ( false === $data ) {
|
634 |
+
switch ( $api ) {
|
635 |
+
case 'stopforumspam':
|
636 |
+
$api_url = 'https://api.stopforumspam.org/api?';
|
637 |
+
$params = array(
|
638 |
+
'ip' => $ip,
|
639 |
+
'json' => '',
|
640 |
+
);
|
641 |
+
break;
|
642 |
+
case 'botscout':
|
643 |
+
$api_url = 'https://botscout.com/test/?';
|
644 |
+
$params = array(
|
645 |
+
'ip' => $ip,
|
646 |
+
'key' => $this->options['botscout_api'],
|
647 |
+
);
|
648 |
+
break;
|
649 |
+
}
|
650 |
+
|
651 |
+
if ( ! empty( $api_url ) ) {
|
652 |
+
$endpoint = $api_url . http_build_query( $params );
|
653 |
+
$response = wp_remote_get( $endpoint, array( 'timeout' => $this->options['api_timeout'] ) );
|
654 |
+
if ( is_array( $response ) && ! is_wp_error( $response ) ) {
|
655 |
+
$body_data = wp_remote_retrieve_body( $response );
|
656 |
+
switch ( $api ) {
|
657 |
+
case 'stopforumspam':
|
658 |
+
$body_data = json_decode( $body_data, true );
|
659 |
+
if (
|
660 |
+
! empty( $body_data['success'] ) &&
|
661 |
+
$body_data['success'] &&
|
662 |
+
! empty( $body_data['ip'] ) &&
|
663 |
+
! empty( $body_data['ip']['appears'] )
|
664 |
+
) {
|
665 |
+
$data = $body_data['ip'];
|
666 |
+
$data['api'] = 'stopforumspam';
|
667 |
+
$data['ip_address'] = $ip;
|
668 |
+
}
|
669 |
+
break;
|
670 |
+
case 'botscout':
|
671 |
+
if ( strpos( $body_data, '!' ) === false ) {
|
672 |
+
list( $matched, $type, $count ) = explode( '|', $body_data );
|
673 |
+
if ( 'Y' === $matched ) {
|
674 |
+
$data = array(
|
675 |
+
'type' => $type,
|
676 |
+
'count' => $count,
|
677 |
+
'api' => 'botscout',
|
678 |
+
'ip_address' => $ip,
|
679 |
+
);
|
680 |
+
}
|
681 |
+
}
|
682 |
+
break;
|
683 |
+
}
|
684 |
+
|
685 |
+
if ( $data ) {
|
686 |
+
wp_cache_set( $cache_key, $data );
|
687 |
+
}
|
688 |
+
}
|
689 |
+
}
|
690 |
+
}
|
691 |
+
|
692 |
+
return $data;
|
693 |
+
}
|
694 |
+
|
695 |
+
/**
|
696 |
+
* Checks if a temporary blocked IP is active.
|
697 |
+
*
|
698 |
+
* @param string $blocked_ip The blocked IP record from the DB.
|
699 |
+
*/
|
700 |
+
public function is_blocked_ip_active( $blocked_ip ) {
|
701 |
+
$current_datetime = strtotime( current_time( 'mysql' ) );
|
702 |
+
$start_block = strtotime( $blocked_ip['start_block'] );
|
703 |
+
$end_block = strtotime( $blocked_ip['end_block'] );
|
704 |
+
if (
|
705 |
+
$current_datetime >= $start_block &&
|
706 |
+
$current_datetime < $end_block
|
707 |
+
) {
|
708 |
+
return true;
|
709 |
+
}
|
710 |
+
|
711 |
+
return false;
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Checks if an IP has been blacklisted.
|
716 |
+
*
|
717 |
+
* @param string $ip The IP address to check.
|
718 |
+
*/
|
719 |
+
public function get_blacklisted_ip( $ip ) {
|
720 |
+
$blacklisted_ip = $this->table_query(
|
721 |
+
'blacklist',
|
722 |
+
array(
|
723 |
+
'type' => 'row',
|
724 |
+
'select' => array(
|
725 |
+
'blacklist_service',
|
726 |
+
'blacklist_id',
|
727 |
+
'last_updated',
|
728 |
+
'attempts',
|
729 |
+
),
|
730 |
+
'where' => array(
|
731 |
+
array(
|
732 |
+
array(
|
733 |
+
'key' => 'user_ip',
|
734 |
+
'value' => $ip,
|
735 |
+
'relation' => '=',
|
736 |
+
),
|
737 |
+
),
|
738 |
+
),
|
739 |
+
'limit' => 1,
|
740 |
+
)
|
741 |
+
);
|
742 |
+
|
743 |
+
return $blacklisted_ip;
|
744 |
+
}
|
745 |
+
|
746 |
+
/**
|
747 |
+
* Checks if an IP has been blocked.
|
748 |
+
*
|
749 |
+
* @param string $ip The IP address to check.
|
750 |
+
*/
|
751 |
+
public function get_blocked_ip( $ip ) {
|
752 |
+
$blocked_ip = $this->table_query(
|
753 |
+
'blocked',
|
754 |
+
array(
|
755 |
+
'type' => 'row',
|
756 |
+
'select' => array(
|
757 |
+
'blocked_type',
|
758 |
+
'start_block',
|
759 |
+
'end_block',
|
760 |
+
'reason',
|
761 |
+
'attempts',
|
762 |
+
),
|
763 |
+
'where' => array(
|
764 |
+
array(
|
765 |
+
array(
|
766 |
+
'key' => 'user_ip',
|
767 |
+
'value' => $ip,
|
768 |
+
'relation' => '=',
|
769 |
+
),
|
770 |
+
),
|
771 |
+
),
|
772 |
+
'limit' => 1,
|
773 |
+
)
|
774 |
+
);
|
775 |
+
|
776 |
+
return $blocked_ip;
|
777 |
+
}
|
778 |
+
|
779 |
+
/**
|
780 |
+
* Queries a database table.
|
781 |
+
*
|
782 |
+
* @param string $table Table key.
|
783 |
+
* @param array $args Array of query arguments.
|
784 |
+
*/
|
785 |
+
public function table_query( $table, $args = array() ) {
|
786 |
+
global $wpdb;
|
787 |
+
|
788 |
+
$sql = 'SELECT';
|
789 |
+
|
790 |
+
// Select.
|
791 |
+
$select = '';
|
792 |
+
if ( ! empty( $args['select'] ) ) {
|
793 |
+
foreach ( $args['select'] as $key => $value ) {
|
794 |
+
if ( $select ) {
|
795 |
+
$select .= ', ';
|
796 |
+
}
|
797 |
+
$select .= $value;
|
798 |
+
}
|
799 |
+
} else {
|
800 |
+
$select = '*';
|
801 |
+
}
|
802 |
+
|
803 |
+
$sql .= ' ' . $select;
|
804 |
+
|
805 |
+
// From.
|
806 |
+
$sql .= ' FROM ' . $this->tables[ $table ];
|
807 |
+
|
808 |
+
// Where.
|
809 |
+
$where = '';
|
810 |
+
if ( ! empty( $args['where'] ) ) {
|
811 |
+
foreach ( $args['where'] as $key => $where_stmt ) {
|
812 |
+
if ( ! $where ) {
|
813 |
+
$where .= 'WHERE ';
|
814 |
+
}
|
815 |
+
|
816 |
+
foreach ( $where_stmt as $k => $array ) {
|
817 |
+
$where .= $array['key'];
|
818 |
+
switch ( $array['relation'] ) {
|
819 |
+
case '=':
|
820 |
+
$where .= ' = ';
|
821 |
+
if ( is_numeric( $array['value'] ) ) {
|
822 |
+
$where .= ' ' . $array['value'];
|
823 |
+
} else {
|
824 |
+
$where .= ' "' . $array['value'] . '"';
|
825 |
+
}
|
826 |
+
break;
|
827 |
+
}
|
828 |
+
}
|
829 |
+
}
|
830 |
+
}
|
831 |
+
|
832 |
+
$sql .= ' ' . $where;
|
833 |
+
|
834 |
+
// Limit.
|
835 |
+
if ( ! empty( $args['limit'] ) ) {
|
836 |
+
$sql .= ' LIMIT ' . $args['limit'];
|
837 |
+
}
|
838 |
+
|
839 |
+
// Offset.
|
840 |
+
if ( ! empty( $args['offset'] ) ) {
|
841 |
+
$sql .= ' OFFSET ' . $args['offset'];
|
842 |
+
}
|
843 |
+
|
844 |
+
if ( ! empty( $args['type'] ) ) {
|
845 |
+
if ( 'row' === $args['type'] ) {
|
846 |
+
return $wpdb->get_row( $sql, ARRAY_A );
|
847 |
+
}
|
848 |
+
} else {
|
849 |
+
return $wpdb->get_results( $sql, ARRAY_A );
|
850 |
+
}
|
851 |
+
}
|
852 |
+
|
853 |
+
/**
|
854 |
+
* Returns the whitelisted IPs.
|
855 |
+
*/
|
856 |
+
public function get_whitelisted_ips() {
|
857 |
+
$whitelist = explode( PHP_EOL, $this->options['ip_whitelist'] );
|
858 |
+
if ( ! $whitelist ) {
|
859 |
+
return array();
|
860 |
+
}
|
861 |
+
|
862 |
+
$whitelisted = array();
|
863 |
+
foreach ( $whitelist as $k => $whitelisted_ip ) {
|
864 |
+
$whitelisted[ $whitelisted_ip ] = $whitelisted_ip;
|
865 |
+
}
|
866 |
+
|
867 |
+
$whitelisted = apply_filters( 'wpzerospam_whitelisted_ips', $whitelisted );
|
868 |
+
|
869 |
+
return $whitelisted;
|
870 |
+
}
|
871 |
+
|
872 |
+
/**
|
873 |
+
* Gets a cookie.
|
874 |
+
*
|
875 |
+
* @param string $cookie_key The cookie of the cookie to retrieve.
|
876 |
+
*/
|
877 |
+
public function get_cookie( $cookie_key ) {
|
878 |
+
$cookie_key = 'wpzerospam_' . $cookie_key;
|
879 |
+
|
880 |
+
return ! empty( $_COOKIE[ $cookie_key ] ) ? $_COOKIE[ $cookie_key ] : false;
|
881 |
+
}
|
882 |
+
|
883 |
+
/**
|
884 |
+
* Sets a cookie.
|
885 |
+
*
|
886 |
+
* @param string $cookie_key The cookie key.
|
887 |
+
* @param string $value The value of the cookie.
|
888 |
+
*/
|
889 |
+
public function set_cookie( $cookie_key, $value, $expiration ) {
|
890 |
+
$current_time = current_time( 'mysql' );
|
891 |
+
|
892 |
+
setcookie( 'wpzerospam_' . $cookie_key, $value, $expiration, COOKIEPATH, COOKIE_DOMAIN );
|
893 |
+
}
|
894 |
+
|
895 |
+
/**
|
896 |
+
* Returns the current user's IP address.
|
897 |
+
*
|
898 |
+
* @link https://www.benmarshall.me/get-ip-address/
|
899 |
+
*/
|
900 |
+
public function get_user_ip() {
|
901 |
+
foreach (
|
902 |
+
array(
|
903 |
+
'HTTP_CLIENT_IP',
|
904 |
+
'HTTP_X_FORWARDED_FOR',
|
905 |
+
'HTTP_X_FORWARDED',
|
906 |
+
'HTTP_X_CLUSTER_CLIENT_IP',
|
907 |
+
'HTTP_FORWARDED_FOR',
|
908 |
+
'HTTP_FORWARDED',
|
909 |
+
'REMOTE_ADDR',
|
910 |
+
)
|
911 |
+
as $key ) {
|
912 |
+
if ( array_key_exists( $key, $_SERVER ) === true ) {
|
913 |
+
foreach ( explode(',', $_SERVER[ $key ]) as $ip_address ) {
|
914 |
+
$ip_address = trim( $ip_address );
|
915 |
+
|
916 |
+
if (
|
917 |
+
filter_var(
|
918 |
+
$ip_address,
|
919 |
+
FILTER_VALIDATE_IP,
|
920 |
+
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
921 |
+
) !== false
|
922 |
+
) {
|
923 |
+
return $ip_address;
|
924 |
+
}
|
925 |
+
}
|
926 |
+
}
|
927 |
+
}
|
928 |
+
|
929 |
+
return false;
|
930 |
+
}
|
931 |
+
}
|
inc/helpers.php
CHANGED
@@ -7,285 +7,6 @@
|
|
7 |
* @link https://benmarshall.me/wordpress-zero-spam/
|
8 |
*/
|
9 |
|
10 |
-
/**
|
11 |
-
* Sets a cookie
|
12 |
-
*/
|
13 |
-
if ( ! function_exists( 'wpzerospam_set_cookie' ) ) {
|
14 |
-
function wpzerospam_set_cookie( $key, $value ) {
|
15 |
-
$options = wpzerospam_options();
|
16 |
-
$expiration = current_time( 'timestamp' ) + ( $options['cookie_expiration'] * DAY_IN_SECONDS );
|
17 |
-
|
18 |
-
setcookie( 'wpzerospam_' . $key, $value, $expiration, COOKIEPATH, COOKIE_DOMAIN );
|
19 |
-
}
|
20 |
-
}
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Get a cookie
|
24 |
-
*/
|
25 |
-
if ( ! function_exists( 'wpzerospam_get_cookie' ) ) {
|
26 |
-
function wpzerospam_get_cookie( $key ) {
|
27 |
-
if ( ! empty( $_COOKIE[ 'wpzerospam_' . $key ] ) ) {
|
28 |
-
return $_COOKIE[ 'wpzerospam_' . $key ];
|
29 |
-
}
|
30 |
-
|
31 |
-
return false;
|
32 |
-
}
|
33 |
-
}
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Check access
|
37 |
-
*
|
38 |
-
* Determines if the current user IP should have access to the site.
|
39 |
-
*
|
40 |
-
* @return array Includes info about the access check.
|
41 |
-
*/
|
42 |
-
if ( ! function_exists( 'wpzerospam_check_access' ) ) {
|
43 |
-
function wpzerospam_check_access() {
|
44 |
-
$ip = wpzerospam_ip();
|
45 |
-
//$ip = '46.229.168.150'; // StopForumSpam testing IP
|
46 |
-
//$ip = '120.40.130.70'; // BotScout testing IP
|
47 |
-
|
48 |
-
// Innocent until proven guilty...
|
49 |
-
$access = [ 'access' => true, 'ip' => $ip ];
|
50 |
-
|
51 |
-
// Always allow authenticated users & users trying to log in access
|
52 |
-
if ( is_user_logged_in() || wpzerospam_is_login() ) {
|
53 |
-
return $access;
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Only check access for actual page vists. Some resource requests like
|
58 |
-
* favicons fire this function which causes duplicate entries in the DB.
|
59 |
-
*
|
60 |
-
* @TODO - Find a way to avoid these checks & ensure this function only gets
|
61 |
-
* fired on page requests vs. resources.
|
62 |
-
*/
|
63 |
-
if (
|
64 |
-
! is_singular() && ! is_page() && ! is_single() && ! is_archive() &&
|
65 |
-
! is_home() && ! is_front_page()
|
66 |
-
) {
|
67 |
-
return $access;
|
68 |
-
}
|
69 |
-
|
70 |
-
$options = wpzerospam_options();
|
71 |
-
|
72 |
-
// 1. Check whitelisted IP addresses
|
73 |
-
$whitelist = wpzerospam_get_whitelist();
|
74 |
-
if ( $whitelist && array_key_exists( $ip, $whitelist ) ) {
|
75 |
-
return $access;
|
76 |
-
}
|
77 |
-
|
78 |
-
// 2. Check if the user's IP address has been blocked
|
79 |
-
$blocked = wpzerospam_is_blocked( $ip );
|
80 |
-
if ( $blocked ) {
|
81 |
-
$access['access'] = false;
|
82 |
-
$access['reason'] = $blocked['reason'];
|
83 |
-
|
84 |
-
return $access;
|
85 |
-
}
|
86 |
-
|
87 |
-
// 3. Check the blacklist
|
88 |
-
$blacklisted = wpzerospam_is_blacklisted( $ip );
|
89 |
-
if ( $blacklisted ) {
|
90 |
-
/**
|
91 |
-
* IP found in the blacklist, check to see if the record needs to be
|
92 |
-
* updated.
|
93 |
-
*/
|
94 |
-
$api_blacklisted = wpzerospam_is_api_blacklisted( $ip, $blacklisted );
|
95 |
-
if ( $api_blacklisted ) {
|
96 |
-
// IP address blacklisted record found & updated
|
97 |
-
$access['access'] = false;
|
98 |
-
$access['reason'] = $api_blacklisted['blacklist_service'];
|
99 |
-
|
100 |
-
return $access;
|
101 |
-
}
|
102 |
-
}
|
103 |
-
|
104 |
-
// 4. Check the API blacklists
|
105 |
-
$api_blacklisted = wpzerospam_is_api_blacklisted( $ip );
|
106 |
-
if ( $api_blacklisted ) {
|
107 |
-
$access['access'] = false;
|
108 |
-
$access['reason'] = $api_blacklisted['blacklist_service'];
|
109 |
-
|
110 |
-
return $access;
|
111 |
-
}
|
112 |
-
|
113 |
-
return $access;
|
114 |
-
}
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Checks & updates blacklist records from APIs
|
119 |
-
*
|
120 |
-
* @param string $ip IP address to check.
|
121 |
-
* @param array $blacklisted_record IP blacklist record from the DB
|
122 |
-
* @return boolean/array False is not blacklisted, otherwise an array with the
|
123 |
-
* blacklisted IP information.
|
124 |
-
*/
|
125 |
-
if ( ! function_exists( 'wpzerospam_is_api_blacklisted' ) ) {
|
126 |
-
function wpzerospam_is_api_blacklisted( $ip, $blacklisted_record = false ) {
|
127 |
-
global $wpdb;
|
128 |
-
|
129 |
-
// No need to check everytime a user visits a page
|
130 |
-
if ( wpzerospam_get_cookie( 'api_blacklist' ) ) { return false; }
|
131 |
-
wpzerospam_set_cookie( 'api_blacklist', current_time( 'timestamp' ) );
|
132 |
-
|
133 |
-
$options = wpzerospam_options();
|
134 |
-
|
135 |
-
if ( $blacklisted_record ) {
|
136 |
-
// Check/update existing blacklist record
|
137 |
-
|
138 |
-
$last_updated = strtotime( $blacklisted_record['last_updated'] );
|
139 |
-
$current_time = current_time( 'timestamp' );
|
140 |
-
$expiration = $last_updated + MONTH_IN_SECONDS;
|
141 |
-
|
142 |
-
if ( $current_time > $expiration ) {
|
143 |
-
// Expired, update the blacklist record in the DB
|
144 |
-
$query = wpzerospam_query_blacklist_api(
|
145 |
-
$ip,
|
146 |
-
$blacklisted_record['blacklist_service']
|
147 |
-
);
|
148 |
-
|
149 |
-
if ( $query ) {
|
150 |
-
if (
|
151 |
-
// Check for Stop Forum Spam confidence level
|
152 |
-
( ! empty( $query['confidence'] ) && $query['confidence'] < $options['stopforumspam_confidence_min'] ) ||
|
153 |
-
// Check for BotScout counts
|
154 |
-
( ! empty( $query['count'] ) && $query['count'] < $options['botscout_count_min'] )
|
155 |
-
) {
|
156 |
-
// Does not meet the stopforumspam confidence minimum, delete record
|
157 |
-
$wpdb->delete( wpzerospam_tables( 'blacklist' ), [
|
158 |
-
'blacklist_id' => $blacklisted_record['blacklist_id']
|
159 |
-
]);
|
160 |
-
|
161 |
-
return false;
|
162 |
-
} else {
|
163 |
-
// Blacklist API found a matching record, update the DB one
|
164 |
-
$blacklisted_record['last_updated'] = current_time( 'mysql' );
|
165 |
-
$blacklisted_record['blacklist_data'] = json_encode( $query );
|
166 |
-
|
167 |
-
$wpdb->update( wpzerospam_tables( 'blacklist' ), $blacklisted_record, [
|
168 |
-
'blacklist_id' => $blacklisted_record['blacklist_id']
|
169 |
-
]);
|
170 |
-
|
171 |
-
return $blacklisted_record;
|
172 |
-
}
|
173 |
-
} else {
|
174 |
-
// Blacklist API didn't find a matching record, delete the DB one
|
175 |
-
$wpdb->delete( wpzerospam_tables( 'blacklist' ), [
|
176 |
-
'blacklist_id' => $blacklisted_record['blacklist_id']
|
177 |
-
]);
|
178 |
-
|
179 |
-
return false;
|
180 |
-
}
|
181 |
-
} else {
|
182 |
-
// Not expired
|
183 |
-
return $blacklisted_record;
|
184 |
-
}
|
185 |
-
} else {
|
186 |
-
// Check all available blacklist APIs
|
187 |
-
$stopforumspam = wpzerospam_query_blacklist_api( $ip, 'stopforumspam' );
|
188 |
-
if ( $stopforumspam ) {
|
189 |
-
if ( ! empty( $stopforumspam['confidence'] ) && $stopforumspam['confidence'] < $options['stopforumspam_confidence_min'] ) {
|
190 |
-
// Does not meet the stopforumspam confidence minimum, delete record
|
191 |
-
$wpdb->delete( wpzerospam_tables( 'blacklist' ), [
|
192 |
-
'user_ip' => $ip
|
193 |
-
]);
|
194 |
-
|
195 |
-
return false;
|
196 |
-
}
|
197 |
-
|
198 |
-
$blacklisted_record = [
|
199 |
-
'blacklist_service' => 'stopforumspam',
|
200 |
-
'user_ip' => $ip,
|
201 |
-
'last_updated' => current_time( 'mysql' ),
|
202 |
-
'blacklist_data' => json_encode( $stopforumspam )
|
203 |
-
];
|
204 |
-
|
205 |
-
$wpdb->replace( wpzerospam_tables( 'blacklist' ), $blacklisted_record );
|
206 |
-
|
207 |
-
return $blacklisted_record;
|
208 |
-
}
|
209 |
-
|
210 |
-
$botscout = wpzerospam_query_blacklist_api( $ip, 'botscout' );
|
211 |
-
if ( $botscout ) {
|
212 |
-
if ( ! empty( $botscout['count'] ) && $botscout['count'] < $options['botscout_count_min'] ) {
|
213 |
-
// Does not meet the botscout count minimum, delete record
|
214 |
-
$wpdb->delete( wpzerospam_tables( 'blacklist' ), [
|
215 |
-
'user_ip' => $ip
|
216 |
-
]);
|
217 |
-
|
218 |
-
return false;
|
219 |
-
}
|
220 |
-
|
221 |
-
$blacklisted_record = [
|
222 |
-
'blacklist_service' => 'botscout',
|
223 |
-
'user_ip' => $ip,
|
224 |
-
'last_updated' => current_time( 'mysql' ),
|
225 |
-
'blacklist_data' => json_encode( $botscout )
|
226 |
-
];
|
227 |
-
|
228 |
-
$wpdb->replace( wpzerospam_tables( 'blacklist' ), $blacklisted_record );
|
229 |
-
|
230 |
-
return $blacklisted_record;
|
231 |
-
}
|
232 |
-
}
|
233 |
-
|
234 |
-
return false;
|
235 |
-
}
|
236 |
-
}
|
237 |
-
|
238 |
-
/**
|
239 |
-
* Adds a access attempt from a blocked user
|
240 |
-
*
|
241 |
-
* @param string $reason The reason for the block
|
242 |
-
*/
|
243 |
-
if ( ! function_exists( 'wpzerospam_attempt_blocked' ) ) {
|
244 |
-
function wpzerospam_attempt_blocked( $ip, $reason ) {
|
245 |
-
global $wpdb;
|
246 |
-
|
247 |
-
$options = wpzerospam_options();
|
248 |
-
|
249 |
-
// Check blocked tables
|
250 |
-
$blocked = wpzerospam_is_blocked( $ip );
|
251 |
-
if ( $blocked ) {
|
252 |
-
// IP already exists in the blocked IP table, increment attempt
|
253 |
-
$attempts = $blocked['attempts'];
|
254 |
-
$attempts++;
|
255 |
-
|
256 |
-
$wpdb->update( wpzerospam_tables( 'blocked' ), [
|
257 |
-
'attempts' => $attempts
|
258 |
-
], [
|
259 |
-
'blocked_id' => $blocked['blocked_id']
|
260 |
-
]);
|
261 |
-
}
|
262 |
-
|
263 |
-
// Check $blacklisted table
|
264 |
-
$blacklisted = wpzerospam_is_blacklisted( $ip );
|
265 |
-
if ( $blacklisted ) {
|
266 |
-
// IP already exists in the blacklisted IP table, increment attempt
|
267 |
-
$attempts = $blacklisted['attempts'];
|
268 |
-
$attempts++;
|
269 |
-
|
270 |
-
$wpdb->update( wpzerospam_tables( 'blacklist' ), [
|
271 |
-
'attempts' => $attempts
|
272 |
-
], [
|
273 |
-
'blacklist_id' => $blacklisted['blacklist_id']
|
274 |
-
]);
|
275 |
-
}
|
276 |
-
|
277 |
-
wpzerospam_log_detection( 'blocked', [ 'reason' => $reason ] );
|
278 |
-
|
279 |
-
if ( 'redirect' == $options['block_handler'] ) {
|
280 |
-
wp_redirect( esc_url( $options['blocked_redirect_url'] ) );
|
281 |
-
exit();
|
282 |
-
} else {
|
283 |
-
status_header( 403 );
|
284 |
-
die( $options['blocked_message'] );
|
285 |
-
}
|
286 |
-
}
|
287 |
-
}
|
288 |
-
|
289 |
/**
|
290 |
* Logs a spam detection.
|
291 |
*
|
7 |
* @link https://benmarshall.me/wordpress-zero-spam/
|
8 |
*/
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
/**
|
11 |
* Logs a spam detection.
|
12 |
*
|
inc/utilities.php
CHANGED
@@ -152,70 +152,6 @@ if ( ! function_exists( 'wpzerospam_options' ) ) {
|
|
152 |
}
|
153 |
}
|
154 |
|
155 |
-
/**
|
156 |
-
* Queries a blacklist API
|
157 |
-
*
|
158 |
-
* @param string $ip The IP address to query
|
159 |
-
* @param string $service The API service to query
|
160 |
-
* @return false/array False if not found, otherwise the IP info.
|
161 |
-
*/
|
162 |
-
if ( ! function_exists( 'wpzerospam_query_blacklist_api' ) ) {
|
163 |
-
function wpzerospam_query_blacklist_api( $ip, $service ) {
|
164 |
-
$options = wpzerospam_options();
|
165 |
-
|
166 |
-
switch( $service ) {
|
167 |
-
case 'stopforumspam':
|
168 |
-
if ( 'enabled' != $options['stop_forum_spam'] ) { return false; }
|
169 |
-
|
170 |
-
$api_url = 'https://api.stopforumspam.org/api?';
|
171 |
-
$params = [ 'ip' => $ip, 'json' => '' ];
|
172 |
-
$endpoint = $api_url . http_build_query( $params );
|
173 |
-
break;
|
174 |
-
case 'botscout':
|
175 |
-
if ( empty( $options['botscout_api'] ) ) { return false; }
|
176 |
-
|
177 |
-
$api_url = 'https://botscout.com/test/?';
|
178 |
-
$params = [ 'ip' => $ip, 'key' => $options['botscout_api'] ];
|
179 |
-
$endpoint = $api_url . http_build_query( $params );
|
180 |
-
break;
|
181 |
-
}
|
182 |
-
|
183 |
-
if ( ! empty( $endpoint ) ) {
|
184 |
-
$response = wp_remote_get( $endpoint, [ 'timeout' => $options['api_timeout'] ] );
|
185 |
-
if ( is_array( $response ) && ! is_wp_error( $response ) ) {
|
186 |
-
$data = wp_remote_retrieve_body( $response );
|
187 |
-
|
188 |
-
switch( $service ) {
|
189 |
-
case 'stopforumspam':
|
190 |
-
$data = json_decode( $data, true );
|
191 |
-
if (
|
192 |
-
! empty( $data['success'] ) &&
|
193 |
-
$data['success'] &&
|
194 |
-
! empty( $data['ip'] ) &&
|
195 |
-
! empty( $data['ip']['appears'] )
|
196 |
-
) {
|
197 |
-
return $data['ip'];
|
198 |
-
}
|
199 |
-
break;
|
200 |
-
case 'botscout':
|
201 |
-
if ( strpos( $data, '!' ) === false ) {
|
202 |
-
list( $matched, $type, $count ) = explode( "|", $data );
|
203 |
-
if ( 'Y' == $matched ) {
|
204 |
-
return [
|
205 |
-
'type' => $type,
|
206 |
-
'count' => $count
|
207 |
-
];
|
208 |
-
}
|
209 |
-
}
|
210 |
-
break;
|
211 |
-
}
|
212 |
-
}
|
213 |
-
}
|
214 |
-
|
215 |
-
return false;
|
216 |
-
}
|
217 |
-
}
|
218 |
-
|
219 |
/**
|
220 |
* Query the database tables
|
221 |
*
|
@@ -329,30 +265,6 @@ if ( ! function_exists( 'wpzerospam_types' ) ) {
|
|
329 |
}
|
330 |
}
|
331 |
|
332 |
-
/**
|
333 |
-
* Whitelisted IPs
|
334 |
-
*
|
335 |
-
* @return array An array of whitelisted IP addresses.
|
336 |
-
*/
|
337 |
-
if ( ! function_exists( 'wpzerospam_get_whitelist' ) ) {
|
338 |
-
function wpzerospam_get_whitelist() {
|
339 |
-
$options = wpzerospam_options();
|
340 |
-
if ( $options['ip_whitelist'] ) {
|
341 |
-
$whitelist = explode( PHP_EOL, $options['ip_whitelist'] );
|
342 |
-
if ( $whitelist ) {
|
343 |
-
$whitelisted = [];
|
344 |
-
foreach( $whitelist as $k => $whitelisted_ip ) {
|
345 |
-
$whitelisted[ $whitelisted_ip ] = $whitelisted_ip;
|
346 |
-
}
|
347 |
-
|
348 |
-
return $whitelisted;
|
349 |
-
}
|
350 |
-
}
|
351 |
-
|
352 |
-
return false;
|
353 |
-
}
|
354 |
-
}
|
355 |
-
|
356 |
/**
|
357 |
* Checks if an IP is blocked
|
358 |
*
|
@@ -395,24 +307,3 @@ if ( ! function_exists( 'wpzerospam_is_blocked' ) ) {
|
|
395 |
return false;
|
396 |
}
|
397 |
}
|
398 |
-
|
399 |
-
/**
|
400 |
-
* Checks if an IP is blacklisted
|
401 |
-
*
|
402 |
-
* @param string IP address to check.
|
403 |
-
* @return boolean/array False is not blacklisted, otherwise an array with the
|
404 |
-
* blacklisted IP information.
|
405 |
-
*/
|
406 |
-
if ( ! function_exists( 'wpzerospam_is_blacklisted' ) ) {
|
407 |
-
function wpzerospam_is_blacklisted( $ip ) {
|
408 |
-
$blacklist_ip = wpzerospam_query_table( 'blacklist', [
|
409 |
-
'select' => [
|
410 |
-
'blacklist_service', 'blacklist_id', 'last_updated', 'attempts'
|
411 |
-
],
|
412 |
-
'where' => [ 'user_ip' => $ip ],
|
413 |
-
'limit' => 1
|
414 |
-
]);
|
415 |
-
|
416 |
-
return $blacklist_ip;
|
417 |
-
}
|
418 |
-
}
|
152 |
}
|
153 |
}
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
/**
|
156 |
* Query the database tables
|
157 |
*
|
265 |
}
|
266 |
}
|
267 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
/**
|
269 |
* Checks if an IP is blocked
|
270 |
*
|
307 |
return false;
|
308 |
}
|
309 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
readme.txt
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
=== WordPress Zero Spam ===
|
2 |
Contributors: bmarshall511, jaredatch, EusebiuOprinoiu
|
3 |
Tags: comments, spam, antispam, anti-spam, comment spam, spambot, spammer, spam free, spam blocker, registration spam
|
4 |
-
Donate link: https://benmarshall.me/donate/?utm_source=wordpress_zero_spam&utm_medium=wordpress_repo&utm_campaign=donate
|
5 |
Requires at least: 5.2
|
6 |
Tested up to: 5.5
|
7 |
Requires PHP: 7.1
|
8 |
-
Stable tag: 4.
|
9 |
License: GNU GPLv3
|
10 |
License URI: https://choosealicense.com/licenses/gpl-3.0/
|
11 |
|
@@ -15,7 +15,7 @@ WordPress Zero Spam makes blocking spam & malicious visitors a cinch. Just insta
|
|
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 — **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 |
|
@@ -47,42 +47,39 @@ In addition, it integrates with other popular plugins to provide all around prot
|
|
47 |
* [Formidable Form Builder](https://wordpress.org/plugins/formidable/) submissions
|
48 |
* and can be easily integrated into any existing theme or plugin
|
49 |
|
50 |
-
WordPress Zero Spam is great at blocking spam — as a site owner there's more you can do to [stop WordPress spam](https://benmarshall.me/stop-wordpress-spam/) in its tracks.
|
51 |
|
52 |
= Multilingual Supported =
|
53 |
|
54 |
-
We’ve integrated multi language support within the framework of our plugin, so you get a translated dashboard out of the box, and developer options to add even more languages.
|
|
|
|
|
|
|
55 |
|
56 |
= Developer API =
|
57 |
|
58 |
WordPress Zero Spam is free and open source. It’s the perfect solution to stopping spam and can be extended and integrated further. It was created and developed with the developer in mind, and we have already seen some truly remarkable addons already developed.
|
59 |
|
60 |
-
To help you get started and learn just how to integrate with WordPress Zero Spam, visit the [plugin's documentation](https://benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
61 |
|
62 |
-
= Translations =
|
63 |
|
64 |
-
|
65 |
-
* [Italian](https://translate.wordpress.org/locale/it/default/wp-plugins/zero-spam/) – (it_IT)
|
66 |
|
67 |
-
|
68 |
|
69 |
-
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
*
|
74 |
-
* If you have any more questions, visit our support on the [Plugin’s Forum](https://wordpress.org/support/plugin/zero-spam/).
|
75 |
-
* For more information, FAQs and API documentation, check out [Zero Spam](https://zerospam.org/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
76 |
|
77 |
= WordPress Zero Spam needs your support =
|
78 |
|
79 |
-
**WordPress Zero Spam is free — completely free & always will be.** It is hard to continue development and support for this free plugin without contributions from users like you. If you enjoy using WordPress Zero Spam and find it useful, please consider making a [donation](https://benmarshall.me/donate/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam). Your donation will help encourage and support the plugin’s continued development and better user support.
|
80 |
-
|
81 |
-
You can also show your support by:
|
82 |
|
83 |
-
*
|
84 |
-
*
|
85 |
-
*
|
86 |
|
87 |
== Installation ==
|
88 |
|
@@ -90,7 +87,7 @@ You can also show your support by:
|
|
90 |
2. Activate the plugin through the Plugins screen (*Plugins > Installed Plugins*).
|
91 |
3. Visit the plugin setting to configure as needed (*Settings > WP Zero Spam*).
|
92 |
|
93 |
-
For more information & developer documentation, see the [plugin’s website](https://benmarshall.me/wordpress-zero-spam).
|
94 |
|
95 |
== Frequently Asked Questions ==
|
96 |
|
@@ -126,11 +123,11 @@ Example with `wpzerospam` class:
|
|
126 |
|
127 |
`<form name="registerform" class="wpzerospam" action="https://yourdomain.local/login/?action=register" method="post" novalidate="novalidate">`
|
128 |
|
129 |
-
If you need help, please don't hesitate to [reach out](https://benmarshall.me/contact/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
130 |
|
131 |
= How do I integrate this into another plugin or theme? =
|
132 |
|
133 |
-
It's easy as adding the class `wpzerospam` to the `form` element, then adding a check in the form processor that the `wpzerospam_key` post value matches the option value in the database using the `wpzerospam_key_check()` helper function. See the [plugin's documentation](https://benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) for more information on available hooks & functions.
|
134 |
|
135 |
= Is JavaScript required to check form submissions? =
|
136 |
|
@@ -150,6 +147,14 @@ Yes. One of the many techniques WordPress Zero Spam employs requires JavaScript
|
|
150 |
|
151 |
== Changelog ==
|
152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
= 4.9.13 =
|
154 |
|
155 |
* Fix - PHP notices for comment options [#209](https://github.com/bmarshall511/wordpress-zero-spam/issues/209)
|
1 |
=== WordPress Zero Spam ===
|
2 |
Contributors: bmarshall511, jaredatch, EusebiuOprinoiu
|
3 |
Tags: comments, spam, antispam, anti-spam, comment spam, spambot, spammer, spam free, spam blocker, registration spam
|
4 |
+
Donate link: https://www.benmarshall.me/donate/?utm_source=wordpress_zero_spam&utm_medium=wordpress_repo&utm_campaign=donate
|
5 |
Requires at least: 5.2
|
6 |
Tested up to: 5.5
|
7 |
Requires PHP: 7.1
|
8 |
+
Stable tag: 4.10.0
|
9 |
License: GNU GPLv3
|
10 |
License URI: https://choosealicense.com/licenses/gpl-3.0/
|
11 |
|
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 — **introducing WordPress Zero Spam**.
|
17 |
|
18 |
+
[WordPress Zero Spam](https://www.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 |
|
47 |
* [Formidable Form Builder](https://wordpress.org/plugins/formidable/) submissions
|
48 |
* and can be easily integrated into any existing theme or plugin
|
49 |
|
50 |
+
WordPress Zero Spam is great at blocking spam — as a site owner there's more you can do to [stop WordPress spam](https://www.benmarshall.me/stop-wordpress-spam/) in its tracks.
|
51 |
|
52 |
= Multilingual Supported =
|
53 |
|
54 |
+
We’ve integrated multi language support within the framework of our plugin, so you get a translated dashboard out of the box, and developer options to add even more languages. Contribute new languages via [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/zero-spam/).
|
55 |
+
|
56 |
+
* [French](https://translate.wordpress.org/locale/fr/default/wp-plugins/zero-spam/) – (fr_FR)
|
57 |
+
* [Italian](https://translate.wordpress.org/locale/it/default/wp-plugins/zero-spam/) – (it_IT)
|
58 |
|
59 |
= Developer API =
|
60 |
|
61 |
WordPress Zero Spam is free and open source. It’s the perfect solution to stopping spam and can be extended and integrated further. It was created and developed with the developer in mind, and we have already seen some truly remarkable addons already developed.
|
62 |
|
63 |
+
To help you get started and learn just how to integrate with WordPress Zero Spam, visit the [plugin's documentation](https://www.benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
64 |
|
|
|
65 |
|
66 |
+
= Help test & become a contributor =
|
|
|
67 |
|
68 |
+
Help test future releases and contribute on the [WordPress Zero Spam GitHub Repository](https://github.com/bmarshall511/wordpress-zero-spam).
|
69 |
|
70 |
+
= Plugin Support =
|
71 |
|
72 |
+
* For usage & tutorials, view the [documentation](https://www.benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
73 |
+
* Have questions? Visit the [WordPress Zero Spam Forum](https://wordpress.org/support/plugin/zero-spam/).
|
74 |
+
* More FAQs and API documentation can be found at [Zero Spam](https://zerospam.org/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
|
|
|
|
75 |
|
76 |
= WordPress Zero Spam needs your support =
|
77 |
|
78 |
+
**WordPress Zero Spam is free — completely free & always will be.** It is hard to continue development and support for this free plugin without contributions from users like you. If you enjoy using WordPress Zero Spam and find it useful, please consider making a [donation](https://www.benmarshall.me/donate/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam). Your donation will help encourage and support the plugin’s continued development and better user support.
|
|
|
|
|
79 |
|
80 |
+
* Like our [Facebook Page](https://www.facebook.com/zerospamorg/)
|
81 |
+
* Follow us on [Twitter](https://www.facebook.com/zerospamorg)
|
82 |
+
* Rate us on [WordPress](https://wordpress.org/support/plugin/zero-spam/reviews/?filter=5/#new-post)
|
83 |
|
84 |
== Installation ==
|
85 |
|
87 |
2. Activate the plugin through the Plugins screen (*Plugins > Installed Plugins*).
|
88 |
3. Visit the plugin setting to configure as needed (*Settings > WP Zero Spam*).
|
89 |
|
90 |
+
For more information & developer documentation, see the [plugin’s website](https://www.benmarshall.me/wordpress-zero-spam).
|
91 |
|
92 |
== Frequently Asked Questions ==
|
93 |
|
123 |
|
124 |
`<form name="registerform" class="wpzerospam" action="https://yourdomain.local/login/?action=register" method="post" novalidate="novalidate">`
|
125 |
|
126 |
+
If you need help, please don't hesitate to [reach out](https://www.benmarshall.me/contact/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam).
|
127 |
|
128 |
= How do I integrate this into another plugin or theme? =
|
129 |
|
130 |
+
It's easy as adding the class `wpzerospam` to the `form` element, then adding a check in the form processor that the `wpzerospam_key` post value matches the option value in the database using the `wpzerospam_key_check()` helper function. See the [plugin's documentation](https://www.benmarshall.me/wordpress-zero-spam/?utm_source=wordpress.org&utm_medium=plugin&utm_campaign=wordpress_zero_spam) for more information on available hooks & functions.
|
131 |
|
132 |
= Is JavaScript required to check form submissions? =
|
133 |
|
147 |
|
148 |
== Changelog ==
|
149 |
|
150 |
+
= 4.10.0 =
|
151 |
+
|
152 |
+
* Enhancement - Various performance improvements & caching added.
|
153 |
+
* Enhancement - Easier to use class methods for integrating Zero Spam into any plugin or theme.
|
154 |
+
* Enhancement - New `WordPress_Zero_Spam` class added.
|
155 |
+
* Enhancement - IPs are now checked against known, safe hosts and user agents (i.e. search engine crawlers).
|
156 |
+
* Enhancement - Added advanced debugging functionality.
|
157 |
+
|
158 |
= 4.9.13 =
|
159 |
|
160 |
* Fix - PHP notices for comment options [#209](https://github.com/bmarshall511/wordpress-zero-spam/issues/209)
|
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.
|
17 |
* Requires at least: 5.2
|
18 |
* Requires PHP: 7.2
|
19 |
* Author: Ben Marshall
|
@@ -24,15 +24,30 @@
|
|
24 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
25 |
*/
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
*/
|
30 |
-
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
31 |
|
32 |
-
// Define plugin constants
|
33 |
define( 'WORDPRESS_ZERO_SPAM', __FILE__ );
|
34 |
define( 'WORDPRESS_ZERO_SPAM_DB_VERSION', '0.5' );
|
35 |
-
define( 'WORDPRESS_ZERO_SPAM_VERSION', '4.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
/**
|
38 |
* Utility helper functions.
|
@@ -122,25 +137,3 @@ if ( wpzerospam_plugin_integration_enabled( 'fluentform' ) ) {
|
|
122 |
if ( wpzerospam_plugin_integration_enabled( 'formidable' ) ) {
|
123 |
require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . 'integrations/formidable/formidable.php';
|
124 |
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Plugin redirect functionality
|
128 |
-
*/
|
129 |
-
if ( ! function_exists( 'wpzerospam_template_redirect' ) ) {
|
130 |
-
function wpzerospam_template_redirect() {
|
131 |
-
// No need to check everytime a user visits a page
|
132 |
-
if ( wpzerospam_get_cookie( 'last_check' ) ) { return false; }
|
133 |
-
|
134 |
-
$options = wpzerospam_options();
|
135 |
-
|
136 |
-
// Check if the current user has access to the site
|
137 |
-
$access = wpzerospam_check_access();
|
138 |
-
|
139 |
-
if ( ! $access['access'] ) {
|
140 |
-
wpzerospam_attempt_blocked( $access['ip'], $access['reason'] );
|
141 |
-
} else {
|
142 |
-
wpzerospam_set_cookie( 'last_check', current_time( 'timestamp' ) );
|
143 |
-
}
|
144 |
-
}
|
145 |
-
}
|
146 |
-
add_action( 'template_redirect', 'wpzerospam_template_redirect' );
|
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.10.0
|
17 |
* Requires at least: 5.2
|
18 |
* Requires PHP: 7.2
|
19 |
* Author: Ben Marshall
|
24 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
25 |
*/
|
26 |
|
27 |
+
// Security Note: Blocks direct access to the plugin PHP files.
|
28 |
+
defined( 'ABSPATH' ) || die();
|
|
|
|
|
29 |
|
30 |
+
// Define plugin constants.
|
31 |
define( 'WORDPRESS_ZERO_SPAM', __FILE__ );
|
32 |
define( 'WORDPRESS_ZERO_SPAM_DB_VERSION', '0.5' );
|
33 |
+
define( 'WORDPRESS_ZERO_SPAM_VERSION', '4.10.0' );
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Include the WordPress Zero Spam plugin class.
|
37 |
+
*/
|
38 |
+
require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . 'classes/class-wordpress-zero-spam.php';
|
39 |
+
|
40 |
+
// Initialize the plugin.
|
41 |
+
$wordpress_zero_spam = new WordPress_Zero_Spam();
|
42 |
+
|
43 |
+
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
|
52 |
/**
|
53 |
* Utility helper functions.
|
137 |
if ( wpzerospam_plugin_integration_enabled( 'formidable' ) ) {
|
138 |
require plugin_dir_path( WORDPRESS_ZERO_SPAM ) . 'integrations/formidable/formidable.php';
|
139 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|