Changeset 135

Show
Ignore:
Timestamp:
12/23/07 19:45:19 (5 years ago)
Author:
d0nut
Message:

trackbacks can only be added to the first posting

Location:
trackback
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • trackback/files/lib/action/TrackbackAction.class.php

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

    r134 r135  
    6262         */ 
    6363        protected function assignVariables () { 
    64                 WBBCore::getTPL()->assign('hasTrackback', $this->hasTrackback); 
    65                 WBBCore::getTPL()->append('additionalSettings', WBBCore::getTPL()->fetch('postTrackbackSetting')); 
     64                // only the first post can have trackbacks 
     65                if($this->eventObj->postID == $this->eventObj->thread->firstPostID) { 
     66                        WBBCore::getTPL()->assign('hasTrackback', $this->hasTrackback); 
     67                        WBBCore::getTPL()->append('additionalSettings', WBBCore::getTPL()->fetch('postTrackbackSetting')); 
     68                } 
    6669        } 
    6770 
     
    8184                                break; 
    8285                        case 'PostAddForm': 
    83                                 $postID = $this->eventObj->newPost->getID(); 
     86                                // only the first post can have trackbacks 
     87                                // $postID = $this->eventObj->newPost->getID(); 
    8488                        break; 
    8589                } 
  • trackback/files/lib/system/event/listener/ThreadPageTrackbackListener.class.php

    r78 r135  
    2121        public function execute($eventObj, $className, $eventName) { 
    2222                $postTrackbacks = array(); 
    23                 $check = array_reduce($eventObj->postList->posts, create_function('$a, $b', 'return @$a->hasTrackback || $b->hasTrackback;')); 
    24                  
    25                 if($check) { 
     23                $check = array_filter($eventObj->postList->posts, create_function('$a', 'return $a->hasTrackback;')); 
     24 
     25                if(count($check) > 0) { 
    2626                        // foreign trackbacks 
    27                         $sql = "SELECT          title, excerpt, url, blog_name 
     27                        $sql = "SELECT          title,  
     28                                                excerpt,  
     29                                                url,  
     30                                                blog_name 
    2831                                FROM            wbb".WBB_N."_trackback 
    2932                                WHERE           postID IN (".$eventObj->postList->postIDs."); "; 
     
    3639                        // fetch data 
    3740                        $row = TrackbackUtil::getPost($eventObj->postList->postIDs); 
    38  
    3941                        WBBCore::getTPL()->assign(array( 
    4042                                'postTrackbacks' => $postTrackbacks, 
    41                                 'postPermalink'=> $row['url'] 
     43                                'postPermalink'=> $row['url'], 
     44                                'postID'=> $row['firstPostID'], 
     45                                'postTopic'=> $row['topic'], 
     46                                'postPreview'=> $row['firstPostPreview'], 
     47                                'postUsername'=> $row['username'], 
     48                                'postTime'=> $row['time'], 
     49                                 
    4250                        )); 
     51                         
     52                        WBBCore::getTPL()->append('specialStyles', WBBCore::getTPL()->fetch('postTrackback')); 
    4353                } 
    4454        } 
  • trackback/options.xml

    r69 r135  
    99                                <defaultvalue><![CDATA[]]></defaultvalue><!--TODO start own pingback service//--> 
    1010                        </option> 
     11                        <option name="akismet_api_key"> 
     12                                <categoryname>message.default</categoryname> 
     13                                <optiontype>text</optiontype> 
     14                                <defaultvalue><![CDATA[]]></defaultvalue> 
     15                        </option> 
    1116                </options> 
    1217        </import> 
  • trackback/templates/postTrackback.tpl

    r37 r135  
    1 {if $post->hasTrackback} 
    2         {capture append=specialStyles} 
    3         <link rel="pingback" href="{PAGE_URL}index.php?action=Pingback" /> 
    4         <!-- 
    5         <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
    6                 xmlns:dc="http://purl.org/dc/elements/1.1/" 
    7                 xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> 
    8         <rdf:Description 
    9                 rdf:about="{$postPermalink}" 
    10                 dc:identifier="{$postPermalink}" 
    11                 trackback:ping="index.php?action=Trackback&amp;postID={$postID}" 
    12                 dc:title="{$post->topic}" 
    13                 dc:subject="TrackBack" 
    14                 dc:description="{$post->firstPostPreview}" 
    15                 dc:creator="{$post->username}" 
    16                 dc:date="{@'r'|gmdate:$post->time}" /> 
    17         </rdf:RDF> 
    18         --> 
    19         {/capture} 
    20          
    21         {if $postTrackbacks[$messageID]|isset} 
    22                 {foreach from=$postTrackbacks[$messageID] item=trackback} 
    23                         {lang}wbb.thread.post.trackback.blog_name{/lang}: {$trackback.blog_name} 
    24                         {lang}wbb.thread.post.trackback.title{/lang}: {$trackback.title}<br /> 
    25                         {lang}wbb.thread.post.trackback.excerpt{/lang}: {$trackback.excerpt}<br /> 
    26                         {lang}wbb.thread.post.trackback.url{/lang}: {$trackback.url}<br /> 
    27                 {/foreach} 
    28         {/if} 
     1{capture append=specialStyles} 
     2<link rel="pingback" href="{PAGE_URL}index.php?action=Pingback" /> 
     3<!-- 
     4<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
     5        xmlns:dc="http://purl.org/dc/elements/1.1/" 
     6        xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> 
     7<rdf:Description 
     8        rdf:about="{$postPermalink}" 
     9        dc:identifier="{$postPermalink}" 
     10        trackback:ping="index.php?action=Trackback&amp;postID={$postID}" 
     11        dc:title="{$postTopic}" 
     12        dc:subject="TrackBack" 
     13        dc:description="{$postPreview}" 
     14        dc:creator="{$postUsername}" 
     15        dc:date="{@'r'|gmdate:$postTime}" /> 
     16</rdf:RDF> 
     17--> 
     18{/capture} 
     19 
     20{if $postTrackbacks[$postID]|isset} 
     21        {foreach from=$postTrackbacks[$messageID] item=trackback} 
     22                {lang}wbb.thread.post.trackback.blog_name{/lang}: {$trackback.blog_name} 
     23                {lang}wbb.thread.post.trackback.title{/lang}: {$trackback.title}<br /> 
     24                {lang}wbb.thread.post.trackback.excerpt{/lang}: {$trackback.excerpt}<br /> 
     25                {lang}wbb.thread.post.trackback.url{/lang}: {$trackback.url}<br /> 
     26        {/foreach} 
    2927{/if}