PluginProbe
WebFinger / 1.3
WebFinger v1.3
4.1.0 trunk 0.5 0.7 0.9 0.9.1 1.0 1.0.1 1.1 1.2 1.3 1.3.1 2.0.0 2.0.1 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 All 36 releases
webfinger / plugin.php

plugin.php in WebFinger 1.3, at plugin.php

452 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Webfinger
4 Plugin URI: http://wordpress.org/extend/plugins/webfinger/
5 Description: Webfinger for WordPress
6 Version: 1.3
7 Author: Matthias Pfefferle
8 Author URI: http://notizblog.org/
9 */
10
11 /**
12 * returns a users default webfinger
13 *
14 * @param mixed $id_or_name_or_object
15 * @param boolean $protocol
16 * @return string
17 */
18 function get_webfinger($id_or_name_or_object = null, $protocol = false) {
19 $webfinger = new WebfingerPlugin();
20 $user = $webfinger->get_user_by_various($id_or_name_or_object);
21
22 if ($user) {
23 $webfinger = $user->user_login."@".parse_url(get_bloginfo('url'), PHP_URL_HOST);
24 if ($protocol) {
25 $webfinger = "acct:".$webfinger;
26 }
27 return $webfinger;
28 } else {
29 return null;
30 }
31 }
32
33 /**
34 * returns all webfingers
35 *
36 * @param mixed $id_or_name_or_object
37 * @param boolean $protocol
38 *
39 * @return array
40 */
41 function get_webfingers($id_or_name_or_object = null, $protocol = false) {
42 $webfinger = new WebfingerPlugin();
43 $user = $webfinger->get_user_by_various($id_or_name_or_object);
44 $webfingers = array();
45
46 if ($user) {
47 $webfingers[] = ($protocol ? "acct:" : "").get_webfinger($user);
48 $webfingers[] = get_author_posts_url($user->ID, $user->user_nicename);
49 $webfingers = apply_filters('webfingers', $webfingers);
50
51 return $webfingers;
52 } else {
53 return array();
54 }
55 }
56
57 /**
58 * webfinger
59 *
60 * @author Matthias Pfefferle
61 */
62 class WebfingerPlugin {
63
64 private $user;
65 private $webfinger_uri;
66
67
68 /**
69 * adds some query vars
70 *
71 * @param array $vars
72 * @return array
73 */
74 public function query_vars($vars) {
75 $vars[] = 'webfinger-uri';
76 $vars[] = 'webfinger';
77 $vars[] = 'format';
78 $vars[] = 'principal';
79 $vars[] = 'service';
80 $vars[] = 'resource';
81 return $vars;
82 }
83
84 /**
85 * parses the request
86 *
87 * @return mixed
88 */
89 public function parse_request() {
90 global $wp_query, $wp;
91
92 $query_vars = $wp->query_vars;
93
94 if( array_key_exists('webfinger-uri', $query_vars) ) {
95 if (!$this->user = $this->get_user_by_uri($query_vars['webfinger-uri'])) {
96 header("HTTP/1.0 404 Not Found");
97 echo "Not Found";
98 exit;
99 }
100
101 $this->webfinger_uri = $query_vars['webfinger-uri'];
102 $accept = explode(',', $_SERVER['HTTP_ACCEPT']);
103
104 if (in_array('application/json', $accept) || (array_key_exists('format', $query_vars) && $query_vars['format'] == "json")) {
105 $this->render_jrd();
106 } else {
107 $this->render_xrd();
108 }
109
110 exit;
111 }
112 }
113
114 public function render_simple_web_discovery($request) {
115 $this->user = $this->get_user_by_uri($request['principal']);
116 $this->webfinger_uri = $request['principal'];
117
118 if ($this->user) {
119 $content = $this->generate_content();
120
121 $swd = array();
122 foreach ($content['links'] as $link) {
123 if ($link['rel'] == $request['service']) {
124 $swd['locations'][] = $link['href'];
125 }
126 }
127
128 $swd = apply_filters('simple_web_discovery', $swd, $this->user, $request['service']);
129
130 if ($swd) {
131 header("Access-Control-Allow-Origin: *");
132 header('Content-Type: application/json; charset=' . get_option('blog_charset'), true);
133 echo json_encode($swd);
134 exit;
135 }
136 }
137
138 header("HTTP/1.0 404 Not Found");
139 echo "Not Found";
140 exit;
141 }
142
143 /**
144 * renders the webfinger file in xml
145 */
146 public function render_xrd() {
147 header("Access-Control-Allow-Origin: *");
148 header('Content-Type: application/xrd+xml; charset=' . get_option('blog_charset'), true);
149 $content_array = $this->generate_content();
150
151 echo "<?xml version='1.0' encoding='".get_option('blog_charset')."'?>\n";
152 echo "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'\n";
153 // add xml-only namespaces
154 do_action('webfinger_ns');
155 echo ">\n";
156
157 echo $this->jrd_to_xrd($content_array);
158 // add xml-only content
159 do_action('webfinger_xrd', $this->user);
160
161 echo "\n</XRD>";
162 }
163
164 /**
165 * renders the webfinger file in json
166 */
167 public function render_jrd() {
168 header("Access-Control-Allow-Origin: *");
169 header('Content-Type: application/json; charset=' . get_option('blog_charset'), true);
170 $webfinger = $this->generate_content();
171
172 echo json_encode($webfinger);
173 }
174
175 /**
176 * generates the webfinger base array (and activate filter)
177 *
178 * @return array
179 */
180 public function generate_content() {
181 $url = get_author_posts_url($this->user->ID, $this->user->user_nicename);
182 $photo = get_user_meta($this->user->ID, 'photo', true);
183 if(!$photo) $photo = 'http://www.gravatar.com/avatar/'.md5($this->user->user_email);
184
185 $webfinger = array('subject' => $this->webfinger_uri,
186 'aliases' => array($url),
187 'links' => array(
188 array('rel' => 'http://webfinger.net/rel/profile-page', 'type' => 'text/html', 'href' => $url),
189 array('rel' => 'http://webfinger.net/rel/avatar', 'href' => $photo)
190 ));
191 if ($this->user->user_url) {
192 $webfinger['links'][] = array('rel' => 'http://webfinger.net/rel/profile-page', 'type' => 'text/html', 'href' => $this->user->user_url);
193 }
194 $webfinger = apply_filters('webfinger', $webfinger, $this->user);
195
196 return $webfinger;
197 }
198
199 /**
200 * recursive helper to generade the xrd-xml from the jrd array
201 *
202 * @param string $host_meta
203 * @return string
204 */
205 public function jrd_to_xrd($webfinger) {
206 $xrd = null;
207
208 foreach ($webfinger as $type => $content) {
209 // print subject
210 if ($type == "subject") {
211 $xrd .= "<Subject>$content</Subject>";
212 continue;
213 }
214
215 // print aliases
216 if ($type == "aliases") {
217 foreach ($content as $uri) {
218 $xrd .= "<Alias>".htmlentities($uri)."</Alias>";
219 }
220 continue;
221 }
222
223 // print properties
224 if ($type == "properties") {
225 foreach ($content as $type => $uri) {
226 $xrd .= "<Property type='".htmlentities($type)."'>".htmlentities($uri)."</Property>";
227 }
228 continue;
229 }
230
231 // print titles
232 if ($type == "titles") {
233 foreach ($content as $key => $value) {
234 if ($key == "default") {
235 $xrd .= "<Title>".htmlentities($value)."</Title>";
236 } else {
237 $xrd .= "<Title xml:lang='".htmlentities($key)."'>".htmlentities($value)."</Title>";
238 }
239 }
240 continue;
241 }
242
243 // print links
244 if ($type == "links") {
245 foreach ($content as $links) {
246 $temp = array();
247 $cascaded = false;
248 $xrd .= "<Link ";
249
250 foreach ($links as $key => $value) {
251 if (is_array($value)) {
252 $temp[$key] = $value;
253 $cascaded = true;
254 } else {
255 $xrd .= htmlentities($key)."='".htmlentities($value)."' ";
256 }
257 }
258 if ($cascaded) {
259 $xrd .= ">";
260 $xrd .= $this->jrd_to_xrd($temp);
261 $xrd .= "</Link>";
262 } else {
263 $xrd .= " />";
264 }
265 }
266
267 continue;
268 }
269 }
270
271 return $xrd;
272 }
273
274 /**
275 * returns a Userobject
276 *
277 * @param string $uri
278 * @return stdClass
279 */
280 private function get_user_by_uri($uri) {
281 global $wpdb;
282
283 $uri = urldecode($uri);
284
285 if (preg_match("~^https?://~i", $uri)) {
286 // check if url matches with a
287 // users profile url
288 foreach (get_users_of_blog() as $user) {
289 if (rtrim(str_replace("www.", "", get_author_posts_url($user->ID, $user->user_nicename)), "/") ==
290 rtrim(str_replace("www.", "", $uri), "/")) {
291 return $user;
292 }
293 }
294 } elseif (preg_match('/^([a-zA-Z]+:)?([^@]+)@([a-zA-Z0-9._-]+)$/i', $uri, $array)) {
295 $username = $array[2];
296 $host = $array[3];
297 $email = $username."@".$host;
298
299 if ($host == parse_url(get_bloginfo('url'), PHP_URL_HOST)) {
300 $sql = "SELECT * FROM $wpdb->users u INNER JOIN $wpdb->usermeta um ON u.id=um.user_id WHERE u.user_email = '$email' OR
301 (um.meta_key = 'jabber' AND um.meta_value = '$email') OR
302 u.user_login = '$username' LIMIT 1;";
303 $user = $wpdb->get_results($wpdb->prepare($sql));
304 if (!empty($user)) {
305 return $user[0];
306 }
307 }
308 }
309
310 return false;
311 }
312
313 /**
314 * add the host meta information
315 */
316 public function add_host_meta_info($array) {
317 $array["links"][] = array("rel" => "lrdd", "template" => get_option('siteurl')."/?webfinger-uri={uri}", "type" => "application/xrd+xml");
318 $array["links"][] = array("rel" => "lrdd", "template" => get_option('siteurl')."/?webfinger-uri={uri}?format=json", "type" => "application/json");
319
320 return $array;
321 }
322
323 /**
324 * adds lrdd-header-link to author profile pages
325 */
326 public function add_html_link() {
327 global $wp_query;
328
329 if (is_author() && !is_feed()) {
330 $author = $wp_query->get_queried_object();
331 $url = get_author_posts_url($author->ID, $author->user_nicename);
332
333 echo "\n";
334 echo "<link rel='lrdd' href='".get_option('siteurl')."/?webfinger-uri=".urlencode($url)."' type='application/xrd+xml' />";
335 echo "\n";
336 }
337 }
338
339 /**
340 * prints webfinger part on the user-site
341 *
342 * @param stdClass $user
343 */
344 public function user_profile_infos($user) {
345 $webfingers = get_webfingers($user, true);
346 ?>
347 <h3 id="webfinger">Webfinger</h3>
348
349 <table class="form-table">
350 <tr>
351 <th scope="row"><?php _e('Your Identifier')?></th>
352 <td>
353 <ul>
354 <?php foreach ($webfingers as $webfinger) { ?>
355 <li><?php echo $webfinger ?></li>
356 <?php } ?>
357 </ul>
358
359 <a href="http://webfinger.org/lookup/<?php echo get_webfinger($user); ?>" target="_blank">Check your webfinger!</a>
360 </td>
361 </tr>
362 </table>
363 <?php
364 }
365
366 /**
367 * add a settings link next to deactive / edit
368 *
369 * @param array $links
370 * @param string $file
371 * @return array
372 */
373 public function settings_link( $links, $file ) {
374 if( preg_match("/webfinger/i", $file) && function_exists( "admin_url" ) ) {
375 $settings_link = '<a href="' . admin_url( 'profile.php#webfinger' ) . '">' . __('Identifiers') . '</a>';
376 array_unshift( $links, $settings_link );
377 }
378 return $links;
379 }
380
381 /**
382 * Convenience method to get user data by ID, username, object or from current user.
383 *
384 * @param mixed $id_or_name_or_object the username, ID or object. If not provided, the current user will be used.
385 * @return bool|object False on failure, User DB row object
386 *
387 * @author Will Norris
388 * @see get_userdata_by_various() # DiSo OpenID-Plugin
389 */
390 public function get_user_by_various($id_or_name_or_object = null) {
391 if ( $id_or_name_or_object === null ) {
392 $user = wp_get_current_user();
393 if ($user == null) return false;
394 return $user->data;
395 } else if ( is_object($id_or_name_or_object) ) {
396 return $id_or_name_or_object;
397 } else if ( is_numeric($id_or_name_or_object) ) {
398 return get_userdata($id_or_name_or_object);
399 } else {
400 return get_userdatabylogin($id_or_name_or_object);
401 }
402 }
403
404 /**
405 * host-meta resource feature
406 *
407 * @param array $query
408 */
409 public function render_host_meta($query) {
410 if (!array_key_exists("resource", $query)) {
411 return;
412 }
413
414 // match user
415 if (!$this->user = $this->get_user_by_uri($query['resource'])) {
416 header("HTTP/1.0 404 Not Found");
417 echo "Resource ".$query['resource']." not found";
418 exit;
419 }
420
421 $this->webfinger_uri = $query['resource'];
422
423 if ($query['well-known'] == "host-meta.json") {
424 $this->render_jrd();
425 } else {
426 $this->render_xrd();
427 }
428 exit;
429 }
430 }
431
432 function webfinger_init() {
433 $webfinger = new WebfingerPlugin();
434
435 // host-meta resource
436 add_action('well_known_host-meta', array(&$webfinger, 'render_host_meta'), -1, 1);
437 add_action('well_known_host-meta.json', array(&$webfinger, 'render_host_meta'), -1, 1);
438 // simple web discovery
439 add_action('well_known_simple-web-discovery', array(&$webfinger, 'render_simple_web_discovery'), 2);
440 add_filter('query_vars', array(&$webfinger, 'query_vars'));
441 add_action('parse_request', array(&$webfinger, 'parse_request'));
442 add_action('wp_head', array(&$webfinger, 'add_html_link'));
443 add_filter('host_meta', array(&$webfinger, 'add_host_meta_info'));
444 add_filter('plugin_action_links', array(&$webfinger, 'settings_link'), 10, 2);
445
446 // add profile parts
447 add_action('show_user_profile', array(&$webfinger, 'user_profile_infos'));
448 add_action('edit_user_profile', array(&$webfinger, 'user_profile_infos'));
449 }
450
451 webfinger_init();
452 ?>