PluginProbe
bbPress / 2.0-beta-3
bbPress v2.0-beta-3
2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 2.2 2.2.1 All 72 releases
bbpress / bbp-includes / bbp-core-akismet.php

bbp-core-akismet.php in bbPress 2.0-beta-3, at bbp-includes/bbp-core-akismet.php

570 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Main bbPress Akismet Class
5 *
6 * @package bbPress
7 * @subpackage Akismet
8 */
9
10 // Exit if accessed directly
11 if ( !defined( 'ABSPATH' ) ) exit;
12
13 if ( !class_exists( 'BBP_Akismet' ) ) :
14 /**
15 * Loads Akismet extension
16 *
17 * @since bbPress (r3277)
18 *
19 * @package bbPress
20 * @subpackage Akismet
21 */
22 class BBP_Akismet {
23
24 /**
25 * The main bbPress Akismet loader (PHP4 compat)
26 *
27 * @since bbPress (r3277)
28 */
29 function BBP_Akismet() {
30 $this->__construct();
31 }
32
33 /**
34 * The main bbPress Akismet loader
35 *
36 * @since bbPress (r3277)
37 *
38 * @uses add_filter()
39 */
40 function __construct() {
41 $this->_setup_actions();
42 }
43
44 /**
45 * Setup the admin hooks
46 *
47 * @since bbPress (r3277)
48 * @access private
49 *
50 * @uses add_filter() To add various filters
51 * @uses add_action() To add various actions
52 */
53 function _setup_actions() {
54
55 // Bail if no akismet
56 if ( !defined( 'AKISMET_VERSION' ) ) return;
57
58 // bbPress functions to check for spam
59 $checks['check'] = array(
60 'bbp_new_topic_pre_insert' => 1, // Topic check
61 'bbp_new_reply_pre_insert' => 1 // Reply check
62 );
63
64 // bbPress functions for spam and ham submissions
65 $checks['submit'] = array(
66 'bbp_spammed_topic' => 10, // Spammed topic
67 'bbp_unspammed_topic' => 10, // Unspammed reply
68 'bbp_spammed_reply' => 10, // Spammed reply
69 'bbp_unspammed_reply' => 10, // Unspammed reply
70 );
71
72 // Add the checks
73 foreach ( $checks as $type => $functions )
74 foreach( $functions as $function => $priority )
75 add_filter( $function, array( $this, $type . '_post' ), $priority );
76
77 // Update post meta
78 add_action( 'wp_insert_post', array( $this, 'update_post_meta' ), 10, 2 );
79 }
80
81 /**
82 * Converts topic/reply data into Akismet comment checking format
83 *
84 * @since bbPress (r3277)
85 *
86 * @param string $post_data
87 *
88 * @global bbPress $bbp
89 *
90 * @uses get_userdata() To get the user data
91 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
92 * @uses get_permalink() To get the permalink of the post parent
93 * @uses bbp_current_author_ip() To get the IP address of the current user
94 * @uses BBP_Akismet::maybe_spam() To check if post is spam
95 * @uses akismet_get_user_roles() To get the role(s) of the current user
96 * @uses do_action() To call the 'bbp_akismet_spam_caught' hook
97 * @uses add_filter() To call the 'bbp_new_reply_pre_set_terms' hook
98 *
99 * @return array Array of post data
100 */
101 function check_post( $post_data ) {
102 global $bbp;
103
104 // Post is not published
105 if ( 'publish' != $post_data['post_status'] )
106 return $post_data;
107
108 // Extract post_data into variables
109 extract( $post_data );
110
111 // Get user data
112 $userdata = get_userdata( $post_author );
113 $anonymous_data = bbp_filter_anonymous_post_data();
114
115 // Put post_data back into usable array
116 $post = array(
117 'comment_author' => $anonymous_data ? $anonymous_data['bbp_anonymous_name'] : $userdata->display_name,
118 'comment_author_email' => $anonymous_data ? $anonymous_data['bbp_anonymous_email'] : $userdata->user_email,
119 'comment_author_url' => $anonymous_data ? $anonymous_data['bbp_anonymous_website'] : $userdata->user_url,
120 'comment_content' => $post_content,
121 'comment_post_ID' => $post_parent,
122 'comment_type' => $post_type,
123 'permalink' => get_permalink( $post_parent ),
124 'referrer' => $_SERVER['HTTP_REFERER'],
125 'user_agent' => $_SERVER['HTTP_USER_AGENT'],
126 'user_ID' => $post_author,
127 'user_ip' => bbp_current_author_ip(),
128 'user_role' => akismet_get_user_roles( $post_author ),
129 );
130
131 // Check the post_data
132 $post = $this->maybe_spam( $post );
133
134 // Get the result
135 $post_data['bbp_akismet_result'] = $post['bbp_akismet_result'];
136 unset( $post['bbp_akismet_result'] );
137
138 // Store the data as submitted
139 $post_data['bbp_post_as_submitted'] = $post;
140
141 // Spam
142 if ( 'true' == $post_data['bbp_akismet_result'] ) {
143
144 // Let plugins do their thing
145 do_action( 'bbp_akismet_spam_caught' );
146
147 // This is spam
148 $post_data['post_status'] = $bbp->spam_status_id;
149
150 // We don't want your spam tags here
151 add_filter( 'bbp_new_reply_pre_set_terms', array( $this, 'filter_post_terms' ), 1, 3 );
152
153 // @todo Spam counter?
154 }
155
156 // @todo Topic/reply moderation? No true/false response - 'pending' or 'draft'
157 // @todo Auto-delete old spam?
158
159 // Log the last post
160 $this->last_post = $post_data;
161
162 // Pass the data back to the filter
163 return $post_data;
164 }
165
166 /**
167 * Submit a post for spamming or hamming
168 *
169 * @since bbPress ({unknown})
170 *
171 * @param int $post_id
172 *
173 * @global bbPress $bbp
174 * @global WP_Query $wpdb
175 * @global string $akismet_api_host
176 * @global string $akismet_api_port
177 * @global object $current_user
178 * @global object $current_site
179 *
180 * @uses current_filter() To get the reply_id
181 * @uses get_post() To get the post object
182 * @uses get_the_author_meta() To get the author meta
183 * @uses get_post_meta() To get the post meta
184 * @uses bbp_get_user_profile_url() To get a user's profile url
185 * @uses get_permalink() To get the permalink of the post_parent
186 * @uses akismet_get_user_roles() To get the role(s) of the post_author
187 * @uses bbp_current_author_ip() To get the IP address of the current user
188 * @uses BBP_Akismet::maybe_spam() To submit the post as ham or spam
189 * @uses update_post_meta() To update the post meta with some Akismet data
190 * @uses do_action() To call the 'bbp_akismet_submit_spam_post' and 'bbp_akismet_submit_ham_post' hooks
191 *
192 * @return array Array of existing topic terms
193 */
194 function submit_post( $post_id = 0 ) {
195 global $bbp, $wpdb, $akismet_api_host, $akismet_api_port, $current_user, $current_site;
196
197 switch ( current_filter() ) {
198
199 // Mysterious, and straight from the can
200 case 'bbp_spammed_topic' :
201 case 'bbp_spammed_reply' :
202 $request_type = 'spam';
203 break;
204
205 // Honey-glazed, a straight off the bone
206 case 'bbp_unspammed_topic' :
207 case 'bbp_unspammed_reply' :
208 $request_type = 'ham';
209 break;
210
211 // Possibly poison...
212 default :
213 return;
214 }
215
216 // Setup some variables
217 $post_id = (int) $post_id;
218
219 // Make sure we have a post
220 if ( !$post = get_post( $post_id ) )
221 return;
222
223 // Bail if we're spamming, but the post_status isn't spam
224 if ( ( 'spam' == $request_type ) && ( $bbp->spam_status_id != $post->post_status ) )
225 return;
226
227 // Set some default post_data
228 $post_data = array(
229 'comment_approved' => $post->post_status,
230 'comment_author' => $post->post_author ? get_the_author_meta( 'display_name', $post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_name', true ),
231 'comment_author_email' => $post->post_author ? get_the_author_meta( 'email', $post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_email', true ),
232 'comment_author_url' => $post->post_author ? bbp_get_user_profile_url( $post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_website', true ),
233 'comment_content' => $post->post_content,
234 'comment_date' => $post->post_date,
235 'comment_ID' => $post_id,
236 'comment_post_ID' => $post->post_parent,
237 'comment_type' => $post->post_type,
238 'permalink' => get_permalink( $post_id ),
239 'user_ID' => $post->post_author,
240 'user_ip' => get_post_meta( $post_id, '_bbp_author_ip', true ),
241 'user_role' => akismet_get_user_roles( $post->post_author ),
242 );
243
244 // Use the original version stored in post_meta if available
245 $as_submitted = get_post_meta( $post_id, '_bbp_akismet_as_submitted', true );
246 if ( $as_submitted && is_array( $as_submitted ) && isset( $as_submitted['comment_content'] ) )
247 $post_data = array_merge( $post_data, $as_submitted );
248
249 // Add the reporter IP address
250 $post_data['reporter_ip'] = bbp_current_author_ip();
251
252 // Add some reporter info
253 if ( is_object( $current_user ) )
254 $post_data['reporter'] = $current_user->user_login;
255
256 // Add the current site domain
257 if ( is_object( $current_site ) )
258 $post_data['site_domain'] = $current_site->domain;
259
260 // Place your slide beneath the microscope
261 $post_data = $this->maybe_spam( $post_data, 'submit', $request_type );
262
263 // Manual user action
264 if ( isset( $post_data['reporter'] ) ) {
265
266 // What kind of action
267 switch ( $request_type ) {
268
269 // Spammy
270 case 'spam' :
271 $this->update_post_history( $post_id, sprintf( __( '%1$s reported this %2$s as spam', 'bbpress' ), $post_data['reporter'], $post_data['comment_type'] ), 'report-spam' );
272 update_post_meta( $post_id, '_bbp_akismet_user_result', 'true' );
273 update_post_meta( $post_id, '_bbp_akismet_user', $post_data['reporter'] );
274 break;
275
276 // Hammy
277 case 'ham' :
278 $this->update_post_history( $post_id, sprintf( __( '%1$s reported this %2$s as not spam', 'bbpress' ), $post_data['reporter'], $post_data['comment_type'] ), 'report-ham' );
279 update_post_meta( $post_id, '_bbp_akismet_user_result', 'false' );
280 update_post_meta( $post_id, '_bbp_akismet_user', $post_data['reporter'] );
281
282 // @todo Topic term revision history
283 break;
284
285 // Possible other actions
286 default :
287 break;
288 }
289 }
290
291 do_action( 'bbp_akismet_submit_' . $request_type . '_post', $post_id, $post_data['bbp_akismet_result'] );
292 }
293
294 /**
295 * Ping Akismet service and check for spam/ham response
296 *
297 * @since bbPress (r3277)
298 *
299 * @param array $post_data
300 * @param string $check Accepts check|submit
301 * @param string $spam Accepts spam|ham
302 *
303 * @global string $akismet_api_host
304 * @global string $akismet_api_port
305 *
306 * @uses akismet_test_mode() To determine if Akismet is in test mode
307 * @uses akismet_http_post() To send data to the mothership for processing
308 *
309 * @return array Array of post data
310 */
311 function maybe_spam( $post_data, $check = 'check', $spam = 'spam' ) {
312 global $akismet_api_host, $akismet_api_port;
313
314 // Define variables
315 $query_string = $path = $response = '';
316
317 // Populate post data
318 $post_data['blog'] = get_option( 'home' );
319 $post_data['blog_charset'] = get_option( 'blog_charset' );
320 $post_data['blog_lang'] = get_locale();
321 $post_data['referrer'] = $_SERVER['HTTP_REFERER'];
322 $post_data['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
323
324 // Akismet Test Mode
325 if ( akismet_test_mode() )
326 $post_data['is_test'] = 'true';
327
328 // Loop through _POST args and rekey strings
329 foreach ( $_POST as $key => $value )
330 if ( is_string( $value ) )
331 $post_data['POST_' . $key] = $value;
332
333 // Keys to ignore
334 $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
335
336 // Loop through _SERVER args and remove whitelisted keys
337 foreach ( $_SERVER as $key => $value ) {
338
339 // Key should not be ignored
340 if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
341 $post_data[$key] = $value;
342
343 // Key should be ignored
344 } else {
345 $post_data[$key] = '';
346 }
347 }
348
349 // Ready...
350 foreach ( $post_data as $key => $data )
351 $query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
352
353 // Aim...
354 if ( 'check' == $check )
355 $path = '/1.1/comment-check';
356 elseif ( 'submit' == $check )
357 $path = '/1.1/submit-' . $spam;
358
359 // Fire!
360 $response = akismet_http_post( $query_string, $akismet_api_host, $path, $akismet_api_port );
361
362 // Check the high-speed cam
363 $post_data['bbp_akismet_result'] = $response[1];
364
365 // This is ham
366 return $post_data;
367 }
368
369 /**
370 * Update post meta after a spam check
371 *
372 * @since bbPress (r3308)
373 *
374 * @param int $post_id
375 * @param object $post
376 *
377 * @global bbPress $bbp
378 * @global object $this->last_post
379 *
380 * @uses get_post() To get the post object
381 * @uses get_userdata() To get the user data
382 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
383 * @uses update_post_meta() To update post meta with Akismet data
384 * @uses BBP_Akismet::update_post_history() To update post Akismet history
385 */
386 function update_post_meta( $post_id = 0, $post ) {
387 global $bbp;
388
389 // Define local variable(s)
390 $as_submitted = false;
391
392 // Setup some variables
393 $post_id = (int) $post_id;
394
395 // Make sure we have a post object
396 if ( !$post = get_post( $post_id ) )
397 return;
398
399 // Get user data
400 $userdata = get_userdata( $post->post_author );
401 $anonymous_data = bbp_filter_anonymous_post_data();
402
403 // Set up Akismet last post data
404 if ( !empty( $this->last_post ) )
405 $as_submitted = $this->last_post['bbp_post_as_submitted'];
406
407 // wp_insert_post() might be called in other contexts. Make sure this is
408 // the same topic/reply as was checked by BBP_Akismet::check_post()
409 if ( is_object( $post ) && !empty( $this->last_post ) && is_array( $as_submitted ) ) {
410
411 // More checks
412 if ( intval( $as_submitted['comment_post_ID'] ) == intval( $post->post_parent )
413 && $as_submitted['comment_author'] == ( $anonymous_data ? $anonymous_data['bbp_anonymous_name'] : $userdata->display_name )
414 && $as_submitted['comment_author_email'] == ( $anonymous_data ? $anonymous_data['bbp_anonymous_email'] : $userdata->user_email )
415 ) {
416
417 // Normal result: true
418 if ( $this->last_post['bbp_akismet_result'] == 'true' ) {
419
420 // Leave a trail so other's know what we did
421 update_post_meta( $post_id, '_bbp_akismet_result', 'true' );
422 $this->update_post_history( $post_id, __( 'Akismet caught this post as spam', 'bbpress' ), 'check-spam' );
423
424 // If post_status isn't the spam status, as expected, leave a note
425 if ( $post->post_status != $bbp->spam_status_id )
426 $this->update_post_history( $post_id, sprintf( __( 'Post status was changed to %s', 'bbpress' ), $post->post_status ), 'status-changed-' . $post->post_status );
427
428 // Normal result: false
429 } elseif ( $this->last_post['bbp_akismet_result'] == 'false' ) {
430
431 // Leave a trail so other's know what we did
432 update_post_meta( $post_id, '_bbp_akismet_result', 'false' );
433 $this->update_post_history( $post_id, __( 'Akismet cleared this post', 'bbpress' ), 'check-ham' );
434
435 // If post_status is the spam status, which isn't expected, leave a note
436 if ( $post->post_status == $bbp->spam_status_id ) {
437
438 // @todo Use wp_blacklist_check()
439
440 $this->update_post_history( $post_id, sprintf( __( 'Post status was changed to %s', 'bbpress' ), $post->post_status ), 'status-changed-' . $post->post_status );
441 }
442
443 // Abnormal result: error
444 } else {
445 // Leave a trail so other's know what we did
446 update_post_meta( $post_id, '_bbp_akismet_error', time() );
447 $this->update_post_history( $post_id, sprintf( __( 'Akismet was unable to check this post (response: %s), will automatically retry again later.', 'bbpress' ), $this->last_post['bbp_akismet_result'] ), 'check-error' );
448 }
449
450 // Record the complete original data as submitted for checking
451 if ( isset( $this->last_post['bbp_post_as_submitted'] ) )
452 update_post_meta( $post_id, '_bbp_akismet_as_submitted', $this->last_post['bbp_post_as_submitted'] );
453 }
454 }
455 }
456
457 /**
458 * Update a post's Akismet history
459 *
460 * @since bbPress (r3308)
461 *
462 * @param int $post_id
463 * @param string $message
464 * @param string $event
465 *
466 * @uses wp_get_current_user() To get the current_user object
467 * @uses add_post_meta() Add Akismet post history
468 */
469 function update_post_history( $post_id = 0, $message = null, $event = null ) {
470
471 // Define local variable(s)
472 $user = '';
473
474 // Get the current user
475 $current_user = wp_get_current_user();
476
477 // Get the user's login name if possible
478 if ( is_object( $current_user ) && isset( $current_user->user_login ) )
479 $user = $current_user->user_login;
480
481 // Setup the event to be saved
482 $event = array(
483 'time' => akismet_microtime(),
484 'message' => $message,
485 'event' => $event,
486 'user' => $user,
487 );
488
489 // Save the event data
490 add_post_meta( $post_id, '_bbp_akismet_history', $event );
491 }
492
493 /**
494 * Get a post's Akismet history
495 *
496 * @since bbPress (r3308)
497 *
498 * @param int $post_id
499 *
500 * @uses wp_get_current_user() To get the current_user object
501 * @uses get_post_meta() Get a post's Akismet history
502 *
503 * @return array Array of a post's Akismet history
504 */
505 function get_post_history( $post_id = 0 ) {
506
507 // Retrieve any previous history
508 $history = get_post_meta( $post_id, '_bbp_akismet_history' );
509
510 // Sort it by the time recorded
511 usort( $history, 'akismet_cmp_time' );
512
513 return $history;
514 }
515
516 /**
517 * Handle any terms submitted with a post flagged as spam
518 *
519 * @since bbPress (r3308)
520 *
521 * @param string $terms Comma-separated list of terms
522 * @param int $topic_id
523 * @param int $reply_id
524 *
525 * @global bbPress $bbp
526 *
527 * @uses bbp_get_reply_id() To get the reply_id
528 * @uses bbp_get_topic_id() To get the topic_id
529 * @uses wp_get_object_terms() To a post's current terms
530 * @uses update_post_meta() To add spam terms to post meta
531 *
532 * @return array Array of existing topic terms
533 */
534 function filter_post_terms( $terms = '', $topic_id = 0, $reply_id = 0 ) {
535 global $bbp;
536
537 // Validate the reply_id and topic_id
538 $reply_id = bbp_get_reply_id( $reply_id );
539 $topic_id = bbp_get_topic_id( $topic_id );
540
541 // Get any pre-existing terms
542 $existing_terms = wp_get_object_terms( $topic_id, $bbp->topic_tag_id, array( 'fields' => 'names' ) );
543
544 // Save the terms for later in case the reply gets hammed
545 if ( !empty( $terms ) )
546 update_post_meta( $reply_id, '_bbp_akismet_spam_terms', $terms );
547
548 // Keep the topic tags the same for now
549 return $existing_terms;
550 }
551
552 }
553 endif;
554
555 /**
556 * Loads Akismet in bbPress global namespace
557 *
558 * @since bbPress (r3277)
559 *
560 * @global bbPress $bbp
561 * @return If bbPress is not active
562 */
563 function bbp_setup_akismet() {
564 global $bbp;
565
566 $bbp->plugins->akismet = new BBP_Akismet();
567 }
568
569 ?>
570