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/IXR_Library.php'); 21require_once (DOKU_INC . 'inc/pluginutils.php'); 22require_once (DOKU_PLUGIN . 'linkback/tools.php'); 23require_once (DOKU_PLUGIN . 'linkback/http.php'); 24 25// Pingback Faultcodes 26define('PINGBACK_ERROR_GENERIC', 0); 27define('PINGBACK_ERROR_SOURCEURI_DOES_NOT_EXIST', 16); 28define('PINGBACK_ERROR_SOURCEURI_DOES_NOT_CONTAIN_LINK', 17); 29define('PINGBACK_ERROR_TARGETURI_DOES_NOT_EXIST', 32); 30define('PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED', 33); 31define('PINGBACK_ERROR_PINGBACK_ALREADY_MADE', 48); 32define('PINGBACK_ERROR_ACCESS_DENIED', 49); 33define('PINGBACK_ERROR_NO_UPSTREAM', 50); 34 35class PingbackServer extends IXR_Server { 36 37 // helper instance 38 var $tools; 39 40 /** 41 * Register service and construct helper 42 */ 43 function __construct() { 44 $this->tools =& plugin_load('tools', 'linkback'); 45 parent::__construct(array ( 46 'pingback.ping' => 'this:ping', 47 48 )); 49 } 50 51 function ping($sourceUri, $targetUri) { 52 // Plugin not enabled? Quit 53 if (plugin_isdisabled('linkback')) 54 return new IXR_Error(PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED, ''); 55 56 // pingback disabled? Quit 57 if (!$this->tools->getConf('enable_pingback')) 58 return new IXR_Error(PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED, ''); 59 60 // Given URLs are no urls? Quit 61 if (!preg_match("#^([a-z0-9\-\.+]+?)://.*#i", $sourceUri)) 62 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 63 if (!preg_match("#^([a-z0-9\-\.+]+?)://.*#i", $targetUri)) 64 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 65 66 // Source URL does not exist? Quit 67 $page = $this->tools->getPage($sourceUri); 68 if (!$page['success'] && ($page['status'] < 200 || $page['status'] >= 300)) 69 return new IXR_Error(PINGBACK_ERROR_SOURCEURI_DOES_NOT_EXIST, ''); 70 71 // Target URL does not match with request? Quit 72 $ID = substr($_SERVER['PATH_INFO'], 1); 73 if ($targetUri != wl($ID, '', true)) 74 return new IXR_Error(PINGBACK_ERROR_GENERIC, ''); 75 76 $file = metaFN($ID, '.linkbacks'); 77 $data = array ( 78 'send' => false, 79 'receive' => false, 80 'display' => false, 81 'sentpings' => array (), 82 'receivedpings' => array (), 83 'number' => 0, 84 85 ); 86 87 if (@ file_exists($file)) 88 $data = unserialize(io_readFile($file, false)); 89 90 // Target URL is not pingback enabled? Quit 91 if (!$data['receive']) 92 return new IXR_Error(PINGBACK_ERROR_TARGETURI_CANNOT_BE_USED, ''); 93 94 // Pingback already done? Quit 95 if ($data['receivedpings'][md5($sourceUri)]) 96 return new IXR_Error(PINGBACK_ERROR_PINGBACK_ALREADY_MADE, ''); 97 98 // Retrieve data from source 99 $linkback = $this->_getTrackbackData($sourceUri, $targetUri, $page); 100 101 // Source URL does not contain link to target? Quit 102 if (!$linkback) 103 return new IXR_Error(PINGBACK_ERROR_SOURCEURI_DOES_NOT_CONTAIN_LINK, ''); 104 105 // Prepare event for Antispam plugins 106 $evt_data = array ( 107 'linkback' => $linkback, 108 'page' => $page, 109 'target' => $targetUri, 110 'show' => true, 111 'log' => array( 112 date('Y/m/d H:i', time()) . ': Received pingback from ' . $linkback['url'] . ' (' . $linkback['lid'] . ')', 113 ), 114 ); 115 $event = new Doku_Event('ACTION_LINKBACK_RECEIVED', $evt_data); 116 if ($event->advise_before()) { 117 $linkback['show'] = $evt_data['show']; 118 if ($this->tools->getConf('usefavicon')) { 119 $linkback['favicon'] = $this->tools->getFavicon($linkback['url'], $page['body']); 120 } 121 122 // add pingback 123 $data['receivedpings'][$linkback['lid']] = $linkback; 124 if ($linkback['show']) 125 $data['number']++; 126 127 io_saveFile($file, serialize($data)); 128 $this->tools->addLogEntry($linkback['received'], $ID, 'cl', '', $linkback['lid']); 129 $this->tools->notify($ID, $linkback); 130 if ($this->tools->getConf('log_processing')) 131 $this->tools->addProcessLogEntry($evt_data['log']); 132 $event->advise_after(); 133 } else { 134 // Pingback was denied 135 if ($this->tools->getConf('log_processing')) 136 $this->tools->addProcessLogEntry($evt_data['log']); 137 $event->advise_after(); 138 return new IXR_Error(PINGBACK_ERROR_ACCESS_DENIED, $helper->getLang('error_noreason')); 139 } 140 } 141 142 /** 143 * Constructs linkback data and checks if source contains a link to target and a title. 144 */ 145 function _getTrackbackData($sourceUri, $targetUri, $page) { 146 // construct unique id for pingback 147 $lid = md5($sourceUri); 148 $linkback = array ( 149 'lid' => $lid, 150 'title' => '', 151 'url' => $sourceUri, 152 'excerpt' => '', 153 'raw_excerpt' => '', 154 'blog_name' => '', 155 'received' => time(), 156 'submitter_ip' => $_SERVER['REMOTE_ADDR'], 157 'submitter_useragent' => $_SERVER['HTTP_USER_AGENT'], 158 'submitter_referer' => $_SERVER['HTTP_REFERER'], 159 'type' => 'pingback', 160 'show' => true, 161 ); 162 163 $searchurl = preg_quote($targetUri, '!'); 164 $regex = '!<a[^>]+?href="' . $searchurl . '"[^>]*?>(.*?)</a>!is'; 165 $regex2 = '!\s(' . $searchurl . ')\s!is'; 166 if (!preg_match($regex, $page['body'], $match) && !preg_match($regex2, $page['body'], $match)) { 167 if ($this->tools->getConf('ping_internal') && (strstr($targetUri, DOKU_URL) == $targetUri)) { 168 $ID = substr($_SERVER['PATH_INFO'], 1); 169 $searchurl = preg_quote(wl($ID, '', false), '!'); 170 171 $regex = '!<a[^>]+?href="' . $searchurl . '"[^>]*?>(.*?)</a>!is'; 172 $regex2 = '!\s(' . $searchurl . ')\s!is'; 173 if (!preg_match($regex, $page['body'], $match) && !preg_match($regex2, $page['body'], $match)) 174 return false; 175 } else { 176 return false; 177 } 178 } 179 $linkback['raw_excerpt'] = '[...] ' . $match[1] . ' [...]'; 180 $linkback['excerpt'] = '[...] ' . strip_tags($match[1]) . ' [...]'; 181 182 $regex = '!<title.*?>(.*?)</title>!is'; 183 if (!preg_match($regex, $page['body'], $match)) 184 return false; 185 $linkback['title'] = strip_tags($match[1]); 186 187 return $linkback; 188 } 189 190} 191 192$server = new PingbackServer(); 193