| [ Index ] |
|
Code source de Serendipity 1.2 |
1 <?php # $Id: functions_trackbacks.inc.php 1747 2007-07-03 08:19:07Z garvinhicking $ 2 # Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team) 3 # All rights reserved. See LICENSE file for licensing details 4 5 if (IN_serendipity !== true) { 6 die ("Don't hack!"); 7 } 8 9 if (defined('S9Y_FRAMEWORK_TRACKBACKS')) { 10 return; 11 } 12 @define('S9Y_FRAMEWORK_TRACKBACKS', true); 13 14 /** 15 * Check a HTTP response if it is a valid XML trackback response 16 * 17 * @access public 18 * @param string HTTP Response string 19 * @return mixed Boolean or error message 20 */ 21 function serendipity_trackback_is_success($resp) { 22 if (preg_match('@<error>(\d+)</error>@', $resp, $matches)) { 23 if ((int) $matches[1] === 0) { 24 return true; 25 } else { 26 if (preg_match('@<message>([^<]+)</message>@', $resp, $matches)) { 27 return $matches[1]; 28 } 29 else { 30 return 'unknown error'; 31 } 32 } 33 } 34 return true; 35 } 36 37 /** 38 * Perform a HTTP query for autodiscovering a pingback URL 39 * 40 * @access public 41 * @param string (deprecated) The URL to try autodiscovery 42 * @param string The response of the original URL 43 * @return 44 */ 45 function serendipity_pingback_autodiscover($loc, $body) { 46 global $serendipity; 47 if (!empty($_SERVER['X-PINGBACK'])) { 48 $pingback = $_SERVER['X-PINGBACK']; 49 } elseif (preg_match('@<link rel="pingback" href="([^"]+)" ?/?>@i', $body, $matches)) { 50 $pingback = $matches[1]; 51 } else { 52 return; 53 } 54 55 // xml-rpc hack 56 $query = " 57 <?xml version=\"1.0\"?> 58 <methodCall> 59 <methodName>pingback.ping</methodName> 60 <params> 61 <param> 62 <name>sourceURI</name> 63 <value><string>{$serendipity['baseURL']}</string></value> 64 </param> 65 <param> 66 <name>targetURI</name> 67 <value><string>$loc</string></value> 68 </param> 69 </params> 70 </methodCall>"; 71 _serendipity_send($pingback, $query); 72 return; 73 } 74 75 /** 76 * Send a track/pingback ping 77 * 78 * @access public 79 * @param string The URL to send a trackback to 80 * @param string The XML data with the trackback contents 81 * @return string Reponse 82 */ 83 function _serendipity_send($loc, $data) { 84 global $serendipity; 85 86 $target = parse_url($loc); 87 if ($target['query'] != '') { 88 $target['query'] = '?' . str_replace('&', '&', $target['query']); 89 } 90 91 if (!is_numeric($target['port'])) { 92 $target['port'] = 80; 93 } 94 95 $uri = $target['scheme'] . '://' . $target['host'] . ':' . $target['port'] . $target['path'] . $target['query']; 96 require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; 97 $options = array('allowRedirects' => true, 'maxRedirects' => 5, 'method' => 'POST'); 98 serendipity_plugin_api::hook_event('backend_http_request', $options, 'trackback_send'); 99 serendipity_request_start(); 100 101 $req = &new HTTP_Request($uri, $options); 102 $req->addRawPostData($data, true); 103 $res = $req->sendRequest(); 104 105 if (PEAR::isError($res)) { 106 serendipity_request_end(); 107 return false; 108 } 109 110 $fContent = $req->getResponseBody(); 111 serendipity_request_end(); 112 return $fContent; 113 } 114 115 /** 116 * Autodiscover a trackback location URL 117 * 118 * @access public 119 * @param string The HTML of the source URL 120 * @param string The source URL 121 * @param string The URL of our blog 122 * @param string The author of our entry 123 * @param string The title of our entry 124 * @param string The text of our entry 125 * @param string A comparsion URL 126 127 * @return string Response 128 */ 129 function serendipity_trackback_autodiscover($res, $loc, $url, $author, $title, $text, $loc2 = '') { 130 if (!preg_match('@trackback:ping(\s*rdf:resource)?\s*=\s*["\'](https?:[^"\']+)["\']@i', $res, $matches)) { 131 $matches = array(); 132 serendipity_plugin_api::hook_event('backend_trackback_check', $matches, $loc); 133 134 // Plugins may say that a URI is valid, in situations where a blog has no valid RDF metadata 135 if (empty($matches[2])) { 136 echo '<div>• ' . sprintf(TRACKBACK_FAILED, TRACKBACK_NOT_FOUND) . '</div>'; 137 return false; 138 } 139 } 140 141 $trackURI = trim($matches[2]); 142 143 if (preg_match('@dc:identifier\s*=\s*["\'](https?:[^\'"]+)["\']@i', $res, $test)) { 144 if ($loc != $test[1] && $loc2 != $test[1]) { 145 echo '<div>• ' . sprintf(TRACKBACK_FAILED, TRACKBACK_URI_MISMATCH) . '</div>'; 146 return false; 147 } 148 } 149 150 $data = 'url=' . rawurlencode($url) 151 . '&title=' . rawurlencode($title) 152 . '&blog_name=' . rawurlencode($author) 153 . '&excerpt=' . rawurlencode(strip_tags($text)); 154 155 printf(TRACKBACK_SENDING, htmlspecialchars($trackURI)); 156 flush(); 157 158 $response = serendipity_trackback_is_success(_serendipity_send($trackURI, $data)); 159 160 if ($response === true) { 161 echo '<div>• ' . TRACKBACK_SENT .'</div>'; 162 } else { 163 echo '<div>• ' . sprintf(TRACKBACK_FAILED, $response) . '</div>'; 164 } 165 166 return $response; 167 } 168 169 /** 170 * Open a URL and autodetect contained ping/trackback locations 171 * 172 * @access public 173 * @param string The URL to autodetect/try 174 * @param string The URL to our blog 175 * @param string The author of our entry 176 * @param string The title of our entry 177 * @param string The body of our entry 178 * @return null 179 */ 180 function serendipity_reference_autodiscover($loc, $url, $author, $title, $text) { 181 global $serendipity; 182 $timeout = 30; 183 184 $u = parse_url($loc); 185 186 if ($u['scheme'] != 'http' && $u['scheme'] != 'https') { 187 return; 188 } elseif ($u['scheme'] == 'https' && !extension_loaded('openssl')) { 189 return; // Trackbacks to HTTPS URLs can only be performed with openssl activated 190 } 191 192 echo '<div>• '. sprintf(TRACKBACK_CHECKING, $loc) .'</div>'; 193 flush(); 194 195 if (empty($u['port'])) { 196 $u['port'] = 80; 197 $port = ''; 198 } else { 199 $port = ':' . $u['port']; 200 } 201 202 if (!empty($u['query'])) { 203 $u['path'] .= '?' . $u['query']; 204 } 205 206 $parsed_loc = $u['scheme'] . '://' . $u['host'] . $port . $u['path']; 207 208 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'])) { 209 echo '<div>• ' . TRACKBACK_NO_DATA . '</div>'; 210 return; 211 } 212 213 require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; 214 $options = array('allowRedirects' => true, 'maxRedirects' => 5, 'method' => 'GET'); 215 serendipity_plugin_api::hook_event('backend_http_request', $options, 'trackback_detect'); 216 serendipity_request_start(); 217 $req = &new HTTP_Request($parsed_loc, $options); 218 $res = $req->sendRequest(); 219 220 if (PEAR::isError($res)) { 221 echo '<div>• ' . sprintf(TRACKBACK_COULD_NOT_CONNECT, $u['host'], $u['port']) .'</div>'; 222 serendipity_request_end(); 223 return; 224 } 225 226 $fContent = $req->getResponseBody(); 227 serendipity_request_end(); 228 229 if (strlen($fContent) != 0) { 230 serendipity_trackback_autodiscover($fContent, $parsed_loc, $url, $author, $title, $text, $loc); 231 serendipity_pingback_autodiscover($loc, $fContent); 232 } else { 233 echo '<div>• ' . TRACKBACK_NO_DATA . '</div>'; 234 } 235 echo '<hr noshade="noshade" />'; 236 } 237 238 /** 239 * Receive a trackback 240 * 241 * @access public 242 * @param int The ID of our entry 243 * @param string The title of the foreign blog 244 * @param string The URL of the foreign blog 245 * @param string The name of the foreign blog 246 * @param string The excerpt text of the foreign blog 247 * @return true 248 */ 249 function add_trackback ($id, $title, $url, $name, $excerpt) { 250 global $serendipity; 251 252 // We can't accept a trackback if we don't get any URL 253 // This is a protocol rule. 254 if (empty($url)) { 255 return 0; 256 } 257 258 // If title is not provided, the value for url will be set as the title 259 // This is a protocol rule. 260 if (empty($title)) { 261 $title = $url; 262 } 263 264 $comment = array( 265 'title' => $title, 266 'url' => $url, 267 'name' => $name, 268 'comment' => $excerpt 269 ); 270 271 $is_utf8 = strtolower(LANG_CHARSET) == 'utf-8'; 272 273 if ($GLOBALS['tb_logging']) { 274 $fp = fopen('trackback2.log', 'a'); 275 fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK TRANSCODING CHECK' . "\n"); 276 } 277 278 foreach($comment AS $idx => $field) { 279 if (is_utf8($field)) { 280 // Trackback is in UTF-8. Check if our blog also is UTF-8. 281 if (!$is_utf8) { 282 if ($GLOBALS['tb_logging']) { 283 fwrite($fp, '[' . date('d.m.Y H:i') . '] Transcoding ' . $idx . ' from UTF-8 to ISO' . "\n"); 284 } 285 $comment[$idx] = utf8_decode($field); 286 } 287 } else { 288 // Trackback is in some native format. We assume ISO-8859-1. Check if our blog is also ISO. 289 if ($is_utf8) { 290 if ($GLOBALS['tb_logging']) { 291 fwrite($fp, '[' . date('d.m.Y H:i') . '] Transcoding ' . $idx . ' from ISO to UTF-8' . "\n"); 292 } 293 $comment[$idx] = utf8_encode($field); 294 } 295 } 296 } 297 298 if ($GLOBALS['tb_logging']) { 299 fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK DATA: ' . print_r($comment, true) . '...' . "\n"); 300 fwrite($fp, '[' . date('d.m.Y H:i') . '] TRACKBACK STORING...' . "\n"); 301 fclose($fp); 302 } 303 304 serendipity_saveComment($id, $comment, 'TRACKBACK'); 305 306 return 1; 307 } 308 309 /** 310 * Receive a pingback 311 * 312 * @access public 313 * @param int The entryid to receive a pingback for 314 * @param string The foreign postdata to add 315 * @return boolean 316 */ 317 function add_pingback ($id, $postdata) { 318 global $serendipity; 319 320 if(preg_match('@<methodcall>\s*<methodName>\s*pingback.ping\s*</methodName>\s*<params>\s*<param>\s*<value>\s*<string>([^<]*)</string>\s*</value>\s*</param>\s*<param>\s*<value>\s*<string>([^<]*)</string>\s*</value>\s*</param>\s*</params>\s*</methodCall>@i', $postdata, $matches)) { 321 $remote = $matches[1]; 322 $local = $matches[2]; 323 $comment['title'] = ''; 324 $comment['url'] = $remote; 325 $comment['comment'] = ''; 326 $comment['name'] = ''; 327 328 serendipity_saveComment($id, $comment, 'PINGBACK'); 329 return 1; 330 } 331 return 0; 332 } 333 334 /** 335 * Create an excerpt for a trackback to send 336 * 337 * @access public 338 * @param string Input text 339 * @return string Output text 340 */ 341 function serendipity_trackback_excerpt($text) { 342 return serendipity_mb('substr', strip_tags($text), 0, 255); 343 } 344 345 /** 346 * Report success of a trackback 347 * 348 * @access public 349 */ 350 function report_trackback_success () { 351 print '<?xml version="1.0" encoding="iso-8859-1"?>' . "\n"; 352 print <<<SUCCESS 353 <response> 354 <error>0</error> 355 </response> 356 SUCCESS; 357 } 358 359 /** 360 * Report failure of a trackback 361 * 362 * @access public 363 */ 364 function report_trackback_failure () { 365 print '<?xml version="1.0" encoding="iso-8859-1"?>' . "\n"; 366 print <<<FAILURE 367 <response> 368 <error>1</error> 369 <message>Danger Will Robinson, trackback failed.</message> 370 </response> 371 FAILURE; 372 } 373 374 /** 375 * Return success of a pingback 376 * 377 * @access public 378 */ 379 function report_pingback_success () { 380 print '<?xml version="1.0"?>' . "\n"; 381 print <<<SUCCESS 382 <methodResponse> 383 <params> 384 <param> 385 <value><string>success</string></value> 386 </param> 387 </params> 388 </methodResponse> 389 SUCCESS; 390 } 391 392 /** 393 * Return failure of a pingback 394 * 395 * @access public 396 */ 397 function report_pingback_failure () { 398 print '<?xml version="1.0"?>' . "\n"; 399 print <<<FAILURE 400 <methodResponse> 401 <fault> 402 <value><i4>0</i4></value> 403 </fault> 404 </methodResponse> 405 FAILURE; 406 } 407 408 /** 409 * Search through link body, and automagically send a trackback ping. 410 * 411 * This is the trackback starter function that searches your text and sees if any 412 * trackback URLs are in there 413 * 414 * @access public 415 * @param int The ID of our entry 416 * @param string The author of our entry 417 * @param string The title of our entry 418 * @param string The text of our entry 419 * @param boolean Dry-Run, without performing trackbacks? 420 * @return 421 */ 422 function serendipity_handle_references($id, $author, $title, $text, $dry_run = false) { 423 global $serendipity; 424 static $old_references = array(); 425 static $saved_references = array(); 426 static $debug = false; 427 428 if ($dry_run) { 429 // Store the current list of references. We might need to restore them for later user. 430 $old_references = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}references WHERE (type = '' OR type IS NULL) AND entry_id = " . (int)$id, false, 'assoc'); 431 432 if ($debug && is_string($old_references)) { 433 echo $old_references . "<br />\n"; 434 } 435 436 if (is_array($old_references) && count($old_references) > 0) { 437 $current_references = array(); 438 foreach($old_references AS $idx => $old_reference) { 439 // We need the current reference ID to restore it later. 440 $saved_references[$old_reference['link'] . $old_reference['name']] = $current_references[$old_reference['link'] . $old_reference['name']] = $old_reference; 441 } 442 } 443 if ($debug) echo "Got references in dry run: <pre>" . print_r($current_references, true) . "</pre><br />\n"; 444 } else { 445 // A dry-run was called previously and restorable references are found. Restore them now. 446 $del = serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}references WHERE (type = '' OR type IS NULL) AND entry_id = " . (int)$id); 447 if ($debug && is_string($del)) { 448 echo $del . "<br />\n"; 449 } 450 451 if ($debug) echo "Deleted references.<br />\n"; 452 453 if (is_array($old_references) && count($old_references) > 0) { 454 $current_references = array(); 455 foreach($old_references AS $idx => $old_reference) { 456 // We need the current reference ID to restore it later. 457 $current_references[$old_reference['link'] . $old_reference['name']] = $old_reference; 458 $q = serendipity_db_insert('references', $old_reference, 'show'); 459 $cr = serendipity_db_query($q); 460 if ($debug && is_string($cr)) { 461 echo $cr . "<br />\n"; 462 } 463 } 464 } 465 466 if ($debug) echo "Got references in final run: <pre>" . print_r($current_references, true) . "</pre><br />\n"; 467 } 468 469 if (!preg_match_all('@<a[^>]+?href\s*=\s*["\']?([^\'" >]+?)[ \'"][^>]*>(.+?)</a>@i', $text, $matches)) { 470 $matches = array(0 => array(), 1 => array()); 471 } else { 472 // remove full matches 473 array_shift($matches); 474 } 475 476 // Make trackback URL 477 $url = serendipity_archiveURL($id, $title, 'baseURL'); 478 479 // Add URL references 480 $locations = $matches[0]; 481 $names = $matches[1]; 482 483 $checked_locations = array(); 484 serendipity_plugin_api::hook_event('backend_trackbacks', $locations); 485 for ($i = 0, $j = count($locations); $i < $j; ++$i) { 486 if ($debug) echo "Checking {$locations[$i]}...<br />\n"; 487 if ($locations[$i][0] == '/') { 488 $locations[$i] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off' ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $locations[$i]; 489 } 490 491 if (isset($checked_locations[$locations[$i]])) { 492 if ($debug) echo "Already checked.<br />\n"; 493 continue; 494 } 495 496 if (preg_match_all('@<img[^>]+?alt=["\']?([^\'">]+?)[\'"][^>]+?>@i', $names[$i], $img_alt)) { 497 if (is_array($img_alt) && is_array($img_alt[0])) { 498 foreach($img_alt[0] as $alt_idx => $alt_img) { 499 // Replace all <img>s within a link with their respective ALT tag, so that references 500 // can be stored with a title. 501 $names[$i] = str_replace($alt_img, $img_alt[1][$alt_idx], $names[$i]); 502 } 503 } 504 } 505 506 $query = "SELECT COUNT(id) FROM {$serendipity['dbPrefix']}references 507 WHERE entry_id = ". (int)$id ." 508 AND link = '" . serendipity_db_escape_string($locations[$i]) . "' 509 AND (type = '' OR type IS NULL)"; 510 511 $row = serendipity_db_query($query, true, 'num'); 512 if ($debug && is_string($row)) { 513 echo $row . "<br />\n"; 514 } 515 516 if ($row[0] > 0 && isset($saved_references[$locations[$i] . $names[$i]])) { 517 if ($debug) echo "Found references for $id, skipping rest<br />\n"; 518 continue; 519 } 520 521 if (!isset($serendipity['noautodiscovery']) || !$serendipity['noautodiscovery']) { 522 if (!$dry_run) { 523 if ($debug) echo "Enabling autodiscovery.<br />\n"; 524 serendipity_reference_autodiscover($locations[$i], $url, $author, $title, serendipity_trackback_excerpt($text)); 525 } elseif ($debug) { 526 echo "Skipping autodiscovery<br />\n"; 527 } 528 $checked_locations[$locations[$i]] = true; // Store trackbacked link so that no further trackbacks will be sent to the same link 529 } elseif ($debug) { 530 echo "Skipping full autodiscovery<br />\n"; 531 } 532 } 533 $del = serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}references WHERE entry_id=" . (int)$id . " AND (type = '' OR type IS NULL)"); 534 if ($debug && is_string($del)) { 535 echo $del . "<br />\n"; 536 } 537 538 if ($debug) echo "Deleted references again.<br />\n"; 539 540 if (!is_array($old_references)) { 541 $old_references = array(); 542 } 543 544 $duplicate_check = array(); 545 for ($i = 0; $i < $j; ++$i) { 546 $i_link = serendipity_db_escape_string(strip_tags($names[$i])); 547 $i_location = serendipity_db_escape_string($locations[$i]); 548 549 // No link with same description AND same text should be inserted. 550 if (isset($duplicate_check[$i_location . $i_link])) { 551 continue; 552 } 553 554 if (isset($current_references[$locations[$i] . $names[$i]])) { 555 $query = "INSERT INTO {$serendipity['dbPrefix']}references (id, entry_id, name, link) VALUES("; 556 $query .= (int)$current_references[$locations[$i] . $names[$i]]['id'] . ", " . (int)$id . ", '" . $i_link . "', '" . $i_location . "')"; 557 $ins = serendipity_db_query($query); 558 if ($debug && is_string($ins)) { 559 echo $ins . "<br />\n"; 560 } 561 $duplicate_check[$locations[$i] . $names[$i]] = true; 562 } else { 563 $query = "INSERT INTO {$serendipity['dbPrefix']}references (entry_id, name, link) VALUES("; 564 $query .= (int)$id . ", '" . $i_link . "', '" . $i_location . "')"; 565 $ins = serendipity_db_query($query); 566 if ($debug && is_string($ins)) { 567 echo $ins . "<br />\n"; 568 } 569 570 $old_references[] = array( 571 'id' => serendipity_db_insert_id('references', 'id'), 572 'name' => $i_link, 573 'link' => $i_location, 574 'entry_id' => (int)$id 575 ); 576 $duplicate_check[$i_location . $i_link] = true; 577 } 578 579 if ($debug) { 580 echo "Current lookup for {$locations[$i]}{$names[$i]} is <pre>" . print_r($current_references[$locations[$i] . $names[$i]], true) . "</pre><br />\n"; 581 echo $query . "<br />\n"; 582 } 583 } 584 585 if ($debug) { 586 echo "Old/Saved locations: <pre>" . print_r($old_references, true) . "</pre><br />\n"; 587 } 588 589 // Add citations 590 preg_match_all('@<cite[^>]*>([^<]+)</cite>@i', $text, $matches); 591 592 foreach ($matches[1] as $citation) { 593 $query = "INSERT INTO {$serendipity['dbPrefix']}references (entry_id, name) VALUES("; 594 $query .= (int)$id . ", '" . serendipity_db_escape_string($citation) . "')"; 595 596 $cite = serendipity_db_query($query); 597 if ($debug && is_string($cite)) { 598 echo $cite . "<br />\n"; 599 } 600 } 601 } 602 603 /** 604 * Check if a string is in UTF-8 format. 605 * 606 * @access public 607 * @param string The string to check 608 * @return bool 609 */ 610 function is_utf8($string) { 611 // From http://w3.org/International/questions/qa-forms-utf-8.html 612 return preg_match('%^(?:' 613 . '[\x09\x0A\x0D\x20-\x7E]' # ASCII 614 . '|[\xC2-\xDF][\x80-\xBF]' # non-overlong 2-byte 615 . '|\xE0[\xA0-\xBF][\x80-\xBF]' # excluding overlongs 616 . '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}' # straight 3-byte 617 . '|\xED[\x80-\x9F][\x80-\xBF]' # excluding surrogates 618 . '|\xF0[\x90-\xBF][\x80-\xBF]{2}' # planes 1-3 619 . '|[\xF1-\xF3][\x80-\xBF]{3}' # planes 4-15 620 . '|\xF4[\x80-\x8F][\x80-\xBF]{2}' # plane 16 621 . ')*$%xs', $string); 622 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sat Nov 24 09:00:37 2007 | par Balluche grâce à PHPXref 0.7 |
|