| 1 | <?php # A class for getting and sending Pingbacks |
|---|
| 2 | $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA); |
|---|
| 3 | if(!defined('JLOG_BASEPATH')) require_once('.'.DIRECTORY_SEPARATOR.'personal'.DIRECTORY_SEPARATOR.'settings.inc.php'); |
|---|
| 4 | require_once(JLOG_BASEPATH.'scripts'.DIRECTORY_SEPARATOR.'ixr-library.inc.php'); |
|---|
| 5 | require_once(JLOG_BASEPATH.'scripts'.DIRECTORY_SEPARATOR.'jlogHTTP_Request.php'); |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | if(defined("JLOG_ADMIN") === false) { |
|---|
| 9 | function ping($args) { |
|---|
| 10 | |
|---|
| 11 | $pingback = new Jlog_GetPingback(JLOG_DB_CONTENT, JLOG_DB_COMMENTS, JLOG_PATH, new_sid()); |
|---|
| 12 | $pingback->get_ping($args); |
|---|
| 13 | if($pingback->validate()) { |
|---|
| 14 | $pingback->write_to_db(); |
|---|
| 15 | return "Thanks for your ping."; |
|---|
| 16 | } |
|---|
| 17 | } |
|---|
| 18 | $server = new IXR_Server(array('pingback.ping' => 'ping')); |
|---|
| 19 | } |
|---|
| 20 | |
|---|
| 21 | class Jlog_GetPingback { |
|---|
| 22 | |
|---|
| 23 | var $errors = array(); // array |
|---|
| 24 | var $method = ""; // string |
|---|
| 25 | var $sourceURI = ""; // string |
|---|
| 26 | var $targetURI = array(); // array incl: orginal, parsed [array from parse_url()], y, m, url |
|---|
| 27 | var $title = ""; // string |
|---|
| 28 | var $sid = ""; // string |
|---|
| 29 | |
|---|
| 30 | function Jlog_GetPingback($db_content, $db_comments, $path, $sid = NULL) { |
|---|
| 31 | $this->db_content = $db_content; |
|---|
| 32 | $this->db_comments = $db_comments; |
|---|
| 33 | $this->path = $path; |
|---|
| 34 | if($sid != NULL) $this->sid = $sid; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | function get_ping($uris) { |
|---|
| 38 | |
|---|
| 39 | $ymurls = array(); |
|---|
| 40 | $tmp_host_got = ""; |
|---|
| 41 | $tmp_host_path_parsed = array(); |
|---|
| 42 | $tmp_host_path = ""; |
|---|
| 43 | |
|---|
| 44 | $this->sourceURI = trim($uris[0]); |
|---|
| 45 | $this->targetURI['orginal'] = trim(str_replace(array('"','<', '>', '&'), array('"', '<', '>', '&'), $uris[1])); |
|---|
| 46 | $this->targetURI['parsed'] = parse_url($this->targetURI['orginal']); |
|---|
| 47 | $tmp_host_got = str_replace('www.', '', $this->targetURI['parsed']['host']).$this->targetURI['parsed']['path']; |
|---|
| 48 | $tmp_host_path_parsed = parse_url($this->path); |
|---|
| 49 | $tmp_host_path = str_replace('www.', '', $tmp_host_path_parsed['host']).'/log.php'; |
|---|
| 50 | |
|---|
| 51 | if(!empty($this->targetURI['parsed']['query']) AND ($tmp_host_got == $tmp_host_path)) { |
|---|
| 52 | |
|---|
| 53 | $ymurls = explode('&', $this->targetURI['parsed']['query']); |
|---|
| 54 | $this->_counter = count($ymurls); |
|---|
| 55 | |
|---|
| 56 | foreach($ymurls AS $ymurl) { |
|---|
| 57 | if(substr($ymurl, 0, 2) == 'y=') $this->targetURI['y'] = substr($ymurl, 2); |
|---|
| 58 | elseif(substr($ymurl, 0, 2) == 'm=') $this->targetURI['m'] = substr($ymurl, 2); |
|---|
| 59 | elseif(substr($ymurl, 0, 4) == 'url=') $this->targetURI['url'] = substr($ymurl, 4); |
|---|
| 60 | } |
|---|
| 61 | } |
|---|
| 62 | else { |
|---|
| 63 | ### Plugin Hook |
|---|
| 64 | global $plugins; |
|---|
| 65 | $tmp_URI = $plugins->callHook('xmlrpcPermalink', $this->targetURI['orginal']); |
|---|
| 66 | |
|---|
| 67 | $regex = "#^".$this->path."/([0-9]{4})/?([0-9]{2})/?([a-z0-9_\-]+)$#"; |
|---|
| 68 | preg_match($regex, $tmp_URI, $matches); |
|---|
| 69 | $this->targetURI['y'] = $matches[1]; |
|---|
| 70 | $this->targetURI['m'] = $matches[2]; |
|---|
| 71 | $this->targetURI['url'] = $matches[3]; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | function validate() { |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | if(!strpos($this->targetURI['orginal'], str_replace(array('http://', 'https://'), '', str_replace('www.', '', $this->path)))) |
|---|
| 80 | $this->send_error(0, 'Target URI ('.$this->targetURI['orginal'].') is not this page: '.$this->path); |
|---|
| 81 | |
|---|
| 82 | |
|---|
| 83 | // is there such a post? |
|---|
| 84 | $sql = "SELECT id, allowpingback FROM ".$this->db_content." WHERE |
|---|
| 85 | YEAR(date) = '".escape_for_mysql($this->targetURI['y'])."' AND |
|---|
| 86 | MONTH(date) = '".escape_for_mysql($this->targetURI['m'])."' AND |
|---|
| 87 | url = '".escape_for_mysql($this->targetURI['url'])."' AND |
|---|
| 88 | section = 'weblog' |
|---|
| 89 | LIMIT 1"; |
|---|
| 90 | $blog = new Query($sql); |
|---|
| 91 | if($blog->error()) $this->send_error(0, 'Could not read my database.'); |
|---|
| 92 | $blogrow = $blog->fetch(); |
|---|
| 93 | |
|---|
| 94 | if($blog->numRows() != 1) $this->send_error(32, 'The specified target URI does not exist.'.$this->targetURI['orginal']); |
|---|
| 95 | if($blogrow['allowpingback'] === 0) $this->send_error(33, 'The specified target URI cannot be used as a target. It it is not a pingback-enabled resource.'); |
|---|
| 96 | else $this->reference = $blogrow['id']; |
|---|
| 97 | |
|---|
| 98 | $s =& new HTTP_Request($this->sourceURI); |
|---|
| 99 | if(PEAR::isError($s->sendRequest())) $this->send_error(16, 'The source URI does not exist.'); |
|---|
| 100 | else { |
|---|
| 101 | $source = $s->getResponseBody(); |
|---|
| 102 | $source = strip_tags(str_replace('<!DOCTYPE','<DOCTYPE', $source), '<title><a>'); |
|---|
| 103 | |
|---|
| 104 | if (!$this->isLinkInHTML($this->targetURI['orginal'], $source)) |
|---|
| 105 | $this->send_error(17, 'The source URI does not contain a link to the target URI, and so cannot be used as a source.'); |
|---|
| 106 | |
|---|
| 107 | preg_match('|<title>([^<]*?)</title>|is', $source, $title); |
|---|
| 108 | |
|---|
| 109 | if(! $utf8 = preg_match ('/charset\s*=\s*utf-8/i', $s->getResponseHeader("Content-Type"))) |
|---|
| 110 | $utf8 = 'application/xhtml+xml' == strtolower(trim($s->getResponseHeader("Content-Type"))); |
|---|
| 111 | |
|---|
| 112 | $this->title = empty($title[1]) ? $this->sourceURI : html_entity_decode($utf8 ? utf8_decode($title[1]) : $title[1]); |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | $sql = "SELECT COUNT(*) AS ping FROM ".$this->db_comments." WHERE |
|---|
| 116 | reference = '".escape_for_mysql($blogrow['id'])."' AND |
|---|
| 117 | homepage = '".escape_for_mysql($this->sourceURI)."' AND |
|---|
| 118 | name = '".escape_for_mysql($this->title)."' AND |
|---|
| 119 | type = 'pingback' |
|---|
| 120 | LIMIT 1"; |
|---|
| 121 | $p = new Query($sql); |
|---|
| 122 | if($p->error()) $this->send_error(0, 'Could not read my database.'); |
|---|
| 123 | $f = $p->fetch(); |
|---|
| 124 | |
|---|
| 125 | if($f['ping'] > 0) $this->send_error(48, 'The pingback has already been registered.'); |
|---|
| 126 | |
|---|
| 127 | if(count($this->errors) > 0) return false; |
|---|
| 128 | else return true; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | function write_to_db() { |
|---|
| 132 | $sql = "INSERT INTO ".$this->db_comments." ( |
|---|
| 133 | sid, |
|---|
| 134 | name, |
|---|
| 135 | homepage, |
|---|
| 136 | reference, |
|---|
| 137 | date, |
|---|
| 138 | type |
|---|
| 139 | ) |
|---|
| 140 | VALUES ( |
|---|
| 141 | '".escape_for_mysql($this->sid)."', |
|---|
| 142 | '".escape_for_mysql($this->title)."', |
|---|
| 143 | '".escape_for_mysql($this->sourceURI)."', |
|---|
| 144 | '".escape_for_mysql($this->reference)."', |
|---|
| 145 | NOW(), |
|---|
| 146 | 'pingback' |
|---|
| 147 | )"; |
|---|
| 148 | $ping = new Query($sql); |
|---|
| 149 | |
|---|
| 150 | if($ping->error()) $this->send_error(0, 'Could not write to database.'); |
|---|
| 151 | |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | function send_error($nr, $string) { |
|---|
| 155 | $this->errors[] = $nr." ".$string; |
|---|
| 156 | $error = new IXR_Error($nr, $string); |
|---|
| 157 | $this->send_xml($error->getXml()); |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | function get_errors() { |
|---|
| 161 | return $this->errors; |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | function send_xml($xml) { |
|---|
| 165 | header('Connection: close'); |
|---|
| 166 | header('Content-Length: '.strlen($xml)); |
|---|
| 167 | header('Content-Type: text/xml'); |
|---|
| 168 | header('Date: '.date('r')); |
|---|
| 169 | echo $xml; |
|---|
| 170 | exit; |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | function isLinkInHTML($search, $html) { |
|---|
| 174 | preg_match_all('#<a[^>]+href\s*=\s*("([^"]+)"|\'([^\']+)\')[^>]*>(.+)</a>#Ui', $html, $matches); |
|---|
| 175 | $links = array_unique(array_merge($matches[2], $matches[3])); |
|---|
| 176 | |
|---|
| 177 | foreach($links as $link) { |
|---|
| 178 | if($search === str_replace('&', '&', $link)) return true; |
|---|
| 179 | } |
|---|
| 180 | return false; |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | class Jlog_SendPingback { |
|---|
| 186 | |
|---|
| 187 | var $pageslinkedto = array(); |
|---|
| 188 | var $useragent = ""; |
|---|
| 189 | |
|---|
| 190 | function Jlog_SendPingback($html, $pagelinkedfrom, $useragent) { |
|---|
| 191 | $this->pagelinkedfrom = $pagelinkedfrom; |
|---|
| 192 | $this->useragent = $useragent; |
|---|
| 193 | |
|---|
| 194 | preg_match_all('#<a[^>]+href\s*=\s*("([^"]+)"|\'([^\']+)\')[^>]*>(.+)</a>#Ui', $html, $matches); |
|---|
| 195 | $pageslinkedto = array(); |
|---|
| 196 | $pageslinkedto = array_unique(array_merge($matches[2], $matches[3])); |
|---|
| 197 | $count = count($pageslinkedto); |
|---|
| 198 | for($i = 0; $count > $i; $i++) { |
|---|
| 199 | if(substr($pageslinkedto[$i], 0, 4) !== "http") unset($pageslinkedto[$i]); |
|---|
| 200 | else $pageslinkedto[$i] = str_replace(array('"','<', '>', '&'), array('"', '<', '>', '&'), $pageslinkedto[$i]); |
|---|
| 201 | } |
|---|
| 202 | $this->pageslinkedto = $pageslinkedto; |
|---|
| 203 | } |
|---|
| 204 | |
|---|
| 205 | function doPingbacks() { |
|---|
| 206 | foreach($this->pageslinkedto as $pagelinkedto) { |
|---|
| 207 | $feedback[] = $this->send($pagelinkedto); |
|---|
| 208 | } |
|---|
| 209 | return $feedback; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | function send($pagelinkedto) { |
|---|
| 213 | |
|---|
| 214 | $s =& new HTTP_Request($pagelinkedto); |
|---|
| 215 | if(PEAR::isError($s->sendRequest())) return $pagelinkedto." — Error: The source URI does not exist."; |
|---|
| 216 | else { |
|---|
| 217 | $xmlrpcserver = $s->getResponseHeader("X-Pingback"); |
|---|
| 218 | if(!empty($xmlrpcserver)); |
|---|
| 219 | else { |
|---|
| 220 | if(preg_match('<link rel="pingback" href="([^"]+)" ?/?>', $s->getResponseBody(), $matches)) { |
|---|
| 221 | $xmlrpcserver = $matches[1]; |
|---|
| 222 | } |
|---|
| 223 | else return $pagelinkedto." — This is not a pingback-enabled resource."; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | $client = new IXR_Client($xmlrpcserver); |
|---|
| 227 | $client->timeout = 3; |
|---|
| 228 | $client->useragent = $this->useragent; |
|---|
| 229 | |
|---|
| 230 | // when set to true, this outputs debug messages by itself |
|---|
| 231 | $client->debug = false; |
|---|
| 232 | |
|---|
| 233 | if (! $client->query('pingback.ping', $this->pagelinkedfrom, $pagelinkedto ) ) |
|---|
| 234 | return $pagelinkedto." — Error: ".$client->getErrorMessage(); |
|---|
| 235 | |
|---|
| 236 | else return $pagelinkedto." — ".$client->getResponse(); |
|---|
| 237 | } |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | } |
|---|
| 241 | ?> |
|---|