/svntrunk/bp-forums/bbpress/bb-includes/class.bb-pingbacks.php

https://bitbucket.org/simplemediacode/bptrunk · PHP · 204 lines · 190 code · 2 blank · 12 comment · 12 complexity · 0c330485a6b5fbc17d28a8d0632603ad MD5 · raw file

  1. <?php
  2. /**
  3. * bbPress class to handle pinging
  4. *
  5. * @package bbPress
  6. */
  7. class BB_Pingbacks
  8. {
  9. /**
  10. * Gets the Pingback endpoint URI provided by a web page specified by URL
  11. *
  12. * @return string|boolean Returns the Pingback endpoint URI if found or false
  13. */
  14. function get_endpoint_uri( $url )
  15. {
  16. // First check for an X-pingback header
  17. if ( !$response = wp_remote_head( $url ) ) {
  18. return false;
  19. }
  20. if ( !$content_type = wp_remote_retrieve_header( $response, 'content-type' ) ) {
  21. return false;
  22. }
  23. if ( preg_match( '#(image|audio|video|model)/#is', $content_type ) ) {
  24. return false;
  25. }
  26. if ( $x_pingback = wp_remote_retrieve_header( $response, 'x-pingback' ) ) {
  27. return trim( $x_pingback );
  28. }
  29. // Fall back to extracting it from the HTML link
  30. if ( !$response = wp_remote_get( $url ) ) {
  31. return false;
  32. }
  33. if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
  34. return false;
  35. }
  36. if ( '' === $response_body = wp_remote_retrieve_body( $response ) ) {
  37. return false;
  38. }
  39. if ( !preg_match_all( '@<link([^>]+)>@im', $response_body, $response_links ) ) {
  40. return false;
  41. }
  42. foreach ( $response_links[1] as $response_link_attributes ) {
  43. $_link = array( 'rel' => false, 'href' => false );
  44. $response_link_attributes = preg_split( '@\s+@im', $response_link_attributes, -1, PREG_SPLIT_NO_EMPTY );
  45. foreach ( $response_link_attributes as $response_link_attribute ) {
  46. if ( $_link['rel'] == 'pingback' && $_link['href'] ) {
  47. return $_link['href'];
  48. }
  49. if ( strpos( $response_link_attribute, '=', 1 ) !== false ) {
  50. list( $_key, $_value ) = explode( '=', $response_link_attribute, 2 );
  51. $_link[strtolower( $_key )] = trim( $_value, "'\"" );
  52. }
  53. }
  54. }
  55. // Fail
  56. return false;
  57. }
  58. /**
  59. * Sends all pingbacks and other ping like requests
  60. *
  61. * At the moment only sends normal pingbacks, but may be
  62. * expanded in the future.
  63. *
  64. * @return integer The number of pings sent
  65. */
  66. function send_all()
  67. {
  68. $pings = BB_Pingbacks::send_all_pingbacks();
  69. return $pings;
  70. }
  71. /**
  72. * Sends all pingbacks
  73. *
  74. * @return integer The number of pings sent
  75. */
  76. function send_all_pingbacks()
  77. {
  78. global $bbdb;
  79. $posts = $bbdb->get_results(
  80. "SELECT
  81. {$bbdb->posts}.post_id,
  82. {$bbdb->posts}.topic_id,
  83. {$bbdb->posts}.post_text
  84. FROM {$bbdb->posts}, {$bbdb->meta}
  85. WHERE {$bbdb->posts}.post_id = {$bbdb->meta}.object_id
  86. AND {$bbdb->meta}.object_type = 'bb_post'
  87. AND {$bbdb->meta}.meta_key = 'pingback_queued';"
  88. );
  89. $pings = 0;
  90. foreach ( $posts as $post ) {
  91. if ( $sent = BB_Pingbacks::send_pingback( $post->topic_id, $post->post_text ) ) {
  92. $pings += $sent;
  93. bb_delete_postmeta( $post->post_id, 'pingback_queued' );
  94. }
  95. }
  96. return $pings;
  97. }
  98. /**
  99. * Sends a single pingback if a link is found
  100. *
  101. * @return integer The number of pingbacks sent
  102. */
  103. function send_pingback( $topic_id, $post_text )
  104. {
  105. if ( !$topic_id || !$post_text ) {
  106. return 0;
  107. }
  108. // Get all links in the text and add them to an array
  109. if ( !preg_match_all( '@<a ([^>]+)>@im', make_clickable( $post_text ), $post_links ) ) {
  110. return 0;
  111. }
  112. $_links = array();
  113. foreach ( $post_links[1] as $post_link_attributes ) {
  114. $post_link_attributes = preg_split( '@\s+@im', $post_link_attributes, -1, PREG_SPLIT_NO_EMPTY );
  115. foreach ( $post_link_attributes as $post_link_attribute ) {
  116. if ( strpos( $post_link_attribute, '=', 1 ) !== false ) {
  117. list( $_key, $_value ) = explode( '=', $post_link_attribute, 2 );
  118. if ( strtolower( $_key ) === 'href' ) {
  119. $_links[] = trim( $_value, "'\"" );
  120. }
  121. }
  122. }
  123. }
  124. // Get pingbacks which have already been performed from this topic
  125. $past_pingbacks = bb_get_topicmeta( $topic_id, 'pingback_performed' );
  126. $new_pingbacks = array();
  127. foreach ( $_links as $_link ) {
  128. // If it's already been pingbacked, then skip it
  129. if ( $past_pingbacks && in_array( $_link, $past_pingbacks ) ) {
  130. continue;
  131. }
  132. // If it's trying to ping itself, then skip it
  133. if ( $topic = bb_get_topic_from_uri( $_link ) ) {
  134. if ( $topic->topic_id === $topic_id ) {
  135. continue;
  136. }
  137. }
  138. // Make sure it's a page on a site and not the root
  139. if ( !$_url = parse_url( $_link ) ) {
  140. continue;
  141. }
  142. if ( !isset( $_url['query'] ) ) {
  143. if ( $_url['path'] == '' || $_url['path'] == '/' ) {
  144. continue;
  145. }
  146. }
  147. // Add the URL to the array of those to be pingbacked
  148. $new_pingbacks[] = $_link;
  149. }
  150. include_once( BACKPRESS_PATH . '/class.ixr.php' );
  151. $count = 0;
  152. foreach ( $new_pingbacks as $pingback_to_url ) {
  153. if ( !$pingback_endpoint_uri = BB_Pingbacks::get_endpoint_uri( $pingback_to_url ) ) {
  154. continue;
  155. }
  156. // Stop this nonsense after 60 seconds
  157. @set_time_limit( 60 );
  158. // Get the URL to pingback from
  159. $pingback_from_url = get_topic_link( $topic_id );
  160. // Using a timeout of 3 seconds should be enough to cover slow servers
  161. $client = new IXR_Client( $pingback_endpoint_uri );
  162. $client->timeout = 3;
  163. $client->useragent .= ' -- bbPress/' . bb_get_option( 'version' );
  164. // When set to true, this outputs debug messages by itself
  165. $client->debug = false;
  166. // If successful or the ping already exists then add to the pingbacked list
  167. if (
  168. $client->query( 'pingback.ping', $pingback_from_url, $pingback_to_url ) ||
  169. ( isset( $client->error->code ) && 48 == $client->error->code )
  170. ) {
  171. $count++;
  172. $past_pingbacks[] = $pingback_to_url;
  173. }
  174. }
  175. bb_update_topicmeta( $topic_id, 'pingback_performed', $past_pingbacks );
  176. return $count;
  177. }
  178. } // END class BB_Pingbacks