web/wp-includes/comment.php
changeset 136 bde1974c263b
child 194 32102edaa81b
equal deleted inserted replaced
135:53cff4b4a802 136:bde1974c263b
       
     1 <?php
       
     2 /**
       
     3  * Manages WordPress comments
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Comment
       
     7  */
       
     8 
       
     9 /**
       
    10  * Checks whether a comment passes internal checks to be allowed to add.
       
    11  *
       
    12  * If comment moderation is set in the administration, then all comments,
       
    13  * regardless of their type and whitelist will be set to false. If the number of
       
    14  * links exceeds the amount in the administration, then the check fails. If any
       
    15  * of the parameter contents match the blacklist of words, then the check fails.
       
    16  *
       
    17  * If the number of links exceeds the amount in the administration, then the
       
    18  * check fails. If any of the parameter contents match the blacklist of words,
       
    19  * then the check fails.
       
    20  *
       
    21  * If the comment is a trackback and part of the blogroll, then the trackback is
       
    22  * automatically whitelisted. If the comment author was approved before, then
       
    23  * the comment is automatically whitelisted.
       
    24  *
       
    25  * If none of the checks fail, then the failback is to set the check to pass
       
    26  * (return true).
       
    27  *
       
    28  * @since 1.2.0
       
    29  * @uses $wpdb
       
    30  *
       
    31  * @param string $author Comment Author's name
       
    32  * @param string $email Comment Author's email
       
    33  * @param string $url Comment Author's URL
       
    34  * @param string $comment Comment contents
       
    35  * @param string $user_ip Comment Author's IP address
       
    36  * @param string $user_agent Comment Author's User Agent
       
    37  * @param string $comment_type Comment type, either user submitted comment,
       
    38  *		trackback, or pingback
       
    39  * @return bool Whether the checks passed (true) and the comments should be
       
    40  *		displayed or set to moderated
       
    41  */
       
    42 function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
       
    43 	global $wpdb;
       
    44 
       
    45 	if ( 1 == get_option('comment_moderation') )
       
    46 		return false; // If moderation is set to manual
       
    47 
       
    48 	if ( get_option('comment_max_links') && preg_match_all("/<[Aa][^>]*[Hh][Rr][Ee][Ff]=['\"]([^\"'>]+)[^>]*>/", apply_filters('comment_text',$comment), $out) >= get_option('comment_max_links') )
       
    49 		return false; // Check # of external links
       
    50 
       
    51 	$mod_keys = trim(get_option('moderation_keys'));
       
    52 	if ( !empty($mod_keys) ) {
       
    53 		$words = explode("\n", $mod_keys );
       
    54 
       
    55 		foreach ( (array) $words as $word) {
       
    56 			$word = trim($word);
       
    57 
       
    58 			// Skip empty lines
       
    59 			if ( empty($word) )
       
    60 				continue;
       
    61 
       
    62 			// Do some escaping magic so that '#' chars in the
       
    63 			// spam words don't break things:
       
    64 			$word = preg_quote($word, '#');
       
    65 
       
    66 			$pattern = "#$word#i";
       
    67 			if ( preg_match($pattern, $author) ) return false;
       
    68 			if ( preg_match($pattern, $email) ) return false;
       
    69 			if ( preg_match($pattern, $url) ) return false;
       
    70 			if ( preg_match($pattern, $comment) ) return false;
       
    71 			if ( preg_match($pattern, $user_ip) ) return false;
       
    72 			if ( preg_match($pattern, $user_agent) ) return false;
       
    73 		}
       
    74 	}
       
    75 
       
    76 	// Comment whitelisting:
       
    77 	if ( 1 == get_option('comment_whitelist')) {
       
    78 		if ( 'trackback' == $comment_type || 'pingback' == $comment_type ) { // check if domain is in blogroll
       
    79 			$uri = parse_url($url);
       
    80 			$domain = $uri['host'];
       
    81 			$uri = parse_url( get_option('home') );
       
    82 			$home_domain = $uri['host'];
       
    83 			if ( $wpdb->get_var($wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_url LIKE (%s) LIMIT 1", '%'.$domain.'%')) || $domain == $home_domain )
       
    84 				return true;
       
    85 			else
       
    86 				return false;
       
    87 		} elseif ( $author != '' && $email != '' ) {
       
    88 			// expected_slashed ($author, $email)
       
    89 			$ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
       
    90 			if ( ( 1 == $ok_to_comment ) &&
       
    91 				( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
       
    92 					return true;
       
    93 			else
       
    94 				return false;
       
    95 		} else {
       
    96 			return false;
       
    97 		}
       
    98 	}
       
    99 	return true;
       
   100 }
       
   101 
       
   102 /**
       
   103  * Retrieve the approved comments for post $post_id.
       
   104  *
       
   105  * @since 2.0.0
       
   106  * @uses $wpdb
       
   107  *
       
   108  * @param int $post_id The ID of the post
       
   109  * @return array $comments The approved comments
       
   110  */
       
   111 function get_approved_comments($post_id) {
       
   112 	global $wpdb;
       
   113 	return $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' ORDER BY comment_date", $post_id));
       
   114 }
       
   115 
       
   116 /**
       
   117  * Retrieves comment data given a comment ID or comment object.
       
   118  *
       
   119  * If an object is passed then the comment data will be cached and then returned
       
   120  * after being passed through a filter. If the comment is empty, then the global
       
   121  * comment variable will be used, if it is set.
       
   122  *
       
   123  * If the comment is empty, then the global comment variable will be used, if it
       
   124  * is set.
       
   125  *
       
   126  * @since 2.0.0
       
   127  * @uses $wpdb
       
   128  *
       
   129  * @param object|string|int $comment Comment to retrieve.
       
   130  * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
       
   131  * @return object|array|null Depends on $output value.
       
   132  */
       
   133 function &get_comment(&$comment, $output = OBJECT) {
       
   134 	global $wpdb;
       
   135 	$null = null;
       
   136 
       
   137 	if ( empty($comment) ) {
       
   138 		if ( isset($GLOBALS['comment']) )
       
   139 			$_comment = & $GLOBALS['comment'];
       
   140 		else
       
   141 			$_comment = null;
       
   142 	} elseif ( is_object($comment) ) {
       
   143 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
   144 		$_comment = $comment;
       
   145 	} else {
       
   146 		if ( isset($GLOBALS['comment']) && ($GLOBALS['comment']->comment_ID == $comment) ) {
       
   147 			$_comment = & $GLOBALS['comment'];
       
   148 		} elseif ( ! $_comment = wp_cache_get($comment, 'comment') ) {
       
   149 			$_comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment));
       
   150 			if ( ! $_comment )
       
   151 				return $null;
       
   152 			wp_cache_add($_comment->comment_ID, $_comment, 'comment');
       
   153 		}
       
   154 	}
       
   155 
       
   156 	$_comment = apply_filters('get_comment', $_comment);
       
   157 
       
   158 	if ( $output == OBJECT ) {
       
   159 		return $_comment;
       
   160 	} elseif ( $output == ARRAY_A ) {
       
   161 		$__comment = get_object_vars($_comment);
       
   162 		return $__comment;
       
   163 	} elseif ( $output == ARRAY_N ) {
       
   164 		$__comment = array_values(get_object_vars($_comment));
       
   165 		return $__comment;
       
   166 	} else {
       
   167 		return $_comment;
       
   168 	}
       
   169 }
       
   170 
       
   171 /**
       
   172  * Retrieve a list of comments.
       
   173  *
       
   174  * The comment list can be for the blog as a whole or for an individual post.
       
   175  *
       
   176  * The list of comment arguments are 'status', 'orderby', 'comment_date_gmt',
       
   177  * 'order', 'number', 'offset', and 'post_id'.
       
   178  *
       
   179  * @since 2.7.0
       
   180  * @uses $wpdb
       
   181  *
       
   182  * @param mixed $args Optional. Array or string of options to override defaults.
       
   183  * @return array List of comments.
       
   184  */
       
   185 function get_comments( $args = '' ) {
       
   186 	global $wpdb;
       
   187 
       
   188 	$defaults = array('status' => '', 'orderby' => 'comment_date_gmt', 'order' => 'DESC', 'number' => '', 'offset' => '', 'post_id' => 0);
       
   189 
       
   190 	$args = wp_parse_args( $args, $defaults );
       
   191 	extract( $args, EXTR_SKIP );
       
   192 
       
   193 	// $args can be whatever, only use the args defined in defaults to compute the key
       
   194 	$key = md5( serialize( compact(array_keys($defaults)) )  );
       
   195 	$last_changed = wp_cache_get('last_changed', 'comment');
       
   196 	if ( !$last_changed ) {
       
   197 		$last_changed = time();
       
   198 		wp_cache_set('last_changed', $last_changed, 'comment');
       
   199 	}
       
   200 	$cache_key = "get_comments:$key:$last_changed";
       
   201 
       
   202 	if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
       
   203 		return $cache;
       
   204 	}
       
   205 
       
   206 	$post_id = absint($post_id);
       
   207 
       
   208 	if ( 'hold' == $status )
       
   209 		$approved = "comment_approved = '0'";
       
   210 	elseif ( 'approve' == $status )
       
   211 		$approved = "comment_approved = '1'";
       
   212 	elseif ( 'spam' == $status )
       
   213 		$approved = "comment_approved = 'spam'";
       
   214 	elseif ( 'trash' == $status )
       
   215 		$approved = "comment_approved = 'trash'";
       
   216 	else
       
   217 		$approved = "( comment_approved = '0' OR comment_approved = '1' )";
       
   218 
       
   219 	$order = ( 'ASC' == $order ) ? 'ASC' : 'DESC';
       
   220 
       
   221 	$orderby = 'comment_date_gmt';  // Hard code for now
       
   222 
       
   223 	$number = absint($number);
       
   224 	$offset = absint($offset);
       
   225 
       
   226 	if ( !empty($number) ) {
       
   227 		if ( $offset )
       
   228 			$number = 'LIMIT ' . $offset . ',' . $number;
       
   229 		else
       
   230 			$number = 'LIMIT ' . $number;
       
   231 
       
   232 	} else {
       
   233 		$number = '';
       
   234 	}
       
   235 
       
   236 	if ( ! empty($post_id) )
       
   237 		$post_where = $wpdb->prepare( 'comment_post_ID = %d AND', $post_id );
       
   238 	else
       
   239 		$post_where = '';
       
   240 
       
   241 	$comments = $wpdb->get_results( "SELECT * FROM $wpdb->comments WHERE $post_where $approved ORDER BY $orderby $order $number" );
       
   242 	wp_cache_add( $cache_key, $comments, 'comment' );
       
   243 
       
   244 	return $comments;
       
   245 }
       
   246 
       
   247 /**
       
   248  * Retrieve all of the WordPress supported comment statuses.
       
   249  *
       
   250  * Comments have a limited set of valid status values, this provides the comment
       
   251  * status values and descriptions.
       
   252  *
       
   253  * @package WordPress
       
   254  * @subpackage Post
       
   255  * @since 2.7.0
       
   256  *
       
   257  * @return array List of comment statuses.
       
   258  */
       
   259 function get_comment_statuses( ) {
       
   260 	$status = array(
       
   261 		'hold'		=> __('Unapproved'),
       
   262 		/* translators: comment status  */
       
   263 		'approve'	=> _x('Approved', 'adjective'),
       
   264 		/* translators: comment status */
       
   265 		'spam'		=> _x('Spam', 'adjective'),
       
   266 	);
       
   267 
       
   268 	return $status;
       
   269 }
       
   270 
       
   271 
       
   272 /**
       
   273  * The date the last comment was modified.
       
   274  *
       
   275  * @since 1.5.0
       
   276  * @uses $wpdb
       
   277  * @global array $cache_lastcommentmodified
       
   278  *
       
   279  * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
       
   280  *		or 'server' locations.
       
   281  * @return string Last comment modified date.
       
   282  */
       
   283 function get_lastcommentmodified($timezone = 'server') {
       
   284 	global $cache_lastcommentmodified, $wpdb;
       
   285 
       
   286 	if ( isset($cache_lastcommentmodified[$timezone]) )
       
   287 		return $cache_lastcommentmodified[$timezone];
       
   288 
       
   289 	$add_seconds_server = date('Z');
       
   290 
       
   291 	switch ( strtolower($timezone)) {
       
   292 		case 'gmt':
       
   293 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
       
   294 			break;
       
   295 		case 'blog':
       
   296 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
       
   297 			break;
       
   298 		case 'server':
       
   299 			$lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
       
   300 			break;
       
   301 	}
       
   302 
       
   303 	$cache_lastcommentmodified[$timezone] = $lastcommentmodified;
       
   304 
       
   305 	return $lastcommentmodified;
       
   306 }
       
   307 
       
   308 /**
       
   309  * The amount of comments in a post or total comments.
       
   310  *
       
   311  * A lot like {@link wp_count_comments()}, in that they both return comment
       
   312  * stats (albeit with different types). The {@link wp_count_comments()} actual
       
   313  * caches, but this function does not.
       
   314  *
       
   315  * @since 2.0.0
       
   316  * @uses $wpdb
       
   317  *
       
   318  * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
       
   319  * @return array The amount of spam, approved, awaiting moderation, and total comments.
       
   320  */
       
   321 function get_comment_count( $post_id = 0 ) {
       
   322 	global $wpdb;
       
   323 
       
   324 	$post_id = (int) $post_id;
       
   325 
       
   326 	$where = '';
       
   327 	if ( $post_id > 0 ) {
       
   328 		$where = $wpdb->prepare("WHERE comment_post_ID = %d", $post_id);
       
   329 	}
       
   330 
       
   331 	$totals = (array) $wpdb->get_results("
       
   332 		SELECT comment_approved, COUNT( * ) AS total
       
   333 		FROM {$wpdb->comments}
       
   334 		{$where}
       
   335 		GROUP BY comment_approved
       
   336 	", ARRAY_A);
       
   337 
       
   338 	$comment_count = array(
       
   339 		"approved"              => 0,
       
   340 		"awaiting_moderation"   => 0,
       
   341 		"spam"                  => 0,
       
   342 		"total_comments"        => 0
       
   343 	);
       
   344 
       
   345 	foreach ( $totals as $row ) {
       
   346 		switch ( $row['comment_approved'] ) {
       
   347 			case 'spam':
       
   348 				$comment_count['spam'] = $row['total'];
       
   349 				$comment_count["total_comments"] += $row['total'];
       
   350 				break;
       
   351 			case 1:
       
   352 				$comment_count['approved'] = $row['total'];
       
   353 				$comment_count['total_comments'] += $row['total'];
       
   354 				break;
       
   355 			case 0:
       
   356 				$comment_count['awaiting_moderation'] = $row['total'];
       
   357 				$comment_count['total_comments'] += $row['total'];
       
   358 				break;
       
   359 			default:
       
   360 				break;
       
   361 		}
       
   362 	}
       
   363 
       
   364 	return $comment_count;
       
   365 }
       
   366 
       
   367 //
       
   368 // Comment meta functions
       
   369 //
       
   370 
       
   371 /**
       
   372  * Add meta data field to a comment.
       
   373  *
       
   374  * @since 2.9
       
   375  * @uses add_metadata
       
   376  * @link http://codex.wordpress.org/Function_Reference/add_comment_meta
       
   377  *
       
   378  * @param int $comment_id Comment ID.
       
   379  * @param string $key Metadata name.
       
   380  * @param mixed $value Metadata value.
       
   381  * @param bool $unique Optional, default is false. Whether the same key should not be added.
       
   382  * @return bool False for failure. True for success.
       
   383  */
       
   384 function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
       
   385 	return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
       
   386 }
       
   387 
       
   388 /**
       
   389  * Remove metadata matching criteria from a comment.
       
   390  *
       
   391  * You can match based on the key, or key and value. Removing based on key and
       
   392  * value, will keep from removing duplicate metadata with the same key. It also
       
   393  * allows removing all metadata matching key, if needed.
       
   394  *
       
   395  * @since 2.9
       
   396  * @uses delete_metadata
       
   397  * @link http://codex.wordpress.org/Function_Reference/delete_comment_meta
       
   398  *
       
   399  * @param int $comment_id comment ID
       
   400  * @param string $meta_key Metadata name.
       
   401  * @param mixed $meta_value Optional. Metadata value.
       
   402  * @return bool False for failure. True for success.
       
   403  */
       
   404 function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
       
   405 	return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
       
   406 }
       
   407 
       
   408 /**
       
   409  * Retrieve comment meta field for a comment.
       
   410  *
       
   411  * @since 2.9
       
   412  * @uses get_metadata
       
   413  * @link http://codex.wordpress.org/Function_Reference/get_comment_meta
       
   414  *
       
   415  * @param int $comment_id Comment ID.
       
   416  * @param string $key The meta key to retrieve.
       
   417  * @param bool $single Whether to return a single value.
       
   418  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
       
   419  *  is true.
       
   420  */
       
   421 function get_comment_meta($comment_id, $key, $single = false) {
       
   422 	return get_metadata('comment', $comment_id, $key, $single);
       
   423 }
       
   424 
       
   425 /**
       
   426  * Update comment meta field based on comment ID.
       
   427  *
       
   428  * Use the $prev_value parameter to differentiate between meta fields with the
       
   429  * same key and comment ID.
       
   430  *
       
   431  * If the meta field for the comment does not exist, it will be added.
       
   432  *
       
   433  * @since 2.9
       
   434  * @uses update_metadata
       
   435  * @link http://codex.wordpress.org/Function_Reference/update_comment_meta
       
   436  *
       
   437  * @param int $comment_id Comment ID.
       
   438  * @param string $key Metadata key.
       
   439  * @param mixed $value Metadata value.
       
   440  * @param mixed $prev_value Optional. Previous value to check before removing.
       
   441  * @return bool False on failure, true if success.
       
   442  */
       
   443 function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
       
   444 	return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
       
   445 }
       
   446 
       
   447 /**
       
   448  * Sanitizes the cookies sent to the user already.
       
   449  *
       
   450  * Will only do anything if the cookies have already been created for the user.
       
   451  * Mostly used after cookies had been sent to use elsewhere.
       
   452  *
       
   453  * @since 2.0.4
       
   454  */
       
   455 function sanitize_comment_cookies() {
       
   456 	if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) ) {
       
   457 		$comment_author = apply_filters('pre_comment_author_name', $_COOKIE['comment_author_'.COOKIEHASH]);
       
   458 		$comment_author = stripslashes($comment_author);
       
   459 		$comment_author = esc_attr($comment_author);
       
   460 		$_COOKIE['comment_author_'.COOKIEHASH] = $comment_author;
       
   461 	}
       
   462 
       
   463 	if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) ) {
       
   464 		$comment_author_email = apply_filters('pre_comment_author_email', $_COOKIE['comment_author_email_'.COOKIEHASH]);
       
   465 		$comment_author_email = stripslashes($comment_author_email);
       
   466 		$comment_author_email = esc_attr($comment_author_email);
       
   467 		$_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
       
   468 	}
       
   469 
       
   470 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) ) {
       
   471 		$comment_author_url = apply_filters('pre_comment_author_url', $_COOKIE['comment_author_url_'.COOKIEHASH]);
       
   472 		$comment_author_url = stripslashes($comment_author_url);
       
   473 		$_COOKIE['comment_author_url_'.COOKIEHASH] = $comment_author_url;
       
   474 	}
       
   475 }
       
   476 
       
   477 /**
       
   478  * Validates whether this comment is allowed to be made or not.
       
   479  *
       
   480  * @since 2.0.0
       
   481  * @uses $wpdb
       
   482  * @uses apply_filters() Calls 'pre_comment_approved' hook on the type of comment
       
   483  * @uses do_action() Calls 'check_comment_flood' hook on $comment_author_IP, $comment_author_email, and $comment_date_gmt
       
   484  *
       
   485  * @param array $commentdata Contains information on the comment
       
   486  * @return mixed Signifies the approval status (0|1|'spam')
       
   487  */
       
   488 function wp_allow_comment($commentdata) {
       
   489 	global $wpdb;
       
   490 	extract($commentdata, EXTR_SKIP);
       
   491 
       
   492 	// Simple duplicate check
       
   493 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
       
   494 	$dupe = "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = '$comment_post_ID' AND comment_approved != 'trash' AND ( comment_author = '$comment_author' ";
       
   495 	if ( $comment_author_email )
       
   496 		$dupe .= "OR comment_author_email = '$comment_author_email' ";
       
   497 	$dupe .= ") AND comment_content = '$comment_content' LIMIT 1";
       
   498 	if ( $wpdb->get_var($dupe) ) {
       
   499 		if ( defined('DOING_AJAX') )
       
   500 			die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
       
   501 
       
   502 		wp_die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
       
   503 	}
       
   504 
       
   505 	do_action( 'check_comment_flood', $comment_author_IP, $comment_author_email, $comment_date_gmt );
       
   506 
       
   507 	if ( isset($user_id) && $user_id) {
       
   508 		$userdata = get_userdata($user_id);
       
   509 		$user = new WP_User($user_id);
       
   510 		$post_author = $wpdb->get_var($wpdb->prepare("SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1", $comment_post_ID));
       
   511 	}
       
   512 
       
   513 	if ( isset($userdata) && ( $user_id == $post_author || $user->has_cap('moderate_comments') ) ) {
       
   514 		// The author and the admins get respect.
       
   515 		$approved = 1;
       
   516 	 } else {
       
   517 		// Everyone else's comments will be checked.
       
   518 		if ( check_comment($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent, $comment_type) )
       
   519 			$approved = 1;
       
   520 		else
       
   521 			$approved = 0;
       
   522 		if ( wp_blacklist_check($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent) )
       
   523 			$approved = 'spam';
       
   524 	}
       
   525 
       
   526 	$approved = apply_filters('pre_comment_approved', $approved);
       
   527 	return $approved;
       
   528 }
       
   529 
       
   530 /**
       
   531  * Check whether comment flooding is occurring.
       
   532  *
       
   533  * Won't run, if current user can manage options, so to not block
       
   534  * administrators.
       
   535  *
       
   536  * @since 2.3.0
       
   537  * @uses $wpdb
       
   538  * @uses apply_filters() Calls 'comment_flood_filter' filter with first
       
   539  *		parameter false, last comment timestamp, new comment timestamp.
       
   540  * @uses do_action() Calls 'comment_flood_trigger' action with parameters with
       
   541  *		last comment timestamp and new comment timestamp.
       
   542  *
       
   543  * @param string $ip Comment IP.
       
   544  * @param string $email Comment author email address.
       
   545  * @param string $date MySQL time string.
       
   546  */
       
   547 function check_comment_flood_db( $ip, $email, $date ) {
       
   548 	global $wpdb;
       
   549 	if ( current_user_can( 'manage_options' ) )
       
   550 		return; // don't throttle admins
       
   551 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - 3600 );
       
   552 	if ( $lasttime = $wpdb->get_var( $wpdb->prepare( "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( `comment_author_IP` = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1", $hour_ago, $ip, $email ) ) ) {
       
   553 		$time_lastcomment = mysql2date('U', $lasttime, false);
       
   554 		$time_newcomment  = mysql2date('U', $date, false);
       
   555 		$flood_die = apply_filters('comment_flood_filter', false, $time_lastcomment, $time_newcomment);
       
   556 		if ( $flood_die ) {
       
   557 			do_action('comment_flood_trigger', $time_lastcomment, $time_newcomment);
       
   558 
       
   559 			if ( defined('DOING_AJAX') )
       
   560 				die( __('You are posting comments too quickly.  Slow down.') );
       
   561 
       
   562 			wp_die( __('You are posting comments too quickly.  Slow down.'), '', array('response' => 403) );
       
   563 		}
       
   564 	}
       
   565 }
       
   566 
       
   567 /**
       
   568  * Separates an array of comments into an array keyed by comment_type.
       
   569  *
       
   570  * @since 2.7.0
       
   571  *
       
   572  * @param array $comments Array of comments
       
   573  * @return array Array of comments keyed by comment_type.
       
   574  */
       
   575 function &separate_comments(&$comments) {
       
   576 	$comments_by_type = array('comment' => array(), 'trackback' => array(), 'pingback' => array(), 'pings' => array());
       
   577 	$count = count($comments);
       
   578 	for ( $i = 0; $i < $count; $i++ ) {
       
   579 		$type = $comments[$i]->comment_type;
       
   580 		if ( empty($type) )
       
   581 			$type = 'comment';
       
   582 		$comments_by_type[$type][] = &$comments[$i];
       
   583 		if ( 'trackback' == $type || 'pingback' == $type )
       
   584 			$comments_by_type['pings'][] = &$comments[$i];
       
   585 	}
       
   586 
       
   587 	return $comments_by_type;
       
   588 }
       
   589 
       
   590 /**
       
   591  * Calculate the total number of comment pages.
       
   592  *
       
   593  * @since 2.7.0
       
   594  * @uses get_query_var() Used to fill in the default for $per_page parameter.
       
   595  * @uses get_option() Used to fill in defaults for parameters.
       
   596  * @uses Walker_Comment
       
   597  *
       
   598  * @param array $comments Optional array of comment objects.  Defaults to $wp_query->comments
       
   599  * @param int $per_page Optional comments per page.
       
   600  * @param boolean $threaded Optional control over flat or threaded comments.
       
   601  * @return int Number of comment pages.
       
   602  */
       
   603 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
       
   604 	global $wp_query;
       
   605 
       
   606 	if ( null === $comments && null === $per_page && null === $threaded && !empty($wp_query->max_num_comment_pages) )
       
   607 		return $wp_query->max_num_comment_pages;
       
   608 
       
   609 	if ( !$comments || !is_array($comments) )
       
   610 		$comments = $wp_query->comments;
       
   611 
       
   612 	if ( empty($comments) )
       
   613 		return 0;
       
   614 
       
   615 	if ( !isset($per_page) )
       
   616 		$per_page = (int) get_query_var('comments_per_page');
       
   617 	if ( 0 === $per_page )
       
   618 		$per_page = (int) get_option('comments_per_page');
       
   619 	if ( 0 === $per_page )
       
   620 		return 1;
       
   621 
       
   622 	if ( !isset($threaded) )
       
   623 		$threaded = get_option('thread_comments');
       
   624 
       
   625 	if ( $threaded ) {
       
   626 		$walker = new Walker_Comment;
       
   627 		$count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
       
   628 	} else {
       
   629 		$count = ceil( count( $comments ) / $per_page );
       
   630 	}
       
   631 
       
   632 	return $count;
       
   633 }
       
   634 
       
   635 /**
       
   636  * Calculate what page number a comment will appear on for comment paging.
       
   637  *
       
   638  * @since 2.7.0
       
   639  * @uses get_comment() Gets the full comment of the $comment_ID parameter.
       
   640  * @uses get_option() Get various settings to control function and defaults.
       
   641  * @uses get_page_of_comment() Used to loop up to top level comment.
       
   642  *
       
   643  * @param int $comment_ID Comment ID.
       
   644  * @param array $args Optional args.
       
   645  * @return int|null Comment page number or null on error.
       
   646  */
       
   647 function get_page_of_comment( $comment_ID, $args = array() ) {
       
   648 	global $wpdb;
       
   649 
       
   650 	if ( !$comment = get_comment( $comment_ID ) )
       
   651 		return;
       
   652 
       
   653 	$defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
       
   654 	$args = wp_parse_args( $args, $defaults );
       
   655 
       
   656 	if ( '' === $args['per_page'] && get_option('page_comments') )
       
   657 		$args['per_page'] = get_query_var('comments_per_page');
       
   658 	if ( empty($args['per_page']) ) {
       
   659 		$args['per_page'] = 0;
       
   660 		$args['page'] = 0;
       
   661 	}
       
   662 	if ( $args['per_page'] < 1 )
       
   663 		return 1;
       
   664 
       
   665 	if ( '' === $args['max_depth'] ) {
       
   666 		if ( get_option('thread_comments') )
       
   667 			$args['max_depth'] = get_option('thread_comments_depth');
       
   668 		else
       
   669 			$args['max_depth'] = -1;
       
   670 	}
       
   671 
       
   672 	// Find this comment's top level parent if threading is enabled
       
   673 	if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
       
   674 		return get_page_of_comment( $comment->comment_parent, $args );
       
   675 
       
   676 	$allowedtypes = array(
       
   677 		'comment' => '',
       
   678 		'pingback' => 'pingback',
       
   679 		'trackback' => 'trackback',
       
   680 	);
       
   681 
       
   682 	$comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
       
   683 
       
   684 	// Count comments older than this one
       
   685 	$oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
       
   686 
       
   687 	// No older comments? Then it's page #1.
       
   688 	if ( 0 == $oldercoms )
       
   689 		return 1;
       
   690 
       
   691 	// Divide comments older than this one by comments per page to get this comment's page number
       
   692 	return ceil( ( $oldercoms + 1 ) / $args['per_page'] );
       
   693 }
       
   694 
       
   695 /**
       
   696  * Does comment contain blacklisted characters or words.
       
   697  *
       
   698  * @since 1.5.0
       
   699  * @uses do_action() Calls 'wp_blacklist_check' hook for all parameters.
       
   700  *
       
   701  * @param string $author The author of the comment
       
   702  * @param string $email The email of the comment
       
   703  * @param string $url The url used in the comment
       
   704  * @param string $comment The comment content
       
   705  * @param string $user_ip The comment author IP address
       
   706  * @param string $user_agent The author's browser user agent
       
   707  * @return bool True if comment contains blacklisted content, false if comment does not
       
   708  */
       
   709 function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
       
   710 	do_action('wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent);
       
   711 
       
   712 	$mod_keys = trim( get_option('blacklist_keys') );
       
   713 	if ( '' == $mod_keys )
       
   714 		return false; // If moderation keys are empty
       
   715 	$words = explode("\n", $mod_keys );
       
   716 
       
   717 	foreach ( (array) $words as $word ) {
       
   718 		$word = trim($word);
       
   719 
       
   720 		// Skip empty lines
       
   721 		if ( empty($word) ) { continue; }
       
   722 
       
   723 		// Do some escaping magic so that '#' chars in the
       
   724 		// spam words don't break things:
       
   725 		$word = preg_quote($word, '#');
       
   726 
       
   727 		$pattern = "#$word#i";
       
   728 		if (
       
   729 			   preg_match($pattern, $author)
       
   730 			|| preg_match($pattern, $email)
       
   731 			|| preg_match($pattern, $url)
       
   732 			|| preg_match($pattern, $comment)
       
   733 			|| preg_match($pattern, $user_ip)
       
   734 			|| preg_match($pattern, $user_agent)
       
   735 		 )
       
   736 			return true;
       
   737 	}
       
   738 	return false;
       
   739 }
       
   740 
       
   741 /**
       
   742  * Retrieve total comments for blog or single post.
       
   743  *
       
   744  * The properties of the returned object contain the 'moderated', 'approved',
       
   745  * and spam comments for either the entire blog or single post. Those properties
       
   746  * contain the amount of comments that match the status. The 'total_comments'
       
   747  * property contains the integer of total comments.
       
   748  *
       
   749  * The comment stats are cached and then retrieved, if they already exist in the
       
   750  * cache.
       
   751  *
       
   752  * @since 2.5.0
       
   753  *
       
   754  * @param int $post_id Optional. Post ID.
       
   755  * @return object Comment stats.
       
   756  */
       
   757 function wp_count_comments( $post_id = 0 ) {
       
   758 	global $wpdb;
       
   759 
       
   760 	$post_id = (int) $post_id;
       
   761 
       
   762 	$stats = apply_filters('wp_count_comments', array(), $post_id);
       
   763 	if ( !empty($stats) )
       
   764 		return $stats;
       
   765 
       
   766 	$count = wp_cache_get("comments-{$post_id}", 'counts');
       
   767 
       
   768 	if ( false !== $count )
       
   769 		return $count;
       
   770 
       
   771 	$where = '';
       
   772 	if ( $post_id > 0 )
       
   773 		$where = $wpdb->prepare( "WHERE comment_post_ID = %d", $post_id );
       
   774 
       
   775 	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
       
   776 
       
   777 	$total = 0;
       
   778 	$approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
       
   779 	$known_types = array_keys( $approved );
       
   780 	foreach( (array) $count as $row_num => $row ) {
       
   781 		// Don't count post-trashed toward totals
       
   782 		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
       
   783 			$total += $row['num_comments'];
       
   784 		if ( in_array( $row['comment_approved'], $known_types ) )
       
   785 			$stats[$approved[$row['comment_approved']]] = $row['num_comments'];
       
   786 	}
       
   787 
       
   788 	$stats['total_comments'] = $total;
       
   789 	foreach ( $approved as $key ) {
       
   790 		if ( empty($stats[$key]) )
       
   791 			$stats[$key] = 0;
       
   792 	}
       
   793 
       
   794 	$stats = (object) $stats;
       
   795 	wp_cache_set("comments-{$post_id}", $stats, 'counts');
       
   796 
       
   797 	return $stats;
       
   798 }
       
   799 
       
   800 /**
       
   801  * Removes comment ID and maybe updates post comment count.
       
   802  *
       
   803  * The post comment count will be updated if the comment was approved and has a
       
   804  * post ID available.
       
   805  *
       
   806  * @since 2.0.0
       
   807  * @uses $wpdb
       
   808  * @uses do_action() Calls 'delete_comment' hook on comment ID
       
   809  * @uses do_action() Calls 'deleted_comment' hook on comment ID after deletion, on success
       
   810  * @uses do_action() Calls 'wp_set_comment_status' hook on comment ID with 'delete' set for the second parameter
       
   811  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
   812  *
       
   813  * @param int $comment_id Comment ID
       
   814  * @return bool False if delete comment query failure, true on success.
       
   815  */
       
   816 function wp_delete_comment($comment_id) {
       
   817 	global $wpdb;
       
   818 	if (!$comment = get_comment($comment_id))
       
   819 		return false;
       
   820 
       
   821 	if (wp_get_comment_status($comment_id) != 'trash' && wp_get_comment_status($comment_id) != 'spam' && EMPTY_TRASH_DAYS > 0)
       
   822 		return wp_trash_comment($comment_id);
       
   823 
       
   824 	do_action('delete_comment', $comment_id);
       
   825 
       
   826 	// Move children up a level.
       
   827 	$children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment_id) );
       
   828 	if ( !empty($children) ) {
       
   829 		$wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment_id));
       
   830 		clean_comment_cache($children);
       
   831 	}
       
   832 
       
   833 	// Delete metadata
       
   834 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d ", $comment_id ) );
       
   835 	if ( !empty($meta_ids) ) {
       
   836 		do_action( 'delete_commentmeta', $meta_ids );
       
   837 		$in_meta_ids = "'" . implode("', '", $meta_ids) . "'";
       
   838 		$wpdb->query( "DELETE FROM $wpdb->commentmeta WHERE meta_id IN ($in_meta_ids)" );
       
   839 		do_action( 'deleted_commentmeta', $meta_ids );
       
   840 	}
       
   841 
       
   842 	if ( ! $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment_id) ) )
       
   843 		return false;
       
   844 	do_action('deleted_comment', $comment_id);
       
   845 
       
   846 	$post_id = $comment->comment_post_ID;
       
   847 	if ( $post_id && $comment->comment_approved == 1 )
       
   848 		wp_update_comment_count($post_id);
       
   849 
       
   850 	clean_comment_cache($comment_id);
       
   851 
       
   852 	do_action('wp_set_comment_status', $comment_id, 'delete');
       
   853 	wp_transition_comment_status('delete', $comment->comment_approved, $comment);
       
   854 	return true;
       
   855 }
       
   856 
       
   857 /**
       
   858  * Moves a comment to the Trash
       
   859  *
       
   860  * @since 2.9.0
       
   861  * @uses do_action() on 'trash_comment' before trashing
       
   862  * @uses do_action() on 'trashed_comment' after trashing
       
   863  *
       
   864  * @param int $comment_id Comment ID.
       
   865  * @return mixed False on failure
       
   866  */
       
   867 function wp_trash_comment($comment_id) {
       
   868 	if ( EMPTY_TRASH_DAYS == 0 )
       
   869 		return wp_delete_comment($comment_id);
       
   870 
       
   871 	if ( !$comment = get_comment($comment_id) )
       
   872 		return false;
       
   873 
       
   874 	do_action('trash_comment', $comment_id);
       
   875 
       
   876 	if ( wp_set_comment_status($comment_id, 'trash') ) {
       
   877 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
       
   878 		add_comment_meta($comment_id, '_wp_trash_meta_time', time() );
       
   879 		do_action('trashed_comment', $comment_id);
       
   880 		return true;
       
   881 	}
       
   882 
       
   883 	return false;
       
   884 }
       
   885 
       
   886 /**
       
   887  * Removes a comment from the Trash
       
   888  *
       
   889  * @since 2.9.0
       
   890  * @uses do_action() on 'untrash_comment' before untrashing
       
   891  * @uses do_action() on 'untrashed_comment' after untrashing
       
   892  *
       
   893  * @param int $comment_id Comment ID.
       
   894  * @return mixed False on failure
       
   895  */
       
   896 function wp_untrash_comment($comment_id) {
       
   897 	if ( ! (int)$comment_id )
       
   898 		return false;
       
   899 
       
   900 	do_action('untrash_comment', $comment_id);
       
   901 
       
   902 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
       
   903 	if ( empty($status) )
       
   904 		$status = '0';
       
   905 
       
   906 	if ( wp_set_comment_status($comment_id, $status) ) {
       
   907 		delete_comment_meta($comment_id, '_wp_trash_meta_time');
       
   908 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
       
   909 		do_action('untrashed_comment', $comment_id);
       
   910 		return true;
       
   911 	}
       
   912 
       
   913 	return false;
       
   914 }
       
   915 
       
   916 /**
       
   917  * Marks a comment as Spam
       
   918  *
       
   919  * @since 2.9.0
       
   920  * @uses do_action() on 'spam_comment' before spamming
       
   921  * @uses do_action() on 'spammed_comment' after spamming
       
   922  *
       
   923  * @param int $comment_id Comment ID.
       
   924  * @return mixed False on failure
       
   925  */
       
   926 function wp_spam_comment($comment_id) {
       
   927 	if ( !$comment = get_comment($comment_id) )
       
   928 		return false;
       
   929 
       
   930 	do_action('spam_comment', $comment_id);
       
   931 
       
   932 	if ( wp_set_comment_status($comment_id, 'spam') ) {
       
   933 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
       
   934 		do_action('spammed_comment', $comment_id);
       
   935 		return true;
       
   936 	}
       
   937 
       
   938 	return false;
       
   939 }
       
   940 
       
   941 /**
       
   942  * Removes a comment from the Spam
       
   943  *
       
   944  * @since 2.9.0
       
   945  * @uses do_action() on 'unspam_comment' before unspamming
       
   946  * @uses do_action() on 'unspammed_comment' after unspamming
       
   947  *
       
   948  * @param int $comment_id Comment ID.
       
   949  * @return mixed False on failure
       
   950  */
       
   951 function wp_unspam_comment($comment_id) {
       
   952 	if ( ! (int)$comment_id )
       
   953 		return false;
       
   954 
       
   955 	do_action('unspam_comment', $comment_id);
       
   956 
       
   957 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
       
   958 	if ( empty($status) )
       
   959 		$status = '0';
       
   960 
       
   961 	if ( wp_set_comment_status($comment_id, $status) ) {
       
   962 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
       
   963 		do_action('unspammed_comment', $comment_id);
       
   964 		return true;
       
   965 	}
       
   966 
       
   967 	return false;
       
   968 }
       
   969 
       
   970 /**
       
   971  * The status of a comment by ID.
       
   972  *
       
   973  * @since 1.0.0
       
   974  *
       
   975  * @param int $comment_id Comment ID
       
   976  * @return string|bool Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
       
   977  */
       
   978 function wp_get_comment_status($comment_id) {
       
   979 	$comment = get_comment($comment_id);
       
   980 	if ( !$comment )
       
   981 		return false;
       
   982 
       
   983 	$approved = $comment->comment_approved;
       
   984 
       
   985 	if ( $approved == NULL )
       
   986 		return false;
       
   987 	elseif ( $approved == '1' )
       
   988 		return 'approved';
       
   989 	elseif ( $approved == '0' )
       
   990 		return 'unapproved';
       
   991 	elseif ( $approved == 'spam' )
       
   992 		return 'spam';
       
   993 	elseif ( $approved == 'trash' )
       
   994 		return 'trash';
       
   995 	else
       
   996 		return false;
       
   997 }
       
   998 
       
   999 /**
       
  1000  * Call hooks for when a comment status transition occurs.
       
  1001  *
       
  1002  * Calls hooks for comment status transitions. If the new comment status is not the same
       
  1003  * as the previous comment status, then two hooks will be ran, the first is
       
  1004  * 'transition_comment_status' with new status, old status, and comment data. The
       
  1005  * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
       
  1006  * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
       
  1007  * comment data.
       
  1008  *
       
  1009  * The final action will run whether or not the comment statuses are the same. The
       
  1010  * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
       
  1011  * parameter and COMMENTTYPE is comment_type comment data.
       
  1012  *
       
  1013  * @since 2.7.0
       
  1014  *
       
  1015  * @param string $new_status New comment status.
       
  1016  * @param string $old_status Previous comment status.
       
  1017  * @param object $comment Comment data.
       
  1018  */
       
  1019 function wp_transition_comment_status($new_status, $old_status, $comment) {
       
  1020 	// Translate raw statuses to human readable formats for the hooks
       
  1021 	// This is not a complete list of comment status, it's only the ones that need to be renamed
       
  1022 	$comment_statuses = array(
       
  1023 		0         => 'unapproved',
       
  1024 		'hold'    => 'unapproved', // wp_set_comment_status() uses "hold"
       
  1025 		1         => 'approved',
       
  1026 		'approve' => 'approved', // wp_set_comment_status() uses "approve"
       
  1027 	);
       
  1028 	if ( isset($comment_statuses[$new_status]) ) $new_status = $comment_statuses[$new_status];
       
  1029 	if ( isset($comment_statuses[$old_status]) ) $old_status = $comment_statuses[$old_status];
       
  1030 
       
  1031 	// Call the hooks
       
  1032 	if ( $new_status != $old_status ) {
       
  1033 		do_action('transition_comment_status', $new_status, $old_status, $comment);
       
  1034 		do_action("comment_${old_status}_to_$new_status", $comment);
       
  1035 	}
       
  1036 	do_action("comment_${new_status}_$comment->comment_type", $comment->comment_ID, $comment);
       
  1037 }
       
  1038 
       
  1039 /**
       
  1040  * Get current commenter's name, email, and URL.
       
  1041  *
       
  1042  * Expects cookies content to already be sanitized. User of this function might
       
  1043  * wish to recheck the returned array for validity.
       
  1044  *
       
  1045  * @see sanitize_comment_cookies() Use to sanitize cookies
       
  1046  *
       
  1047  * @since 2.0.4
       
  1048  *
       
  1049  * @return array Comment author, email, url respectively.
       
  1050  */
       
  1051 function wp_get_current_commenter() {
       
  1052 	// Cookies should already be sanitized.
       
  1053 
       
  1054 	$comment_author = '';
       
  1055 	if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) )
       
  1056 		$comment_author = $_COOKIE['comment_author_'.COOKIEHASH];
       
  1057 
       
  1058 	$comment_author_email = '';
       
  1059 	if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) )
       
  1060 		$comment_author_email = $_COOKIE['comment_author_email_'.COOKIEHASH];
       
  1061 
       
  1062 	$comment_author_url = '';
       
  1063 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
       
  1064 		$comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
       
  1065 
       
  1066 	return compact('comment_author', 'comment_author_email', 'comment_author_url');
       
  1067 }
       
  1068 
       
  1069 /**
       
  1070  * Inserts a comment to the database.
       
  1071  *
       
  1072  * The available comment data key names are 'comment_author_IP', 'comment_date',
       
  1073  * 'comment_date_gmt', 'comment_parent', 'comment_approved', and 'user_id'.
       
  1074  *
       
  1075  * @since 2.0.0
       
  1076  * @uses $wpdb
       
  1077  *
       
  1078  * @param array $commentdata Contains information on the comment.
       
  1079  * @return int The new comment's ID.
       
  1080  */
       
  1081 function wp_insert_comment($commentdata) {
       
  1082 	global $wpdb;
       
  1083 	extract(stripslashes_deep($commentdata), EXTR_SKIP);
       
  1084 
       
  1085 	if ( ! isset($comment_author_IP) )
       
  1086 		$comment_author_IP = '';
       
  1087 	if ( ! isset($comment_date) )
       
  1088 		$comment_date = current_time('mysql');
       
  1089 	if ( ! isset($comment_date_gmt) )
       
  1090 		$comment_date_gmt = get_gmt_from_date($comment_date);
       
  1091 	if ( ! isset($comment_parent) )
       
  1092 		$comment_parent = 0;
       
  1093 	if ( ! isset($comment_approved) )
       
  1094 		$comment_approved = 1;
       
  1095 	if ( ! isset($comment_karma) )
       
  1096 		$comment_karma = 0;
       
  1097 	if ( ! isset($user_id) )
       
  1098 		$user_id = 0;
       
  1099 	if ( ! isset($comment_type) )
       
  1100 		$comment_type = '';
       
  1101 
       
  1102 	$data = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id');
       
  1103 	$wpdb->insert($wpdb->comments, $data);
       
  1104 
       
  1105 	$id = (int) $wpdb->insert_id;
       
  1106 
       
  1107 	if ( $comment_approved == 1 )
       
  1108 		wp_update_comment_count($comment_post_ID);
       
  1109 
       
  1110 	$comment = get_comment($id);
       
  1111 	do_action('wp_insert_comment', $id, $comment);
       
  1112 
       
  1113 	return $id;
       
  1114 }
       
  1115 
       
  1116 /**
       
  1117  * Filters and sanitizes comment data.
       
  1118  *
       
  1119  * Sets the comment data 'filtered' field to true when finished. This can be
       
  1120  * checked as to whether the comment should be filtered and to keep from
       
  1121  * filtering the same comment more than once.
       
  1122  *
       
  1123  * @since 2.0.0
       
  1124  * @uses apply_filters() Calls 'pre_user_id' hook on comment author's user ID
       
  1125  * @uses apply_filters() Calls 'pre_comment_user_agent' hook on comment author's user agent
       
  1126  * @uses apply_filters() Calls 'pre_comment_author_name' hook on comment author's name
       
  1127  * @uses apply_filters() Calls 'pre_comment_content' hook on the comment's content
       
  1128  * @uses apply_filters() Calls 'pre_comment_user_ip' hook on comment author's IP
       
  1129  * @uses apply_filters() Calls 'pre_comment_author_url' hook on comment author's URL
       
  1130  * @uses apply_filters() Calls 'pre_comment_author_email' hook on comment author's email address
       
  1131  *
       
  1132  * @param array $commentdata Contains information on the comment.
       
  1133  * @return array Parsed comment information.
       
  1134  */
       
  1135 function wp_filter_comment($commentdata) {
       
  1136 	if ( isset($commentdata['user_ID']) )
       
  1137 		$commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_ID']);
       
  1138 	elseif ( isset($commentdata['user_id']) )
       
  1139 		$commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_id']);
       
  1140 	$commentdata['comment_agent']        = apply_filters('pre_comment_user_agent', $commentdata['comment_agent']);
       
  1141 	$commentdata['comment_author']       = apply_filters('pre_comment_author_name', $commentdata['comment_author']);
       
  1142 	$commentdata['comment_content']      = apply_filters('pre_comment_content', $commentdata['comment_content']);
       
  1143 	$commentdata['comment_author_IP']    = apply_filters('pre_comment_user_ip', $commentdata['comment_author_IP']);
       
  1144 	$commentdata['comment_author_url']   = apply_filters('pre_comment_author_url', $commentdata['comment_author_url']);
       
  1145 	$commentdata['comment_author_email'] = apply_filters('pre_comment_author_email', $commentdata['comment_author_email']);
       
  1146 	$commentdata['filtered'] = true;
       
  1147 	return $commentdata;
       
  1148 }
       
  1149 
       
  1150 /**
       
  1151  * Whether comment should be blocked because of comment flood.
       
  1152  *
       
  1153  * @since 2.1.0
       
  1154  *
       
  1155  * @param bool $block Whether plugin has already blocked comment.
       
  1156  * @param int $time_lastcomment Timestamp for last comment.
       
  1157  * @param int $time_newcomment Timestamp for new comment.
       
  1158  * @return bool Whether comment should be blocked.
       
  1159  */
       
  1160 function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
       
  1161 	if ( $block ) // a plugin has already blocked... we'll let that decision stand
       
  1162 		return $block;
       
  1163 	if ( ($time_newcomment - $time_lastcomment) < 15 )
       
  1164 		return true;
       
  1165 	return false;
       
  1166 }
       
  1167 
       
  1168 /**
       
  1169  * Adds a new comment to the database.
       
  1170  *
       
  1171  * Filters new comment to ensure that the fields are sanitized and valid before
       
  1172  * inserting comment into database. Calls 'comment_post' action with comment ID
       
  1173  * and whether comment is approved by WordPress. Also has 'preprocess_comment'
       
  1174  * filter for processing the comment data before the function handles it.
       
  1175  *
       
  1176  * @since 1.5.0
       
  1177  * @uses apply_filters() Calls 'preprocess_comment' hook on $commentdata parameter array before processing
       
  1178  * @uses do_action() Calls 'comment_post' hook on $comment_ID returned from adding the comment and if the comment was approved.
       
  1179  * @uses wp_filter_comment() Used to filter comment before adding comment.
       
  1180  * @uses wp_allow_comment() checks to see if comment is approved.
       
  1181  * @uses wp_insert_comment() Does the actual comment insertion to the database.
       
  1182  *
       
  1183  * @param array $commentdata Contains information on the comment.
       
  1184  * @return int The ID of the comment after adding.
       
  1185  */
       
  1186 function wp_new_comment( $commentdata ) {
       
  1187 	$commentdata = apply_filters('preprocess_comment', $commentdata);
       
  1188 
       
  1189 	$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
       
  1190 	if ( isset($commentdata['user_ID']) )
       
  1191 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
       
  1192 	elseif ( isset($commentdata['user_id']) )
       
  1193 		$commentdata['user_id'] = (int) $commentdata['user_id'];
       
  1194 
       
  1195 	$commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
       
  1196 	$parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
       
  1197 	$commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
       
  1198 
       
  1199 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
       
  1200 	$commentdata['comment_agent']     = substr($_SERVER['HTTP_USER_AGENT'], 0, 254);
       
  1201 
       
  1202 	$commentdata['comment_date']     = current_time('mysql');
       
  1203 	$commentdata['comment_date_gmt'] = current_time('mysql', 1);
       
  1204 
       
  1205 	$commentdata = wp_filter_comment($commentdata);
       
  1206 
       
  1207 	$commentdata['comment_approved'] = wp_allow_comment($commentdata);
       
  1208 
       
  1209 	$comment_ID = wp_insert_comment($commentdata);
       
  1210 
       
  1211 	do_action('comment_post', $comment_ID, $commentdata['comment_approved']);
       
  1212 
       
  1213 	if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
       
  1214 		if ( '0' == $commentdata['comment_approved'] )
       
  1215 			wp_notify_moderator($comment_ID);
       
  1216 
       
  1217 		$post = &get_post($commentdata['comment_post_ID']); // Don't notify if it's your own comment
       
  1218 
       
  1219 		if ( get_option('comments_notify') && $commentdata['comment_approved'] && $post->post_author != $commentdata['user_id'] )
       
  1220 			wp_notify_postauthor($comment_ID, $commentdata['comment_type']);
       
  1221 	}
       
  1222 
       
  1223 	return $comment_ID;
       
  1224 }
       
  1225 
       
  1226 /**
       
  1227  * Sets the status of a comment.
       
  1228  *
       
  1229  * The 'wp_set_comment_status' action is called after the comment is handled and
       
  1230  * will only be called, if the comment status is either 'hold', 'approve', or
       
  1231  * 'spam'. If the comment status is not in the list, then false is returned and
       
  1232  * if the status is 'delete', then the comment is deleted without calling the
       
  1233  * action.
       
  1234  *
       
  1235  * @since 1.0.0
       
  1236  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
  1237  *
       
  1238  * @param int $comment_id Comment ID.
       
  1239  * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'delete'.
       
  1240  * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default is false.
       
  1241  * @return bool False on failure or deletion and true on success.
       
  1242  */
       
  1243 function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
       
  1244 	global $wpdb;
       
  1245 
       
  1246 	$status = '0';
       
  1247 	switch ( $comment_status ) {
       
  1248 		case 'hold':
       
  1249 		case '0':
       
  1250 			$status = '0';
       
  1251 			break;
       
  1252 		case 'approve':
       
  1253 		case '1':
       
  1254 			$status = '1';
       
  1255 			if ( get_option('comments_notify') ) {
       
  1256 				$comment = get_comment($comment_id);
       
  1257 				wp_notify_postauthor($comment_id, $comment->comment_type);
       
  1258 			}
       
  1259 			break;
       
  1260 		case 'spam':
       
  1261 			$status = 'spam';
       
  1262 			break;
       
  1263 		case 'trash':
       
  1264 			$status = 'trash';
       
  1265 			break;
       
  1266 		default:
       
  1267 			return false;
       
  1268 	}
       
  1269 
       
  1270 	$comment_old = wp_clone(get_comment($comment_id));
       
  1271 
       
  1272 	if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array('comment_ID' => $comment_id) ) ) {
       
  1273 		if ( $wp_error )
       
  1274 			return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
       
  1275 		else
       
  1276 			return false;
       
  1277 	}
       
  1278 
       
  1279 	clean_comment_cache($comment_id);
       
  1280 
       
  1281 	$comment = get_comment($comment_id);
       
  1282 
       
  1283 	do_action('wp_set_comment_status', $comment_id, $comment_status);
       
  1284 	wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
       
  1285 
       
  1286 	wp_update_comment_count($comment->comment_post_ID);
       
  1287 
       
  1288 	return true;
       
  1289 }
       
  1290 
       
  1291 /**
       
  1292  * Updates an existing comment in the database.
       
  1293  *
       
  1294  * Filters the comment and makes sure certain fields are valid before updating.
       
  1295  *
       
  1296  * @since 2.0.0
       
  1297  * @uses $wpdb
       
  1298  * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
       
  1299  *
       
  1300  * @param array $commentarr Contains information on the comment.
       
  1301  * @return int Comment was updated if value is 1, or was not updated if value is 0.
       
  1302  */
       
  1303 function wp_update_comment($commentarr) {
       
  1304 	global $wpdb;
       
  1305 
       
  1306 	// First, get all of the original fields
       
  1307 	$comment = get_comment($commentarr['comment_ID'], ARRAY_A);
       
  1308 
       
  1309 	// Escape data pulled from DB.
       
  1310 	$comment = esc_sql($comment);
       
  1311 
       
  1312 	$old_status = $comment['comment_approved'];
       
  1313 
       
  1314 	// Merge old and new fields with new fields overwriting old ones.
       
  1315 	$commentarr = array_merge($comment, $commentarr);
       
  1316 
       
  1317 	$commentarr = wp_filter_comment( $commentarr );
       
  1318 
       
  1319 	// Now extract the merged array.
       
  1320 	extract(stripslashes_deep($commentarr), EXTR_SKIP);
       
  1321 
       
  1322 	$comment_content = apply_filters('comment_save_pre', $comment_content);
       
  1323 
       
  1324 	$comment_date_gmt = get_gmt_from_date($comment_date);
       
  1325 
       
  1326 	if ( !isset($comment_approved) )
       
  1327 		$comment_approved = 1;
       
  1328 	else if ( 'hold' == $comment_approved )
       
  1329 		$comment_approved = 0;
       
  1330 	else if ( 'approve' == $comment_approved )
       
  1331 		$comment_approved = 1;
       
  1332 
       
  1333 	$data = compact('comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt');
       
  1334 	$wpdb->update($wpdb->comments, $data, compact('comment_ID'));
       
  1335 
       
  1336 	$rval = $wpdb->rows_affected;
       
  1337 
       
  1338 	clean_comment_cache($comment_ID);
       
  1339 	wp_update_comment_count($comment_post_ID);
       
  1340 	do_action('edit_comment', $comment_ID);
       
  1341 	$comment = get_comment($comment_ID);
       
  1342 	wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
       
  1343 	return $rval;
       
  1344 }
       
  1345 
       
  1346 /**
       
  1347  * Whether to defer comment counting.
       
  1348  *
       
  1349  * When setting $defer to true, all post comment counts will not be updated
       
  1350  * until $defer is set to false. When $defer is set to false, then all
       
  1351  * previously deferred updated post comment counts will then be automatically
       
  1352  * updated without having to call wp_update_comment_count() after.
       
  1353  *
       
  1354  * @since 2.5.0
       
  1355  * @staticvar bool $_defer
       
  1356  *
       
  1357  * @param bool $defer
       
  1358  * @return unknown
       
  1359  */
       
  1360 function wp_defer_comment_counting($defer=null) {
       
  1361 	static $_defer = false;
       
  1362 
       
  1363 	if ( is_bool($defer) ) {
       
  1364 		$_defer = $defer;
       
  1365 		// flush any deferred counts
       
  1366 		if ( !$defer )
       
  1367 			wp_update_comment_count( null, true );
       
  1368 	}
       
  1369 
       
  1370 	return $_defer;
       
  1371 }
       
  1372 
       
  1373 /**
       
  1374  * Updates the comment count for post(s).
       
  1375  *
       
  1376  * When $do_deferred is false (is by default) and the comments have been set to
       
  1377  * be deferred, the post_id will be added to a queue, which will be updated at a
       
  1378  * later date and only updated once per post ID.
       
  1379  *
       
  1380  * If the comments have not be set up to be deferred, then the post will be
       
  1381  * updated. When $do_deferred is set to true, then all previous deferred post
       
  1382  * IDs will be updated along with the current $post_id.
       
  1383  *
       
  1384  * @since 2.1.0
       
  1385  * @see wp_update_comment_count_now() For what could cause a false return value
       
  1386  *
       
  1387  * @param int $post_id Post ID
       
  1388  * @param bool $do_deferred Whether to process previously deferred post comment counts
       
  1389  * @return bool True on success, false on failure
       
  1390  */
       
  1391 function wp_update_comment_count($post_id, $do_deferred=false) {
       
  1392 	static $_deferred = array();
       
  1393 
       
  1394 	if ( $do_deferred ) {
       
  1395 		$_deferred = array_unique($_deferred);
       
  1396 		foreach ( $_deferred as $i => $_post_id ) {
       
  1397 			wp_update_comment_count_now($_post_id);
       
  1398 			unset( $_deferred[$i] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */
       
  1399 		}
       
  1400 	}
       
  1401 
       
  1402 	if ( wp_defer_comment_counting() ) {
       
  1403 		$_deferred[] = $post_id;
       
  1404 		return true;
       
  1405 	}
       
  1406 	elseif ( $post_id ) {
       
  1407 		return wp_update_comment_count_now($post_id);
       
  1408 	}
       
  1409 
       
  1410 }
       
  1411 
       
  1412 /**
       
  1413  * Updates the comment count for the post.
       
  1414  *
       
  1415  * @since 2.5.0
       
  1416  * @uses $wpdb
       
  1417  * @uses do_action() Calls 'wp_update_comment_count' hook on $post_id, $new, and $old
       
  1418  * @uses do_action() Calls 'edit_posts' hook on $post_id and $post
       
  1419  *
       
  1420  * @param int $post_id Post ID
       
  1421  * @return bool False on '0' $post_id or if post with ID does not exist. True on success.
       
  1422  */
       
  1423 function wp_update_comment_count_now($post_id) {
       
  1424 	global $wpdb;
       
  1425 	$post_id = (int) $post_id;
       
  1426 	if ( !$post_id )
       
  1427 		return false;
       
  1428 	if ( !$post = get_post($post_id) )
       
  1429 		return false;
       
  1430 
       
  1431 	$old = (int) $post->comment_count;
       
  1432 	$new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
       
  1433 	$wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
       
  1434 
       
  1435 	if ( 'page' == $post->post_type )
       
  1436 		clean_page_cache( $post_id );
       
  1437 	else
       
  1438 		clean_post_cache( $post_id );
       
  1439 
       
  1440 	do_action('wp_update_comment_count', $post_id, $new, $old);
       
  1441 	do_action('edit_post', $post_id, $post);
       
  1442 
       
  1443 	return true;
       
  1444 }
       
  1445 
       
  1446 //
       
  1447 // Ping and trackback functions.
       
  1448 //
       
  1449 
       
  1450 /**
       
  1451  * Finds a pingback server URI based on the given URL.
       
  1452  *
       
  1453  * Checks the HTML for the rel="pingback" link and x-pingback headers. It does
       
  1454  * a check for the x-pingback headers first and returns that, if available. The
       
  1455  * check for the rel="pingback" has more overhead than just the header.
       
  1456  *
       
  1457  * @since 1.5.0
       
  1458  *
       
  1459  * @param string $url URL to ping.
       
  1460  * @param int $deprecated Not Used.
       
  1461  * @return bool|string False on failure, string containing URI on success.
       
  1462  */
       
  1463 function discover_pingback_server_uri($url, $deprecated = 2048) {
       
  1464 
       
  1465 	$pingback_str_dquote = 'rel="pingback"';
       
  1466 	$pingback_str_squote = 'rel=\'pingback\'';
       
  1467 
       
  1468 	/** @todo Should use Filter Extension or custom preg_match instead. */
       
  1469 	$parsed_url = parse_url($url);
       
  1470 
       
  1471 	if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
       
  1472 		return false;
       
  1473 
       
  1474 	//Do not search for a pingback server on our own uploads
       
  1475 	$uploads_dir = wp_upload_dir();
       
  1476 	if ( 0 === strpos($url, $uploads_dir['baseurl']) )
       
  1477 		return false;
       
  1478 
       
  1479 	$response = wp_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
       
  1480 
       
  1481 	if ( is_wp_error( $response ) )
       
  1482 		return false;
       
  1483 
       
  1484 	if ( isset( $response['headers']['x-pingback'] ) )
       
  1485 		return $response['headers']['x-pingback'];
       
  1486 
       
  1487 	// Not an (x)html, sgml, or xml page, no use going further.
       
  1488 	if ( isset( $response['headers']['content-type'] ) && preg_match('#(image|audio|video|model)/#is', $response['headers']['content-type']) )
       
  1489 		return false;
       
  1490 
       
  1491 	// Now do a GET since we're going to look in the html headers (and we're sure its not a binary file)
       
  1492 	$response = wp_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
       
  1493 
       
  1494 	if ( is_wp_error( $response ) )
       
  1495 		return false;
       
  1496 
       
  1497 	$contents = $response['body'];
       
  1498 
       
  1499 	$pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
       
  1500 	$pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
       
  1501 	if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
       
  1502 		$quote = ($pingback_link_offset_dquote) ? '"' : '\'';
       
  1503 		$pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
       
  1504 		$pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
       
  1505 		$pingback_href_start = $pingback_href_pos+6;
       
  1506 		$pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
       
  1507 		$pingback_server_url_len = $pingback_href_end - $pingback_href_start;
       
  1508 		$pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
       
  1509 
       
  1510 		// We may find rel="pingback" but an incomplete pingback URL
       
  1511 		if ( $pingback_server_url_len > 0 ) { // We got it!
       
  1512 			return $pingback_server_url;
       
  1513 		}
       
  1514 	}
       
  1515 
       
  1516 	return false;
       
  1517 }
       
  1518 
       
  1519 /**
       
  1520  * Perform all pingbacks, enclosures, trackbacks, and send to pingback services.
       
  1521  *
       
  1522  * @since 2.1.0
       
  1523  * @uses $wpdb
       
  1524  */
       
  1525 function do_all_pings() {
       
  1526 	global $wpdb;
       
  1527 
       
  1528 	// Do pingbacks
       
  1529 	while ($ping = $wpdb->get_row("SELECT * FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1")) {
       
  1530 		$mid = $wpdb->get_var( "SELECT meta_id FROM {$wpdb->postmeta} WHERE post_id = {$ping->ID} AND meta_key = '_pingme' LIMIT 1");
       
  1531 		do_action( 'delete_postmeta', $mid );
       
  1532 		$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_id = %d", $mid ) );
       
  1533 		do_action( 'deleted_postmeta', $mid );
       
  1534 		pingback($ping->post_content, $ping->ID);
       
  1535 	}
       
  1536 
       
  1537 	// Do Enclosures
       
  1538 	while ($enclosure = $wpdb->get_row("SELECT * FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1")) {
       
  1539 		$mid = $wpdb->get_var( $wpdb->prepare("SELECT meta_id FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_encloseme'", $enclosure->ID) );
       
  1540 		do_action( 'delete_postmeta', $mid );
       
  1541 		$wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE meta_id =  %d", $mid) );
       
  1542 		do_action( 'deleted_postmeta', $mid );
       
  1543 		do_enclose($enclosure->post_content, $enclosure->ID);
       
  1544 	}
       
  1545 
       
  1546 	// Do Trackbacks
       
  1547 	$trackbacks = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'");
       
  1548 	if ( is_array($trackbacks) )
       
  1549 		foreach ( $trackbacks as $trackback )
       
  1550 			do_trackbacks($trackback);
       
  1551 
       
  1552 	//Do Update Services/Generic Pings
       
  1553 	generic_ping();
       
  1554 }
       
  1555 
       
  1556 /**
       
  1557  * Perform trackbacks.
       
  1558  *
       
  1559  * @since 1.5.0
       
  1560  * @uses $wpdb
       
  1561  *
       
  1562  * @param int $post_id Post ID to do trackbacks on.
       
  1563  */
       
  1564 function do_trackbacks($post_id) {
       
  1565 	global $wpdb;
       
  1566 
       
  1567 	$post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) );
       
  1568 	$to_ping = get_to_ping($post_id);
       
  1569 	$pinged  = get_pung($post_id);
       
  1570 	if ( empty($to_ping) ) {
       
  1571 		$wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
       
  1572 		return;
       
  1573 	}
       
  1574 
       
  1575 	if ( empty($post->post_excerpt) )
       
  1576 		$excerpt = apply_filters('the_content', $post->post_content);
       
  1577 	else
       
  1578 		$excerpt = apply_filters('the_excerpt', $post->post_excerpt);
       
  1579 	$excerpt = str_replace(']]>', ']]&gt;', $excerpt);
       
  1580 	$excerpt = wp_html_excerpt($excerpt, 252) . '...';
       
  1581 
       
  1582 	$post_title = apply_filters('the_title', $post->post_title);
       
  1583 	$post_title = strip_tags($post_title);
       
  1584 
       
  1585 	if ( $to_ping ) {
       
  1586 		foreach ( (array) $to_ping as $tb_ping ) {
       
  1587 			$tb_ping = trim($tb_ping);
       
  1588 			if ( !in_array($tb_ping, $pinged) ) {
       
  1589 				trackback($tb_ping, $post_title, $excerpt, $post_id);
       
  1590 				$pinged[] = $tb_ping;
       
  1591 			} else {
       
  1592 				$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_ping', '')) WHERE ID = %d", $post_id) );
       
  1593 			}
       
  1594 		}
       
  1595 	}
       
  1596 }
       
  1597 
       
  1598 /**
       
  1599  * Sends pings to all of the ping site services.
       
  1600  *
       
  1601  * @since 1.2.0
       
  1602  *
       
  1603  * @param int $post_id Post ID. Not actually used.
       
  1604  * @return int Same as Post ID from parameter
       
  1605  */
       
  1606 function generic_ping($post_id = 0) {
       
  1607 	$services = get_option('ping_sites');
       
  1608 
       
  1609 	$services = explode("\n", $services);
       
  1610 	foreach ( (array) $services as $service ) {
       
  1611 		$service = trim($service);
       
  1612 		if ( '' != $service )
       
  1613 			weblog_ping($service);
       
  1614 	}
       
  1615 
       
  1616 	return $post_id;
       
  1617 }
       
  1618 
       
  1619 /**
       
  1620  * Pings back the links found in a post.
       
  1621  *
       
  1622  * @since 0.71
       
  1623  * @uses $wp_version
       
  1624  * @uses IXR_Client
       
  1625  *
       
  1626  * @param string $content Post content to check for links.
       
  1627  * @param int $post_ID Post ID.
       
  1628  */
       
  1629 function pingback($content, $post_ID) {
       
  1630 	global $wp_version;
       
  1631 	include_once(ABSPATH . WPINC . '/class-IXR.php');
       
  1632 
       
  1633 	// original code by Mort (http://mort.mine.nu:8080)
       
  1634 	$post_links = array();
       
  1635 
       
  1636 	$pung = get_pung($post_ID);
       
  1637 
       
  1638 	// Variables
       
  1639 	$ltrs = '\w';
       
  1640 	$gunk = '/#~:.?+=&%@!\-';
       
  1641 	$punc = '.:?\-';
       
  1642 	$any = $ltrs . $gunk . $punc;
       
  1643 
       
  1644 	// Step 1
       
  1645 	// Parsing the post, external links (if any) are stored in the $post_links array
       
  1646 	// This regexp comes straight from phpfreaks.com
       
  1647 	// http://www.phpfreaks.com/quickcode/Extract_All_URLs_on_a_Page/15.php
       
  1648 	preg_match_all("{\b http : [$any] +? (?= [$punc] * [^$any] | $)}x", $content, $post_links_temp);
       
  1649 
       
  1650 	// Step 2.
       
  1651 	// Walking thru the links array
       
  1652 	// first we get rid of links pointing to sites, not to specific files
       
  1653 	// Example:
       
  1654 	// http://dummy-weblog.org
       
  1655 	// http://dummy-weblog.org/
       
  1656 	// http://dummy-weblog.org/post.php
       
  1657 	// We don't wanna ping first and second types, even if they have a valid <link/>
       
  1658 
       
  1659 	foreach ( (array) $post_links_temp[0] as $link_test ) :
       
  1660 		if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
       
  1661 				&& !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
       
  1662 			if ( $test = @parse_url($link_test) ) {
       
  1663 				if ( isset($test['query']) )
       
  1664 					$post_links[] = $link_test;
       
  1665 				elseif ( ($test['path'] != '/') && ($test['path'] != '') )
       
  1666 					$post_links[] = $link_test;
       
  1667 			}
       
  1668 		endif;
       
  1669 	endforeach;
       
  1670 
       
  1671 	do_action_ref_array('pre_ping', array(&$post_links, &$pung));
       
  1672 
       
  1673 	foreach ( (array) $post_links as $pagelinkedto ) {
       
  1674 		$pingback_server_url = discover_pingback_server_uri($pagelinkedto, 2048);
       
  1675 
       
  1676 		if ( $pingback_server_url ) {
       
  1677 			@ set_time_limit( 60 );
       
  1678 			 // Now, the RPC call
       
  1679 			$pagelinkedfrom = get_permalink($post_ID);
       
  1680 
       
  1681 			// using a timeout of 3 seconds should be enough to cover slow servers
       
  1682 			$client = new IXR_Client($pingback_server_url);
       
  1683 			$client->timeout = 3;
       
  1684 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom);
       
  1685 			// when set to true, this outputs debug messages by itself
       
  1686 			$client->debug = false;
       
  1687 
       
  1688 			if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
       
  1689 				add_ping( $post_ID, $pagelinkedto );
       
  1690 		}
       
  1691 	}
       
  1692 }
       
  1693 
       
  1694 /**
       
  1695  * Check whether blog is public before returning sites.
       
  1696  *
       
  1697  * @since 2.1.0
       
  1698  *
       
  1699  * @param mixed $sites Will return if blog is public, will not return if not public.
       
  1700  * @return mixed Empty string if blog is not public, returns $sites, if site is public.
       
  1701  */
       
  1702 function privacy_ping_filter($sites) {
       
  1703 	if ( '0' != get_option('blog_public') )
       
  1704 		return $sites;
       
  1705 	else
       
  1706 		return '';
       
  1707 }
       
  1708 
       
  1709 /**
       
  1710  * Send a Trackback.
       
  1711  *
       
  1712  * Updates database when sending trackback to prevent duplicates.
       
  1713  *
       
  1714  * @since 0.71
       
  1715  * @uses $wpdb
       
  1716  *
       
  1717  * @param string $trackback_url URL to send trackbacks.
       
  1718  * @param string $title Title of post.
       
  1719  * @param string $excerpt Excerpt of post.
       
  1720  * @param int $ID Post ID.
       
  1721  * @return mixed Database query from update.
       
  1722  */
       
  1723 function trackback($trackback_url, $title, $excerpt, $ID) {
       
  1724 	global $wpdb;
       
  1725 
       
  1726 	if ( empty($trackback_url) )
       
  1727 		return;
       
  1728 
       
  1729 	$options = array();
       
  1730 	$options['timeout'] = 4;
       
  1731 	$options['body'] = array(
       
  1732 		'title' => $title,
       
  1733 		'url' => get_permalink($ID),
       
  1734 		'blog_name' => get_option('blogname'),
       
  1735 		'excerpt' => $excerpt
       
  1736 	);
       
  1737 
       
  1738 	$response = wp_remote_post($trackback_url, $options);
       
  1739 
       
  1740 	if ( is_wp_error( $response ) )
       
  1741 		return;
       
  1742 
       
  1743 	$tb_url = addslashes( $trackback_url );
       
  1744 	$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', '$tb_url') WHERE ID = %d", $ID) );
       
  1745 	return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_url', '')) WHERE ID = %d", $ID) );
       
  1746 }
       
  1747 
       
  1748 /**
       
  1749  * Send a pingback.
       
  1750  *
       
  1751  * @since 1.2.0
       
  1752  * @uses $wp_version
       
  1753  * @uses IXR_Client
       
  1754  *
       
  1755  * @param string $server Host of blog to connect to.
       
  1756  * @param string $path Path to send the ping.
       
  1757  */
       
  1758 function weblog_ping($server = '', $path = '') {
       
  1759 	global $wp_version;
       
  1760 	include_once(ABSPATH . WPINC . '/class-IXR.php');
       
  1761 
       
  1762 	// using a timeout of 3 seconds should be enough to cover slow servers
       
  1763 	$client = new IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
       
  1764 	$client->timeout = 3;
       
  1765 	$client->useragent .= ' -- WordPress/'.$wp_version;
       
  1766 
       
  1767 	// when set to true, this outputs debug messages by itself
       
  1768 	$client->debug = false;
       
  1769 	$home = trailingslashit( get_option('home') );
       
  1770 	if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
       
  1771 		$client->query('weblogUpdates.ping', get_option('blogname'), $home);
       
  1772 }
       
  1773 
       
  1774 //
       
  1775 // Cache
       
  1776 //
       
  1777 
       
  1778 /**
       
  1779  * Removes comment ID from the comment cache.
       
  1780  *
       
  1781  * @since 2.3.0
       
  1782  * @package WordPress
       
  1783  * @subpackage Cache
       
  1784  *
       
  1785  * @param int|array $id Comment ID or array of comment IDs to remove from cache
       
  1786  */
       
  1787 function clean_comment_cache($ids) {
       
  1788 	foreach ( (array) $ids as $id )
       
  1789 		wp_cache_delete($id, 'comment');
       
  1790 }
       
  1791 
       
  1792 /**
       
  1793  * Updates the comment cache of given comments.
       
  1794  *
       
  1795  * Will add the comments in $comments to the cache. If comment ID already exists
       
  1796  * in the comment cache then it will not be updated. The comment is added to the
       
  1797  * cache using the comment group with the key using the ID of the comments.
       
  1798  *
       
  1799  * @since 2.3.0
       
  1800  * @package WordPress
       
  1801  * @subpackage Cache
       
  1802  *
       
  1803  * @param array $comments Array of comment row objects
       
  1804  */
       
  1805 function update_comment_cache($comments) {
       
  1806 	foreach ( (array) $comments as $comment )
       
  1807 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
  1808 }
       
  1809 
       
  1810 //
       
  1811 // Internal
       
  1812 //
       
  1813 
       
  1814 /**
       
  1815  * Close comments on old posts on the fly, without any extra DB queries.  Hooked to the_posts.
       
  1816  *
       
  1817  * @access private
       
  1818  * @since 2.7.0
       
  1819  *
       
  1820  * @param object $posts Post data object.
       
  1821  * @return object
       
  1822  */
       
  1823 function _close_comments_for_old_posts( $posts ) {
       
  1824 	if ( empty($posts) || !is_singular() || !get_option('close_comments_for_old_posts') )
       
  1825 		return $posts;
       
  1826 
       
  1827 	$days_old = (int) get_option('close_comments_days_old');
       
  1828 	if ( !$days_old )
       
  1829 		return $posts;
       
  1830 
       
  1831 	if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * 24 * 60 * 60 ) ) {
       
  1832 		$posts[0]->comment_status = 'closed';
       
  1833 		$posts[0]->ping_status = 'closed';
       
  1834 	}
       
  1835 
       
  1836 	return $posts;
       
  1837 }
       
  1838 
       
  1839 /**
       
  1840  * Close comments on an old post.  Hooked to comments_open and pings_open.
       
  1841  *
       
  1842  * @access private
       
  1843  * @since 2.7.0
       
  1844  *
       
  1845  * @param bool $open Comments open or closed
       
  1846  * @param int $post_id Post ID
       
  1847  * @return bool $open
       
  1848  */
       
  1849 function _close_comments_for_old_post( $open, $post_id ) {
       
  1850 	if ( ! $open )
       
  1851 		return $open;
       
  1852 
       
  1853 	if ( !get_option('close_comments_for_old_posts') )
       
  1854 		return $open;
       
  1855 
       
  1856 	$days_old = (int) get_option('close_comments_days_old');
       
  1857 	if ( !$days_old )
       
  1858 		return $open;
       
  1859 
       
  1860 	$post = get_post($post_id);
       
  1861 
       
  1862 	if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * 24 * 60 * 60 ) )
       
  1863 		return false;
       
  1864 
       
  1865 	return $open;
       
  1866 }
       
  1867 
       
  1868 ?>