1. Go to this page and download the library: Download rikudou/activity-pub library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
rikudou / activity-pub example snippets
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
use Rikudou\ActivityPub\Dto\Source\MarkdownSource;
$note = new Note();
$note->id = 'https://example.com/notes/123';
$note->content = 'Hello <strong>there</strong>!';
$note->attributedTo = 'https://example.com/user/some-actor';
$note->to = 'https://example.com/user/some-other-actor';
$note->inReplyTo = 'https://example.com/notes/120';
$note->published = new DateTimeImmutable();
$note->source = new MarkdownSource('Hello **there**');
echo json_encode($note, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
$note = new Note();
$note->id = '123';
use Rikudou\ActivityPub\Enum\ValidatorMode;
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
$note = new Note();
$note->validatorMode = ValidatorMode::None;
$note->id = '123';
echo json_encode($note, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
use Rikudou\ActivityPub\Enum\ValidatorMode;
use Rikudou\ActivityPub\GlobalSettings;
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
GlobalSettings::$validatorMode = ValidatorMode::None;
$note = new Note();
$note->id = '123';
echo json_encode($note, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
use function Rikudou\ActivityPub\runInNoValidationContext;
T | JSON_UNESCAPED_SLASHES);
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
$note = new Note();
$note->id = 'https://example.com/note/1';
$note->set('customProperty', 'customValue');
echo json_encode($note, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Note;
use function Rikudou\ActivityPub\runInNoValidationContext;
', 'customValue'));
echo json_encode($note, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;
use Rikudou\ActivityPub\Vocabulary\Core\BaseObject;
final class Cat extends BaseObject
{
public string $type {
get => 'Cat';
}
}
use Rikudou\ActivityPub\Vocabulary\Core\BaseObject;
final class Cat extends BaseObject
{
public string $type {
get => 'Cat';
}
public ?int $lives = null;
}
use Rikudou\ActivityPub\Attribute\RequiredProperty;
use Rikudou\ActivityPub\Enum\ValidatorMode;
use Rikudou\ActivityPub\Vocabulary\Core\BaseObject;
final class Cat extends BaseObject
{
public string $type {
get => 'Cat';
}
#[RequiredProperty(ValidatorMode::Lax)]
public ?int $lives = null;
}
$cat = new Cat();
$cat->id = 'https://example.com/meow';
echo json_encode($cat, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), PHP_EOL;
// Uncaught Rikudou\ActivityPub\Exception\MissingRequiredPropertyException: The property "Cat:lives" is
use Rikudou\ActivityPub\Attribute\RequiredProperty;
use Rikudou\ActivityPub\Enum\ValidatorMode;
use Rikudou\ActivityPub\GlobalSettings;
use Rikudou\ActivityPub\Vocabulary\Core\BaseObject;
use Rikudou\ActivityPub\Vocabulary\Core\Link;
use Rikudou\ActivityPub\Vocabulary\Extended\Activity\Announce;
use Rikudou\ActivityPub\Vocabulary\Extended\Activity\Create;
use Rikudou\ActivityPub\Vocabulary\Extended\Actor\Person;
final class Cat extends BaseObject
{
public string $type {
get => 'Cat';
}
#[RequiredProperty(ValidatorMode::Lax)]
public ?int $lives = null;
}
$cat = new Cat();
$cat->id = 'https://example.com/meow';
$cat->lives = 9;
$cat->name = 'Meowth';
$me = new Person();
$me->id = 'https://example.com/me';
$me->name = 'James';
$me->inbox = 'https://example.com/inbox';
$me->outbox = 'https://example.com/outbox';
$me->following = 'https://example.com/following';
$me->followers = 'https://example.com/following';
$create = new Create();
$create->id = 'https://example.com/create/meow';
$create->actor = $me;
$create->object = $cat;
$create->to = Link::publicAudienceLink(); // a special link that indicates that the target is public
$announcer = new Person();
$announcer->id = 'https://example.com/not-me';
$announcer->name = 'Jessie';
$announcer->inbox = 'https://example.com/inbox-jessie';
$announcer->outbox = 'https://example.com/outbox-jessie';
$announcer->following = 'https://example.com/following-jessie';
$announcer->followers = 'https://example.com/following-jessie';
$announce = new Announce();
$announce->id = 'https://example.com/announce/create/meow';
$announce->to = $create->to;
$announce->actor = $announcer;
$announce->object = $create;
echo json_encode($announce, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), PHP_EOL;
use Rikudou\ActivityPub\Attribute\RequiredProperty;
use Rikudou\ActivityPub\Enum\ValidatorMode;
use Rikudou\ActivityPub\Vocabulary\Core\BaseObject;
use Rikudou\ActivityPub\Vocabulary\Parser\DefaultTypeParser;
final class Cat extends BaseObject
{
public string $type {
get => 'Cat';
}
#[RequiredProperty(ValidatorMode::Lax)]
public ?int $lives = null;
}
$parser = new DefaultTypeParser();
$parser->registerType('Cat', Cat::class);
$catJson = <<<'JSON'
{
"type": "Cat",
"lives": 9,
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/meow",
"name": "Meowth"
}
JSON;
$reconstructedCat = $parser->parseJson($catJson);
// all the following are true
assert($reconstructedCat instanceof Cat);
assert($reconstructedCat->lives === 9);
assert($reconstructedCat->name === 'Meowth');
assert($reconstructedCat->id === 'https://example.com/meow');
use Rikudou\ActivityPub\Dto\KeyPair;
use Rikudou\ActivityPub\Dto\PublicKey;
use Rikudou\ActivityPub\Server\KeyGenerator\OpenSslActorKeyGenerator;
use Rikudou\ActivityPub\Vocabulary\Contract\ActivityPubActor;
use Rikudou\ActivityPub\Vocabulary\Extended\Actor\Person;
function storePrivateKeyInDatabase(ActivityPubActor $actor, KeyPair $keyPair): void
{
$privateKey = $keyPair->privateKey;
// todo store it somewhere securely
}
// create a minimal valid Actor object
$me = new Person();
$me->id = 'https://example.com/person/1';
$me->inbox = 'https://example.com/person/1/inbox';
$me->outbox = 'https://example.com/person/1/outbox';
$me->following = 'https://example.com/person/1/following';
$me->followers = 'https://example.com/person/1/followers';
// instantiate a specific implementation of the KeyGenerator interface, there's currently only this one
$keyGenerator = new OpenSslActorKeyGenerator();
// generate the private and public key-pair
// if you provide an instance of actor as the first parameter, it will automatically create
$keyPair = $keyGenerator->generate($me);
// alternatively, you can assign the public key manually
$keyPair = $keyGenerator->generate();
$me->publicKey = new PublicKey(
// adding #main-key is a convention, and it's not really important what exactly is there, important is that you can fetch
// the public key at that URL and that it's unique (thus it cannot be the same as the owner id)
id: $me->id . '#main-key',
owner: $me->id,
publicKeyPem: $keyPair->publicKey,
);
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Rikudou\ActivityPub\Server\Signing\RequestSigner;
use Rikudou\ActivityPub\Vocabulary\Contract\ActivityPubActivity;
use Rikudou\ActivityPub\Vocabulary\Contract\ActivityPubActor;
private ClientInterface $httpClient,
) {
}
public function sendOutgoingActivity(
ActivityPubActor $actor,
#[SensitiveParameter]
string $actorPrivateKey,
ActivityPubActivity $activity,
): void {
// you should send the activity to other fields as well, this is just for illustration
$recipients = $activity->to;
foreach ($recipients as $recipient) {
// for simplicity, let's assume this is always an actor, but it can also be a link
assert($recipient instanceof ActivityPubActor);
// you need to specify at least the request method,
$request = $this->requestFactory
->createRequest('POST', $recipient->inbox)
->withBody(
Utils::streamFor(
json_encode($activity),
),
)
;
// now let's sign it!
$request = $this->requestSigner->signRequest(
$request,
$actor->publicKey->id,
$actorPrivateKey,
);
$response = $this->httpClient->sendRequest($request);
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
// todo handle bad responses in some way
}
}
}
}
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Rikudou\ActivityPub\Server\Signing\RequestValidator;
class IncomingActivityHandler
{
public function __construct(
// Just like before, an interface that's implemented by RequestSignerAndValidator
private RequestValidator $requestValidator,
) {
}
public function handle(
ServerRequestInterface $incomingRequest,
): ResponseInterface {
if ($incomingRequest->getMethod() !== 'POST') {
// todo return 405
}
if (!$this->requestValidator->isRequestValid($incomingRequest)) {
// todo return 403 or something
}
// todo handle the request
}
}
use Psr\Http\Message\ResponseInterface;
use Rikudou\ActivityPub\Exception\ActivityPubException;
use Rikudou\ActivityPub\Exception\ResourceException;
use Rikudou\ActivityPub\Exception\WebFingerException;
use Rikudou\ActivityPub\Server\ObjectFetcher\ObjectFetcher;
use Rikudou\ActivityPub\Server\ObjectFetcher\WebFinger;
use Rikudou\ActivityPub\Vocabulary\Extended\Actor\Person;
use Rikudou\ActivityPub\Vocabulary\Extended\Object\Article;
class SomeController
{
public function __construct(
private WebFinger $webFinger,
private ObjectFetcher $objectFetcher,
) {
}
public function someMethod(): ResponseInterface
{
$account = '[email protected]';
try {
$webFingerResponse = $this->webFinger->find($account);
$object = $this->objectFetcher->fetch($webFingerResponse);
assert($object instanceof Person);
// todo do something with the object
} catch (WebFingerException $e) {
// todo handle that something went wrong
} catch (ResourceException $e) {
// todo handle that something went wrong with fetching the person
} catch (ActivityPubException $e) {
// todo handle all other exceptions thrown by the package
}
}
public function anotherMethod(): ResponseInterface
{
$resource = 'https://example.com/posts/1';
$object = $this->objectFetcher->fetch($resource);
assert($object instanceof Article);
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.