Browse Source

Start work on accepting webmentions

Next step is to figure out how/where to save them.
master
Chimo 4 years ago
parent
commit
972603ea4c
5 changed files with 200 additions and 8 deletions
  1. 20
    2
      WebmentionsPlugin.php
  2. 60
    0
      actions/webmentions.php
  3. 50
    0
      classes/Webmention.php
  4. 2
    0
      composer.json
  5. 68
    6
      composer.lock

+ 20
- 2
WebmentionsPlugin.php View File

@@ -22,14 +22,32 @@ class WebmentionsPlugin extends Plugin {
// Notice wasn't posted by a local user
// We only send mentions from local users
if (!($user instanceof User)) {
error_log("notice from remote user", 4);
return true;
}

$client = new IndieWeb\MentionClient($url, $html);
$sent = $client->sendSupportedMentions();

error_log("Sent $sent mentions", 4);
return true;
}

/**
* Add webmention <link> endpoint after <title>
*/
function onEndShowHeadTitle($action) {
$endpoint = common_local_url('webmentions');
$action->element("link", array("rel" => "webmention", "href" => $endpoint));

return true;
}

/**
* Webmention handler
*/
function onRouterInitialized($m)
{
$m->connect('api/webmentions', array('action' => 'webmentions'));

return true;
}


+ 60
- 0
actions/webmentions.php View File

@@ -0,0 +1,60 @@
<?php
if (!defined('GNUSOCIAL')) {
exit(1);
}

class WebmentionsAction extends ApiAction
{
protected function prepare(array $args=array())
{
parent::prepare($args);

$this->source = $this->arg('source');
$this->target = $this->arg('target');

if (!isset($this->target) || !isset($this->source)) {
$this->clientError(_('Missing argument. Needs "source" and "target"'), 400);
}

return true;
}

protected function handle()
{
parent::handle();

// Get notice id from URL. We assume it's the "filename" part:
// http://example.org/notice/1234
$path = parse_url($this->target, PHP_URL_PATH);

if ($path === false) {
$this->clientError(_('Invalid target url'), 400);
}

$notice_id = basename($path);

// Fetch notice corresponding to $this->target URL
$notice = Notice::getKV('id', $notice_id);

// If notice doesn't exist, bail
if (!($notice instanceof Notice)) {
$this->clientError(_('Invalid target url'), 400);
return true;
}

// TODO: Make Webmention::get static?
$webmention = new Webmention();
$wm = $webmention->get($this->source, $this->target);

if ($wm !== null) {
// Found webmention
// TODO: Check type (comment, like, mention...)
// TODO: Save in DB

// Thank you, come again
header($_SERVER['SERVER_PROTOCOL'] . ' 200 Accepted');
} else {
$this->clientError(_('Unknown Error'), 400);
}
}
}

+ 50
- 0
classes/Webmention.php View File

@@ -0,0 +1,50 @@
<?php

class Webmention {
// TODO: Make Webmention::get static?
// TODO: Handle mentions on pages that don't use mf2
public function get($sourceURL, $targetURL) {
// Fetch HTML from source page
$html = $this->http_get($sourceURL);

// Parse microformats
$mf = Mf2\parse($html, $sourceURL);

// Get webmention type
$webmention = $this->get_type($mf, $targetURL);

// FIXME: we need a better way to ensure $targetUrl is a link
// https://github.com/pear2/Services_Linkback/blob/2afd453254c531925484196670e2953f669ae141/src/PEAR2/Services/Linkback/Server/Callback/LinkExists.php#L40
// https://github.com/indieweb/php-mf2/blob/master/Mf2/Parser.php#L966
// https://stackoverflow.com/questions/2087103/how-to-get-innerhtml-of-domnode
if (!stristr($html, $targetURL)) {
error_log("Fake webmention from: " . $sourceURL, 4);
return null;
}

return $webmention;
}

private function get_type($mf, $targetURL) {
foreach($mf['items'] as $microformat) {
return IndieWeb\comments\parse($microformat, $targetURL);
}
}

private function http_get($sourceURL) {
ob_start();
$ch = curl_init($sourceURL);
curl_setopt($ch, CURLOPT_USERAGENT, 'github.com/chimo/gs-webmentions');
curl_setopt($ch, CURLOPT_HEADER, 0);
$ok = curl_exec($ch);
curl_close($ch);
$sourceHTML = ob_get_contents();
ob_end_clean();

if ($ok !== false) {
return $sourceHTML;
}

return false;
}
}

+ 2
- 0
composer.json View File

@@ -1,5 +1,7 @@
{
"require": {
"mf2/mf2": "0.2.10",
"indieweb/comments": "0.1.9",
"indieweb/mention-client": "^0.4.7"
}
}

+ 68
- 6
composer.lock View File

@@ -4,8 +4,47 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "5ef7c5ede992dd23d84c3fa1af03645d",
"hash": "a79e5b82834470c03f8cb8d42a21d61c",
"packages": [
{
"name": "indieweb/comments",
"version": "0.1.9",
"source": {
"type": "git",
"url": "https://github.com/indieweb/php-comments.git",
"reference": "b61bc2d8821c714dc9f7fb9a732597e1ade39c5a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/indieweb/php-comments/zipball/b61bc2d8821c714dc9f7fb9a732597e1ade39c5a",
"reference": "b61bc2d8821c714dc9f7fb9a732597e1ade39c5a",
"shasum": ""
},
"require": {
"tantek/cassis": "0.1.16124"
},
"type": "library",
"autoload": {
"files": [
"src/indieweb/comments.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Aaron Parecki",
"homepage": "http://aaronparecki.com"
}
],
"keywords": [
"comments",
"indieweb"
],
"time": "2015-01-19 02:06:14"
},
{
"name": "indieweb/mention-client",
"version": "0.4.7",
@@ -47,16 +86,16 @@
},
{
"name": "mf2/mf2",
"version": "v0.2.12",
"version": "v0.2.10",
"source": {
"type": "git",
"url": "https://github.com/indieweb/php-mf2.git",
"reference": "6701504876d6c9242eb310b35f41d40d9785ab4e"
"reference": "e514512cd8706d48bd33ae169b66427b32c777e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/indieweb/php-mf2/zipball/6701504876d6c9242eb310b35f41d40d9785ab4e",
"reference": "6701504876d6c9242eb310b35f41d40d9785ab4e",
"url": "https://api.github.com/repos/indieweb/php-mf2/zipball/e514512cd8706d48bd33ae169b66427b32c777e3",
"reference": "e514512cd8706d48bd33ae169b66427b32c777e3",
"shasum": ""
},
"require": {
@@ -96,7 +135,30 @@
"parser",
"semantic"
],
"time": "2015-07-12 14:10:01"
"time": "2015-04-29 09:49:04"
},
{
"name": "tantek/cassis",
"version": "v0.1.16124",
"source": {
"type": "git",
"url": "https://github.com/tantek/cassis.git",
"reference": "b9ec7142179950010c896ec3894aece0a56b0029"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tantek/cassis/zipball/b9ec7142179950010c896ec3894aece0a56b0029",
"reference": "b9ec7142179950010c896ec3894aece0a56b0029",
"shasum": ""
},
"type": "library",
"autoload": {
"files": [
"cassis-loader.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"time": "2014-02-18 20:17:32"
}
],
"packages-dev": [],

Loading…
Cancel
Save