Last active
August 29, 2015 14:22
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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