src/ActivityPhp/Server/Actor/ActorFactory.php
<?php
/*
* This file is part of the ActivityPhp package.
*
* Copyright (c) landrok at github.com/landrok
*
* For the full copyright and license information, please see
* <https://github.com/landrok/activitypub/blob/master/LICENSE>.
*/
namespace ActivityPhp\Server\Actor;
use ActivityPhp\Server;
use ActivityPhp\Server\Http\Request;
use ActivityPhp\Type;
use Exception;
/**
* \ActivityPhp\Server\ActorFactory provides a factory for server-side
* actor.
*/
abstract class ActorFactory
{
/**
* @var null|\ActivityPhp\Server
*/
protected static $server;
/**
* Create an actor from its profile url
*
* @param string $url
* @return \ActivityPhp\Type\Extended\AbstractActor
* @throws \Exception if actor does not exist
*/
public static function create(string $url)
{
// Is it a local actor?
if (parse_url($url, PHP_URL_HOST) == self::$server->config('instance.host')
&& parse_url($url, PHP_URL_PORT) == self::$server->config('instance.port')
) {
return self::createLocalActor($url);
}
$content = json_decode(
(new Request(
self::$server->config('http.timeout'),
self::$server->config('http.agent')
))->get($url),
true
);
if (! is_array($content)
|| ! count($content)
|| ! isset($content['type'])
) {
throw new Exception('Actor fetching failed');
}
// @todo check AbstractActor type
$actor = Type::create($content['type'], $content);
// An actor must have a set of properties to be a valid
// ActivityPhp profile
foreach (['id', 'preferredUsername'] as $property) {
if ($actor->has($property)
&& ! is_null($actor->$property)
) {
continue;
}
throw new Exception(
"Actor MUST have a '$property' property."
);
}
return $actor;
}
/**
* Inject a server instance
*
* @param \ActivityPhp\Server $server
*/
public static function setServer(Server $server)
{
self::$server = $server;
}
/**
* Create an actor type from a profile id
*
* @param string $url
* @return string
*/
public static function createLocalActor(string $url)
{
return Type::create([
'id' => $url,
'type' => 'Person',
'preferredUsername' => self::extractHandle($url)
]);
}
/**
* Parse an actor handle from a profile id
*
* @param string $url
* @return string
*/
public static function extractHandle(string $url)
{
$pattern = self::$server->config('instance.actorPath');
$pattern = str_replace(
['<handle>', '@'],
['([\w\d\-]+)', '\@'],
$pattern
);
if (! preg_match("#{$pattern}#", $url, $matches)) {
throw new Exception(
sprintf(
'Failed to extract username from URL "%s", pattern="%s"',
$url,
$pattern
)
);
}
return $matches[1];
}
}