wp_xmlrpc_server::pingback_ping( array $args )
Retrieves a pingback and registers it.
Parameters
- $args
-
(Required) Method arguments. Note: arguments must be ordered as documented.
- 'pagelinkedfrom'
(string) - 'pagelinkedto'
(string)
- 'pagelinkedfrom'
Return
(string|IXR_Error)
Source
File: wp-includes/class-wp-xmlrpc-server.php
public function pingback_ping( $args ) {
global $wpdb;
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
do_action( 'xmlrpc_call', 'pingback.ping' );
$this->escape( $args );
$pagelinkedfrom = str_replace( '&', '&', $args[0] );
$pagelinkedto = str_replace( '&', '&', $args[1] );
$pagelinkedto = str_replace( '&', '&', $pagelinkedto );
/**
* Filters the pingback source URI.
*
* @since WP-3.6.0
*
* @param string $pagelinkedfrom URI of the page linked from.
* @param string $pagelinkedto URI of the page linked to.
*/
$pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto );
if ( ! $pagelinkedfrom )
return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) );
// Check if the page linked to is in our site
$pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
if ( !$pos1 )
return $this->pingback_error( 0, __( 'Is there no link to us?' ) );
// let's find which post is linked to
// FIXME: does url_to_postid() cover all these cases already?
// if so, then let's use it and drop the old code.
$urltest = parse_url($pagelinkedto);
if ( $post_ID = url_to_postid($pagelinkedto) ) {
// $way
} elseif ( isset( $urltest['path'] ) && preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
// the path defines the post_ID (archives/p/XXXX)
$blah = explode('/', $match[0]);
$post_ID = (int) $blah[1];
} elseif ( isset( $urltest['query'] ) && preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
// the querystring defines the post_ID (?p=XXXX)
$blah = explode('=', $match[0]);
$post_ID = (int) $blah[1];
} elseif ( isset($urltest['fragment']) ) {
// an #anchor is there, it's either...
if ( intval($urltest['fragment']) ) {
// ...an integer #XXXX (simplest case)
$post_ID = (int) $urltest['fragment'];
} elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
// ...a post id in the form 'post-###'
$post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
} elseif ( is_string($urltest['fragment']) ) {
// ...or a string #title, a little more complicated
$title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
$sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title );
if (! ($post_ID = $wpdb->get_var($sql)) ) {
// returning unknown error '0' is better than die()ing
return $this->pingback_error( 0, '' );
}
}
} else {
// TODO: Attempt to extract a post ID from the given URL
return $this->pingback_error( 33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );
}
$post_ID = (int) $post_ID;
$post = get_post($post_ID);
if ( !$post ) // Post_ID not found
return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );
if ( $post_ID == url_to_postid($pagelinkedfrom) )
return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) );
// Check if pings are on
if ( !pings_open($post) )
return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );
// Let's check that the remote site didn't already pingback this entry
if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) );
// very stupid, but gives time to the 'from' server to publish !
sleep(1);
$remote_ip = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] );
$user_agent = classicpress_user_agent();
// Let's check the remote site
$http_api_args = array(
'timeout' => 10,
'redirection' => 0,
'limit_response_size' => 153600, // 150 KB
'user-agent' => "$user_agent; verifying pingback from $remote_ip",
'headers' => array(
'X-Pingback-Forwarded-For' => $remote_ip,
),
);
$request = wp_safe_remote_get( $pagelinkedfrom, $http_api_args );
$remote_source = $remote_source_original = wp_remote_retrieve_body( $request );
if ( ! $remote_source ) {
return $this->pingback_error( 16, __( 'The source URL does not exist.' ) );
}
/**
* Filters the pingback remote source.
*
* @since WP-2.5.0
*
* @param string $remote_source Response source for the page linked from.
* @param string $pagelinkedto URL of the page linked to.
*/
$remote_source = apply_filters( 'pre_remote_source', $remote_source, $pagelinkedto );
// Work around bug in strip_tags():
$remote_source = str_replace( '<!DOC', '<DOC', $remote_source );
$remote_source = preg_replace( '/[\r\n\t ]+/', ' ', $remote_source ); // normalize spaces
$remote_source = preg_replace( "/<\/*(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $remote_source );
preg_match( '|<title>([^<]*?)</title>|is', $remote_source, $matchtitle );
$title = isset( $matchtitle[1] ) ? $matchtitle[1] : '';
if ( empty( $title ) ) {
return $this->pingback_error( 32, __( 'We cannot find a title on that page.' ) );
}
$remote_source = strip_tags( $remote_source, '<a>' ); // just keep the tag we need
$p = explode( "\n\n", $remote_source );
$preg_target = preg_quote($pagelinkedto, '|');
foreach ( $p as $para ) {
if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
// If the URL isn't in a link context, keep looking
if ( empty($context) )
continue;
// We're going to use this fake tag to mark the context in a bit
// the marker is needed in case the link text appears more than once in the paragraph
$excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
// prevent really long link text
if ( strlen($context[1]) > 100 )
$context[1] = substr($context[1], 0, 100) . '…';
$marker = '<wpcontext>'.$context[1].'</wpcontext>'; // set up our marker
$excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
$excerpt = strip_tags($excerpt, '<wpcontext>'); // strip all tags but our context marker
$excerpt = trim($excerpt);
$preg_marker = preg_quote($marker, '|');
$excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
$excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
break;
}
}
if ( empty($context) ) // Link to target not found
return $this->pingback_error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) );
$pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
$context = '[…] ' . esc_html( $excerpt ) . ' […]';
$pagelinkedfrom = $this->escape( $pagelinkedfrom );
$comment_post_ID = (int) $post_ID;
$comment_author = $title;
$comment_author_email = '';
$this->escape($comment_author);
$comment_author_url = $pagelinkedfrom;
$comment_content = $context;
$this->escape($comment_content);
$comment_type = 'pingback';
$commentdata = compact(
'comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email',
'comment_content', 'comment_type', 'remote_source', 'remote_source_original'
);
$comment_ID = wp_new_comment($commentdata);
if ( is_wp_error( $comment_ID ) ) {
return $this->pingback_error( 0, $comment_ID->get_error_message() );
}
/**
* Fires after a post pingback has been sent.
*
* @since WP-0.71
*
* @param int $comment_ID Comment ID.
*/
do_action( 'pingback_post', $comment_ID );
/* translators: 1: URL of the page linked from, 2: URL of the page linked to */
return sprintf( __( 'Pingback from %1$s to %2$s registered. Keep the web talking! :-)' ), $pagelinkedfrom, $pagelinkedto );
}
Changelog
Version | Description |
---|---|
WP-1.5.0 | Introduced. |