]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/LinkbackPlugin.php
first version of plugin for pingback and trackback (no trackback yet)
[quix0rs-gnu-social.git] / plugins / LinkbackPlugin.php
1 <?php
2 /**
3  * Laconica, the distributed open-source microblogging tool
4  *
5  * Plugin to do linkbacks for notices containing links
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Plugin
23  * @package   Laconica
24  * @author    Evan Prodromou <evan@controlyourself.ca>
25  * @copyright 2009 Control Yourself, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27  * @link      http://laconi.ca/
28  */
29
30 if (!defined('LACONICA')) {
31     exit(1);
32 }
33
34 require_once('Auth/Yadis/Yadis.php');
35
36 define('LINKBACKPLUGIN_VERSION', '0.1');
37
38 /**
39  * Plugin to do linkbacks for notices containing URLs
40  *
41  * After new notices are saved, we check their text for URLs. If there
42  * are URLs, we test each URL to see if it supports any
43  *
44  * @category Plugin
45  * @package  Laconica
46  * @author   Evan Prodromou <evan@controlyourself.ca>
47  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
48  * @link     http://laconi.ca/
49  *
50  * @see      Event
51  */
52
53 class LinkbackPlugin extends Plugin
54 {
55     var $notice = null;
56
57     function __construct()
58     {
59         parent::__construct();
60     }
61
62     function onEndNoticeSave($notice)
63     {
64         if ($notice->is_local == 1) {
65             // Try to avoid actually mucking with the
66             // notice content
67             $c = $notice->content;
68             $this->notice = $notice;
69             // Ignoring results
70             common_replace_urls_callback($c,
71                                          array($this, 'linkbackUrl'));
72         }
73         return true;
74     }
75
76     function linkbackUrl($url)
77     {
78         $orig = $url;
79         $url = htmlspecialchars_decode($orig);
80         $scheme = parse_url($url, PHP_URL_SCHEME);
81         if (!in_array($scheme, array('http', 'https'))) {
82             return $orig;
83         }
84
85         // XXX: Do a HEAD first to save some time/bandwidth
86
87         $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
88
89         $result = $fetcher->get($url,
90                                 array('User-Agent: ' . $this->userAgent(),
91                                       'Accept: application/html+xml,text/html'));
92
93         if (!in_array($result->status, array('200', '206'))) {
94             return $orig;
95         }
96
97         if (array_key_exists('X-Pingback', $result->headers)) {
98             $endpoint = $result->headers['X-Pingback'];
99         } else if (preg_match('/<link rel="pingback" href="([^"]+)" ?/?>/',
100                               $result->body,
101                               $match)) {
102             $endpoint = $match[1];
103         } else {
104             // XXX: do Trackback lookup
105             return $orig;
106         }
107
108         $this->pingback($url, $endpoint);
109         return $orig;
110     }
111
112     function pingback($url, $endpoint)
113     {
114         $args = array($this->notice->uri, $url);
115
116         $request = xmlrpc_encode_request('pingback.ping', $args);
117         $context = stream_context_create(array('http' => array('method' => "POST",
118                                                                'header' =>
119                                                                "Content-Type: text/xml\r\n".
120                                                                "User-Agent: " . $this->userAgent(),
121                                                                'content' => $request)));
122         $file = file_get_contents($endpoint, false, $context);
123         $response = xmlrpc_decode($file);
124         if (xmlrpc_is_fault($response)) {
125             common_log(LOG_WARNING,
126                        "Pingback error for '$url' ($endpoint): ".
127                        "$response[faultString] ($response[faultCode])");
128         } else {
129             common_log(LOG_INFO,
130                        "Pingback success for '$url' ($endpoint): ".
131                        "'$response'");
132         }
133     }
134
135     function userAgent()
136     {
137         return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION .
138           ' Laconica/' . LACONICA_VERSION;
139     }
140 }