jonnybarnes.uk/app/Jobs/SendWebMentions.php
Jonny Barnes e3fff4b9a8 Squashed commit of the following:
commit 41ab44ed1d86a1d0788089cf2d79e3c9ab8e2ba6
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Aug 9 20:58:13 2017 +0100

    Add a test for a swarm checkin with no text

commit b4986ba3207374d11438e00d05a6f1ae1720bd49
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Aug 9 20:57:44 2017 +0100

    A migration that makes the note column of the notes table nullable

commit 80ac4d38c992e59733f60e844f376e36507fb8ee
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Aug 9 20:57:04 2017 +0100

    Don’t fail when the text content of a note is empty

commit 874acdd3b31028c06d19cdbe9ef34bbc9660a704
Author: Jonny Barnes <jonny@jonnybarnes.uk>
Date:   Wed Aug 9 20:55:12 2017 +0100

    Allow no content for the actual note, maybe its just a picture. Also provide some context for swarm checkins
2017-08-09 20:59:22 +01:00

140 lines
3.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Jobs;
use App\Note;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendWebMentions implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
protected $note;
/**
* Create the job instance, inject dependencies.
*
* @param Note $note
* @return void
*/
public function __construct(Note $note)
{
$this->note = $note;
}
/**
* Execute the job.
*
* @param \GuzzleHttp\Client $guzzle
* @return void
*/
public function handle(Client $guzzle)
{
//grab the URLs
$urlsInReplyTo = explode(' ', $this->note->in_reply_to);
$urlsNote = $this->getLinks($this->note->note);
$urls = array_filter(array_merge($urlsInReplyTo, $urlsNote)); //filter out none URLs
foreach ($urls as $url) {
$endpoint = $this->discoverWebmentionEndpoint($url, $guzzle);
if ($endpoint) {
$guzzle->post($endpoint, [
'form_params' => [
'source' => $this->note->longurl,
'target' => $url,
],
]);
}
}
}
/**
* Discover if a URL has a webmention endpoint.
*
* @param string The URL
* @param \GuzzleHttp\Client $guzzle
* @return string The webmention endpoint URL
*/
public function discoverWebmentionEndpoint($url, $guzzle)
{
//lets not send webmentions to myself
if (parse_url($url, PHP_URL_HOST) == config('app.longurl')) {
return false;
}
if (starts_with($url, '/notes/tagged/')) {
return false;
}
$endpoint = null;
$response = $guzzle->get($url);
//check HTTP Headers for webmention endpoint
$links = \GuzzleHttp\Psr7\parse_header($response->getHeader('Link'));
foreach ($links as $link) {
if (mb_stristr($link['rel'], 'webmention')) {
return $this->resolveUri(trim($link[0], '<>'), $url);
}
}
//failed to find a header so parse HTML
$html = (string) $response->getBody();
$mf2 = new \Mf2\Parser($html, $url);
$rels = $mf2->parseRelsAndAlternates();
if (array_key_exists('webmention', $rels[0])) {
$endpoint = $rels[0]['webmention'][0];
} elseif (array_key_exists('http://webmention.org/', $rels[0])) {
$endpoint = $rels[0]['http://webmention.org/'][0];
}
if ($endpoint) {
return $this->resolveUri($endpoint, $url);
}
return false;
}
/**
* Get the URLs from a note.
*
* @param string $html
* @return array $urls
*/
public function getLinks($html)
{
if ($html == '' || is_null($html)) {
return [];
}
$urls = [];
$dom = new \DOMDocument();
$dom->loadHTML($html);
$anchors = $dom->getElementsByTagName('a');
foreach ($anchors as $anchor) {
$urls[] = ($anchor->hasAttribute('href')) ? $anchor->getAttribute('href') : false;
}
return $urls;
}
/**
* Resolve a URI if necessary.
*
* @param string $url
* @param string $base
* @return string
*/
public function resolveUri(string $url, string $base): string
{
$endpoint = \GuzzleHttp\Psr7\uri_for($url);
if ($endpoint->getScheme() != '') {
return (string) $endpoint;
}
return (string) \GuzzleHttp\Psr7\Uri::resolve(
\GuzzleHttp\Psr7\uri_for($base),
$endpoint
);
}
}