| 1 | <?php |
|---|
| 2 | require_once(WBB_DIR.'lib/page/PublicSEORewriter.class.php'); |
|---|
| 3 | require_once(WCF_DIR.'lib/util/StringUtil.class.php'); |
|---|
| 4 | require_once(WBB_DIR.'lib/data/post/Post.class.php'); |
|---|
| 5 | require_once(WBB_DIR.'lib/util/IXR.class.php'); |
|---|
| 6 | require_once(WBB_DIR.'lib/util/TrackbackUtil.class.php'); |
|---|
| 7 | require_once(WBB_DIR.'lib/data/thread/Thread.class.php'); |
|---|
| 8 | |
|---|
| 9 | // Some browser-embedded clients send cookies. We don't want them. |
|---|
| 10 | $_COOKIE = array(); |
|---|
| 11 | |
|---|
| 12 | // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default, |
|---|
| 13 | // but we can do it ourself. |
|---|
| 14 | if(!isset($HTTP_RAW_POST_DATA)) { |
|---|
| 15 | $HTTP_RAW_POST_DATA = file_get_contents('php://input'); |
|---|
| 16 | } |
|---|
| 17 | |
|---|
| 18 | # fix for mozBlog and other cases where '<?xml' isn't on the very first line |
|---|
| 19 | if(isset($HTTP_RAW_POST_DATA)) { |
|---|
| 20 | $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA); |
|---|
| 21 | } |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | /** |
|---|
| 25 | * xmlrpc util |
|---|
| 26 | * |
|---|
| 27 | * @author Torben Brodt |
|---|
| 28 | * @package de.easy-coding.wcf.trackback |
|---|
| 29 | * @license GNU General Public License <http://opensource.org/licenses/gpl-3.0.html> |
|---|
| 30 | */ |
|---|
| 31 | class XMLRPCServer extends IXR_Server { |
|---|
| 32 | protected $rewriter; |
|---|
| 33 | |
|---|
| 34 | /** |
|---|
| 35 | * constructor |
|---|
| 36 | */ |
|---|
| 37 | public function __construct() { |
|---|
| 38 | $this->methods = array( |
|---|
| 39 | 'pingback.ping' => 'this:pingback_ping' |
|---|
| 40 | ); |
|---|
| 41 | |
|---|
| 42 | $this->rewriter = new PublicSEORewriter(); |
|---|
| 43 | |
|---|
| 44 | parent::IXR_Server($this->methods); |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | /** |
|---|
| 48 | * escapes strings |
|---|
| 49 | * @param arr |
|---|
| 50 | */ |
|---|
| 51 | protected function escape(&$arr) { |
|---|
| 52 | foreach ($arr as $k => $v ) { |
|---|
| 53 | $arr[$k] = escapeString($v); |
|---|
| 54 | } |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | /** |
|---|
| 58 | * gets a pingback and registers it |
|---|
| 59 | * @param args array(linkedfrom, linkedto) |
|---|
| 60 | */ |
|---|
| 61 | public function pingback_ping($args) { |
|---|
| 62 | $this->escape($args); |
|---|
| 63 | |
|---|
| 64 | $pagelinkedfrom = StringUtil::decodeHTML($args[0]); |
|---|
| 65 | $pagelinkedto = StringUtil::decodeHTML($args[1]); |
|---|
| 66 | |
|---|
| 67 | $title = ''; |
|---|
| 68 | |
|---|
| 69 | $error_code = -1; |
|---|
| 70 | |
|---|
| 71 | // Check if the page linked to is in our site |
|---|
| 72 | $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', PAGE_URL)); |
|---|
| 73 | if(!$pos1) { |
|---|
| 74 | return new IXR_Error(0, 'Is there no link to us?'); |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | // let's find which post is linked to |
|---|
| 78 | $threadID = $this->rewriter->thread2threadID($pagelinkedto); |
|---|
| 79 | if($threadID === NULL) { |
|---|
| 80 | return new IXR_Error(33, 'The specified target URL cannot be resolved as a thread url.'); |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | $thread = new Thread($threadID); |
|---|
| 84 | |
|---|
| 85 | // Check if post exists |
|---|
| 86 | if($thread->firstPostID) { |
|---|
| 87 | $post = new Post($thread->firstPostID); |
|---|
| 88 | } else { |
|---|
| 89 | return new IXR_Error(33, 'The specified target URL cannot be used as a target. It doesn\'t exist.'); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | // Check if pings are on |
|---|
| 93 | if(!$post->hasTrackback) { |
|---|
| 94 | return new IXR_Error(33, 'The specified target URL cannot be used as a target. It is not a pingback-enabled resource.'); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | // check for duplicates |
|---|
| 98 | $sql = "SELECT COUNT(*) AS c |
|---|
| 99 | FROM wbb".WBB_N."_trackback |
|---|
| 100 | WHERE postID = ".$post->postID." |
|---|
| 101 | AND url = '".escapeString($pagelinkedfrom)."' "; |
|---|
| 102 | |
|---|
| 103 | $row = WBBCore::getDB()->getFirstRow($sql); |
|---|
| 104 | if(intval($row['c']) > 0) { |
|---|
| 105 | return new IXR_Error(48, 'The pingback has already been registered.'); |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | // very stupid, but gives time to the 'from' server to publish ! |
|---|
| 109 | sleep(1); |
|---|
| 110 | |
|---|
| 111 | // Let's check the remote site |
|---|
| 112 | extract(parse_url($pagelinkedfrom), EXTR_SKIP); |
|---|
| 113 | |
|---|
| 114 | $path = ( !isset($path) ) ? '/' : $path; |
|---|
| 115 | $path .= ( isset($query) ) ? '?' . $query : ''; |
|---|
| 116 | $port = ( isset($port) ) ? $port : 80; |
|---|
| 117 | |
|---|
| 118 | // Try to connect to the server at $host |
|---|
| 119 | $fp = @fsockopen($host, $port, $errno, $errstr, 2); |
|---|
| 120 | if(!$fp) { |
|---|
| 121 | return new IXR_Error(16, 'The source URL does not exist.'); |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | $request = "GET $path HTTP/1.1\r\nHost: $host\r\nUser-Agent: ".TrackbackUtil::$agent." \r\n\r\n"; |
|---|
| 125 | fputs($fp, $request); |
|---|
| 126 | $linea = ''; |
|---|
| 127 | while (!feof($fp)) { |
|---|
| 128 | $linea .= fgets($fp, 4096); |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | // Work around bug in strip_tags(): |
|---|
| 132 | $linea = str_replace('<!DOC', '<DOC', $linea); |
|---|
| 133 | $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces |
|---|
| 134 | $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea ); |
|---|
| 135 | |
|---|
| 136 | preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle); |
|---|
| 137 | $title = $matchtitle[1]; |
|---|
| 138 | if(empty($title)) { |
|---|
| 139 | return new IXR_Error(32, 'We cannot find a title on that page.'); |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | $linea = strip_tags($linea, '<a>'); // just keep the tag we need |
|---|
| 143 | $p = explode("\n\n", $linea); |
|---|
| 144 | |
|---|
| 145 | $preg_target = preg_quote($pagelinkedto); |
|---|
| 146 | |
|---|
| 147 | foreach($p as $para) { |
|---|
| 148 | if(strpos($para, $pagelinkedto) !== false) { // it exists, but is it a link? |
|---|
| 149 | preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context); |
|---|
| 150 | |
|---|
| 151 | // If the URL isn't in a link context, keep looking |
|---|
| 152 | if(empty($context)) { |
|---|
| 153 | continue; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | // We're going to use this fake tag to mark the context in a bit |
|---|
| 157 | // the marker is needed in case the link text appears more than once in the paragraph |
|---|
| 158 | $excerpt = preg_replace('|\</?wpcontext\>|', '', $para); |
|---|
| 159 | |
|---|
| 160 | // prevent really long link text |
|---|
| 161 | if(strlen($context[1]) > 100) { |
|---|
| 162 | $context[1] = substr($context[1], 0, 100).'...'; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | $marker = '<wpcontext>'.$context[1].'</wpcontext>'; // set up our marker |
|---|
| 166 | $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker |
|---|
| 167 | $excerpt = strip_tags($excerpt, '<wpcontext>'); // strip all tags but our context marker |
|---|
| 168 | $excerpt = trim($excerpt); |
|---|
| 169 | $preg_marker = preg_quote($marker); |
|---|
| 170 | $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt); |
|---|
| 171 | $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper |
|---|
| 172 | break; |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | if(empty($context)) { |
|---|
| 177 | // Link to target not found |
|---|
| 178 | return new IXR_Error(17, 'The source URL does not contain a link to the target URL, and so cannot be used as a source.'); |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | // save incoming |
|---|
| 182 | TrackbackUtil::save($postID, $pagelinkedto, $title, $excerpt, $pagelinkedfrom, $title); |
|---|
| 183 | |
|---|
| 184 | return sprintf('Pingback from %1$s to %2$s registered. Keep the web talking! :-)', $pagelinkedfrom, $pagelinkedto); |
|---|
| 185 | } |
|---|
| 186 | } |
|---|
| 187 | ?> |
|---|