Dotclear

Changeset 3415:5cdbb2593595


Ignore:
Timestamp:
11/23/16 08:21:31 (9 years ago)
Author:
Jean-Christian Denis
Branch:
default
Message:

Open trackbacks with behaviors and add basic Webmention support, closes #1917

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • admin/post.php

    r3340 r3415  
    169169          { 
    170170               try { 
     171                    # --BEHAVIOR-- adminBeforePingTrackback 
     172                    $core->callBehavior('adminBeforePingTrackback',$tb_url,$post_id,$tb_post_title,$tb_excerpt,$tb_post_url); 
     173 
    171174                    $TB->ping($tb_url, $post_id, $tb_post_title, $tb_excerpt, $tb_post_url); 
    172175               } catch (Exception $e) { 
  • inc/core/class.dc.trackback.php

    r3340 r3415  
    3535     } 
    3636 
    37      /// @name Send trackbacks 
     37     /// @name Send 
    3838     //@{ 
    3939     /** 
     
    8181 
    8282          $ping_parts = explode('|',$url); 
    83  
    84           # Let's walk by the trackback way 
    85           if (count($ping_parts) < 2) { 
     83          # Maybe a webmention 
     84          if (count($ping_parts) == 3) { 
     85               $payload = http_build_query(array( 
     86                    'source' => $post_url, 
     87                    'target' => $ping_parts[1] 
     88               )); 
     89 
     90               try { 
     91                    $http = self::initHttp($ping_parts[0],$path); 
     92                    $http->setMoreHeader('Content-Type: application/x-www-form-urlencoded'); 
     93                    $http->post($path,$payload,'UTF-8'); 
     94 
     95                    # Read response status 
     96                    $status = $http->getStatus(); 
     97                    $ping_error = '0'; 
     98               } 
     99               catch (Exception $e) { 
     100                    throw new Exception(__('Unable to ping URL')); 
     101               } 
     102 
     103               if (!in_array($status,array('200','201','202'))) { 
     104                    $ping_error = $http->getStatus(); 
     105                    $ping_msg = __('Bad server response code'); 
     106               } 
     107          } 
     108          # No, let's walk by the trackback way 
     109          elseif (count($ping_parts) < 2) { 
    86110               $data = array( 
    87111                    'title' => $post_title, 
     
    93117 
    94118               # Ping 
    95                try 
    96                { 
     119               try { 
    97120                    $http = self::initHttp($url,$path); 
    98121                    $http->post($path,$data,'UTF-8'); 
    99122                    $res = $http->getContent(); 
    100123               } 
    101                catch (Exception $e) 
    102                { 
     124               catch (Exception $e) { 
    103125                    throw new Exception(__('Unable to ping URL')); 
    104126               } 
     
    109131               '</response>|msU'; 
    110132 
    111                if (!preg_match($pattern,$res,$match)) 
    112                { 
     133               if (!preg_match($pattern,$res,$match)) { 
    113134                    throw new Exception(sprintf(__('%s is not a ping URL'),$url)); 
    114135               } 
     
    135156          if ($ping_error != '0') { 
    136157               throw new Exception(sprintf(__('%s, ping error:'),$url).' '.$ping_msg); 
    137           } else { 
     158          } 
     159          else { 
    138160               # Notify ping result in database 
    139161               $cur = $this->con->openCursor($this->table); 
     
    147169     //@} 
    148170 
    149      private function pingAlreadyDone($post_id, $from_url) 
    150      { 
    151           $params = array( 
    152                'post_id' => $post_id, 
    153                'comment_site' => $from_url, 
    154                'comment_trackback' => 1, 
    155           ); 
    156  
    157           $rs = $this->core->blog->getComments($params, true); 
    158           if ($rs && !$rs->isEmpty()) { 
    159                return ($rs->f(0)); 
    160           } 
    161  
    162           return false; 
    163      } 
    164  
    165      private function addBacklink($post_id, $url, $blog_name, $title, $excerpt, &$comment) 
    166      { 
    167           if (empty($blog_name)) { 
    168                $blog_name = 'Anonymous blog'; 
    169           } 
    170  
    171           $comment = 
    172           "<!-- TB -->\n". 
    173           '<p><strong>'.($title ?: $blog_name)."</strong></p>\n". 
    174           '<p>'.$excerpt.'</p>'; 
    175  
    176           $cur = $this->core->con->openCursor($this->core->prefix.'comment'); 
    177           $cur->comment_author = (string) $blog_name; 
    178           $cur->comment_site = (string) $url; 
    179           $cur->comment_content = (string) $comment; 
    180           $cur->post_id = $post_id; 
    181           $cur->comment_trackback = 1; 
    182           $cur->comment_status = $this->core->blog->settings->system->trackbacks_pub ? 1 : -1; 
    183           $cur->comment_ip = http::realIP(); 
    184  
    185           # --BEHAVIOR-- publicBeforeTrackbackCreate 
    186           $this->core->callBehavior('publicBeforeTrackbackCreate',$cur); 
    187           if ($cur->post_id) { 
    188                $comment_id = $this->core->blog->addComment($cur); 
    189  
    190                # --BEHAVIOR-- publicAfterTrackbackCreate 
    191                $this->core->callBehavior('publicAfterTrackbackCreate',$cur,$comment_id); 
    192           } 
    193      } 
    194  
    195      /// @name Receive trackbacks 
     171     /// @name Receive 
    196172     //@{ 
    197173     /** 
     
    200176     @param    post_id        <b>integer</b>      Post ID 
    201177     */ 
    202      public function receive($post_id) 
     178     public function receiveTrackback($post_id) 
    203179     { 
    204180          header('Content-Type: text/xml; charset=UTF-8'); 
     
    226202          $msg = ''; 
    227203 
    228           if ($this->core->blog === null) 
    229           { 
     204          if ($this->core->blog === null) { 
    230205               $err = true; 
    231206               $msg = 'No blog.'; 
    232207          } 
    233           elseif ($url == '') 
    234           { 
     208          elseif ($url == '') { 
    235209               $err = true; 
    236210               $msg = 'URL parameter is required.'; 
     
    241215          } 
    242216 
    243           if (!$err) 
    244           { 
     217          if (!$err) { 
    245218               $post = $this->core->blog->getPosts(array('post_id'=>$post_id,'post_type'=>'')); 
    246219 
    247                if ($post->isEmpty()) 
    248                { 
     220               if ($post->isEmpty()) { 
    249221                    $err = true; 
    250222                    $msg = 'No such post.'; 
    251223               } 
    252                elseif (!$post->trackbacksActive()) 
    253                { 
     224               elseif (!$post->trackbacksActive()) { 
    254225                    $err = true; 
    255226                    $msg = 'Trackbacks are not allowed for this post or weblog.'; 
     
    257228 
    258229               $url = trim(html::clean($url)); 
    259                if ($this->pingAlreadyDone($post->post_id, $url)) { 
     230               if ($this->pingAlreadyDone($post->post_id,$url)) { 
    260231                    $err = true; 
    261232                    $msg = 'The trackback has already been registered'; 
     
    263234          } 
    264235 
    265           if (!$err) 
    266           { 
     236          if (!$err) { 
    267237               $charset = self::getCharsetFromRequest(); 
    268238 
     
    293263               $blog_name = text::cutString($blog_name,60); 
    294264 
    295                try 
    296                { 
    297                     $this->addBacklink($post_id, $url, $blog_name, $title, $excerpt, $comment); 
    298                } 
    299                catch (Exception $e) 
    300                { 
     265               try { 
     266                    $this->addBacklink($post_id,$url,$blog_name,$title,$excerpt,$comment); 
     267               } 
     268               catch (Exception $e) { 
    301269                    $err = 1; 
    302270                    $msg = 'Something went wrong : '.$e->getMessage(); 
     
    327295          echo $resp."</response>"; 
    328296     } 
    329      //@} 
    330  
    331      /// @name Receive pingbacks 
    332      //@{ 
     297 
    333298     /** 
    334299     Receives a pingback and insert it as a comment of given post. 
     
    337302     @param    to_url              <b>string</b>       Target URL 
    338303     */ 
    339      public function receive_pb($from_url, $to_url) 
     304     public function receivePingback($from_url,$to_url) 
     305     { 
     306          try { 
     307               $posts = $this->getTargetPost($to_url); 
     308 
     309               if ($this->pingAlreadyDone($posts->post_id,$from_url)) { 
     310                    throw new Exception(__('Don\'t repeat yourself, please.'), 48); 
     311               } 
     312 
     313               $remote_content = $this->getRemoteContent($from_url); 
     314 
     315               # We want a title... 
     316               if (!preg_match('!<title>([^<].*?)</title>!mis',$remote_content,$m)) { 
     317                    throw new Exception(__('Where\'s your title?'), 0); 
     318               } 
     319               $title = trim(html::clean($m[1])); 
     320               $title = html::decodeEntities($title); 
     321               $title = html::escapeHTML($title); 
     322               $title = text::cutString($title,60); 
     323 
     324               preg_match('!<body[^>]*?>(.*)?</body>!msi',$remote_content,$m); 
     325               $source = $m[1]; 
     326               $source = preg_replace('![\r\n\s]+!ms',' ',$source); 
     327               $source = preg_replace( "/<\/*(h\d|p|th|td|li|dt|dd|pre|caption|input|textarea|button)[^>]*>/","\n\n",$source ); 
     328               $source = strip_tags($source,'<a>'); 
     329               $source = explode("\n\n",$source); 
     330 
     331               $excerpt = ''; 
     332               foreach ($source as $line) { 
     333                    if (strpos($line, $to_url) !== false) { 
     334                         if (preg_match("!<a[^>]+?".$to_url."[^>]*>([^>]+?)</a>!",$line,$m)) { 
     335                              $excerpt = strip_tags($line); 
     336                              break; 
     337                         } 
     338                    } 
     339               } 
     340               if ($excerpt) { 
     341                    $excerpt = '(&#8230;) '.text::cutString(html::escapeHTML($excerpt),200).' (&#8230;)'; 
     342               } 
     343               else { 
     344                    $excerpt = '(&#8230;)'; 
     345               } 
     346 
     347               $this->addBacklink($posts->post_id,$from_url,'',$title,$excerpt,$comment); 
     348          } 
     349          catch (Exception $e) { 
     350               throw new Exception(__('Sorry, an internal problem has occured.'),0); 
     351          } 
     352 
     353          return __('Thanks, mate. It was a pleasure.'); 
     354     } 
     355 
     356     /** 
     357     Receives a webmention and insert it as a comment of given post. 
     358      
     359     NB: plugin Fair Trackback check source content to find url. 
     360 
     361     @return   <b>null</b>    Null on success, else throw an exception 
     362     */ 
     363     public function receiveWebmention() 
     364     { 
     365          $err = $post_id = false; 
     366          header('Content-Type: text/html; charset=UTF-8'); 
     367 
     368          try { 
     369               # Check if post and target are valid URL 
     370               if (empty($_POST['source']) || empty($_POST['target'])) { 
     371                    throw new Exception('Source or target is not valid',0); 
     372               } 
     373 
     374               $from_url = urldecode($_POST['source']); 
     375               $to_url = urldecode($_POST['target']); 
     376 
     377               self::checkURLs($from_url,$to_url); 
     378 
     379               # Try to find post 
     380               $posts = $this->getTargetPost($to_url); 
     381               $post_id = $posts->post_id; 
     382 
     383               # Check if it's an updated mention 
     384               if ($this->pingAlreadyDone($post_id,$from_url)) { 
     385                    $this->delBacklink($post_id,$from_url); 
     386               } 
     387 
     388               # Create a comment for received webmention 
     389               // maybe better to try to fetch a title from the source ?... 
     390               $title = __('A website mention this entry.'); 
     391               $comment = ''; 
     392               $excerpt = sprintf('<a href="%s" rel="nofollow">%s</a>',$from_url,$from_url); 
     393               $this->addBacklink($post_id,$from_url,'',$title,$excerpt,$comment); 
     394 
     395               # All done, thanks 
     396               $code = $this->core->blog->settings->system->trackbacks_pub ? 200 : 202; 
     397               http::head($code); 
     398               return; 
     399          } 
     400          catch (Exception $e) { 
     401               $err = $e->getMessage(); 
     402          } 
     403 
     404          http::head(400); 
     405          echo $err ?: 'Something went wrong.'; 
     406          return; 
     407     } 
     408 
     409     /** 
     410     Check if a post previously received a ping a from an URL. 
     411 
     412     @param    post_id   <b>integer</b>      Post ID 
     413     @param    from_url  <b>string</b>       Source URL 
     414     @return   <b>boolean</b> 
     415     */ 
     416     private function pingAlreadyDone($post_id,$from_url) 
     417     { 
     418          $params = array( 
     419               'post_id' => $post_id, 
     420               'comment_site' => $from_url, 
     421               'comment_trackback' => 1, 
     422          ); 
     423 
     424          $rs = $this->core->blog->getComments($params,true); 
     425          if ($rs && !$rs->isEmpty()) { 
     426               return ($rs->f(0)); 
     427          } 
     428 
     429          return false; 
     430     } 
     431 
     432     /** 
     433     Create a comment marked as trackback for a given post. 
     434 
     435     @param    post_id   <b>integer</b>      Post ID 
     436     @param    url       <b>string</b>       Discovered URL 
     437     @param    blog name <b>string</b>       Source blog name 
     438     @param    title     <b>string</b>       Comment title 
     439     @param    excerpt   <b>string</b>       Source excerpt 
     440     @param    comment   <b>string</b>       Comment content 
     441     */ 
     442     private function addBacklink($post_id,$url,$blog_name,$title,$excerpt,&$comment) 
     443     { 
     444          if (empty($blog_name)) { 
     445               $blog_name = 'Anonymous blog'; 
     446          } 
     447 
     448          $comment = 
     449          "<!-- TB -->\n". 
     450          '<p><strong>'.($title ?: $blog_name)."</strong></p>\n". 
     451          '<p>'.$excerpt.'</p>'; 
     452 
     453          $cur = $this->core->con->openCursor($this->core->prefix.'comment'); 
     454          $cur->comment_author = (string) $blog_name; 
     455          $cur->comment_site = (string) $url; 
     456          $cur->comment_content = (string) $comment; 
     457          $cur->post_id = $post_id; 
     458          $cur->comment_trackback = 1; 
     459          $cur->comment_status = $this->core->blog->settings->system->trackbacks_pub ? 1 : -1; 
     460          $cur->comment_ip = http::realIP(); 
     461 
     462          # --BEHAVIOR-- publicBeforeTrackbackCreate 
     463          $this->core->callBehavior('publicBeforeTrackbackCreate',$cur); 
     464          if ($cur->post_id) { 
     465               $comment_id = $this->core->blog->addComment($cur); 
     466 
     467               # --BEHAVIOR-- publicAfterTrackbackCreate 
     468               $this->core->callBehavior('publicAfterTrackbackCreate',$cur,$comment_id); 
     469          } 
     470     } 
     471 
     472     /** 
     473     Delete previously received comment made from an URL for a given post. 
     474 
     475     @param    post_id   <b>integer</b>      Post ID 
     476     @param    url       <b>string</b>       Source URL 
     477     */ 
     478     private function delBacklink($post_id,$url) 
     479     { 
     480          $this->con->execute( 
     481               'DELETE FROM '.$this->core->prefix.'comment '. 
     482               'WHERE post_id = '.((integer) $post_id).' '. 
     483               "AND comment_site = '".$this->core->con->escape((string) $url)."' ". 
     484               'AND comment_trackback = 1 ' 
     485          ); 
     486     } 
     487 
     488     /** 
     489     Find Charset from HTTP headers. 
     490 
     491     @param    header    <b>string</b>       Source header 
     492     @return   <b>string</b> 
     493     */ 
     494     private static function getCharsetFromRequest($header = '') 
     495     { 
     496          if (!$header && isset($_SERVER['CONTENT_TYPE'])) { 
     497               $header = $_SERVER['CONTENT_TYPE']; 
     498          } 
     499 
     500          if ($header) { 
     501               if (preg_match('|charset=([a-zA-Z0-9-]+)|',$header,$m)) { 
     502                    return $m[1]; 
     503               } 
     504          } 
     505 
     506          return null; 
     507     } 
     508 
     509     /** 
     510     Detect encoding. 
     511 
     512     @param    content        <b>string</b>       Source URL 
     513     @return   <b>string</b> 
     514     */ 
     515     private static function detectCharset($content) 
     516     { 
     517          return mb_detect_encoding($content, 
     518                    'UTF-8,ISO-8859-1,ISO-8859-2,ISO-8859-3,'. 
     519                    'ISO-8859-4,ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,'. 
     520                    'ISO-8859-9,ISO-8859-10,ISO-8859-13,ISO-8859-14,ISO-8859-15'); 
     521     } 
     522 
     523     /** 
     524     Retreive local post from a given IRL 
     525 
     526     @param    to_url         <b>string</b>       Target URL 
     527     @return   <b>string</b> 
     528     */ 
     529     private function getTargetPost($to_url) 
    340530     { 
    341531          $reg = '!^'.preg_quote($this->core->blog->url).'(.*)!'; 
     
    343533 
    344534          # Are you dumb? 
    345           if (!preg_match($reg, $to_url, $m)) { 
    346                throw new Exception(__('Any chance you ping one of my contents? No? Really?'), 0); 
     535          if (!preg_match($reg,$to_url,$m)) { 
     536               throw new Exception(__('Any chance you ping one of my contents? No? Really?'),0); 
    347537          } 
    348538 
     
    352542          $post_types = $this->core->getPostTypes(); 
    353543          foreach ($post_types as $k => $v) { 
    354                $reg = '!^'.preg_quote(str_replace('%s', '', $v['public_url'])).'(.*)!'; 
    355                if (preg_match($reg, $url_part, $n)) { 
     544               $reg = '!^'.preg_quote(str_replace('%s','',$v['public_url'])).'(.*)!'; 
     545               if (preg_match($reg,$url_part,$n)) { 
    356546                    $p_type = $k; 
    357547                    $post_url = $n[1]; 
     
    361551 
    362552          if (empty($p_type)) { 
    363                throw new Exception(__('Sorry but you can not ping this type of content.'), 33); 
     553               throw new Exception(__('Sorry but you can not ping this type of content.'),33); 
    364554          } 
    365555 
     
    373563          # Missed! 
    374564          if ($posts->isEmpty()) { 
    375                throw new Exception(__('Oops. Kinda "not found" stuff. Please check the target URL twice.'), 33); 
     565               throw new Exception(__('Oops. Kinda "not found" stuff. Please check the target URL twice.'),33); 
    376566          } 
    377567 
    378568          # Nice try. But, sorry, no. 
    379569          if (!$posts->trackbacksActive()) { 
    380                throw new Exception(__('Sorry, dude. This entry does not accept pingback at the moment.'), 33); 
    381           } 
    382  
    383           if ($this->pingAlreadyDone($posts->post_id, $from_url)) { 
    384                throw new Exception(__('Don\'t repeat yourself, please.'), 48); 
    385           } 
    386  
    387           # OK. We've found our champion. Time to check the remote part. 
    388           try { 
    389                $http = self::initHttp($from_url, $from_path); 
    390  
    391                # First round : just to be sure the ping comes from an acceptable resource type. 
    392                $http->setHeadersOnly(true); 
    393                $http->get($from_path); 
    394                $c_type = explode(';', $http->getHeader('content-type')); 
    395  
    396                # Bad luck. Bye, bye... 
    397                if (!in_array($c_type[0],array('text/html', 'application/xhtml+xml'))) { 
    398                     throw new Exception(__('Your source URL does not look like a supported content type. Sorry. Bye, bye!'), 0); 
    399                } 
    400  
    401                # Second round : let's go fetch and parse the remote content 
    402                $http->setHeadersOnly(false); 
    403                $http->get($from_path); 
    404                $remote_content = $http->getContent(); 
    405  
    406                $charset = self::getCharsetFromRequest($http->getHeader('content-type')); 
    407  
    408                if (!$charset) { 
    409                     $charset = self::detectCharset($remote_content); 
    410                } 
    411  
    412                if (strtolower($charset) != 'utf-8') { 
    413                     $remote_content = iconv($charset,'UTF-8',$remote_content); 
    414                } 
    415  
    416                # We want a title... 
    417                if (!preg_match('!<title>([^<].*?)</title>!mis', $remote_content, $m)) { 
    418                     throw new Exception(__('Where\'s your title?'), 0); 
    419                } 
    420                $title = trim(html::clean($m[1])); 
    421                $title = html::decodeEntities($title); 
    422                $title = html::escapeHTML($title); 
    423                $title = text::cutString($title,60); 
    424  
    425                preg_match('!<body[^>]*?>(.*)?</body>!msi', $remote_content, $m); 
    426                $source = $m[1]; 
    427                $source = preg_replace('![\r\n\s]+!ms',' ',$source); 
    428                $source = preg_replace( "/<\/*(h\d|p|th|td|li|dt|dd|pre|caption|input|textarea|button)[^>]*>/", "\n\n", $source ); 
    429                $source = strip_tags($source, '<a>'); 
    430                $source = explode("\n\n",$source); 
    431  
    432                $excerpt = ''; 
    433                foreach ($source as $line) { 
    434                     if (strpos($line, $to_url) !== false) { 
    435                          if (preg_match("!<a[^>]+?".$to_url."[^>]*>([^>]+?)</a>!", $line, $m)) { 
    436                               $excerpt = strip_tags($line); 
    437                               break; 
    438                          } 
    439                     } 
    440                } 
    441                if ($excerpt) { 
    442                     $excerpt = '(&#8230;) '.text::cutString(html::escapeHTML($excerpt),200).' (&#8230;)'; 
    443                } 
    444                else { 
    445                     $excerpt = '(&#8230;)'; 
    446                } 
    447  
    448                $this->addBacklink($posts->post_id, $from_url, '', $title, $excerpt, $comment); 
    449           } 
    450           catch (Exception $e) { 
    451                throw new Exception(__('Sorry, an internal problem has occured.'), 0); 
    452           } 
    453  
    454           return __('Thanks, mate. It was a pleasure.'); 
     570               throw new Exception(__('Sorry, dude. This entry does not accept pingback at the moment.'),33); 
     571          } 
     572 
     573          return $posts; 
     574     } 
     575 
     576     /** 
     577     Returns content of a distant page 
     578 
     579     @param    from_url       <b>string</b>       Target URL 
     580     @return   <b>string</b> 
     581     */ 
     582     private function getRemoteContent($from_url) 
     583     { 
     584          $http = self::initHttp($from_url,$from_path); 
     585 
     586          # First round : just to be sure the ping comes from an acceptable resource type. 
     587          $http->setHeadersOnly(true); 
     588          $http->get($from_path); 
     589          $c_type = explode(';',$http->getHeader('content-type')); 
     590 
     591          # Bad luck. Bye, bye... 
     592          if (!in_array($c_type[0],array('text/html','application/xhtml+xml'))) { 
     593               throw new Exception(__('Your source URL does not look like a supported content type. Sorry. Bye, bye!'),0); 
     594          } 
     595 
     596          # Second round : let's go fetch and parse the remote content 
     597          $http->setHeadersOnly(false); 
     598          $http->get($from_path); 
     599          $remote_content = $http->getContent(); 
     600 
     601          # Convert content charset 
     602          $charset = self::getCharsetFromRequest($http->getHeader('content-type')); 
     603          if (!$charset) { 
     604               $charset = self::detectCharset($remote_content); 
     605          } 
     606          if (strtolower($charset) != 'utf-8') { 
     607               $remote_content = iconv($charset,'UTF-8',$remote_content); 
     608          } 
     609 
     610          return $remote_content; 
    455611     } 
    456612     //@} 
    457613 
    458      private static function initHttp($url,&$path) 
    459      { 
    460           $client = netHttp::initClient($url,$path); 
    461           $client->setTimeout(5); 
    462           $client->setUserAgent('Dotclear - http://www.dotclear.org/'); 
    463           $client->useGzip(false); 
    464           $client->setPersistReferers(false); 
    465  
    466           return $client; 
    467      } 
    468  
    469      private static function getCharsetFromRequest($header = '') 
    470      { 
    471           if (!$header && isset($_SERVER['CONTENT_TYPE'])) { 
    472                $header = $_SERVER['CONTENT_TYPE']; 
    473           } 
    474  
    475           if ($header) { 
    476                if (preg_match('|charset=([a-zA-Z0-9-]+)|',$header,$m)) { 
    477                     return $m[1]; 
    478                } 
    479           } 
    480  
    481           return null; 
    482      } 
    483  
    484      private static function detectCharset($content) 
    485      { 
    486           return mb_detect_encoding($content, 
    487                     'UTF-8,ISO-8859-1,ISO-8859-2,ISO-8859-3,'. 
    488                     'ISO-8859-4,ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,'. 
    489                     'ISO-8859-9,ISO-8859-10,ISO-8859-13,ISO-8859-14,ISO-8859-15'); 
    490      } 
    491  
    492      /// @name Trackbacks auto discovery 
     614     /// @name Discover 
    493615     //@{ 
    494616     /** 
     
    512634          return $res; 
    513635     } 
    514      //@} 
    515  
     636 
     637     /** 
     638     Find links into a text. 
     639 
     640     @param    text      <b>string</b>       Text to scan 
     641     @return   <b>array</b> 
     642     */ 
    516643     private function getTextLinks($text) 
    517644     { 
     
    519646 
    520647          # href attribute on "a" tags 
    521           if (preg_match_all('/<a ([^>]+)>/ms', $text, $match, PREG_SET_ORDER)) 
    522           { 
     648          if (preg_match_all('/<a ([^>]+)>/ms',$text,$match,PREG_SET_ORDER)) { 
    523649               for ($i = 0; $i<count($match); $i++) 
    524650               { 
    525                     if (preg_match('/href="((https?:\/)?\/[^"]+)"/ms', $match[$i][1], $matches)) { 
     651                    if (preg_match('/href="((https?:\/)?\/[^"]+)"/ms',$match[$i][1],$matches)) { 
    526652                         $res[$matches[1]] = 1; 
    527653                    } 
     
    531657 
    532658          # cite attributes on "blockquote" and "q" tags 
    533           if (preg_match_all('/<(blockquote|q) ([^>]+)>/ms', $text, $match, PREG_SET_ORDER)) 
    534           { 
     659          if (preg_match_all('/<(blockquote|q) ([^>]+)>/ms',$text,$match,PREG_SET_ORDER)) { 
    535660               for ($i = 0; $i<count($match); $i++) 
    536661               { 
    537                     if (preg_match('/cite="((https?:\/)?\/[^"]+)"/ms', $match[$i][2], $matches)) { 
     662                    if (preg_match('/cite="((https?:\/)?\/[^"]+)"/ms',$match[$i][2],$matches)) { 
    538663                         $res[$matches[1]] = 1; 
    539664                    } 
     
    544669     } 
    545670 
     671     /** 
     672     Check remote header/content to find api trace. 
     673 
     674     @param    url       <b>string</b>       URL to scan 
     675     @return   <b>string</b> 
     676     */ 
    546677     private function getPingURL($url) 
    547678     { 
     
    550681          } 
    551682 
    552           try 
    553           { 
     683          try { 
    554684               $http = self::initHttp($url,$path); 
    555685               $http->get($path); 
    556686               $page_content = $http->getContent(); 
    557687               $pb_url = $http->getHeader('x-pingback'); 
    558           } 
    559           catch (Exception $e) 
    560           { 
     688               $wm_url = $http->getHeader('link'); 
     689          } 
     690          catch (Exception $e) { 
    561691               return false; 
    562692          } 
     
    587717 
    588718          $url_path = parse_url($url, PHP_URL_PATH); 
    589           $sanitized_url = str_replace($url_path, html::sanitizeURL($url_path), $url); 
     719          $sanitized_url = str_replace($url_path, html::sanitizeURL($url_path),$url); 
    590720 
    591721          for ($i=0; $i<count($rdf_all); $i++) 
     
    600730          } 
    601731 
     732          # Nothing, let's try webmention. Only support x/html content 
     733          if ($wm_url) { 
     734               $type = explode(';',$http->getHeader('content-type')); 
     735               if (!in_array($type[0],array('text/html','application/xhtml+xml'))) { 
     736                    $wm_url = false; 
     737               } 
     738          } 
     739 
     740          # Check HTTP headers for a Link: <ENDPOINT_URL>; rel="webmention" 
     741          $wm_api = false; 
     742          if ($wm_url) { 
     743               if(preg_match('~<((?:https?://)?[^>]+)>; rel="?(?:https?://webmention.org/?|webmention)"?~',$wm_url,$match)) { 
     744                    if (filter_var($match[1],FILTER_VALIDATE_URL) && preg_match('!^https?:!',$match[1])) { 
     745                         $wm_api = $match[1]; 
     746                    } 
     747               } 
     748          } 
     749 
     750          # Else check content for <link href="ENDPOINT_URL" rel="webmention" /> 
     751          if ($wm_url && !$wm_api) { 
     752               $content = preg_replace('/<!--(.*)-->/Us','',$page_content); 
     753               if (preg_match('/<(?:link|a)[ ]+href="([^"]*)"[ ]+rel="[^" ]* ?webmention ?[^" ]*"[ ]*\/?>/i',$content,$match) 
     754                || preg_match('/<(?:link|a)[ ]+rel="[^" ]* ?webmention ?[^" ]*"[ ]+href="([^"]*)"[ ]*\/?>/i',$content,$match)) { 
     755                    $wm_api = $match[1]; 
     756               } 
     757          } 
     758 
     759          # We have a winner, let's add some tricks to make diference 
     760          if ($wm_api) { 
     761               return $wm_api.'|'.$url.'|webmention'; 
     762          } 
     763 
    602764          return null; 
    603765     } 
     766     //@} 
     767 
     768     /** 
     769     HTTP helper. 
     770 
     771     @param    url       <b>string</b>       URL 
     772     @param    path      <b>string</b>       Path 
     773     @return   <b>object</b> 
     774     */ 
     775     private static function initHttp($url,&$path) 
     776     { 
     777          $client = netHttp::initClient($url,$path); 
     778          $client->setTimeout(5); 
     779          $client->setUserAgent('Dotclear - http://www.dotclear.org/'); 
     780          $client->useGzip(false); 
     781          $client->setPersistReferers(false); 
     782 
     783          return $client; 
     784     } 
     785 
     786     /** 
     787     URL helper. 
     788 
     789     @param    from_url       <b>string</b>       URL a 
     790     @param    to_url         <b>string</b>       URL b 
     791     */ 
     792     public static function checkURLs($from_url,$to_url) 
     793     { 
     794          if (!(filter_var($from_url, FILTER_VALIDATE_URL) && preg_match('!^https?://!',$from_url))) { 
     795               throw new Exception(__('No valid source URL provided? Try again!'), 0); 
     796          } 
     797 
     798          if (!(filter_var($to_url, FILTER_VALIDATE_URL) && preg_match('!^https?://!',$to_url))) { 
     799               throw new Exception(__('No valid target URL provided? Try again!'), 0); 
     800          } 
     801 
     802          if (html::sanitizeURL(urldecode($from_url)) == html::sanitizeURL(urldecode($to_url))) { 
     803               throw new Exception(__('LOL!'), 0); 
     804          } 
     805     } 
    604806} 
  • inc/core/class.dc.xmlrpc.php

    r3170 r3415  
    16361636     public function pingback_ping($from_url, $to_url) 
    16371637     { 
    1638           # Come on, buddy! Don't make me waste time with this kind of silliness... 
    1639           if (!(filter_var($from_url, FILTER_VALIDATE_URL) && preg_match('!^https?://!',$from_url))) { 
    1640                throw new Exception(__('No valid source URL provided? Try again!'), 0); 
    1641           } 
    1642  
    1643           if (!(filter_var($to_url, FILTER_VALIDATE_URL) && preg_match('!^https?://!',$to_url))) { 
    1644                throw new Exception(__('No valid target URL provided? Try again!'), 0); 
    1645           } 
    1646  
    1647           if (html::sanitizeURL(urldecode($from_url)) == html::sanitizeURL(urldecode($to_url))) { 
    1648                throw new Exception(__('LOL!'), 0); 
    1649           } 
     1638          dcTrackback::checkURLs($from_url,$to_url); 
     1639 
     1640          $args = array('type'=>'pingback','from_url'=>$from_url,'to_url'=>$to_url); 
    16501641 
    16511642          # Time to get things done... 
    16521643          $this->setBlog(true); 
     1644 
     1645          # --BEHAVIOR-- publicBeforeReceiveTrackback 
     1646          $this->core->callBehavior('publicBeforeReceiveTrackback',$this->core,$args); 
     1647 
    16531648          $tb = new dcTrackback($this->core); 
    1654           return $tb->receive_pb($from_url, $to_url); 
     1649          return $tb->receivePingback($from_url,$to_url); 
    16551650     } 
    16561651} 
  • inc/prepend.php

    r3403 r3415  
    286286$core->url->register('feed','feed','^feed/(.+)$',array('dcUrlHandlers','feed')); 
    287287$core->url->register('trackback','trackback','^trackback/(.+)$',array('dcUrlHandlers','trackback')); 
     288$core->url->register('webmention','webmention','^webmention(/.+)?$',array('dcUrlHandlers','webmention')); 
    288289$core->url->register('rsd','rsd','^rsd$',array('dcUrlHandlers','rsd')); 
    289290$core->url->register('xmlrpc','xmlrpc','^xmlrpc/(.+)$',array('dcUrlHandlers','xmlrpc')); 
  • inc/public/lib.urlhandlers.php

    r3030 r3415  
    520520                    if ($_ctx->posts->trackbacksActive()) { 
    521521                         header('X-Pingback: '.$core->blog->url.$core->url->getURLFor("xmlrpc",$core->blog->id)); 
     522                         header('Link: <'.$core->blog->url.$core->url->getURLFor('webmention').'>; rel="webmention"'); 
    522523                    } 
    523524                    self::serveDocument('post.html'); 
     
    681682               self::p404(); 
    682683          } else { 
     684               $core =& $GLOBALS['core']; 
     685               if (!is_array($args)) $args = array(); 
     686               $args['type'] = 'trackback'; 
     687 
     688               # --BEHAVIOR-- publicBeforeReceiveTrackback 
     689               $core->callBehavior('publicBeforeReceiveTrackback',$core,$args); 
     690 
    683691               $tb = new dcTrackback($GLOBALS['core']); 
    684                $tb->receive($args); 
    685           } 
     692               $tb->receiveTrackback($args); 
     693          } 
     694     } 
     695 
     696     public static function webmention($args) 
     697     { 
     698          $core =& $GLOBALS['core']; 
     699          if (!is_array($args)) $args = array(); 
     700          $args['type'] = 'webmention'; 
     701 
     702          # --BEHAVIOR-- publicBeforeReceiveTrackback 
     703          $core->callBehavior('publicBeforeReceiveTrackback',$core,$args); 
     704 
     705          $tb = new dcTrackback($core); 
     706          $tb->receiveWebmention(); 
    686707     } 
    687708 
Note: See TracChangeset for help on using the changeset viewer.

Sites map