(\d+)@', $resp, $matches)) { if ((int) $matches[1] === 0) { return true; } else { if (preg_match('@([^<]+)@', $resp, $matches)) { return $matches[1]; } else { return 'unknown error'; } } } return true; } /** * Perform a HTTP query for autodiscovering a pingback URL * * @access public * @param string (deprecated) The URL to try autodiscovery * @param string The response of the original URL * @return */ function serendipity_pingback_autodiscover($loc, $body) { global $serendipity; if (!empty($_SERVER['X-PINGBACK'])) { $pingback = $_SERVER['X-PINGBACK']; } elseif (preg_match('@@i', $body, $matches)) { $pingback = $matches[1]; } else { return; } // xml-rpc hack $query = " pingback.ping sourceURI {$serendipity['baseURL']} targetURI $loc "; _serendipity_send($pingback, $query); return; } /** * Send a track/pingback ping * * @access public * @param string The URL to send a trackback to * @param string The XML data with the trackback contents * @return string Reponse */ function _serendipity_send($loc, $data) { global $serendipity; $target = parse_url($loc); if ($target['query'] != '') { $target['query'] = '?' . str_replace('&', '&', $target['query']); } if (!is_numeric($target['port'])) { $target['port'] = 80; } $uri = $target['scheme'] . '://' . $target['host'] . ':' . $target['port'] . $target['path'] . $target['query']; require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; $options = array('allowRedirects' => true, 'maxRedirects' => 5, 'method' => 'POST'); serendipity_plugin_api::hook_event('backend_http_request', $options, 'trackback_send'); serendipity_request_start(); $req = &new HTTP_Request($uri, $options); $req->addRawPostData($data, true); $res = $req->sendRequest(); if (PEAR::isError($res)) { serendipity_request_end(); return false; } $fContent = $req->getResponseBody(); serendipity_request_end(); return $fContent; } /** * Autodiscover a trackback location URL * * @access public * @param string The HTML of the source URL * @param string The source URL * @param string The URL of our blog * @param string The author of our entry * @param string The title of our entry * @param string The text of our entry * @param string A comparsion URL * @return string Response */ function serendipity_trackback_autodiscover($res, $loc, $url, $author, $title, $text, $loc2 = '') { if (!preg_match('@trackback:ping(\s*rdf:resource)?\s*=\s*["\'](https?:[^"\']+)["\']@i', $res, $matches)) { $matches = array(); serendipity_plugin_api::hook_event('backend_trackback_check', $matches, $loc); // Plugins may say that a URI is valid, in situations where a blog has no valid RDF metadata if (empty($matches[2])) { echo '
• ' . sprintf(TRACKBACK_FAILED, TRACKBACK_NOT_FOUND) . '
'; return false; } } $trackURI = trim($matches[2]); if (preg_match('@dc:identifier\s*=\s*["\'](https?:[^\'"]+)["\']@i', $res, $test)) { if ($loc != $test[1] && $loc2 != $test[1]) { echo '
• ' . sprintf(TRACKBACK_FAILED, TRACKBACK_URI_MISMATCH) . '
'; return false; } } $data = 'url=' . rawurlencode($url) . '&title=' . rawurlencode($title) . '&blog_name=' . rawurlencode($author) . '&excerpt=' . rawurlencode(strip_tags($text)); printf(TRACKBACK_SENDING, htmlspecialchars($trackURI)); flush(); $response = serendipity_trackback_is_success(_serendipity_send($trackURI, $data)); if ($response === true) { echo '
• ' . TRACKBACK_SENT .'
'; } else { echo '
• ' . sprintf(TRACKBACK_FAILED, $response) . '
'; } return $response; } /** * Open a URL and autodetect contained ping/trackback locations * * @access public * @param string The URL to autodetect/try * @param string The URL to our blog * @param string The author of our entry * @param string The title of our entry * @param string The body of our entry * @return null */ function serendipity_reference_autodiscover($loc, $url, $author, $title, $text) { global $serendipity; $timeout = 30; $u = parse_url($loc); if ($u['scheme'] != 'http' && $u['scheme'] != 'https') { return; } elseif ($u['scheme'] == 'https' && !extension_loaded('openssl')) { return; // Trackbacks to HTTPS URLs can only be performed with openssl activated } echo '
• '. sprintf(TRACKBACK_CHECKING, $loc) .'
'; flush(); if (empty($u['port'])) { $u['port'] = 80; $port = ''; } else { $port = ':' . $u['port']; } if (!empty($u['query'])) { $u['path'] .= '?' . $u['query']; } $parsed_loc = $u['scheme'] . '://' . $u['host'] . $port . $u['path']; if (preg_match('@\.(jpe?g|aiff?|gif|png|pdf|doc|rtf|wave?|mp2|mp4|mpe?g3|mpe?g4|divx|xvid|bz2|mpe?g|avi|mp3|xl?|ppt|pps|xslt?|xsd|zip|tar|t?gz|swf|rm|ram?|exe|mov|qt|midi?|qcp|emf|wmf|snd|pmg|w?bmp|gcd|mms|ogg|ogm|rv|wmv|wma|jad|3g?|jar)$@i', $u['path'])) { echo '
• ' . TRACKBACK_NO_DATA . '
'; return; } require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; $options = array('allowRedirects' => true, 'maxRedirects' => 5, 'method' => 'GET'); serendipity_plugin_api::hook_event('backend_http_request', $options, 'trackback_detect'); serendipity_request_start(); $req = &new HTTP_Request($parsed_loc, $options); $res = $req->sendRequest(); if (PEAR::isError($res)) { echo '
• ' . sprintf(TRACKBACK_COULD_NOT_CONNECT, $u['host'], $u['port']) .'
'; serendipity_request_end(); return; } $fContent = $req->getResponseBody(); serendipity_request_end(); if (strlen($fContent) != 0) { serendipity_trackback_autodiscover($fContent, $parsed_loc, $url, $author, $title, $text, $loc); serendipity_pingback_autodiscover($loc, $fContent); } else { echo '
• ' . TRACKBACK_NO_DATA . '
'; } echo '
'; } /** * Receive a trackback * * @access public * @param int The ID of our entry * @param string The title of the foreign blog * @param string The URL of the foreign blog * @param string The name of the foreign blog * @param string The excerpt text of the foreign blog * @return true */ function add_trackback ($id, $title, $url, $name, $excerpt) { global $serendipity; // We can't accept a trackback if we don't get any URL // This is a protocol rule. if (empty($url)) { return 0; } // If title is not provided, the value for url will be set as the title // This is a protocol rule. if (empty($title)) { $title = $url; } $comment = array( 'title' => $title, 'url' => $url, 'name' => $name, 'comment' => $excerpt ); $is_utf8 = strtolower(LANG_CHARSET) == 'utf-8'; if ($GLOBALS['tb_logging']) { $fp = fopen('trackback2.log', 'a'); fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK TRANSCODING CHECK' . "\n"); } foreach($comment AS $idx => $field) { if (is_utf8($field)) { // Trackback is in UTF-8. Check if our blog also is UTF-8. if (!$is_utf8) { if ($GLOBALS['tb_logging']) { fwrite($fp, '[' . date('d.m.Y H:i') . '] Transcoding ' . $idx . ' from UTF-8 to ISO' . "\n"); } $comment[$idx] = utf8_decode($field); } } else { // Trackback is in some native format. We assume ISO-8859-1. Check if our blog is also ISO. if ($is_utf8) { if ($GLOBALS['tb_logging']) { fwrite($fp, '[' . date('d.m.Y H:i') . '] Transcoding ' . $idx . ' from ISO to UTF-8' . "\n"); } $comment[$idx] = utf8_encode($field); } } } if ($GLOBALS['tb_logging']) { fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK DATA: ' . print_r($comment, true) . '...' . "\n"); fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK STORING...' . "\n"); fclose($fp); } serendipity_saveComment($id, $comment, 'TRACKBACK'); return 1; } /** * Receive a pingback * * @access public * @param int The entryid to receive a pingback for * @param string The foreign postdata to add * @return boolean */ function add_pingback ($id, $postdata) { global $serendipity; if(preg_match('@\s*\s*pingback.ping\s*\s*\s*\s*\s*([^<])*\s*\s*\s*\s*\s*([^<])*\s*\s*\s*\s*@i', $postdata, $matches)) { $remote = $matches[1]; $local = $matches[2]; $comment['title'] = ''; $comment['url'] = $remote; $comment['comment'] = ''; $comment['name'] = ''; serendipity_saveComment($id, $comment, 'PINGBACK'); return 1; } return 0; } /** * Create an excerpt for a trackback to send * * @access public * @param string Input text * @return string Output text */ function serendipity_trackback_excerpt($text) { return serendipity_mb('substr', strip_tags($text), 0, 255); } /** * Report success of a trackback * * @access public */ function report_trackback_success () { print '' . "\n"; print << 0 SUCCESS; } /** * Report failure of a trackback * * @access public */ function report_trackback_failure () { print '' . "\n"; print << 1 Danger Will Robinson, trackback failed. FAILURE; } /** * Return success of a pingback * * @access public */ function report_pingback_success () { print '' . "\n"; print << success SUCCESS; } /** * Return failure of a pingback * * @access public */ function report_pingback_failure () { print '' . "\n"; print << 0 FAILURE; } /** * Search through link body, and automagically send a trackback ping. * * This is the trackback starter function that searches your text and sees if any * trackback URLs are in there * * @access public * @param int The ID of our entry * @param string The author of our entry * @param string The title of our entry * @param string The text of our entry * @return */ function serendipity_handle_references($id, $author, $title, $text) { global $serendipity; if (!preg_match_all('@]+?href\s*=\s*["\']?([^\'" >]+?)[ \'"][^>]*>(.+?)@i', $text, $matches)) { $matches = array(0 => array(), 1 => array()); } else { // remove full matches array_shift($matches); } // Make trackback URL $url = serendipity_archiveURL($id, $title, 'baseURL'); // Add URL references $locations = $matches[0]; $names = $matches[1]; $tmpid = serendipity_db_escape_string($id); $checked_locations = array(); serendipity_plugin_api::hook_event('backend_trackbacks', $locations); for ($i = 0, $j = count($locations); $i < $j; ++$i) { if ($locations[$i][0] == '/') { $locations[$i] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off' ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $locations[$i]; } if (isset($checked_locations[$locations[$i]])) { continue; } if (preg_match_all('@]+?alt=["\']?([^\'">]+?)[\'"][^>]+?>@i', $names[$i], $img_alt)) { if (is_array($img_alt) && is_array($img_alt[0])) { foreach($img_alt[0] as $alt_idx => $alt_img) { // Replace all s within a link with their respective ALT tag, so that references // can be stored with a title. $names[$i] = str_replace($alt_img, $img_alt[1][$alt_idx], $names[$i]); } } } $query = "SELECT COUNT(id) FROM {$serendipity['dbPrefix']}references WHERE entry_id = '". (int)$tmpid ."' AND link = '" . serendipity_db_escape_string($locations[$i]) . "' AND type = ''"; $row = serendipity_db_query($query, true, 'num'); if ($row[0] > 0) { continue; } if (!isset($serendipity['noautodiscovery']) || !$serendipity['noautodiscovery']) { serendipity_reference_autodiscover($locations[$i], $url, $author, $title, serendipity_trackback_excerpt($text)); $checked_locations[$locations[$i]] = true; // Store trackbacked link so that no further trackbacks will be sent to the same link } } serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}references WHERE entry_id='" . (int)$tmpid . "' AND type = ''"); for ($i = 0; $i < $j; ++$i) { $query = "INSERT INTO {$serendipity['dbPrefix']}references (entry_id, name, link) VALUES("; $query .= "'" . (int)$tmpid . "', '" . serendipity_db_escape_string(strip_tags($names[$i])) . "', '"; $query .= serendipity_db_escape_string($locations[$i]) . "')"; serendipity_db_query($query); } // Add citations preg_match_all('@]*>([^<]+)@i', $text, $matches); foreach ($matches[1] as $citation) { $query = "INSERT INTO {$serendipity['dbPrefix']}references (entry_id, name) VALUES("; $query .= "'" . (int)$tmpid . "', '" . serendipity_db_escape_string($citation) . "')"; serendipity_db_query($query); } } /** * Check if a string is in UTF-8 format. * * @access public * @param string The string to check * @return bool */ function is_utf8($string) { // From http://w3.org/International/questions/qa-forms-utf-8.html return preg_match('%^(?:' . '[\x09\x0A\x0D\x20-\x7E]' # ASCII . '|[\xC2-\xDF][\x80-\xBF]' # non-overlong 2-byte . '|\xE0[\xA0-\xBF][\x80-\xBF]' # excluding overlongs . '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}' # straight 3-byte . '|\xED[\x80-\x9F][\x80-\xBF]' # excluding surrogates . '|\xF0[\x90-\xBF][\x80-\xBF]{2}' # planes 1-3 . '|[\xF1-\xF3][\x80-\xBF]{3}' # planes 4-15 . '|\xF4[\x80-\x8F][\x80-\xBF]{2}' # plane 16 . ')*$%xs', $string); }