| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
function trackback_page($node) {
|
| 5 |
$output[] = '<?xml version="1.0" encoding="utf-8"?>';
|
| 6 |
$output[] = '<response>';
|
| 7 |
|
| 8 |
$trackback = trackback_receive($node);
|
| 9 |
if (empty($trackback->error)) {
|
| 10 |
db_query("INSERT INTO {trackback_received} (nid, created, site, name, subject, url, excerpt, status) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $trackback->nid, $trackback->created, $trackback->site, $trackback->name, $trackback->subject, $trackback->url, $trackback->excerpt, $trackback->status);
|
| 11 |
$trackback->trid = db_last_insert_id('trackback_received', 'trid');
|
| 12 |
trackback_invoke_trackback($trackback, 'insert');
|
| 13 |
watchdog('trackback', 'Added trackback %subject.', array('%subject' => $trackback->subject), WATCHDOG_NOTICE, _trackback_path($trackback, t('view')));
|
| 14 |
$output[] = '<error>0</error>';
|
| 15 |
}
|
| 16 |
else {
|
| 17 |
$output[] = '<error>1</error>';
|
| 18 |
$output[] = '<message>'. $trackback->error .'</message>';
|
| 19 |
}
|
| 20 |
$output[] = '</response>';
|
| 21 |
|
| 22 |
header('Content-Type: text/xml');
|
| 23 |
print implode("\n", $output) ."\n";
|
| 24 |
}
|
| 25 |
|
| 26 |
function trackback_receive($node) {
|
| 27 |
$trackback = new stdClass();
|
| 28 |
if (empty($_REQUEST['url']) || !_trackback_valid_url($_REQUEST['url'])) {
|
| 29 |
$trackback->error = t('Missing TrackBack url.');
|
| 30 |
}
|
| 31 |
elseif (variable_get('trackback_reject_oneway', 0)) {
|
| 32 |
$reply = drupal_http_request($_REQUEST['url']);
|
| 33 |
if (!empty($reply->error)) {
|
| 34 |
$trackback->error = t('Could not retrieve the sender page.');
|
| 35 |
}
|
| 36 |
elseif (stristr($reply->data, $GLOBALS['base_url'] .'/') === FALSE) {
|
| 37 |
$trackback->error = t('The sender page does not refer to recipient site.');
|
| 38 |
}
|
| 39 |
}
|
| 40 |
|
| 41 |
if (empty($trackback->error)) {
|
| 42 |
$trackback->nid = $node->nid;
|
| 43 |
$trackback->created = time();
|
| 44 |
$trackback->site = ip_address();
|
| 45 |
|
| 46 |
list($name, $subject, $excerpt) = _trackback_optional_params('blog_name', 'title', 'excerpt');
|
| 47 |
$trackback->name = strip_tags($name ? $name : $_REQUEST['url']);
|
| 48 |
$trackback->subject = $subject ? $subject : $_REQUEST['url'];
|
| 49 |
$trackback->url = $_REQUEST['url'];
|
| 50 |
$trackback->excerpt = strlen($excerpt) > 255 ? truncate_utf8($excerpt, 252) .'...' : $excerpt;
|
| 51 |
$trackback->status = (variable_get('trackback_moderation', 0) == 0) ? 1 : 0;
|
| 52 |
|
| 53 |
trackback_invoke_trackback($trackback, 'receive');
|
| 54 |
}
|
| 55 |
return $trackback;
|
| 56 |
}
|
| 57 |
|
| 58 |
function _trackback_optional_params() {
|
| 59 |
$args = func_get_args();
|
| 60 |
foreach ($args as $i) {
|
| 61 |
$params[] = isset($_REQUEST[$i]) ? $_REQUEST[$i] : '';
|
| 62 |
}
|
| 63 |
if (preg_match('/;\s*charset=([^\s;]+)/i', $_SERVER['CONTENT_TYPE'], $match)) {
|
| 64 |
$charset = $match[1];
|
| 65 |
}
|
| 66 |
else {
|
| 67 |
$utf8 = '/^(?:[\s\x21-\x7F]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}|[\xF8-\xFB][\x80-\xBF]{4}|[\xFC-\xFD][\x80-\xBF]{5})*$/';
|
| 68 |
$sample = implode(' ', $params);
|
| 69 |
if (!preg_match($utf8, $sample)) {
|
| 70 |
global $locale;
|
| 71 |
$defaults = array(
|
| 72 |
'be' => 5, 'cs' => 2, 'el' => 7, 'hr' => 2, 'hu' => 2, 'pl' => 2,
|
| 73 |
'ro' => 2, 'ru' => 5, 'sk' => 2, 'sl' => 2, 'tr' => 9, 'uk' => 5,
|
| 74 |
'ja' => array('ISO-2022-JP', 'EUC-JP', 'SJIS'),
|
| 75 |
'ko' => array('ISO-2022-KR', 'EUC-KR'),
|
| 76 |
'zh-hans' => array('HZ', 'EUC-CN'),
|
| 77 |
'zh-hant' => array('BIG-5', 'EUC-TW')
|
| 78 |
);
|
| 79 |
if ($charset = $defaults[$locale] and is_array($charset)) {
|
| 80 |
if (function_exists('mb_detect_encoding')) {
|
| 81 |
$charset = @mb_detect_encoding($sample, $charset);
|
| 82 |
}
|
| 83 |
else {
|
| 84 |
foreach ($charset as $charset) {
|
| 85 |
if (drupal_convert_to_utf8($sample, $charset) != '') break;
|
| 86 |
$charset = NULL;
|
| 87 |
}
|
| 88 |
}
|
| 89 |
}
|
| 90 |
if (!$charset) {
|
| 91 |
$charset = 'ISO-8859-1'; // or 'ISO-8859-15'
|
| 92 |
}
|
| 93 |
elseif (!is_string($charset)) {
|
| 94 |
$charset = 'ISO-8859-'. $charset;
|
| 95 |
}
|
| 96 |
}
|
| 97 |
}
|
| 98 |
if ($charset && strcasecmp($charset, 'UTF-8') != 0) {
|
| 99 |
foreach ($params as $i => $t) {
|
| 100 |
if ($t != '') {
|
| 101 |
$t = drupal_convert_to_utf8($t, $charset);
|
| 102 |
if ($t != '') {
|
| 103 |
$params[$i] = $t;
|
| 104 |
}
|
| 105 |
}
|
| 106 |
}
|
| 107 |
}
|
| 108 |
return $params;
|
| 109 |
}
|
| 110 |
|
| 111 |
function _trackback_send($node) {
|
| 112 |
$urls = array();
|
| 113 |
if (!empty($node->trackback_urls)) {
|
| 114 |
foreach (explode("\n", $node->trackback_urls) as $url) {
|
| 115 |
if ($url = trim($url)) {
|
| 116 |
$urls[$url] = TRUE;
|
| 117 |
}
|
| 118 |
}
|
| 119 |
}
|
| 120 |
if ($node->status && variable_get('trackback_auto_detection_enabled', 0) == 1) {
|
| 121 |
$urls += trackback_urls_via_nodebody($node);
|
| 122 |
}
|
| 123 |
$retry = array();
|
| 124 |
if (isset($node->trackback_urls_to_retry)) {
|
| 125 |
$retry = array_diff($node->trackback_urls_to_retry, array(0));
|
| 126 |
}
|
| 127 |
_trackback_ping($node, $urls, $retry);
|
| 128 |
}
|
| 129 |
|
| 130 |
function trackback_urls_via_nodebody($node) {
|
| 131 |
$trackback_urls = array();
|
| 132 |
|
| 133 |
// First, grab anything that looks like a url from the body of the node.
|
| 134 |
$node = node_build_content($node);
|
| 135 |
$content = drupal_render($node->content);
|
| 136 |
$pattern = '((?:http|https)://[a-z0-9;/?:@&=+#$,_.!~*()%-]+)';
|
| 137 |
|
| 138 |
if (variable_get('trackback_link_only', 0)) {
|
| 139 |
$content = strip_tags($content, '<a>'); // remove comment.
|
| 140 |
$pattern = '<a\s+[^>]*href\s*=\s*(?:"|\')'. $pattern;
|
| 141 |
}
|
| 142 |
|
| 143 |
if (preg_match_all('`'. $pattern .'`i', $content, $parsed_urls)) {
|
| 144 |
$parsed_urls = array_unique($parsed_urls[1]);
|
| 145 |
foreach ($parsed_urls as $url) {
|
| 146 |
|
| 147 |
// Now, send http HEAD requests so we can see if the content type is something that *might* contain autodetection text.
|
| 148 |
// In other words, check if Content-Type of each URL is text based rather than digital.
|
| 149 |
$url = html_entity_decode($url, ENT_QUOTES);
|
| 150 |
if (_trackback_url_parsable_content($url)) {
|
| 151 |
|
| 152 |
//Finally, download each page, scan each, and compile a list of all the trackback URLs listed in the first RDF of each scanned page.
|
| 153 |
$reply = drupal_http_request($url);
|
| 154 |
if (empty($reply->error)) {
|
| 155 |
$url = preg_replace('/.*<rdf:RDF.*trackback:ping="([^"]+)".*<\/rdf:RDF>.*/s', '\1', $reply->data);
|
| 156 |
if (_trackback_valid_url($url)) {
|
| 157 |
$trackback_urls[$url] = FALSE;
|
| 158 |
}
|
| 159 |
}
|
| 160 |
}
|
| 161 |
}
|
| 162 |
}
|
| 163 |
return $trackback_urls;
|
| 164 |
}
|
| 165 |
|
| 166 |
// Since autodetection might encounter a link to a media file, we first want to make a
|
| 167 |
// simple 'HEAD' HTTP request instead of an actual GET. This results in having to make
|
| 168 |
// an extra drupal_http_request() later for an actual GET, but it is worth it considering
|
| 169 |
// the strong likelihood that auto-detection may encounter a URL that links to a media file.
|
| 170 |
function _trackback_url_parsable_content($url) {
|
| 171 |
global $base_url;
|
| 172 |
|
| 173 |
if (!strstr($url, $base_url)) {
|
| 174 |
$http_reply = drupal_http_request($url, array(), 'HEAD');
|
| 175 |
$content_type = $http_reply->headers['Content-Type'];
|
| 176 |
|
| 177 |
return (substr_count($content_type, 'text/html') || substr_count($content_type, 'application/xhtml+xml') || substr_count($content_type, 'application/xml') || substr_count($content_type, 'text/xml'));
|
| 178 |
}
|
| 179 |
}
|
| 180 |
|
| 181 |
function _trackback_ping($node, $urls, $force = array()) {
|
| 182 |
if ($urls) {
|
| 183 |
$result = db_query('SELECT url FROM {trackback_sent} WHERE nid=%d', $node->nid);
|
| 184 |
while ($sent = db_fetch_object($result)) {
|
| 185 |
unset($urls[$sent->url]);
|
| 186 |
}
|
| 187 |
}
|
| 188 |
$urls += $force;
|
| 189 |
if ($urls) {
|
| 190 |
$node = node_build_content($node, TRUE);
|
| 191 |
$node->teaser = drupal_render($node->content);
|
| 192 |
$node->teaser = preg_replace(array('/<p\b/i', '/<div\b/i'), array("\n\$0", ' $0'), $node->teaser);
|
| 193 |
$params = array(
|
| 194 |
'title' => $node->title,
|
| 195 |
'excerpt' => truncate_utf8(trim(strip_tags($node->teaser)), 255),
|
| 196 |
'blog_name' => variable_get('site_name', ''),
|
| 197 |
'url' => url('node/'. $node->nid, array('absolute' => TRUE))
|
| 198 |
);
|
| 199 |
$query = array();
|
| 200 |
foreach ($params as $key => $value) {
|
| 201 |
$query[] = $key .'='. urlencode($value);
|
| 202 |
}
|
| 203 |
$query = implode('&', $query);
|
| 204 |
foreach ($urls as $url => $type) {
|
| 205 |
$reply = drupal_http_request($url, array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'), 'POST', $query);
|
| 206 |
$succ = 0;
|
| 207 |
if (empty($reply->error) && preg_match('|<error>([0-9]+)</error>|', $reply->data, $match)) {
|
| 208 |
$succ = $match[1] ? 0 : 1;
|
| 209 |
}
|
| 210 |
db_lock_table('trackback_sent');
|
| 211 |
db_query("UPDATE {trackback_sent} SET successful=%d WHERE nid=%d AND url='%s'", $succ, $node->nid, $url);
|
| 212 |
if (!db_affected_rows()) {
|
| 213 |
db_query("INSERT INTO {trackback_sent} (nid, url, successful) VALUES (%d, '%s', %d)", $node->nid, $url, $succ);
|
| 214 |
}
|
| 215 |
db_unlock_tables();
|
| 216 |
}
|
| 217 |
}
|
| 218 |
}
|