Skip to content

Instantly share code, notes, and snippets.

@davidpeach
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidpeach/9d7bec6a81f2780245e9 to your computer and use it in GitHub Desktop.
Save davidpeach/9d7bec6a81f2780245e9 to your computer and use it in GitHub Desktop.
My Laravel 5 Webmention Controller from my personal website. This file handles both the receiving of webmentions and then their later conversion into comments / mentions on my site.
<?php namespace App\Http\Controllers;
use App\Mention;
use App\Webmention;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
use Mf2\Parser as Mf2Parser;
use Illuminate\Http\Request;
class WebmentionsController extends Controller {
private $authorName;
private $authorUrl;
private $authorAvatar;
private $content;
private $mentionType;
private $source;
private $target;
private $postId;
private $originalUrl;
private $publishedAt;
private $mf;
public function index()
{
// Get any unapproved webmentions
$webmentions = Webmention::where('approved', false)->get();
return view('webmentions.index', compact('webmentions'));
}
// I have an admin form with a list of all receieved webmentions.
// When I tick the webmentions I want to approve, it hits this function.
public function convertWebmentionsToMentions(Request $request)
{
if ( ! empty($request->input('approved')))
{
foreach ($request->input('approved') as $id)
{
if ($this->convertWebmention($id))
{
// Flag the converted webmention as approved
$mentions = Webmention::where('id', $id)->update(['approved' => 1]);
}
}
}
return redirect('review-webmentions');
}
// This converts each webmention I have ticked in turn.
private function convertWebmention($id)
{
// Set everything to empty (for use with multiple convertions)
$this->authorName = '';
$this->authorUrl = '';
$this->authorAvatar = '';
$this->content = '';
$this->mentionType = '';
$this->source = '';
$this->target = '';
$this->postId = '';
$this->originalUrl = '';
$this->publishedAt = '';
$this->mf = '';
// Eloquent DB query
$webmention = Webmention::find($id);
// Sources to parse.
$this->source = $webmention->source;
$this->target = $webmention->target;
// Quick switch for testing.
$urlToParse = $this->source;
// Fetch the url contents with MF2 parser.
$mf = \Mf2\fetch($urlToParse);
$this->mf = $mf;
// If we have no 'items', abort.
if (empty($mf['items']))
{
return;
}
$mfItems = $mf['items'];
$hEntryKey = null;
$hCardKey = null;
// Find which is h-entry and which is h-card
foreach ($mfItems as $key => $value)
{
if ( ! empty($value['type']) && is_array($value['type']))
{
if (in_array('h-entry', $value['type']))
{
$hEntryKey = $key;
}
else if (in_array('h-card', $value['type']))
{
$hCardKey = $key;
}
}
}
// Check whether mf properties is empty. If is empty, abort.
if (empty($mfItems[$hEntryKey]['properties']))
{
return;
}
// Assign the type of mention
$this->setMentionType($mfItems[$hEntryKey]);
$properties = $mfItems[$hEntryKey]['properties'];
// Get the author information
if ( ! empty($properties['author']) && is_array($properties['author']))
{
$author = $this->setAuthorProperties($properties['author'][0]);
}
else if ( ! empty($properties['author']))
{
$this->authorName = $properties['author'];
}
else if ( ! empty($mfItems[$hCardKey]) && is_array($mfItems[$hCardKey]))
{
$author = $this->setAuthorProperties($mfItems[$hCardKey]);
}
// Get the content
// To do - Handle p-summary
if ( ! empty($properties['content']) && is_array($properties['content']))
{
$this->content = $properties['content'][0]['value'];
}
if (empty($this->content))
{
if ( ! empty($properties['name']) && is_array($properties['name']))
{
$this->content = $properties['name'][0];
}
}
// Get the URL to the original URL
if (strpos($this->source, 'brid-gy') === false)
{
$this->originalUrl = $this->source;
}
else
{
$this->setOriginalUrl($properties);
}
if (empty($this->originalUrl))
{
$this->originalUrl = $this->authorUrl;
}
$this->setPublished($properties);
$this->setTargetPostId();
return $this->saveMention();
}
/**
* Save the Mention to the mentions table
*
*/
private function saveMention()
{
$insertArray = [
'post_id' => $this->postId,
'content' => $this->content,
'original_url' => $this->originalUrl,
'author_name' => $this->authorName,
'author_url' => $this->authorUrl,
'author_avatar' => $this->authorAvatar,
'mention_type' => $this->mentionType,
'published_at' => $this->publishedAt,
'hentry' => serialize($this->mf),
];
return Mention::create($insertArray);
}
private function setPublished($properties)
{
if ( ! empty($properties['published']) && is_array($properties['published']))
{
$this->publishedAt = Carbon::createFromFormat(DATE_ISO8601, $properties['published'][0])->toDateTimeString();
}
else
{
$this->publishedAt = Carbon::now();
}
}
private function setOriginalUrl($properties)
{
if ( ! empty($properties['url']) && is_array($properties['url']))
{
$this->originalUrl = $properties['url'][0];
}
}
private function setTargetPostId()
{
$this->target = $this->target . '/';
$this->target = trim($this->target, '/');
$array = explode('/', $this->target);
if ( ! empty($array) && is_array($array))
{
$this->postId = (int)(end($array));
}
}
/**
* Set the mention type from the type array that contains h-entry.
*
*
*/
private function setMentionType($hEntry)
{
// Default mention type
$this->mentionType = 'reply';
if (in_array('h-as-like', $hEntry['type']))
{
$this->mentionType = 'like';
}
if (array_key_exists('in-reply-to', $hEntry['properties']))
{
$this->mention_type = 'reply';
}
else if (array_key_exists('like-of', $hEntry['properties']) || array_key_exists('like', $hEntry['properties']) || array_key_exists('u-like-of', $hEntry['properties']))
{
$this->mention_type = 'like';
}
else if (array_key_exists('repost-of', $hEntry['properties']))
{
$this->mention_type = 'repost';
}
}
/**
* Sets the author private variables from values within an h-card
*
*/
private function setAuthorProperties($authorInfo)
{
if ( ! empty($authorInfo['type']) && is_array($authorInfo['type']))
{
// Must be h-card
if (in_array('h-card', $authorInfo['type']))
{
if ( ! empty($authorInfo['properties']))
{
$authorProps = $authorInfo['properties'];
$this->authorName = $this->getAuthorPropertyName($authorProps);
$this->authorUrl = $this->getAuthorPropertyUrl($authorProps);
$this->authorAvatar = $this->getAuthorPropertyAvatar($authorProps);
}
}
else
{
return false;
}
}
else
{
return false;
}
}
private function getAuthorPropertyName($authorProps)
{
if ( ! empty($authorProps['name']) && is_array($authorProps['name']))
{
return $authorProps['name'][0];
}
else
{
return '';
}
}
private function getAuthorPropertyUrl($authorProps)
{
if ( ! empty($authorProps['url']) && is_array($authorProps['url']))
{
return $authorProps['url'][0];
}
else
{
return '';
}
}
private function getAuthorPropertyAvatar($authorProps)
{
if ( ! empty($authorProps['photo']) && is_array($authorProps['photo']))
{
return $authorProps['photo'][0];
}
else
{
return '';
}
}
/**
* Create the webmention entry to parse later on.
* When somebody hits my /webmention URL, the request is routed to this method.
*/
public function receiveWebmention(Request $request)
{
// First ensure we have the required source and target
if (empty($request->input('source')) || empty($request->input('target')) )
{
abort(400);
}
// Store them variables, bitch !
$source = $request->input('source');
$target = $request->input('target');
// Get the contents of the source ...
$contents = file_get_contents($source);
// If the contents of source does not contain the target permalink, abort.
if (strpos($contents, $target) === false)
{
abort(400);
}
// Finally log the Webmention for processing later.
Webmention::create(['source' => $source, 'target' => $target]);
// Return a 202 'accepted' status
http_response_code(202);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment