Build Status Test Coverage

ActivityPhp is an implementation of ActivityPub layers in PHP.

It provides two layers:

As the two layers are implemented, it aims to be an ActivityPub conformant Federated Server.

All normalized types are implemented too. If you need to create a new one, just extend existing implementations.


Basics


Requirements


Install

composer require landrok/activitypub

Types

Type factory

You can instanciate ActivityStreams types using their short name.

use ActivityPhp\Type;

$link = Type::create('Link');
$note = Type::create('Note');

Instanciating a type and setting properties is possible with the second parameter.

use ActivityPhp\Type;

$note = Type::create('Note', [
    'content' => 'A content for my note'
]);

Starting from an array with a ‘type’ key, it’s even possible to directly instanciate your type.

use ActivityPhp\Type;

$array = [
    'type'    => 'Note',
    'content' => 'A content for my note'
];

$note = Type::create($array);

You may create a type from a JSON string with the fromJson() method. JSON must have a type key.

use ActivityPhp\Type;

$json = '
{
    "type": "Note",
    "content": "A content for my note"
}';

$note = Type::fromJson($json);

When a property does not exist, an Exception is thrown in strict mode. You can define 3 different behaviours:

use ActivityPhp\Type;
use ActivityPhp\Type\TypeConfiguration;

$note = Type::create('Note');

// Ignore mode
TypeConfiguration::set('undefined_properties', 'ignore');
$note->undefinedProperty = 'https://example.com/custom-notes/1';
echo $note->undefinedProperty; // null

// Include mode
TypeConfiguration::set('undefined_properties', 'include');
$note->undefinedProperty = 'https://example.com/custom-notes/1';
echo $note->undefinedProperty; // https://example.com/custom-notes/1

// Strict mode
TypeConfiguration::set('undefined_properties', 'strict');
$note->undefinedProperty = 'https://example.com/custom-notes/1'; // Exception


Properties names

Whatever be your object or link, you can get all properties names with getProperties() method.

use ActivityPhp\Type;

$link = Type::create('Link');

print_r( $link->getProperties() );

Would output something like:

Array
(
    [0] => type
    [1] => id
    [2] => name
    [3] => nameMap
    [4] => href
    [5] => hreflang
    [6] => mediaType
    [7] => rel
    [8] => height
    [9] => preview
    [10] => width
)

All properties and their values

In order to dump all properties and associated values, use toArray() method.

use ActivityPhp\Type;

$link = Type::create('Link');
$link->setName('An example');
$link->setHref('http://example.com');

print_r(
    $link->toArray()
);

Would output something like:

Array
(
    [type] => Link
    [name] => An example
    [href] => http://example.com
)

JSON export

In order to export a type as JSON, use toJson() method.

use ActivityPhp\Type;

$link = Type::create('Link');
$link->setName('An example');
$link->setHref('http://example.com');

echo $link->toJson();

Would output something like:

{"type":"Link","name":"An example","href":"http:\/\/example.com"}

It’s possible to give PHP JSON options as parameter

use ActivityPhp\Type;

$link = Type::create('Link');
$link->setName('An example');
$link->setHref('http://example.com');

echo $link->toJson(JSON_PRETTY_PRINT);

Would output something like:

{
    "type": "Link",
    "name": "An example",
    "href": "http:\/\/example.com"
}


Get a property

There are 3 equivalent ways to get a value.

use ActivityPhp\Type;

$note = Type::create('Note');

// Each method returns the same value
echo $note->id;
echo $note->get('id');
echo $note->getId();

Set a property

There are 3 equivalent ways to set a value.

use ActivityPhp\Type;

$note = Type::create('Note');

$note->id = 'https://example.com/custom-notes/1';
$note->set('id', 'https://example.com/custom-notes/1');
$note->setId('https://example.com/custom-notes/1');

Whenever you assign a value, the format of this value is checked.

This action is made by a validator. If rules are not respected an Exception is thrown.

When a property does not exist, an Exception is thrown in strict mode. You can define 3 different behaviours:

use ActivityPhp\Type;
use ActivityPhp\Type\TypeConfiguration;

$note = Type::create('Note');

// Ignore mode
TypeConfiguration::set('undefined_properties', 'ignore');
$note->undefinedProperty = 'https://example.com/custom-notes/1';
echo $note->undefinedProperty; // null

// Include mode
TypeConfiguration::set('undefined_properties', 'include');
$note->undefinedProperty = 'https://example.com/custom-notes/1';
echo $note->undefinedProperty; // https://example.com/custom-notes/1

// Strict mode
TypeConfiguration::set('undefined_properties', 'strict');
$note->undefinedProperty = 'https://example.com/custom-notes/1'; // Exception


Set several properties

With Type factory, you can instanciate a type and set several properties.

use ActivityPhp\Type;

$note = Type::create('Note', [
    'id'   => 'https://example.com/custom-notes/1',
    'name' => 'An important note',
]);


Check if property exists

use ActivityPhp\Type;

$note = Type::create('Note');

echo $note->has('id'); // true
echo $note->has('anotherProperty'); // false


Create a copy

Sometimes you may use a copy in order not to affect values of the original type.

use ActivityPhp\Type;

$note = Type::create('Note', ['name' => 'Original name']);

$copy = $note->copy()->setName('Copy name');

echo $copy->name; // Copy name
echo $note->name; // Original name

You can copy and chain methods to affect only values of the copied type.


Use native types

All core and extended types can be used with a classic instanciation.

use ActivityPhp\Type\Extended\Object\Note;

$note = new Note();

Same way with the Type factory:

use ActivityPhp\Type;

$note = Type::create('Note');

Use your own extended types

If you need some custom attributes, you can extend predefined types.

use ActivityPhp\Type\Extended\Object\Note;

// Define
class MyNote extends Note
{
    // Override basic type
    protected $type = 'CustomNote';

    // Custom property
    protected $myProperty;
}

// Add a custom class definition (<object name>, <classname>)
Type::add('MyNote', MyNote::class);

There are 2 ways to instanciate a type:

$note = new MyNote();
$note->id = 'https://example.com/custom-notes/1';
$note->myProperty = 'Custom Value';

echo $note->getMyProperty(); // Custom Value

use ActivityPhp\Type;

// Now the new object type is available
$note = Type::create('MyNote', [
    'id' => 'https://example.com/custom-notes/1',
    'myProperty' => 'Custom Value'
]);

Extending types preserves benefits of getters, setters and their validators.


Create your own property validator

Use a custom property validator when you define custom attributes or when you want to override ActivityPub attribute default validation.

Regarding to previous example with a custom attribute $myProperty, if you try to set this property, it would be done without any check on values you’re providing.

You can easily cope with that implementing a custom validator using Validator.

use ActivityPhp\Type\ValidatorInterface;
use ActivityPhp\Type\Validator;

// Create a custom validator that implements ValidatorInterface
class MyPropertyValidator implements ValidatorInterface
{
    // A public validate() method is mandatory
    public function validate($value, $container)
    {
        return true;
    }
}

// Attach this custom validator to a property
Validator::add('myProperty', MyPropertyValidator::class);

// Now all values are checked with the validate() method
// 'myProperty' is passed to the first argument
// $note is passed to the second one.

$note->myProperty = 'Custom Value';

An equivalent way is to use Type factory and addValidator() method:

use ActivityPhp\Type;

// Attach this custom validator to a property
Type::addValidator('myProperty', MyPropertyValidator::class);


Now that we know how to use types, let’s see what types are implemented and how to use them thanks to the ActivityStreams Types manual.


Server

A server instance is the entry point to a federation.

Its purpose is to receive, send and forward activities appropriately.

A minimalistic approach is:

use ActivityPhp\Server;

$server = new Server();

It’s sufficient to make some public requests.

For more advanced server configurations, Have a look at Server Manual.

WebFinger

WebFinger is a protocol that allows for discovery of information about people.

Given a handle, ActivityPub instances can discover profiles using this protocol.

use ActivityPhp\Server;

$server = new Server();

$handle = 'bob@example.org';

// Get a WebFinger instance
$webfinger = $server->actor($handle)->webfinger();

In this implementation, we can use an Object Identifier (URI) instead of a WebFinger handle.

use ActivityPhp\Server;

$server = new Server();

$handle = 'https://example.org/users/bob';

// Get a WebFinger instance
$webfinger = $server->actor($handle)->webfinger();

WebFinger::toArray()

Get all WebFinger data as an array.

use ActivityPhp\Server;

$server = new Server();

$handle = 'bob@example.org';

// Get a WebFinger instance
$webfinger = $server->actor($handle)->webfinger();

// Dumps all properties
print_r($webfinger->toArray());

// A one line call
print_r(
    $server->actor($handle)->webfinger()->toArray()
);

Would output something like:

Array
(
    [subject] => acct:bob@example.org
    [aliases] => Array
        (
            [0] => http://example.org/users/bob
        )
    [links] => Array
        (
            [0] => Array
                (
                    [rel] => self
                    [type] => application/activity+json
                    [href] => http://example.org/users/bob
                )
        )
)

WebFinger::getSubject()

Get a WebFinger resource.

echo $webfinger->getSubject();

// Would output 'acct:bob@example.org'

WebFinger::getProfileId()

Get ActivityPub object identifier (URI).

echo $webfinger->getProfileId();

// Would output 'http://example.org/users/bob'

WebFinger::getHandle()

Get a profile handle.

echo $webfinger->getHandle();

// Would output 'bob@example.org'

WebFinger::getAliases()

Get all aliases entries for this profile.

print_r(
    $webfinger->getAliases()
);

Would output something like:

Array
(
    [0] => http://example.org/users/bob
)

Get all links entries for this profile.


print_r(
    $webfinger->getLinks()
);

Would output something like:

Array
(
    [0] => Array
        (
            [rel] => self
            [type] => application/activity+json
            [href] => http://example.org/users/bob
        )
)


Server examples


More


Edit this document on GitHub