1<?php 2 3/** 4 * Pingback server for use with the DokuWiki Linkback Plugin. 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Gina Haeussge <osd@foosel.net> 8 * @link http://wiki.foosel.net/snippets/dokuwiki/linkback 9 */ 10 11if (!defined('DOKU_INC')) 12 define('DOKU_INC', realpath(dirname(__FILE__) . '/../../../../') . '/'); 13 14if (!defined('NL')) 15 define('NL', "\n"); 16 17require_once (DOKU_INC . 'inc/init.php'); 18require_once (DOKU_INC . 'inc/common.php'); 19require_once (DOKU_INC . 'inc/events.php'); 20require_once (DOKU_INC . 'inc/HTTPClient.php'); 21require_once (DOKU_INC . 'inc/IXR_Library.php'); 22require_once (DOKU_INC . 'inc/pluginutils.php'); 23 24// Pingback Faultcodes 25define('PINGBACK_ERROR_GENERIC', 0); 26define('PINGBACK_ERROR_SOURCEURI_DOES_NOT_EXIST', 16); 27define('PINGBACK_ERROR_SOURCEURI_DOES_NOT_CONTAIN_LINK', 17); 28define('PINGBACK_ERROR_TARGETURI_DOES_NOT_EXIST', 32); 29define('PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED', 33); 30define('PINGBACK_ERROR_PINGBACK_ALREADY_MADE', 48); 31define('PINGBACK_ERROR_ACCESS_DENIED', 49); 32define('PINGBACK_ERROR_NO_UPSTREAM', 50); 33 34/** 35 * Class PingbackServer 36 */ 37class PingbackServer extends IXR_Server { 38 39 /** @var helper_plugin_blogtng_linkback */ 40 var $tools; 41 42 /** 43 * Register service and construct helper 44 */ 45 function __construct() { 46 /** @var helper_plugin_blogtng_linkback tools */ 47 $this->tools = plugin_load('helper', 'blogtng_linkback'); 48 parent::__construct(array('pingback.ping' => 'this:ping')); 49 } 50 51 /** 52 * Send a HTTP get request to @$sourceUri and extract linkback 53 * data for @$targetUri from the response. 54 * 55 * @param $sourceUri 56 * @param $targetUri 57 * @return IXR_Error 58 */ 59 function ping($sourceUri, $targetUri) { 60 global $ID; 61 $ID = substr($_SERVER['PATH_INFO'], 1); 62 63 if (is_null($this->tools) || !$this->tools->linkbackAllowed()) { 64 return new IXR_Error(PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED, ''); 65 } 66 67 // Given URLs are no urls? Quit 68 if (!preg_match("#^([a-z0-9\-\.+]+?)://.*#i", $sourceUri)) 69 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 70 if (!preg_match("#^([a-z0-9\-\.+]+?)://.*#i", $targetUri)) 71 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 72 73 // Source URL does not exist? Quit 74 $http = new DokuHTTPClient; 75 $page = $http->get($sourceUri); 76 if ($page === false) 77 return new IXR_Error(PINGBACK_ERROR_SOURCEURI_DOES_NOT_EXIST, ''); 78 79 // Target URL does not match with request? Quit 80 if ($targetUri != wl($ID, '', true)) 81 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 82 83 // Retrieve data from source 84 $linkback = $this->_getTrackbackData($sourceUri, $targetUri, $page); 85 86 // Source URL does not contain link to target? Quit 87 if (!$linkback) 88 return new IXR_Error(PINGBACK_ERROR_SOURCEURI_DOES_NOT_CONTAIN_LINK, ''); 89 90 if (!$this->tools->saveLinkback('pingback', $linkback['title'], 91 $sourceUri, $linkback['excerpt'], $ID)) { 92 return new IXR_Error(PINGBACK_ERROR_PINGBACK_ALREADY_MADE, ''); 93 } 94 } 95 96 /** 97 * Constructs linkback data and checks if source contains a link to target and a title. 98 * 99 * @param $sourceUri 100 * @param $targetUri 101 * @param $page 102 * @return array|bool 103 */ 104 function _getTrackbackData($sourceUri, $targetUri, $page) { 105 $linkback = array (); 106 107 $searchurl = preg_quote($targetUri, '!'); 108 $regex = '!<a[^>]+?href="' . $searchurl . '"[^>]*?>(.*?)</a>!is'; 109 $regex2 = '!\s(' . $searchurl . ')\s!is'; 110 if (!preg_match($regex, $page, $match) && !preg_match($regex2, $page, $match)) { 111 // FIXME internal pings 112 if ((strstr($targetUri, DOKU_URL) == $targetUri)) { 113 $ID = substr($_SERVER['PATH_INFO'], 1); 114 $searchurl = preg_quote(wl($ID, '', false), '!'); 115 116 $regex = '!<a[^>]+?href="' . $searchurl . '"[^>]*?>(.*?)</a>!is'; 117 $regex2 = '!\s(' . $searchurl . ')\s!is'; 118 if (!preg_match($regex, $page, $match) && !preg_match($regex2, $page, $match)) 119 return false; 120 } else { 121 return false; 122 } 123 } 124 $linkback['excerpt'] = '[…] ' . strip_tags($match[1]) . ' […]'; 125 126 $regex = '!<title.*?>(.*?)</title>!is'; 127 if (!preg_match($regex, $page, $match)) 128 return false; 129 $linkback['title'] = strip_tags($match[1]); 130 131 return $linkback; 132 } 133} 134 135$server = new PingbackServer(); 136