| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | Plugin Name: Kitten's Spaminator |
|---|
| 4 | Version: 1.0rc7 |
|---|
| 5 | Plugin URI: http://blog.mookitty.co.uk/wordpress/spaminator/ |
|---|
| 6 | Description: Spam prevention and blocking using tarpitting and strike counting. Comments are assigned strikes for spam content, and a comment that meets the criteria for spam is blocked from posting.<br>If you're using WP 1.3 or higher, you have an admin menu under "Options" if you wish to change the defaults. For 1.2 users, you must edit the plugin file directly.<br><strong> Copyright 2004, Released under the GPL.</strong> |
|---|
| 7 | Author: Kitten |
|---|
| 8 | Author URI: http://blog.mookitty.co.uk |
|---|
| 9 | |
|---|
| 10 | INSTALLATION INSTRUCTIONS |
|---|
| 11 | ========================= |
|---|
| 12 | 1) If you're viewing this on the web, select all and paste it into a new text file named "kittens-spaminator.php" |
|---|
| 13 | |
|---|
| 14 | 2) Copy the "kittens-spaminator.php" file to your wp-contents/plugins directory. |
|---|
| 15 | |
|---|
| 16 | 3) On your plugins admin page, activate the plugin. |
|---|
| 17 | |
|---|
| 18 | 4) Enjoy your freedom from spam! |
|---|
| 19 | |
|---|
| 20 | 4a) Configure options if you don't like the defaults. Use the admin page for WP 1.3+, edit |
|---|
| 21 | edit this file for 1.2. |
|---|
| 22 | ========================= |
|---|
| 23 | |
|---|
| 24 | Change Log: |
|---|
| 25 | 0.1a - initial release |
|---|
| 26 | 0.2a - add more stuff |
|---|
| 27 | 0.3a - add whitelisting, fix checker function |
|---|
| 28 | 0.3b - fix debug code error |
|---|
| 29 | 0.4a - changed even more stuff |
|---|
| 30 | 0.5a - add crapflood check, change default values |
|---|
| 31 | 0.6a - add stike if no email,etc |
|---|
| 32 | 0.6b - fix php error |
|---|
| 33 | 0.7a - add check for empty email (Donncha) |
|---|
| 34 | 0.8a - add encoded char check, from functions.php |
|---|
| 35 | 0.9a - add post ID check, from techgnome |
|---|
| 36 | 0.9b - clean up email stuff & version |
|---|
| 37 | 0.10a - add user regex for especially annoying spam |
|---|
| 38 | 0.10b - fix user regex bug |
|---|
| 39 | 0.10c - fix another user regex bug |
|---|
| 40 | 0.10d - clean up code, add TODO |
|---|
| 41 | 0.11a - add URL check, fix strpos errors, interface for $strike_cnt |
|---|
| 42 | 0.11b - add user regex for email |
|---|
| 43 | 1.0rc - Release candidate, add GPL license |
|---|
| 44 | 1.0rc2 - Add admin page skel, 1.2 fixes, name whitelisting, "how" in email, clear TODOs |
|---|
| 45 | fix excessive links bug, change default for no referrer, double stripslashes on the |
|---|
| 46 | comment (to make the comment_url filter work to detect strange urls), fix html |
|---|
| 47 | entities |
|---|
| 48 | 1.0rc3 - Add check for real url in URL field, expand character entities check, check |
|---|
| 49 | all urls for dashes (most spam urls have dashes). Change user_regex_c to hopefully |
|---|
| 50 | catch the garbage spammer. Add record keeping on passed comments. |
|---|
| 51 | 1.0rc4 - Now used now 'preprocess' comment filter hook, only works with v1.5 nightlies from |
|---|
| 52 | Jan 5th or later. New email address for returned mail. |
|---|
| 53 | 1.0rc5 - New shiny admin interface + Kitten's regex service. |
|---|
| 54 | 1.0rc6 - Fix install bug. |
|---|
| 55 | 1.0rc7 - Sanitize regex service text, trim form fields. |
|---|
| 56 | */ |
|---|
| 57 | |
|---|
| 58 | /**************---------------- CLASS DEFINITIONS ----------------**************/ |
|---|
| 59 | /// Admin page |
|---|
| 60 | if ( ! class_exists( 'spaminator_admin_page' ) ) : |
|---|
| 61 | class spaminator_admin_page |
|---|
| 62 | { |
|---|
| 63 | function spaminator_admin_page( $post = '' ) |
|---|
| 64 | { |
|---|
| 65 | $this->installed = get_settings( 'spaminator_status' ); |
|---|
| 66 | // Get and load old options |
|---|
| 67 | $this->opts = get_settings( 'spaminator_settings' ); |
|---|
| 68 | if ( count( $this->opts ) == 6 ) { |
|---|
| 69 | foreach ( $this->opts as $key => $val ) $this->$key = $val; |
|---|
| 70 | } |
|---|
| 71 | // Override with new options |
|---|
| 72 | if ( 'Save Options' == $post['save_spaminator_options'] ) { |
|---|
| 73 | $this->save_options = trim( $post['save_spaminator_options'] ); |
|---|
| 74 | $this->strikes = trim( $post['spaminator_strikes'] ); |
|---|
| 75 | $this->user_regex_c = trim( $post['spaminator_comment_regex'] ); |
|---|
| 76 | $this->user_regex_e = trim( $post['spaminator_email_regex'] ); |
|---|
| 77 | $this->nap_time = trim( $post['spaminator_naptime'] ); |
|---|
| 78 | $this->send_mail = trim( $post['spaminator_sendmail'] ); |
|---|
| 79 | $this->crap_flood = trim( $post['spaminator_crapflood'] ); |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | if ( 'Remove Options' == $post['remove_spaminator_options'] ) { |
|---|
| 83 | $this->remove_options(); |
|---|
| 84 | } |
|---|
| 85 | |
|---|
| 86 | // Need to set things up |
|---|
| 87 | $this->install_options = $post['install_spaminator_options']; |
|---|
| 88 | $this->process_options(); |
|---|
| 89 | |
|---|
| 90 | // Get regex list |
|---|
| 91 | if ( 'Get Regexs' == $post['get_regexs'] ) { |
|---|
| 92 | $this->get_regexs(); |
|---|
| 93 | } |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | function process_options() |
|---|
| 97 | { |
|---|
| 98 | // Install |
|---|
| 99 | if ( 'Install now' == $this->install_options && 'installed' != $this->installed ) { |
|---|
| 100 | add_option( 'spaminator_status', 'installed', 'Spaminator install flag' ); |
|---|
| 101 | $settings = array( 'strikes' => 5, |
|---|
| 102 | 'user_regex_e' => '/^byob.*[0-9]{1,4}/i', |
|---|
| 103 | 'user_regex_c' => '/bea?stiality|rape|incest/i', |
|---|
| 104 | 'nap_time' => 60, |
|---|
| 105 | 'send_mail' => TRUE, |
|---|
| 106 | 'crap_flood' => 60 ); |
|---|
| 107 | add_option( 'spaminator_settings', $settings, 'Spaminator options' ); |
|---|
| 108 | $this->installed = get_settings( 'spaminator_status' ); |
|---|
| 109 | $this->opts = get_settings( 'spaminator_settings' ); |
|---|
| 110 | if ( count( $this->opts ) == 6 ) { |
|---|
| 111 | foreach ( $this->opts as $key => $val ) $this->$key = $val; |
|---|
| 112 | } else { |
|---|
| 113 | die( "There was a problem installing the default settings. Please try again." ); |
|---|
| 114 | } |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | // Save new options |
|---|
| 118 | if ( 'Save Options' == $this->save_options ) { |
|---|
| 119 | $settings = array( 'strikes' => $this->strikes, |
|---|
| 120 | 'user_regex_c' => $this->user_regex_c, |
|---|
| 121 | 'user_regex_e' => $this->user_regex_e, |
|---|
| 122 | 'nap_time' => $this->nap_time, |
|---|
| 123 | 'send_mail' => $this->send_mail, |
|---|
| 124 | 'crap_flood' => $this->crap_flood ); |
|---|
| 125 | update_option( 'spaminator_settings', $settings ); |
|---|
| 126 | $this->updated = '<div class="updated"><p>The Spaminator’s settings were updated successfully.</p></div>' . "\n"; |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | function get_regexs() |
|---|
| 131 | { |
|---|
| 132 | $f = @fopen( "http://mookitty.co.uk/regexs.txt", 'r' ); |
|---|
| 133 | $data = @fread( $f, 2048 ); // even if corrupted, only 2K max |
|---|
| 134 | @fclose( $f ); |
|---|
| 135 | |
|---|
| 136 | if ( strlen( $data ) < 1 ) { |
|---|
| 137 | $this->regexs = 'Sorry, no data available.<br />See <a href="http://mookitty.co.uk/regexs.txt">this page</a> for the latest.'; |
|---|
| 138 | } else { |
|---|
| 139 | $this->regexs = htmlentities( $data ); |
|---|
| 140 | } |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | function remove_options() |
|---|
| 144 | { |
|---|
| 145 | delete_option( 'spaminator_status' ); |
|---|
| 146 | delete_option( 'spaminator_settings' ); |
|---|
| 147 | $this->installed = ''; |
|---|
| 148 | $this->updated = '<div class="updated"><p style="color: red;"><strong>The Spaminator’s settings were removed.</strong> You are now using the built in defaults.</p></div>' . "\n"; |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | function display_admin_page() |
|---|
| 152 | { |
|---|
| 153 | if ( 'installed' == $this->installed ) { |
|---|
| 154 | return $this->show_form(); |
|---|
| 155 | } else { |
|---|
| 156 | return $this->show_install_form(); |
|---|
| 157 | } |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | function show_install_form() |
|---|
| 161 | { |
|---|
| 162 | $text = $this->updated; |
|---|
| 163 | $text .= '<div class="wrap"><h2>Install The Spaminator’s Config</h2>' . "\n"; |
|---|
| 164 | $text .= '<form method="post" action="">' . "\n"; |
|---|
| 165 | $text .= '<h3>Do you want to be able to configure The Spaminator from this admin page?</h3>' . "\n"; |
|---|
| 166 | $text .= "<p>This will install The Spaminator's options in your database.</p>" . "\n"; |
|---|
| 167 | $text .= '<input type="submit" name="install_spaminator_options" value="Install now" />' . "\n"; |
|---|
| 168 | $text .= '</form>'. "\n"; |
|---|
| 169 | $text .= '</div>' . "\n"; |
|---|
| 170 | return $text; |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | function show_form() |
|---|
| 174 | { |
|---|
| 175 | $text = $this->updated; |
|---|
| 176 | $text .= '<div class="wrap"><h2>Configure The Spaminator</h2>' . "\n"; |
|---|
| 177 | $text .= '<form method="post" action="" name="spaminator_options">' . "\n"; |
|---|
| 178 | $text .= '<table>' . "\n"; |
|---|
| 179 | $text .= '<tr><td>Strikes:</td>' . "\n"; |
|---|
| 180 | $text .= '<td><input type="text" name="spaminator_strikes" value="'.$this->strikes.'" /></td>' . "\n"; |
|---|
| 181 | $text .= '<td>The number of "hits" needed to kill a comment as spam.</td></tr>' . "\n"; |
|---|
| 182 | |
|---|
| 183 | $text .= '<tr><td>Send email?</td>' . "\n"; |
|---|
| 184 | $text .= '<td><select name="spaminator_sendmail">' . "\n"; |
|---|
| 185 | if ( $this->send_mail ) { |
|---|
| 186 | $text .= '<option value="1" selected="selected">Yes </option>' . "\n"; |
|---|
| 187 | $text .= '<option value="0">No</option>' . "\n"; |
|---|
| 188 | } else { |
|---|
| 189 | $text .= '<option value="1">Yes </option>' . "\n"; |
|---|
| 190 | $text .= '<option value="0" selected="selected">No</option>' . "\n"; |
|---|
| 191 | } |
|---|
| 192 | $text .= '</select></td>' . "\n"; |
|---|
| 193 | $text .= '<td>Send email confirmation of each comment killed?</td></tr>' . "\n"; |
|---|
| 194 | |
|---|
| 195 | |
|---|
| 196 | $text .= '<tr><td>Nap Time:</td>' . "\n"; |
|---|
| 197 | $text .= '<td><input type="text" name="spaminator_naptime" value="'.$this->nap_time.'" /></td>' . "\n"; |
|---|
| 198 | $text .= '<td>How long to tarpit the spammer, in seconds.</td></tr>' . "\n"; |
|---|
| 199 | |
|---|
| 200 | $text .= '<tr><td>Crap Flood:</td>' . "\n"; |
|---|
| 201 | $text .= '<td><input type="text" name="spaminator_crapflood" value="'.$this->crap_flood.'" /></td>' . "\n"; |
|---|
| 202 | $text .= '<td>Minimum amount of time allowed between comments from same IP address.</td></tr>' . "\n"; |
|---|
| 203 | |
|---|
| 204 | |
|---|
| 205 | $text .= '<tr><td>Email regex:</td>' . "\n"; |
|---|
| 206 | $text .= '<td><input type="text" name="spaminator_email_regex" value="'.$this->user_regex_e.'" /></td>' . "\n"; |
|---|
| 207 | $text .= '<td>Special pattern in the email address of the commenter to kill comments.</td></tr>' . "\n"; |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | $text .= '<tr><td>Comment regex:</td>' . "\n"; |
|---|
| 211 | $text .= '<td><input type="text" name="spaminator_comment_regex" value="'.$this->user_regex_c.'" /></td>' . "\n"; |
|---|
| 212 | $text .= '<td>Special pattern in the comment body to kill comments.</td></tr>' . "\n"; |
|---|
| 213 | |
|---|
| 214 | $text .= '</table>' . "\n"; |
|---|
| 215 | $text .= '<input type="submit" name="save_spaminator_options" value="Save Options" />' . "\n"; |
|---|
| 216 | $text .= '</form>'. "\n"; |
|---|
| 217 | $text .= '</div>' . "\n"; |
|---|
| 218 | |
|---|
| 219 | $text .= '<div class="wrap"><h2>Kitten\'s Regex Service</h2>' . "\n"; |
|---|
| 220 | if ( !empty( $this->regexs ) ) { |
|---|
| 221 | $text .= "<pre>$this->regexs</pre>"; |
|---|
| 222 | } else { |
|---|
| 223 | $text .= '<p>If you\'d like to see <a href="http://blog.mookitty.co.uk/wordpress/regex-service/">Kitten\'s custom regexs</a> that she\'s currently using to keep spam away, click the button below:</p>' . "\n"; |
|---|
| 224 | $text .= '<p><strong style="color: red">Notice:</strong> This is highly dependant on your server configuration, and may not work. You\'ve been warned.</p>' . "\n"; |
|---|
| 225 | $text .= '<form method="post" action="" name="kittens_regexs">' . "\n"; |
|---|
| 226 | $text .= '<input type="submit" name="get_regexs" value="Get Regexs" />' . "\n"; |
|---|
| 227 | $text .= '</form>' . "\n"; |
|---|
| 228 | } |
|---|
| 229 | $text .= '</div>' . "\n"; |
|---|
| 230 | |
|---|
| 231 | $text .= '<div class="wrap"><h2>Remove The Spaminator’s Options</h2>' . "\n"; |
|---|
| 232 | $text .= '<p><strong style="color: red">Help!</strong> I\'ve totally screwed up my settings and want to use the built in defaults.</p>' . "\n"; |
|---|
| 233 | $text .= '<form method="post" action="" name="remove_spaminator_options">' . "\n"; |
|---|
| 234 | $text .= '<p>Really remove the user options?</p>' . "\n"; |
|---|
| 235 | $text .= '<input type="submit" name="remove_spaminator_options" value="Remove Options" />' . "\n"; |
|---|
| 236 | $text .= '</form>'. "\n"; |
|---|
| 237 | $text .= '</div>' . "\n"; |
|---|
| 238 | |
|---|
| 239 | return $text; |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | endif; |
|---|
| 243 | |
|---|
| 244 | /// Spam redirector class |
|---|
| 245 | if ( ! class_exists( 'spam_killer' ) ) : |
|---|
| 246 | class spam_killer |
|---|
| 247 | { |
|---|
| 248 | // Class vars |
|---|
| 249 | var $how; |
|---|
| 250 | var $post; |
|---|
| 251 | var $strikes; |
|---|
| 252 | var $strike_cnt; |
|---|
| 253 | var $word_list; |
|---|
| 254 | var $nap_time; |
|---|
| 255 | var $send_mail; |
|---|
| 256 | var $crap_flood; |
|---|
| 257 | |
|---|
| 258 | function spam_killer( $post ) |
|---|
| 259 | { |
|---|
| 260 | $options = array( |
|---|
| 261 | //================================================================== |
|---|
| 262 | // Adjust the number of strikes needed to reject a comment |
|---|
| 263 | strikes => 5, // Number |
|---|
| 264 | //================================================================== |
|---|
| 265 | // Change this to fight a particular spammer |
|---|
| 266 | user_regex_c => '/bea?stiality|rape|incest/i', // Text string |
|---|
| 267 | user_regex_e => '/^byob.*[0-9]{1,4}/i', // Text string |
|---|
| 268 | //================================================================== |
|---|
| 269 | // Adjust the nap time to vary the TarPit delay |
|---|
| 270 | nap_time => 60, // Time in seconds |
|---|
| 271 | //================================================================== |
|---|
| 272 | // Change to TRUE to enable sending email when a spammer is caught |
|---|
| 273 | send_mail => true, // TRUE or FALSE |
|---|
| 274 | //================================================================== |
|---|
| 275 | // Adjust the minimum time between posts (crapflooding) |
|---|
| 276 | crap_flood => 60, // Time in seconds |
|---|
| 277 | //================================================================== |
|---|
| 278 | ); |
|---|
| 279 | |
|---|
| 280 | $installed = get_settings( 'spaminator_status' ); |
|---|
| 281 | |
|---|
| 282 | if ( 'installed' == $installed ) { // this is set via the admin page |
|---|
| 283 | $saved_options = get_settings( 'spaminator_settings' ); |
|---|
| 284 | if ( is_array( $saved_options ) ) $options = $saved_options; // override |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | foreach ( $options as $key => $opt ) $this->$key = $opt; |
|---|
| 288 | |
|---|
| 289 | $this->post = $post; |
|---|
| 290 | $this->strike_cnt = 0; |
|---|
| 291 | $this->word_list = get_settings('moderation_keys'); |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | function count_strikes( $str = 0, $how ) |
|---|
| 295 | { |
|---|
| 296 | $this->how[] = $how; // list all checks so far |
|---|
| 297 | $this->strike_cnt += $str; |
|---|
| 298 | |
|---|
| 299 | // stats |
|---|
| 300 | $this->post['comment_content'] .= "<!-- X-spaminator-strike: $how, $str -->"; |
|---|
| 301 | |
|---|
| 302 | if ( $this->strike_cnt >= $this->strikes ) { |
|---|
| 303 | |
|---|
| 304 | // Maybe send mail - we got spammer tail |
|---|
| 305 | if ( $this->send_mail ) { |
|---|
| 306 | $why = implode( ", ", $this->how ); |
|---|
| 307 | $body = "The Spaminator has killed a comment.\r\n\r\n"; |
|---|
| 308 | $body .= "The details:\r\n"; |
|---|
| 309 | $body .= "Strikes : $this->strike_cnt/$this->strikes\r\n"; |
|---|
| 310 | $body .= "How : $why\r\n"; |
|---|
| 311 | $body .= "IP Addr : ".$_SERVER['REMOTE_ADDR']."\r\n"; |
|---|
| 312 | $body .= "Referer : ".$_SERVER['HTTP_REFERER']."\r\n"; |
|---|
| 313 | $body .= "Client : ".$_SERVER['HTTP_USER_AGENT']."\r\n"; |
|---|
| 314 | $body .= "Request : ".$_SERVER['REQUEST_METHOD']." ". $_SERVER['REQUEST_URI']."\r\n"; |
|---|
| 315 | $body .= "Post ID : ".$this->post['comment_post_ID']."\r\n"; |
|---|
| 316 | $body .= "Email : ".$this->post['comment_author_email']."\r\n"; |
|---|
| 317 | $body .= "Author : ".$this->post['comment_author']."\r\n"; |
|---|
| 318 | $body .= "URL : ".$this->post['comment_author_url']."\r\n"; |
|---|
| 319 | $body .= "Body:\r\n"; |
|---|
| 320 | $body .= $this->post['comment_content']."\r\n\r\n"; |
|---|
| 321 | $body .= "--\r\nThis email has been sent because the Spaminator plugin is set to send emails when a suspected spam has been blocked.\r\nTo not receive these emails change the ".'$this->send_mail'." variable to FALSE.\r\n\r\nThanks for using this plugin, hope it helps!\r\nhttp://mookitty.co.uk/devblog/"; |
|---|
| 322 | $headers = "From: The Spaminator <wp.spaminator@gmail.com>"; |
|---|
| 323 | $to = "[" . get_settings('blogname') . "] Spaminator: Spammer caught!"; |
|---|
| 324 | |
|---|
| 325 | @mail( get_settings('admin_email'), $to, $body, $headers ); |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | // Let's waste spambot time: |
|---|
| 329 | sleep ( $this->nap_time ); |
|---|
| 330 | |
|---|
| 331 | // Make sure the bot thinks that spam was posted: |
|---|
| 332 | header( "HTTP/1.0 200 OK" ); |
|---|
| 333 | |
|---|
| 334 | // Tell humans something else: |
|---|
| 335 | echo "<p>Sorry, you've been prevented from commenting on this blog.</p>\n"; |
|---|
| 336 | echo "<p>Either your comment content was found to contain spam, or<br />\n"; |
|---|
| 337 | echo "your IP address (or a subnet of your IP address) has spammed this blog before.</p>\n"; |
|---|
| 338 | echo "<p>If you think you got this page in error, your entered name might be too short.</p>\n"; |
|---|
| 339 | echo "<p>You can also complain to <a href=\"wp.spaminator@gmail.com\">wp.spaminator@gmail.com</a>. View source to see why you got blocked.\n"; |
|---|
| 340 | echo "<p>Strike count: $this->strike_cnt</p>\n"; |
|---|
| 341 | echo "\n<!-- ", implode( ", ", $this->how ), " -->"; |
|---|
| 342 | exit; |
|---|
| 343 | } |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | function process_comment() |
|---|
| 347 | { |
|---|
| 348 | global $wpdb, $table_prefix; |
|---|
| 349 | if ( empty($wpdb->comments) ) $wpdb->comments = $table_prefix . 'comments'; |
|---|
| 350 | if ( empty($wpdb->posts) ) $wpdb->posts = $table_prefix . 'posts'; |
|---|
| 351 | |
|---|
| 352 | /// Set up vars to use: |
|---|
| 353 | |
|---|
| 354 | $type = $this->post['comment_type']; |
|---|
| 355 | $url = parse_url( $this->post['comment_author_url'] ); |
|---|
| 356 | $postID = $this->post['comment_post_ID']; |
|---|
| 357 | $author = $this->post['comment_author']; |
|---|
| 358 | if ( empty( $this->post['comment_author_email'] ) ) { |
|---|
| 359 | if ( 'trackback' == $type ) { |
|---|
| 360 | $this->post['comment_author_email'] = 'trackback@' . $url['host']; |
|---|
| 361 | } elseif ( 'pingback' == $type ) { |
|---|
| 362 | $this->post['comment_author_email'] = 'pingback@' . $url['host']; |
|---|
| 363 | } |
|---|
| 364 | } |
|---|
| 365 | $email = $this->post['comment_author_email']; |
|---|
| 366 | // Filter the text so that links show up, etc. |
|---|
| 367 | $comment = apply_filters( 'comment_text', stripslashes(stripslashes($this->post['comment_content'])) ); |
|---|
| 368 | // $forward = $this->post['redirect_to']; |
|---|
| 369 | $remote = $_SERVER['REMOTE_ADDR']; |
|---|
| 370 | $referer = $_SERVER['HTTP_REFERER']; |
|---|
| 371 | $iplist = preg_grep( "/^([0-9]{1,3}\.?){2}/", explode("\n", $this->word_list) ); |
|---|
| 372 | $wdlist = explode( "\n", $this->word_list ); |
|---|
| 373 | $wdlist = array_diff( $wdlist, $iplist ); |
|---|
| 374 | // Get email for whitelist |
|---|
| 375 | if ( !empty( $email ) ) { |
|---|
| 376 | $whlist = $wpdb->get_row("SELECT comment_approved, comment_author FROM $wpdb->comments WHERE comment_author_email = '$email' AND comment_approved = '1' AND NOW()+0 > UNIX_TIMESTAMP( DATE_ADD( comment_date, INTERVAL 1 DAY ) ) GROUP BY comment_author;"); |
|---|
| 377 | } else { |
|---|
| 378 | $whlist = '0'; |
|---|
| 379 | } |
|---|
| 380 | |
|---|
| 381 | // This returns a unix timestamp |
|---|
| 382 | $cfchck = $wpdb->get_var("SELECT UNIX_TIMESTAMP(comment_date) FROM $wpdb->comments WHERE comment_author_IP = '$remote' ORDER BY comment_date_gmt DESC LIMIT 1;"); |
|---|
| 383 | |
|---|
| 384 | /// Check for spam: |
|---|
| 385 | |
|---|
| 386 | // User regex check |
|---|
| 387 | if ( preg_match( $this->user_regex_c, $comment ) > 0 ) { |
|---|
| 388 | $this->count_strikes( 10, 'user regex - comment' ); |
|---|
| 389 | } |
|---|
| 390 | if ( preg_match( $this->user_regex_e, $email ) > 0 ) { |
|---|
| 391 | $this->count_strikes( 10, 'user regex - email '); |
|---|
| 392 | } |
|---|
| 393 | |
|---|
| 394 | // If non-existing post, spam for sure |
|---|
| 395 | if ( !$wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE ID = '$postID'") ) { |
|---|
| 396 | $this->count_strikes( 10, 'non-existant post' ); |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | // If previously approved, they get a headstart |
|---|
| 400 | if ( '1' == $whlist->comment_approved ) $this->count_strikes( -3, 'whitelist' ); |
|---|
| 401 | |
|---|
| 402 | // Check referer, see if a bot is directly inserting comment |
|---|
| 403 | if ( FALSE === strpos( $referer, get_settings('siteurl') ) ) { |
|---|
| 404 | $this->count_strikes( 3, 'bad referer - spambot?' ); |
|---|
| 405 | } |
|---|
| 406 | |
|---|
| 407 | // Check IP, see if it's a known spammer |
|---|
| 408 | $this->checker( $iplist, $remote, 5, 'IP check' ); |
|---|
| 409 | |
|---|
| 410 | // Check for crapflood |
|---|
| 411 | if ( $cfchck + $this->crap_flood > time() ) { |
|---|
| 412 | $this->count_strikes( 3, 'crap flooding' ); |
|---|
| 413 | } |
|---|
| 414 | |
|---|
| 415 | // Count links |
|---|
| 416 | if ( (count(explode('http', $comment)) - 1 ) > ( (int) get_settings('comment_max_links') ) ) { |
|---|
| 417 | $this->count_strikes( 3, 'excessive links' ); |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | // Check email |
|---|
| 421 | $this->checker( $wdlist, $email, 1, 'email check' ); |
|---|
| 422 | |
|---|
| 423 | // Check author |
|---|
| 424 | // If the email is whitelisted, the name gets a free pass |
|---|
| 425 | // the most recent version of the name is used |
|---|
| 426 | if ( $author != $whlist->comment_author ) { |
|---|
| 427 | $this->checker( $wdlist, $author, 1, 'author check' ); |
|---|
| 428 | } |
|---|
| 429 | |
|---|
| 430 | // Check URL |
|---|
| 431 | // 3 points here, in case of "no body links" spam |
|---|
| 432 | $this->checker( $wdlist, $url['host'], 3, 'author url' ); |
|---|
| 433 | |
|---|
| 434 | // Check comment |
|---|
| 435 | $this->checker( $wdlist, $comment, 1, 'comment body' ); |
|---|
| 436 | |
|---|
| 437 | // From functions.php: |
|---|
| 438 | // Useless numeric encoding is a pretty good spam indicator: |
|---|
| 439 | // Extract entities: |
|---|
| 440 | if (preg_match_all('/&#?(\d+);/', $url['host'] . $author . $email, $chars)) { |
|---|
| 441 | foreach ($chars[1] as $char) { |
|---|
| 442 | // If it's an encoded char in the normal ASCII set, reject |
|---|
| 443 | if ($char < 128) $this->count_strikes( 1, 'html entity' ); |
|---|
| 444 | } |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | // Check for dashes in urls |
|---|
| 448 | // Urls that are auto formatted will get counted twice - feature, not bug! |
|---|
| 449 | preg_match_all( '#(http:)?//([^\s"\'<>]*)#i', $comment, $match ); |
|---|
| 450 | array_push( $match[2], $url['host'] ); |
|---|
| 451 | array_push( $match[2], $email ); |
|---|
| 452 | $cnt_dash = 0; |
|---|
| 453 | foreach ( $match[2] as $u ) { |
|---|
| 454 | $cnt_dash += substr_count( $u, '-' ); |
|---|
| 455 | } |
|---|
| 456 | if ( $cnt_dash > 0 ) { |
|---|
| 457 | $this->count_strikes( $cnt_dash, 'url dashes' ); |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | // Check if provided url is legit |
|---|
| 461 | if ( strlen( $url['host'] ) > 0 && ! checkdnsrr( $url['host'], 'A' ) ) { |
|---|
| 462 | $this->count_strikes( 4, "unknown url, $url" ); |
|---|
| 463 | } |
|---|
| 464 | |
|---|
| 465 | return $this->post; |
|---|
| 466 | |
|---|
| 467 | } // end of function process_comment |
|---|
| 468 | |
|---|
| 469 | function checker( $haystack, $needle, $strike_val, $how ) |
|---|
| 470 | { |
|---|
| 471 | if ( is_array( $haystack ) && count( $haystack ) > 0 && strlen( $needle ) > 3 ) { |
|---|
| 472 | foreach ( $haystack as $item ) { |
|---|
| 473 | $item = trim( $item ); |
|---|
| 474 | // skip empties & shorts in mod keys, faster than filtering list |
|---|
| 475 | if ( strlen( $item ) < 3 ) continue; |
|---|
| 476 | |
|---|
| 477 | $word_cnt = substr_count( $needle, $item ); |
|---|
| 478 | if ( $word_cnt > 0 ) { |
|---|
| 479 | $this->count_strikes( $strike_val * $word_cnt, $how . ' - ' . $item ); |
|---|
| 480 | } |
|---|
| 481 | } |
|---|
| 482 | } |
|---|
| 483 | // Add a strike if email, etc is empty |
|---|
| 484 | if ( empty( $needle ) ) $this->count_strikes( 1, "empty field - $how" ); |
|---|
| 485 | if ( ! empty( $needle ) && strlen( $needle ) <=3 ) $this->count_strikes( 1, 'short field' ); |
|---|
| 486 | |
|---|
| 487 | // Record keeping |
|---|
| 488 | $this->post['comment_content'] .= "<!-- X-spaminator-passed: $how -->"; |
|---|
| 489 | |
|---|
| 490 | } // end of function checker |
|---|
| 491 | |
|---|
| 492 | } // end class spam killer |
|---|
| 493 | endif; |
|---|
| 494 | /**************-------------- END CLASS DEFINITIONS --------------**************/ |
|---|
| 495 | |
|---|
| 496 | /**************---------------- STANDALONE SECTION ---------------**************/ |
|---|
| 497 | /// Control block if comment posted. |
|---|
| 498 | if ( ! function_exists( 'spaminate_comment' ) ) { |
|---|
| 499 | function spaminate_comment( $comment ) { |
|---|
| 500 | $incoming_spam = new spam_killer( $comment ); |
|---|
| 501 | $foo = $incoming_spam->process_comment(); |
|---|
| 502 | return $foo; |
|---|
| 503 | } |
|---|
| 504 | } |
|---|
| 505 | |
|---|
| 506 | // Adds the menu item |
|---|
| 507 | if ( ! function_exists( 'add_spaminator_menu' ) ) { |
|---|
| 508 | function add_spaminator_menu() |
|---|
| 509 | { |
|---|
| 510 | add_options_page(__('Spaminator Config'), __('Spaminator'), 9, 'kittens-spaminator.php'); |
|---|
| 511 | } |
|---|
| 512 | } elseif ( 'kittens-spaminator.php' == $_GET['page'] ) { |
|---|
| 513 | $spamiator_iface = new spaminator_admin_page( $_POST ); |
|---|
| 514 | echo $spamiator_iface->display_admin_page(); |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | add_action('preprocess_comment', 'spaminate_comment'); |
|---|
| 518 | add_action('admin_menu', 'add_spaminator_menu'); |
|---|
| 519 | /**************-------------- END STANDALONE SECTION -------------**************/ |
|---|
| 520 | |
|---|
| 521 | ?> |
|---|