root/trackback/files/lib/util/TrackbackUtil.class.php @ 136

Revision 136, 10.3 kB (checked in by d0nut, 5 years ago)

released version 0.0.5 - the first official release of trackback mod

Line 
1<?php
2// import seorewriter
3require_once(WCF_DIR.'lib/page/PublicSEORewriter.class.php');
4require_once(WCF_DIR.'lib/util/FileUtil.class.php');
5
6/**
7 * trackback util
8 *
9 * @author      Torben Brodt
10 * @package     de.easy-coding.wbb.trackback
11 * @license     GNU General Public License <http://opensource.org/licenses/gpl-3.0.html>
12 */
13class TrackbackUtil {
14        protected $agent = 'Woltlab Burning Board Trackback Mod';
15
16        /**
17         * fetchs necessery postdata
18         * @param postIDs
19         * @return array
20         */
21        public static function getPost($postIDs) {
22                if(!is_array($postIDs))
23                        $postIDs = array($postIDs);
24       
25                // fetch thread data
26                $sql = "SELECT          thread.*
27                        FROM            wbb".WBB_N."_post post
28                        LEFT JOIN       wbb".WBB_N."_thread thread
29                        ON              (thread.threadID=post.threadID)
30                        WHERE           postID IN (".implode(',', $postIDs).") ";
31
32                $row = WCF::getDB()->getFirstRow($sql);
33                               
34                $rewriter = new PublicSEORewriter();
35               
36                // public seo rewriter: cache
37                $rewriter->publicCacheThreads($row['threadID'], $row);
38               
39                // public seo rewriter use
40                $row['url'] = $rewriter->publicParseThreadURLs($row['threadID'], '');
41               
42                return $row;
43        }
44       
45        /**
46         *
47         * @param postPermalink
48         * @param postID
49         * @param postTopic
50         * @param postPreview
51         * @param postUsername
52         * @param postTime
53         */
54        public static function getRDF($postPermalink, $postID, $postTopic, $postPreview, $postUsername, $postTime) {
55                $page_url = FileUtil::addTrailingSlash(PAGE_URL);
56                return '<link rel="pingback" href="'.$page_url.'index.php?action=Pingback" />
57<!--
58<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
59        xmlns:dc="http://purl.org/dc/elements/1.1/"
60        xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
61<rdf:Description
62        rdf:about="'.$postPermalink.'"
63        dc:identifier="'.$postPermalink.'"
64        trackback:ping="index.php?action=Trackback&amp;postID='.$postID.'"
65        dc:title="'.$postTopic.'"
66        dc:subject="TrackBack"
67        dc:description="'.$postPreview.'"
68        dc:creator="'.$postUsername.'"
69        dc:date="'.date('r', $postTime).'" />
70</rdf:RDF>
71-->';
72        }
73       
74        /**
75         * saves incoming ping/trackback
76         * @param postID
77         * @param postURL
78         * @param title
79         * @param excerpt
80         * @param url
81         * @param blog_name
82         */
83        public static function save($postID, $postURL, $title, $excerpt, $url, $blog_name) {
84                // akismet check spam
85                $isSpam = self::isSpam($title, $excerpt, $url, $blog_name);
86       
87                // insert trackback data
88                $sql = "INSERT INTO     wbb".WBB_N."_trackback
89                        (
90                                        postID,
91                                        postURL,
92                                        title,
93                                        excerpt,
94                                        url,
95                                        blog_name,
96                                        isSpam
97                        ) VALUES (
98                                        {$postID},
99                                        '".escapeString($postURL)."',
100                                        '".escapeString($title)."',
101                                        '".escapeString($excerpt)."',
102                                        '".escapeString($url)."',
103                                        '".escapeString($blog_name)."',
104                                        $isSpam
105                        );";
106
107                WBBCore::getDB()->sendQuery($sql);
108        }
109       
110        /**
111         * does track and ping operations on alien urls
112         * @param postID
113         * @param alienurl
114         * @param page_title
115         * @param author
116         * @param url
117         * @param title
118         * @param excerpt
119         */
120        public static function trackAndPing($postID, $alienurl, $page_title, $author, $url, $title, $excerpt) {
121                $content = ""; // hold as reference
122
123                // auto discovery
124                $pingbacks = self::discover_pingback_uri($alienurl, $content);
125                $trackbacks = count($pingbacks) > 0 ? array() : self::discover_trackback_uri($content);
126               
127                // merge pingbacks with public pingback services
128                $pingbacks = array_merge($pingbacks, explode("\n", StringUtil::unifyNewlines(MESSAGE_PINGBACK)));
129
130                // send pingbacks
131                foreach($pingbacks as $pingbackurl) {
132                        self::send_pingback($alienurl, $pingbackurl, $page_title, $url);
133                        self::save_log($postID, $alienurl);
134                }
135
136                // send trackbacks
137                foreach($trackbacks as $trackbackurl) {
138                        self::send_trackback($trackbackurl, $page_title, $author, $url, $title, $excerpt);
139                        self::save_log($postID, $alienurl);
140                }
141        }
142       
143        /**
144         * akismet check
145         * @param title
146         * @param excerpt
147         * @param url
148         * @param blog_name
149         */     
150        protected static function isSpam($title, $excerpt, $url, $blog_name) {
151                if(AKISMET_API_KEY == '')
152                        return true;
153               
154                // WCF includes
155                require_once(WCF_DIR.'lib/util/AkismetUtil.class.php');
156
157                $akismet = new AkismetUtil(AKISMET_API_KEY,PAGE_URL);
158                $akismet->setCommentType('trackback');
159                $akismet->setPermalink($myurl); //absolute
160               
161                // assign post data
162                $akismet->setCommentAuthor($title);
163                $akismet->setCommentAuthorURL($url);
164                $akismet->setCommentContent($excerpt);
165
166                return $akismet->isCommentSpam();
167        }
168       
169        /**
170         * discover pingback uri
171         * @param url
172         * @param contents (reference)
173         * @return pingbacks
174         */
175        protected static function discover_pingback_uri($url, &$contents) {
176                $pingbacks = array(); // return var
177
178                $byte_count = 0;
179                $headers = '';
180                $pingback_str_dquote = 'rel="pingback"';
181                $pingback_str_squote = 'rel=\'pingback\'';
182                $x_pingback_str = 'x-pingback: ';
183                $pingback_href_original_pos = 27;
184
185                // parse url
186                $parse = parse_url($url);
187                $host =  (isset($parse['host'])) ? $parse['host'] : null;
188                $path  = (isset($parse['path'])) ? $parse['path'] : '/';
189                $path .= (isset($parse['query'])) ? "?".$parse['query'] : '';
190                $port  = (isset($parse['port'])) ? $parse['port'] : 80;
191
192                // Try to connect to the server at $host
193                $fp = @fsockopen($host, $port, $errno, $errstr, 2);
194                if ( !$fp ) // Couldn't open a connection to $host
195                        return false;
196
197                // Send the GET request
198                $request = "GET {$path} HTTP/1.1\r\nHost: $host\r\nUser-Agent: {self::agent} \r\n\r\n";
199                fputs($fp, $request);
200
201                // Let's check for an X-Pingback header first
202                while ( !feof($fp) ) {
203                        $line = fgets($fp, 512);
204                        if(trim($line) == '') //empty line = headers complete
205                                break;
206
207                        $headers .= trim($line)."\n";
208                        $x_pingback_header_offset = strpos(strtolower($headers), $x_pingback_str);
209
210                        if($x_pingback_header_offset) {
211                                // We got it!
212                                preg_match('#x-pingback: (.+)#is', $headers, $matches);
213                                $pingbacks[] = trim($matches[1]);
214                        }
215
216                        if(strpos(strtolower($headers), 'content-type: ')) {
217                                preg_match('#content-type: (.+)#is', $headers, $matches);
218                                $content_type = trim($matches[1]);
219                        }
220                }
221
222                if ( preg_match('#(image|audio|video|model)/#is', $content_type) ) // Not an (x)html, sgml, or xml page, no use going further
223                        return false;
224
225                while ( !feof($fp) ) {
226                        $line = fgets($fp, 1024);
227                        $contents .= trim($line);
228                        $pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
229                        $pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
230                        if($pingback_link_offset_dquote || $pingback_link_offset_squote) {
231                                $quote = ($pingback_link_offset_dquote) ? '"' : '\'';
232                                $pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
233                                $pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
234                                $pingback_href_start = $pingback_href_pos+6;
235                                $pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
236                                $pingback_server_url_len = $pingback_href_end - $pingback_href_start;
237                                $pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
238                                // We may find rel="pingback" but an incomplete pingback URL
239                                if ( $pingback_server_url_len > 0 ) {
240                                        // We got it!
241                                        $pingbacks[] = $pingback_server_url;
242                                }
243                        }
244                        $byte_count += strlen($line);
245                        if ( $byte_count > $timeout_bytes ) {
246                                // It's no use going further, there probably isn't any pingback
247                                // server to find in this file. (Prevents loading large files.)
248                                break;
249                        }
250                }
251               
252                return $pingbacks;
253        }
254       
255        /**
256         * discover trackback uri
257         * @param contents
258         * @return trackbacks
259         */
260        protected static function discover_trackback_uri($contents) {
261                $rdf = array(); // <- holds list of RDF segments
262
263                if ($contents) {
264                        preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $contents, $link_rdf, PREG_SET_ORDER);
265
266                        // Loop through all rdf segments
267                        for ($i = 0; $i < count($link_rdf); $i++) {
268                                if (preg_match('|dc:identifier="' . preg_quote($link) . '"|ms', $link_rdf[$i][1])) {
269                                        $rdf[] = trim($link_rdf[$i][1]);
270                                } 
271                        } 
272                }
273
274                // Loop through the RDFs array and extract trackback URIs
275                $trackbacks = array(); // <- holds list of trackback URIs
276                foreach($rdf as $rdf_url) {
277                        if (preg_match('/trackback:ping="([^"]+)"/', $rdf_url, $array)) {
278                                $trackbacks[] = trim($array[1]);
279                        } 
280                } 
281
282                return $trackbacks;
283        }
284
285
286        /**
287         * Send a Pingback
288         * @param alienurl -> the main url from the destination site
289         * @param pingbackurl -> the pingback url from the destination site
290         * @param url -> the own url
291         */
292        protected static function send_pingback($alienurl, $pingbackurl, $url) {
293                require_once(WBB_DIR.'lib/util/IXR.class.php');
294
295                // using a timeout of 3 seconds should be enough to cover slow servers
296                $client = new IXR_Client($pingbackurl);
297                $client->timeout = 3;
298                $client->useragent = self::agent;
299
300                // when set to true, this outputs debug messages by itself
301                $client->debug = false;
302
303                // Already registered
304                if ($client->query('pingback.ping', $url, $alienurl) || (isset($client->error->code) && 48 == $client->error->code)) {
305                        add_ping($post_ID, $pagelinkedto);
306                }
307        }
308
309        /**
310         * Send a Trackback
311         * @param trackbackurl
312         * @param page_title
313         * @param author
314         * @param url
315         * @param title
316         * @param excerpt
317         */
318        protected static function send_trackback($trackbackurl, $page_title, $author, $url, $title, $excerpt) {
319                $blog_name = urlencode($page_title);
320                $author = urlencode($author);
321                $title = urlencode($title);
322                $excerpt = urlencode($excerpt);
323
324                $query_string = "title=$title&url=$url&blog_name=$blog_name&excerpt=$excerpt";
325
326                $parse = parse_url($trackback_url);
327                $http_request = 'POST ' . $parse['path'] . ($parse['query'] ? '?'.$parse['query'] : '') . " HTTP/1.0\r\n";
328                $http_request .= 'Host: '.$parse['host']."\r\n";
329                $http_request .= 'Content-Type: application/x-www-form-urlencoded; charset='.CHARSET."\r\n";
330                $http_request .= 'Content-Length: '.strlen($query_string)."\r\n";
331                $http_request .= "User-Agent: {self::agent}";
332                $http_request .= "\r\n\r\n";
333                $http_request .= $query_string;
334
335                $fs = @fsockopen($parse['host'], isset($parse['port'])?$parse['port']:80, $errno, $errstr, 4);
336                @fputs($fs, $http_request);
337                @fclose($fs);
338        }
339       
340        /**
341         * saves log
342         * @param postID
343         * @param alienURL
344         */
345        protected static function save_log($postID, $alienurl) {
346                $sql = "INSERT INTO     wbb".WBB_N."_trackbackLog
347                        (
348                                        postID,
349                                        alienURL,
350                                        timestamp
351                        ) VALUES (
352                                        {$postID},
353                                        '".escapeString($alienurl)."',
354                                        ".time()."
355                        );";
356
357                WBBCore::getDB()->sendQuery($sql);
358        }
359} 
360?>
Note: See TracBrowser for help on using the browser.