web/wp-content/plugins/bbpress/includes/extend/akismet.php
changeset 196 5e8dcbe22c24
equal deleted inserted replaced
195:c7c0fbc09788 196:5e8dcbe22c24
       
     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
       
    26 	 *
       
    27 	 * @since bbPress (r3277)
       
    28 	 *
       
    29 	 * @uses add_filter()
       
    30 	 */
       
    31 	public function __construct() {
       
    32 		$this->setup_actions();
       
    33 	}
       
    34 
       
    35 	/**
       
    36 	 * Setup the admin hooks
       
    37 	 *
       
    38 	 * @since bbPress (r3277)
       
    39 	 * @access private
       
    40 	 *
       
    41 	 * @uses add_filter() To add various filters
       
    42 	 * @uses add_action() To add various actions
       
    43 	 */
       
    44 	private function setup_actions() {
       
    45 
       
    46 		// Prevent debug notices
       
    47 		$checks = array();
       
    48 
       
    49 		// bbPress functions to check for spam
       
    50 		$checks['check']  = array(
       
    51 			'bbp_new_topic_pre_insert'  => 1,  // New topic check
       
    52 			'bbp_new_reply_pre_insert'  => 1,  // New reply check
       
    53 			'bbp_edit_topic_pre_insert' => 1,  // Edit topic check
       
    54 			'bbp_edit_reply_pre_insert' => 1   // Edit reply check
       
    55 		);
       
    56 
       
    57 		// bbPress functions for spam and ham submissions
       
    58 		$checks['submit'] = array(
       
    59 			'bbp_spammed_topic'   => 10, // Spammed topic
       
    60 			'bbp_unspammed_topic' => 10, // Unspammed reply
       
    61 			'bbp_spammed_reply'   => 10, // Spammed reply
       
    62 			'bbp_unspammed_reply' => 10, // Unspammed reply
       
    63 		);
       
    64 
       
    65 		// Add the checks
       
    66 		foreach ( $checks as $type => $functions )
       
    67 			foreach( $functions as $function => $priority )
       
    68 				add_filter( $function, array( $this, $type . '_post'  ), $priority );
       
    69 
       
    70 		// Update post meta
       
    71 		add_action( 'wp_insert_post', array( $this, 'update_post_meta' ), 10, 2 );
       
    72 	}
       
    73 
       
    74 	/**
       
    75 	 * Converts topic/reply data into Akismet comment checking format
       
    76 	 *
       
    77 	 * @since bbPress (r3277)
       
    78 	 *
       
    79 	 * @param string $post_data
       
    80 	 *
       
    81 	 * @uses get_userdata() To get the user data
       
    82 	 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
       
    83 	 * @uses bbp_get_topic_permalink() To get the permalink of the topic
       
    84 	 * @uses bbp_get_reply_url() To get the permalink of the reply
       
    85 	 * @uses bbp_current_author_ip() To get the IP address of the current user
       
    86 	 * @uses BBP_Akismet::maybe_spam() To check if post is spam
       
    87 	 * @uses akismet_get_user_roles() To get the role(s) of the current user
       
    88 	 * @uses do_action() To call the 'bbp_akismet_spam_caught' hook
       
    89 	 * @uses add_filter() To call the 'bbp_new_reply_pre_set_terms' hook
       
    90 	 *
       
    91 	 * @return array Array of post data
       
    92 	 */
       
    93 	public function check_post( $post_data ) {
       
    94 
       
    95 		// Define local variables
       
    96 		$user_data = array();
       
    97 		$post_permalink = '';
       
    98 
       
    99 		// Post is not published
       
   100 		if ( bbp_get_public_status_id() != $post_data['post_status'] )
       
   101 			return $post_data;
       
   102 
       
   103 		// Cast the post_author to 0 if it's empty
       
   104 		if ( empty( $post_data['post_author'] ) )
       
   105 			$post_data['post_author'] = 0;
       
   106 
       
   107 		/** Author ************************************************************/
       
   108 
       
   109 		// Get user data
       
   110 		$userdata       = get_userdata( $post_data['post_author'] );
       
   111 		$anonymous_data = bbp_filter_anonymous_post_data();
       
   112 
       
   113 		// Author is anonymous
       
   114 		if ( !empty( $anonymous_data ) ) {
       
   115 			$user_data['name']    = $anonymous_data['bbp_anonymous_name'];
       
   116 			$user_data['email']   = $anonymous_data['bbp_anonymous_name'];
       
   117 			$user_data['website'] = $anonymous_data['bbp_anonymous_name'];
       
   118 
       
   119 		// Author is logged in
       
   120 		} elseif ( !empty( $userdata ) ) {
       
   121 			$user_data['name']    = $userdata->display_name;
       
   122 			$user_data['email']   = $userdata->user_email;
       
   123 			$user_data['website'] = $userdata->user_url;
       
   124 
       
   125 		// Missing author data, so set some empty strings
       
   126 		} else {
       
   127 			$user_data['name']    = '';
       
   128 			$user_data['email']   = '';
       
   129 			$user_data['website'] = '';
       
   130 		}
       
   131 
       
   132 		/** Post **************************************************************/
       
   133 
       
   134 		// Use post parent for permalink
       
   135 		if ( !empty( $post_data['post_parent'] ) )
       
   136 			$post_permalink = get_permalink( $post_data['post_parent'] );
       
   137 
       
   138 		// Put post_data back into usable array
       
   139 		$_post = array(
       
   140 			'comment_author'       => $user_data['name'],
       
   141 			'comment_author_email' => $user_data['email'],
       
   142 			'comment_author_url'   => $user_data['website'],
       
   143 			'comment_content'      => $post_data['post_content'],
       
   144 			'comment_post_ID'      => $post_data['post_parent'],
       
   145 			'comment_type'         => $post_data['post_type'],
       
   146 			'permalink'            => $post_permalink,
       
   147 			'referrer'             => $_SERVER['HTTP_REFERER'],
       
   148 			'user_agent'           => $_SERVER['HTTP_USER_AGENT'],
       
   149 			'user_ID'              => $post_data['post_author'],
       
   150 			'user_ip'              => bbp_current_author_ip(),
       
   151 			'user_role'            => akismet_get_user_roles( $post_data['post_author'] ),
       
   152 		);
       
   153 
       
   154 		// Check the post_data
       
   155 		$_post = $this->maybe_spam( $_post );
       
   156 
       
   157 		// Get the result
       
   158 		$post_data['bbp_akismet_result'] = $_post['bbp_akismet_result'];
       
   159 		unset( $_post['bbp_akismet_result'] );
       
   160 
       
   161 		// Store the data as submitted
       
   162 		$post_data['bbp_post_as_submitted'] = $_post;
       
   163 
       
   164 		// Allow post_data to be manipulated
       
   165 		do_action_ref_array( 'bbp_akismet_check_post', $post_data );
       
   166 
       
   167 		// Spam
       
   168 		if ( 'true' == $post_data['bbp_akismet_result'] ) {
       
   169 
       
   170 			// Let plugins do their thing
       
   171 			do_action( 'bbp_akismet_spam_caught' );
       
   172 
       
   173 			// This is spam
       
   174 			$post_data['post_status'] = bbp_get_spam_status_id();
       
   175 
       
   176 			// We don't want your spam tags here
       
   177 			add_filter( 'bbp_new_reply_pre_set_terms', array( $this, 'filter_post_terms' ), 1, 3 );
       
   178 
       
   179 			// @todo Spam counter?
       
   180 		}
       
   181 
       
   182 		// @todo Topic/reply moderation? No true/false response - 'pending' or 'draft'
       
   183 		// @todo Auto-delete old spam?
       
   184 
       
   185 		// Log the last post
       
   186 		$this->last_post = $post_data;
       
   187 
       
   188 		// Pass the data back to the filter
       
   189 		return $post_data;
       
   190 	}
       
   191 
       
   192 	/**
       
   193 	 * Submit a post for spamming or hamming
       
   194 	 *
       
   195 	 * @since bbPress (r3277)
       
   196 	 *
       
   197 	 * @param int $post_id
       
   198 	 *
       
   199 	 * @global WP_Query $wpdb
       
   200 	 * @global string $akismet_api_host
       
   201 	 * @global string $akismet_api_port
       
   202 	 * @global object $current_user
       
   203 	 * @global object $current_site
       
   204 	 *
       
   205 	 * @uses current_filter() To get the reply_id
       
   206 	 * @uses get_post() To get the post object
       
   207 	 * @uses get_the_author_meta() To get the author meta
       
   208 	 * @uses get_post_meta() To get the post meta
       
   209 	 * @uses bbp_get_user_profile_url() To get a user's profile url
       
   210 	 * @uses get_permalink() To get the permalink of the post_parent
       
   211 	 * @uses akismet_get_user_roles() To get the role(s) of the post_author
       
   212 	 * @uses bbp_current_author_ip() To get the IP address of the current user
       
   213 	 * @uses BBP_Akismet::maybe_spam() To submit the post as ham or spam
       
   214 	 * @uses update_post_meta() To update the post meta with some Akismet data
       
   215 	 * @uses do_action() To call the 'bbp_akismet_submit_spam_post' and 'bbp_akismet_submit_ham_post' hooks
       
   216 	 *
       
   217 	 * @return array Array of existing topic terms
       
   218 	 */
       
   219 	public function submit_post( $post_id = 0 ) {
       
   220 		global $current_user, $current_site;
       
   221 
       
   222 		// Innocent until proven guilty
       
   223 		$request_type   = 'ham';
       
   224 		$current_filter = current_filter();
       
   225 
       
   226 		// Check this filter and adjust the $request_type accordingly
       
   227 		switch ( $current_filter ) {
       
   228 
       
   229 			// Mysterious, and straight from the can
       
   230 			case 'bbp_spammed_topic' :
       
   231 			case 'bbp_spammed_reply' :
       
   232 				$request_type = 'spam';
       
   233 				break;
       
   234 
       
   235 			// Honey-glazed, a straight off the bone
       
   236 			case 'bbp_unspammed_topic' :
       
   237 			case 'bbp_unspammed_reply' :
       
   238 				$request_type = 'ham';
       
   239 				break;
       
   240 
       
   241 			// Possibly poison...
       
   242 			default :
       
   243 				return;
       
   244 		}
       
   245 
       
   246 		// Setup some variables
       
   247 		$post_id = (int) $post_id;
       
   248 
       
   249 		// Make sure we have a post
       
   250 		$_post = get_post( $post_id );
       
   251 
       
   252 		// Bail if get_post() fails
       
   253 		if ( empty( $_post ) )
       
   254 			return;
       
   255 
       
   256 		// Bail if we're spamming, but the post_status isn't spam
       
   257 		if ( ( 'spam' == $request_type ) && ( bbp_get_spam_status_id() != $_post->post_status ) )
       
   258 			return;
       
   259 
       
   260 		// Set some default post_data
       
   261 		$post_data = array(
       
   262 			'comment_approved'     => $_post->post_status,
       
   263 			'comment_author'       => $_post->post_author ? get_the_author_meta( 'display_name', $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_name',    true ),
       
   264 			'comment_author_email' => $_post->post_author ? get_the_author_meta( 'email',        $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_email',   true ),
       
   265 			'comment_author_url'   => $_post->post_author ? bbp_get_user_profile_url(            $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_website', true ),
       
   266 			'comment_content'      => $_post->post_content,
       
   267 			'comment_date'         => $_post->post_date,
       
   268 			'comment_ID'           => $post_id,
       
   269 			'comment_post_ID'      => $_post->post_parent,
       
   270 			'comment_type'         => $_post->post_type,
       
   271 			'permalink'            => get_permalink( $post_id ),
       
   272 			'user_ID'              => $_post->post_author,
       
   273 			'user_ip'              => get_post_meta( $post_id, '_bbp_author_ip', true ),
       
   274 			'user_role'            => akismet_get_user_roles( $_post->post_author ),
       
   275 		);
       
   276 
       
   277 		// Use the original version stored in post_meta if available
       
   278 		$as_submitted = get_post_meta( $post_id, '_bbp_akismet_as_submitted', true );
       
   279 		if ( $as_submitted && is_array( $as_submitted ) && isset( $as_submitted['comment_content'] ) )
       
   280 			$post_data = array_merge( $post_data, $as_submitted );
       
   281 
       
   282 		// Add the reporter IP address
       
   283 		$post_data['reporter_ip']  = bbp_current_author_ip();
       
   284 
       
   285 		// Add some reporter info
       
   286 		if ( is_object( $current_user ) )
       
   287 		    $post_data['reporter'] = $current_user->user_login;
       
   288 
       
   289 		// Add the current site domain
       
   290 		if ( is_object( $current_site ) )
       
   291 			$post_data['site_domain'] = $current_site->domain;
       
   292 
       
   293 		// Place your slide beneath the microscope
       
   294 		$post_data = $this->maybe_spam( $post_data, 'submit', $request_type );
       
   295 
       
   296 		// Manual user action
       
   297 		if ( isset( $post_data['reporter'] ) ) {
       
   298 
       
   299 			// What kind of action
       
   300 			switch ( $request_type ) {
       
   301 
       
   302 				// Spammy
       
   303 				case 'spam' :
       
   304 					$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' );
       
   305 					update_post_meta( $post_id, '_bbp_akismet_user_result', 'true'                 );
       
   306 					update_post_meta( $post_id, '_bbp_akismet_user',        $post_data['reporter'] );
       
   307 					break;
       
   308 
       
   309 				// Hammy
       
   310 				case 'ham'  :
       
   311 					$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'  );
       
   312 					update_post_meta( $post_id, '_bbp_akismet_user_result', 'false'                 );
       
   313 					update_post_meta( $post_id, '_bbp_akismet_user',         $post_data['reporter'] );
       
   314 
       
   315 					// @todo Topic term revision history
       
   316 					break;
       
   317 
       
   318 				// Possible other actions
       
   319 				default :
       
   320 					break;
       
   321 			}
       
   322 		}
       
   323 
       
   324 		do_action( 'bbp_akismet_submit_' . $request_type . '_post', $post_id, $post_data['bbp_akismet_result'] );
       
   325 	}
       
   326 
       
   327 	/**
       
   328 	 * Ping Akismet service and check for spam/ham response
       
   329 	 *
       
   330 	 * @since bbPress (r3277)
       
   331 	 *
       
   332 	 * @param array $post_data
       
   333 	 * @param string $check Accepts check|submit
       
   334 	 * @param string $spam Accepts spam|ham
       
   335 	 *
       
   336 	 * @global string $akismet_api_host
       
   337 	 * @global string $akismet_api_port
       
   338 	 *
       
   339 	 * @uses akismet_test_mode() To determine if Akismet is in test mode
       
   340 	 * @uses akismet_http_post() To send data to the mothership for processing
       
   341 	 *
       
   342 	 * @return array Array of post data
       
   343 	 */
       
   344 	private function maybe_spam( $post_data, $check = 'check', $spam = 'spam' ) {
       
   345 		global $akismet_api_host, $akismet_api_port;
       
   346 
       
   347 		// Define variables
       
   348 		$query_string = $path = $response = '';
       
   349 
       
   350 		// Populate post data
       
   351 		$post_data['blog']         = get_option( 'home' );
       
   352 		$post_data['blog_charset'] = get_option( 'blog_charset' );
       
   353 		$post_data['blog_lang']    = get_locale();
       
   354 		$post_data['referrer']     = $_SERVER['HTTP_REFERER'];
       
   355 		$post_data['user_agent']   = $_SERVER['HTTP_USER_AGENT'];
       
   356 
       
   357 		// Akismet Test Mode
       
   358 		if ( akismet_test_mode() )
       
   359 			$post_data['is_test'] = 'true';
       
   360 
       
   361 		// Loop through _POST args and rekey strings
       
   362 		foreach ( $_POST as $key => $value )
       
   363 			if ( is_string( $value ) )
       
   364 				$post_data['POST_' . $key] = $value;
       
   365 
       
   366 		// Keys to ignore
       
   367 		$ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
       
   368 
       
   369 		// Loop through _SERVER args and remove whitelisted keys
       
   370 		foreach ( $_SERVER as $key => $value ) {
       
   371 
       
   372 			// Key should not be ignored
       
   373 			if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
       
   374 				$post_data[$key] = $value;
       
   375 
       
   376 			// Key should be ignored
       
   377 			} else {
       
   378 				$post_data[$key] = '';
       
   379 			}
       
   380 		}
       
   381 
       
   382 		// Ready...
       
   383 		foreach ( $post_data as $key => $data )
       
   384 			$query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
       
   385 
       
   386 		// Aim...
       
   387 		if ( 'check' == $check ) {
       
   388 			$path = '/1.1/comment-check';
       
   389 		} elseif ( 'submit' == $check ) {
       
   390 			$path = '/1.1/submit-' . $spam;
       
   391 		}
       
   392 
       
   393 		// Fire!
       
   394 		$response = $this->http_post( $query_string, $akismet_api_host, $path, $akismet_api_port );
       
   395 
       
   396 		// Check the high-speed cam
       
   397 		if ( !empty( $response[1] ) ) {
       
   398 			$post_data['bbp_akismet_result'] = $response[1];
       
   399 		} else {
       
   400 			$post_data['bbp_akismet_result'] = __( 'No response', 'bbpress' );
       
   401 		}
       
   402 
       
   403 		// This is ham
       
   404 		return $post_data;
       
   405 	}
       
   406 
       
   407 	/**
       
   408 	 * Update post meta after a spam check
       
   409 	 *
       
   410 	 * @since bbPress (r3308)
       
   411 	 *
       
   412 	 * @param int $post_id
       
   413 	 * @param object $_post
       
   414 	 *
       
   415 	 * @global object $this->last_post
       
   416 	 *
       
   417 	 * @uses get_post() To get the post object
       
   418 	 * @uses get_userdata() To get the user data
       
   419 	 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
       
   420 	 * @uses update_post_meta() To update post meta with Akismet data
       
   421 	 * @uses BBP_Akismet::update_post_history() To update post Akismet history
       
   422 	 */
       
   423 	public function update_post_meta( $post_id = 0, $_post = false ) {
       
   424 
       
   425 		// Define local variable(s)
       
   426 		$as_submitted = false;
       
   427 
       
   428 		// Setup some variables
       
   429 		$post_id = (int) $post_id;
       
   430 
       
   431 		// Ensure we have a post object
       
   432 		if ( empty( $_post ) )
       
   433 			$_post = get_post( $post_id );
       
   434 
       
   435 		// Set up Akismet last post data
       
   436 		if ( !empty( $this->last_post ) )
       
   437 			$as_submitted = $this->last_post['bbp_post_as_submitted'];
       
   438 
       
   439 		// wp_insert_post() might be called in other contexts. Ensure this is
       
   440 		// the same topic/reply as was checked by BBP_Akismet::check_post()
       
   441 		if ( is_object( $_post ) && !empty( $this->last_post ) && is_array( $as_submitted ) ) {
       
   442 
       
   443 			// Get user data
       
   444 			$userdata       = get_userdata( $_post->post_author );
       
   445 			$anonymous_data = bbp_filter_anonymous_post_data();
       
   446 
       
   447 			// More checks
       
   448 			if (	intval( $as_submitted['comment_post_ID'] )    == intval( $_post->post_parent )
       
   449 					&&      $as_submitted['comment_author']       == ( $anonymous_data ? $anonymous_data['bbp_anonymous_name']  : $userdata->display_name )
       
   450 					&&      $as_submitted['comment_author_email'] == ( $anonymous_data ? $anonymous_data['bbp_anonymous_email'] : $userdata->user_email   )
       
   451 				) {
       
   452 
       
   453 				// Normal result: true
       
   454 				if ( $this->last_post['bbp_akismet_result'] == 'true' ) {
       
   455 
       
   456 					// Leave a trail so other's know what we did
       
   457 					update_post_meta( $post_id, '_bbp_akismet_result', 'true' );
       
   458 					$this->update_post_history( $post_id, __( 'Akismet caught this post as spam', 'bbpress' ), 'check-spam' );
       
   459 
       
   460 					// If post_status isn't the spam status, as expected, leave a note
       
   461 					if ( $_post->post_status != bbp_get_spam_status_id() ) {
       
   462 						$this->update_post_history( $post_id, sprintf( __( 'Post status was changed to %s', 'bbpress' ), $_post->post_status ), 'status-changed-' . $_post->post_status );
       
   463 					}
       
   464 
       
   465 				// Normal result: false
       
   466 				} elseif ( $this->last_post['bbp_akismet_result'] == 'false' ) {
       
   467 
       
   468 					// Leave a trail so other's know what we did
       
   469 					update_post_meta( $post_id, '_bbp_akismet_result', 'false' );
       
   470 					$this->update_post_history( $post_id, __( 'Akismet cleared this post', 'bbpress' ), 'check-ham' );
       
   471 
       
   472 					// If post_status is the spam status, which isn't expected, leave a note
       
   473 					if ( $_post->post_status == bbp_get_spam_status_id() ) {
       
   474 
       
   475 						// @todo Use wp_blacklist_check()
       
   476 
       
   477 						$this->update_post_history( $post_id, sprintf( __( 'Post status was changed to %s', 'bbpress' ), $_post->post_status ), 'status-changed-' . $_post->post_status );
       
   478 					}
       
   479 
       
   480 				// Abnormal result: error
       
   481 				} else {
       
   482 					// Leave a trail so other's know what we did
       
   483 					update_post_meta( $post_id, '_bbp_akismet_error', time() );
       
   484 					$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' );
       
   485 				}
       
   486 
       
   487 				// Record the complete original data as submitted for checking
       
   488 				if ( isset( $this->last_post['bbp_post_as_submitted'] ) ) {
       
   489 					update_post_meta( $post_id, '_bbp_akismet_as_submitted', $this->last_post['bbp_post_as_submitted'] );
       
   490 				}
       
   491 			}
       
   492 		}
       
   493 	}
       
   494 
       
   495 	/**
       
   496 	 * Update a post's Akismet history
       
   497 	 *
       
   498 	 * @since bbPress (r3308)
       
   499 	 *
       
   500 	 * @param int $post_id
       
   501 	 * @param string $message
       
   502 	 * @param string $event
       
   503 	 *
       
   504 	 * @uses wp_get_current_user() To get the current_user object
       
   505 	 * @uses add_post_meta() Add Akismet post history
       
   506 	 */
       
   507 	private function update_post_history( $post_id = 0, $message = null, $event = null ) {
       
   508 
       
   509 		// Define local variable(s)
       
   510 		$user = '';
       
   511 
       
   512 		// Get the current user
       
   513 		$current_user = wp_get_current_user();
       
   514 
       
   515 		// Get the user's login name if possible
       
   516 		if ( is_object( $current_user ) && isset( $current_user->user_login ) )
       
   517 			$user = $current_user->user_login;
       
   518 
       
   519 		// Setup the event to be saved
       
   520 		$event = array(
       
   521 			'time'    => akismet_microtime(),
       
   522 			'message' => $message,
       
   523 			'event'   => $event,
       
   524 			'user'    => $user,
       
   525 		);
       
   526 
       
   527 		// Save the event data
       
   528 		add_post_meta( $post_id, '_bbp_akismet_history', $event );
       
   529 	}
       
   530 
       
   531 	/**
       
   532 	 * Get a post's Akismet history
       
   533 	 *
       
   534 	 * @since bbPress (r3308)
       
   535 	 *
       
   536 	 * @param int $post_id
       
   537 	 *
       
   538 	 * @uses wp_get_current_user() To get the current_user object
       
   539 	 * @uses get_post_meta() Get a post's Akismet history
       
   540 	 *
       
   541 	 * @return array Array of a post's Akismet history
       
   542 	 */
       
   543 	public function get_post_history( $post_id = 0 ) {
       
   544 
       
   545 		// Retrieve any previous history
       
   546 		$history = get_post_meta( $post_id, '_bbp_akismet_history' );
       
   547 
       
   548 		// Sort it by the time recorded
       
   549 		usort( $history, 'akismet_cmp_time' );
       
   550 
       
   551 		return $history;
       
   552 	}
       
   553 
       
   554 	/**
       
   555 	 * Handle any terms submitted with a post flagged as spam
       
   556 	 *
       
   557 	 * @since bbPress (r3308)
       
   558 	 *
       
   559 	 * @param string $terms Comma-separated list of terms
       
   560 	 * @param int $topic_id
       
   561 	 * @param int $reply_id
       
   562 	 *
       
   563 	 * @uses bbp_get_reply_id() To get the reply_id
       
   564 	 * @uses bbp_get_topic_id() To get the topic_id
       
   565 	 * @uses wp_get_object_terms() To a post's current terms
       
   566 	 * @uses update_post_meta() To add spam terms to post meta
       
   567 	 *
       
   568 	 * @return array Array of existing topic terms
       
   569 	 */
       
   570 	public function filter_post_terms( $terms = '', $topic_id = 0, $reply_id = 0 ) {
       
   571 
       
   572 		// Validate the reply_id and topic_id
       
   573 		$reply_id = bbp_get_reply_id( $reply_id );
       
   574 		$topic_id = bbp_get_topic_id( $topic_id );
       
   575 
       
   576 		// Get any pre-existing terms
       
   577 		$existing_terms = wp_get_object_terms( $topic_id, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
       
   578 
       
   579 		// Save the terms for later in case the reply gets hammed
       
   580 		if ( !empty( $terms ) )
       
   581 			update_post_meta( $reply_id, '_bbp_akismet_spam_terms', $terms );
       
   582 
       
   583 		// Keep the topic tags the same for now
       
   584 		return $existing_terms;
       
   585 	}
       
   586 
       
   587 	/**
       
   588 	 * Submit data to Akismet service with unique bbPress User Agent
       
   589 	 *
       
   590 	 * This code is directly taken from the akismet_http_post() function and
       
   591 	 * documented to bbPress 2.0 standard.
       
   592 	 *
       
   593 	 * @since bbPress (r3466)
       
   594 	 *
       
   595 	 * @param string $request The request we are sending
       
   596 	 * @param string $host The host to send our request to
       
   597 	 * @param string $path The path from the host
       
   598 	 * @param string $port The port to use
       
   599 	 * @param string $ip Optional Override $host with an IP address
       
   600 	 * @uses bbp_get_version() To get the current bbPress version
       
   601 	 * @return mixed WP_Error on error, array on success, empty on failure
       
   602 	 */
       
   603 	private function http_post( $request, $host, $path, $port = 80, $ip = '' ) {
       
   604 
       
   605 		// Preload required variables
       
   606 		$bbp_version    = bbp_get_version();
       
   607 		$content_length = strlen( $request );
       
   608 		$http_host      = $host;
       
   609 		$blog_charset   = get_option( 'blog_charset' );
       
   610 		$response       = '';
       
   611 		$errno          = null;
       
   612 		$errstr         = null;
       
   613 
       
   614 		// Untque User Agent
       
   615 		$akismet_ua     = "bbPress/{$bbp_version} | ";
       
   616 		$akismet_ua    .= 'Akismet/' . constant( 'AKISMET_VERSION' );
       
   617 
       
   618 		// Use specific IP (if provided)
       
   619 		if ( !empty( $ip ) && long2ip( ip2long( $ip ) ) )
       
   620 			$http_host = $ip;
       
   621 
       
   622 		// WP HTTP class is available
       
   623 		if ( function_exists( 'wp_remote_post' ) ) {
       
   624 
       
   625 			// Setup the arguments
       
   626 			$http_args = array(
       
   627 				'body'             => $request,
       
   628 				'headers'          => array(
       
   629 					'Content-Type' => 'application/x-www-form-urlencoded; charset=' . $blog_charset,
       
   630 					'Host'         => $host,
       
   631 					'User-Agent'   => $akismet_ua
       
   632 				),
       
   633 				'httpversion'      => '1.0',
       
   634 				'timeout'          => 15
       
   635 			);
       
   636 
       
   637 			// Where we are sending our request
       
   638 			$akismet_url = 'http://' . $http_host . $path;
       
   639 
       
   640 			// Send the request
       
   641 			$response    = wp_remote_post( $akismet_url, $http_args );
       
   642 
       
   643 			// Bail if the response is an error
       
   644 			if ( is_wp_error( $response ) )
       
   645 				return '';
       
   646 
       
   647 			// No errors so return response
       
   648 			return array( $response['headers'], $response['body'] );
       
   649 
       
   650 		// WP HTTP class is not available (Why not?)
       
   651 		} else {
       
   652 
       
   653 			// Header info to use with our socket
       
   654 			$http_request  = "POST {$path} HTTP/1.0\r\n";
       
   655 			$http_request .= "Host: {$host}\r\n";
       
   656 			$http_request .= "Content-Type: application/x-www-form-urlencoded; charset={$blog_charset}\r\n";
       
   657 			$http_request .= "Content-Length: {$content_length}\r\n";
       
   658 			$http_request .= "User-Agent: {$akismet_ua}\r\n";
       
   659 			$http_request .= "\r\n";
       
   660 			$http_request .= $request;
       
   661 
       
   662 			// Open a socket connection
       
   663 			if ( false != ( $fs = @fsockopen( $http_host, $port, $errno, $errstr, 10 ) ) ) {
       
   664 
       
   665 				// Write our request to the pointer
       
   666 				fwrite( $fs, $http_request );
       
   667 
       
   668 				// Loop through pointer and compile a response
       
   669 				while ( !feof( $fs ) ) {
       
   670 					// One TCP-IP packet at a time
       
   671 					$response .= fgets( $fs, 1160 );
       
   672 				}
       
   673 
       
   674 				// Close our socket
       
   675 				fclose( $fs );
       
   676 
       
   677 				// Explode the response into usable data
       
   678 				$response = explode( "\r\n\r\n", $response, 2 );
       
   679 			}
       
   680 
       
   681 			// Return the response ('' if error/empty)
       
   682 			return $response;
       
   683 		}
       
   684 	}
       
   685 }
       
   686 endif;