landrok / activitypub
基于 ActivityStreams 2.0 数据格式的 ActivityPub 协议的 PHP 实现。
Requires
- php: ^7.4|^8.0
- guzzlehttp/guzzle: >=6.3
- monolog/monolog: ^1.12|^2.0|^3.0
- phpseclib/phpseclib: ^3.0.7
- psr/cache: ^1.0|^2.0|^3.0
- symfony/cache: >=4.0
- symfony/http-foundation: >=3.4
Requires (Dev)
README
ActivityPhp 是 PHP 中 ActivityPub 层的实现。
它提供两层:
- 一个 客户端到服务器协议,或称为 "社交 API"。此协议允许客户端代表用户进行操作。
- 一个 服务器到服务器协议,或称为 "联盟协议"。此协议用于在不同服务器上的参与者之间分发活动,将它们绑定到同一个社交图谱中。
随着这两层的实现,它旨在成为符合 ActivityPub 的联邦服务器
所有规范化的类型都已实现。如果您需要创建一个新的类型,只需扩展现有类型即可。
查看完整文档 或下面的概述。
目录
要求
- 支持 PHP 7.4 | 8.0+
安装
composer require landrok/activitypub
ActivityStreams 核心类型
提供所有核心类型
use ActivityPhp\Type\Core\Activity; use ActivityPhp\Type\Core\Collection; use ActivityPhp\Type\Core\CollectionPage; use ActivityPhp\Type\Core\IntransitiveActivity; use ActivityPhp\Type\Core\Link; use ActivityPhp\Type\Core\ObjectType; use ActivityPhp\Type\Core\OrderedCollection; use ActivityPhp\Type\Core\OrderedCollectionPage;
ActivityStreams 扩展类型
提供所有扩展类型
参与者类型
use ActivityPhp\Type\Extended\Actor\Application; use ActivityPhp\Type\Extended\Actor\Group; use ActivityPhp\Type\Extended\Actor\Organization; use ActivityPhp\Type\Extended\Actor\Person; use ActivityPhp\Type\Extended\Actor\Service;
活动类型
use ActivityPhp\Type\Extended\Activity\Accept; use ActivityPhp\Type\Extended\Activity\Add; use ActivityPhp\Type\Extended\Activity\Announce; use ActivityPhp\Type\Extended\Activity\Arrive; use ActivityPhp\Type\Extended\Activity\Block; use ActivityPhp\Type\Extended\Activity\Create; use ActivityPhp\Type\Extended\Activity\Delete; use ActivityPhp\Type\Extended\Activity\Dislike; use ActivityPhp\Type\Extended\Activity\Flag; use ActivityPhp\Type\Extended\Activity\Follow; use ActivityPhp\Type\Extended\Activity\Ignore; use ActivityPhp\Type\Extended\Activity\Invite; use ActivityPhp\Type\Extended\Activity\Join; use ActivityPhp\Type\Extended\Activity\Leave; use ActivityPhp\Type\Extended\Activity\Like; use ActivityPhp\Type\Extended\Activity\Listen; use ActivityPhp\Type\Extended\Activity\Move; use ActivityPhp\Type\Extended\Activity\Offer; use ActivityPhp\Type\Extended\Activity\Question; use ActivityPhp\Type\Extended\Activity\Read; use ActivityPhp\Type\Extended\Activity\Reject; use ActivityPhp\Type\Extended\Activity\Remove; use ActivityPhp\Type\Extended\Activity\TentativeAccept; use ActivityPhp\Type\Extended\Activity\TentativeReject; use ActivityPhp\Type\Extended\Activity\Travel; use ActivityPhp\Type\Extended\Activity\Undo; use ActivityPhp\Type\Extended\Activity\Update; use ActivityPhp\Type\Extended\Activity\View;
对象类型
use ActivityPhp\Type\Extended\Object\Article; use ActivityPhp\Type\Extended\Object\Audio; use ActivityPhp\Type\Extended\Object\Document; use ActivityPhp\Type\Extended\Object\Event; use ActivityPhp\Type\Extended\Object\Image; use ActivityPhp\Type\Extended\Object\Mention; use ActivityPhp\Type\Extended\Object\Note; use ActivityPhp\Type\Extended\Object\Page; use ActivityPhp\Type\Extended\Object\Place; use ActivityPhp\Type\Extended\Object\Profile; use ActivityPhp\Type\Extended\Object\Relationship; use ActivityPhp\Type\Extended\Object\Tombstone; use ActivityPhp\Type\Extended\Object\Video;
类型
类型工厂
您可以使用它们的短名称实例化 ActivityStreams 类型。
use ActivityPhp\Type; $link = Type::create('Link'); $note = Type::create('Note');
使用第二个参数,您可以实例化一个类型并设置属性。
use ActivityPhp\Type; $note = Type::create('Note', [ 'content' => 'A content for my note' ]);
从具有 'type' 键的数组开始,甚至可以直接实例化您的类型。
use ActivityPhp\Type; $array = [ 'type' => 'Note', 'content' => 'A content for my note' ]; $note = Type::create($array);
属性名称
对于任何对象或链接,您都可以使用 getProperties()
方法获取所有属性名称。
use ActivityPhp\Type; $link = Type::create('Link'); print_r( $link->getProperties() );
输出类似以下内容
Array
(
[0] => type
[1] => id
[2] => name
[3] => nameMap
[4] => href
[5] => hreflang
[6] => mediaType
[7] => rel
[8] => height
[9] => preview
[10] => width
)
所有属性及其值
要转储所有属性及其关联的值,请使用 toArray()
方法。
use ActivityPhp\Type; $link = Type::create('Link'); $link->setName('An example'); $link->setHref('http://example.com'); print_r( $link->toArray() );
输出类似以下内容
Array
(
[type] => Link
[name] => An example
[href] => http://example.com
)
获取一个属性
有 3 种等效的方式来获取值。
use ActivityPhp\Type; $note = Type::create('Note'); // Each method returns the same value echo $note->id; echo $note->get('id'); echo $note->getId();
设置一个属性
有 3 种等效的方式来设置值。
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');
在您分配值时,将检查此值的格式。
此操作由验证器执行。如果不遵守规则,将抛出异常。
当属性不存在时,在严格模式下会抛出异常。您可以定义 3 种不同的行为
- 抛出异常(默认=严格)
- 忽略属性(忽略)
- 设置属性(包含)
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
设置多个属性
使用 类型工厂,您可以实例化一个类型并设置多个属性。
use ActivityPhp\Type; $note = Type::create('Note', [ 'id' => 'https://example.com/custom-notes/1', 'name' => 'An important note', ]);
创建一个副本
有时您可能使用副本以不影响原始类型的值。
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
您可以复制并链式调用方法来仅影响副本类型的值。
检查属性是否存在
use ActivityPhp\Type; $note = Type::create('Note'); echo $note->has('id'); // true echo $note->has('anotherProperty'); // false
使用原生类型
所有核心和扩展类型都使用经典实例化。
use ActivityPhp\Type\Extended\Object\Note; $note = new Note();
与类型工厂相同的方式
use ActivityPhp\Type; $note = Type::create('Note');
使用您自己的扩展类型
如果您需要一些自定义属性,可以扩展预定义的类型。
- 创建您自己的类型
use ActivityPhp\Type\Extended\Object\Note; class MyNote extends Note { // Override basic type protected $type = 'CustomNote'; // Custom property protected $myProperty; }
有两种方式来实例化一个类型
- 一个经典的 PHP 调用
$note = new MyNote(); $note->id = 'https://example.com/custom-notes/1'; $note->myProperty = 'Custom Value'; echo $note->getMyProperty(); // Custom Value
- 使用类型工厂
use ActivityPhp\Type; $note = Type::create('MyNote', [ 'id' => 'https://example.com/custom-notes/1', 'myProperty' => 'Custom Value' ]);
扩展类型可以保留获取器、设置器和它们的验证器的优势。
创建您自己的属性验证器
当您定义自定义属性或想要覆盖ActivityPub属性的默认验证时,请使用自定义属性验证器。
关于前面的自定义属性示例 $myProperty
,如果您尝试设置此属性,它将不会对您提供的值进行任何检查。
您可以通过使用 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';
另一种等效的方法是使用类型工厂和 addValidator()
方法。
use ActivityPhp\Type; // Attach this custom validator to a property Type::addValidator('myProperty', MyPropertyValidator::class);
服务器
服务器实例是联邦的入口点。
其目的是适当接收、发送和转发活动。
最小化方法如下
use ActivityPhp\Server; $server = new Server();
有关更多配置参数,请参阅完整文档
WebFinger
WebFinger 是一种允许发现有关人员的信息的协议。
给定一个处理程序,ActivityPub 实例可以使用此协议发现配置文件。
use ActivityPhp\Server; $server = new Server(); $handle = 'bob@example.org'; // Get a WebFinger instance $webfinger = $server->actor($handle)->webfinger();
在此实现中,我们可以使用对象标识符(URI)而不是 WebFinger 处理程序。
use ActivityPhp\Server; $server = new Server(); $handle = 'https://example.org/users/bob'; // Get a WebFinger instance $webfinger = $server->actor($handle)->webfinger();
WebFinger::toArray()
获取所有 WebFinger 数据作为数组。
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() );
输出类似以下内容
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()
获取 WebFinger 资源。
echo $webfinger->getSubject(); // Would output 'acct:bob@example.org'
WebFinger::getProfileId()
获取 ActivityPub 对象标识符(URI)。
echo $webfinger->getProfileId(); // Would output 'http://example.org/users/bob'
WebFinger::getHandle()
获取配置文件处理程序。
echo $webfinger->getHandle(); // Would output 'bob@example.org'
WebFinger::getAliases()
获取此配置文件的全部别名条目。
print_r( $webfinger->getAliases() );
输出类似以下内容
Array
(
[0] => http://example.org/users/bob
)
WebFinger::getLinks()
获取此配置文件的全部链接条目。
print_r( $webfinger->getLinks() );
输出类似以下内容
Array
(
[0] => Array
(
[rel] => self
[type] => application/activity+json
[href] => http://example.org/users/bob
)
)
更多
-
要讨论新功能、提供反馈或简单地分享想法,您可以在 Mastodon 上联系我,链接为 https://phpc.social/@landrok