{"id":13593780,"url":"https://github.com/landrok/activitypub","last_synced_at":"2025-04-12T18:52:24.276Z","repository":{"id":33607817,"uuid":"159376457","full_name":"landrok/activitypub","owner":"landrok","description":"A PHP implementation of ActivityPub protocol based upon the ActivityStreams 2.0 data format.","archived":false,"fork":false,"pushed_at":"2024-04-07T16:56:34.000Z","size":566,"stargazers_count":262,"open_issues_count":10,"forks_count":32,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-10-29T22:32:45.383Z","etag":null,"topics":["activitypub","activitystreams","federated","federated-social-web","protocol"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/landrok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["landrok"],"ko_fi":"landrok"}},"created_at":"2018-11-27T17:50:02.000Z","updated_at":"2024-10-29T20:38:30.000Z","dependencies_parsed_at":"2023-12-13T06:35:30.800Z","dependency_job_id":"b1384e9c-3d49-4e96-89cb-29cbc926002b","html_url":"https://github.com/landrok/activitypub","commit_stats":{"total_commits":329,"total_committers":7,"mean_commits":47.0,"dds":0.03951367781155013,"last_synced_commit":"8d5249d2f3e4b8c089099a567a2f5754041f9d7b"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landrok%2Factivitypub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landrok%2Factivitypub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landrok%2Factivitypub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landrok%2Factivitypub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/landrok","download_url":"https://codeload.github.com/landrok/activitypub/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248618237,"owners_count":21134200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activitypub","activitystreams","federated","federated-social-web","protocol"],"created_at":"2024-08-01T16:01:24.429Z","updated_at":"2025-04-12T18:52:24.253Z","avatar_url":"https://github.com/landrok.png","language":"PHP","funding_links":["https://github.com/sponsors/landrok","https://ko-fi.com/landrok"],"categories":["PHP","Libraries"],"sub_categories":["PHP"],"readme":"ActivityPhp\n===========\n\n[![Build Status](https://github.com/landrok/activitypub/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/landrok/activitypub/actions/workflows/php.yml)\n[![Maintainability](https://api.codeclimate.com/v1/badges/410c804f4cd03cc39b60/maintainability)](https://codeclimate.com/github/landrok/activitypub/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/410c804f4cd03cc39b60/test_coverage)](https://codeclimate.com/github/landrok/activitypub/test_coverage)\n\nActivityPhp is an implementation of ActivityPub layers in PHP.\n\nIt provides two layers:\n\n- A __client to server protocol__, or \"Social API\"\n    This protocol permits a client to act on behalf of a user.\n- A [__server to server protocol__](#server), or \"Federation Protocol\"\n    This protocol is used to distribute activities between actors on different servers, tying them into the same social graph.\n\nAs the two layers are implemented, it aims to be an ActivityPub conformant Federated Server\n\nAll normalized types are implemented too. If you need to create a new\none, just extend existing types.\n\n[See the full documentation](https://landrok.github.io/activitypub) or\nan overview below.\n\nTable of contents\n=================\n\n- [Install](#install)\n- [Requirements](#requirements)\n- [ActivityStreams Core Types](#activitystreams-core-types)\n- [ActivityStreams Extended Types](#activitystreams-extended-types)\n- [Types](#types)\n    - [Type factory](#type-factory)\n    - [Properties names](#properties-names)\n    - [All properties and their values](#all-properties-and-their-values)\n    - [Set several properties](#set-several-properties)\n    - [Get a property](#get-a-property)\n    - [Set a property](#set-a-property)\n    - [Check if property exists](#check-if-property-exists)\n    - [Create a copy](#create-a-copy)\n    - [Use native types](#use-native-types)\n    - [Use your own extended types](#use-your-own-extended-types)\n    - [Create your own property validator](#create-your-own-property-validator)\n    - [Dialects management](https://landrok.github.io/activitypub/activitypub-dialects-management.html)\n- [Server](#server)\n    - [Server configuration](https://landrok.github.io/activitypub/activitypub-server-usage.html)\n    - [Verify HTTP signatures](https://landrok.github.io/activitypub/activitypub-server-verify-http-signatures.html)\n    - [WebFinger](#webfinger)\n    - [WebFinger::toArray()](#webfingertoarray)\n    - [WebFinger::getSubject()](#webfingergetsubject)\n    - [WebFinger::getProfileId()](#webfingergetprofileid)\n    - [WebFinger::getHandle()](#webfingergethandle)\n    - [WebFinger::getAliases()](#webfingergetaliases)\n    - [WebFinger::getLinks()](#webfingergetlinks)\n\n________________________________________________________________________\n\nRequirements\n------------\n\n- Supports PHP 7.4 | 8.0+\n\n________________________________________________________________________\n\nInstall\n-------\n\n```sh\ncomposer require landrok/activitypub\n```\n\n________________________________________________________________________\n\nActivityStreams Core Types\n--------------------------\n\nAll core types are provided:\n\n```php\nuse ActivityPhp\\Type\\Core\\Activity;\nuse ActivityPhp\\Type\\Core\\Collection;\nuse ActivityPhp\\Type\\Core\\CollectionPage;\nuse ActivityPhp\\Type\\Core\\IntransitiveActivity;\nuse ActivityPhp\\Type\\Core\\Link;\nuse ActivityPhp\\Type\\Core\\ObjectType;\nuse ActivityPhp\\Type\\Core\\OrderedCollection;\nuse ActivityPhp\\Type\\Core\\OrderedCollectionPage;\n```\n\n________________________________________________________________________\n\nActivityStreams Extended Types\n------------------------------\n\nAll extended types are provided:\n\n### Actor types\n\n```php\nuse ActivityPhp\\Type\\Extended\\Actor\\Application;\nuse ActivityPhp\\Type\\Extended\\Actor\\Group;\nuse ActivityPhp\\Type\\Extended\\Actor\\Organization;\nuse ActivityPhp\\Type\\Extended\\Actor\\Person;\nuse ActivityPhp\\Type\\Extended\\Actor\\Service;\n```\n\n### Activity types\n\n```php\nuse ActivityPhp\\Type\\Extended\\Activity\\Accept;\nuse ActivityPhp\\Type\\Extended\\Activity\\Add;\nuse ActivityPhp\\Type\\Extended\\Activity\\Announce;\nuse ActivityPhp\\Type\\Extended\\Activity\\Arrive;\nuse ActivityPhp\\Type\\Extended\\Activity\\Block;\nuse ActivityPhp\\Type\\Extended\\Activity\\Create;\nuse ActivityPhp\\Type\\Extended\\Activity\\Delete;\nuse ActivityPhp\\Type\\Extended\\Activity\\Dislike;\nuse ActivityPhp\\Type\\Extended\\Activity\\Flag;\nuse ActivityPhp\\Type\\Extended\\Activity\\Follow;\nuse ActivityPhp\\Type\\Extended\\Activity\\Ignore;\nuse ActivityPhp\\Type\\Extended\\Activity\\Invite;\nuse ActivityPhp\\Type\\Extended\\Activity\\Join;\nuse ActivityPhp\\Type\\Extended\\Activity\\Leave;\nuse ActivityPhp\\Type\\Extended\\Activity\\Like;\nuse ActivityPhp\\Type\\Extended\\Activity\\Listen;\nuse ActivityPhp\\Type\\Extended\\Activity\\Move;\nuse ActivityPhp\\Type\\Extended\\Activity\\Offer;\nuse ActivityPhp\\Type\\Extended\\Activity\\Question;\nuse ActivityPhp\\Type\\Extended\\Activity\\Read;\nuse ActivityPhp\\Type\\Extended\\Activity\\Reject;\nuse ActivityPhp\\Type\\Extended\\Activity\\Remove;\nuse ActivityPhp\\Type\\Extended\\Activity\\TentativeAccept;\nuse ActivityPhp\\Type\\Extended\\Activity\\TentativeReject;\nuse ActivityPhp\\Type\\Extended\\Activity\\Travel;\nuse ActivityPhp\\Type\\Extended\\Activity\\Undo;\nuse ActivityPhp\\Type\\Extended\\Activity\\Update;\nuse ActivityPhp\\Type\\Extended\\Activity\\View;\n```\n\n### Object types\n\n```php\nuse ActivityPhp\\Type\\Extended\\Object\\Article;\nuse ActivityPhp\\Type\\Extended\\Object\\Audio;\nuse ActivityPhp\\Type\\Extended\\Object\\Document;\nuse ActivityPhp\\Type\\Extended\\Object\\Event;\nuse ActivityPhp\\Type\\Extended\\Object\\Image;\nuse ActivityPhp\\Type\\Extended\\Object\\Mention;\nuse ActivityPhp\\Type\\Extended\\Object\\Note;\nuse ActivityPhp\\Type\\Extended\\Object\\Page;\nuse ActivityPhp\\Type\\Extended\\Object\\Place;\nuse ActivityPhp\\Type\\Extended\\Object\\Profile;\nuse ActivityPhp\\Type\\Extended\\Object\\Relationship;\nuse ActivityPhp\\Type\\Extended\\Object\\Tombstone;\nuse ActivityPhp\\Type\\Extended\\Object\\Video;\n```\n\n________________________________________________________________________\n\nTypes\n-----\n\n### Type factory\n\nYou can instanciate ActivityStreams types using their short name.\n\n```php\nuse ActivityPhp\\Type;\n\n$link = Type::create('Link');\n$note = Type::create('Note');\n\n```\n\nInstanciating a type and setting properties is possible with the second\nparameter.\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note', [\n    'content' =\u003e 'A content for my note'\n]);\n\n```\n\nStarting from an array with a 'type' key, it's even possible to directly\ninstanciate your type.\n\n```php\nuse ActivityPhp\\Type;\n\n$array = [\n    'type'    =\u003e 'Note',\n    'content' =\u003e 'A content for my note'\n];\n\n$note = Type::create($array);\n\n```\n________________________________________________________________________\n\n### Properties names\n\nWhatever be your object or link, you can get all properties names with\n`getProperties()` method.\n\n```php\nuse ActivityPhp\\Type;\n\n$link = Type::create('Link');\n\nprint_r(\n    $link-\u003egetProperties()\n);\n```\n\nWould output something like:\n\n```\nArray\n(\n    [0] =\u003e type\n    [1] =\u003e id\n    [2] =\u003e name\n    [3] =\u003e nameMap\n    [4] =\u003e href\n    [5] =\u003e hreflang\n    [6] =\u003e mediaType\n    [7] =\u003e rel\n    [8] =\u003e height\n    [9] =\u003e preview\n    [10] =\u003e width\n)\n```\n\n________________________________________________________________________\n\n### All properties and their values\n\nIn order to dump all properties and associated values, use `toArray()`\nmethod.\n\n```php\nuse ActivityPhp\\Type;\n\n$link = Type::create('Link');\n$link-\u003esetName('An example');\n$link-\u003esetHref('http://example.com');\n\nprint_r(\n    $link-\u003etoArray()\n);\n```\n\nWould output something like:\n\n```\nArray\n(\n    [type] =\u003e Link\n    [name] =\u003e An example\n    [href] =\u003e http://example.com\n)\n```\n\n________________________________________________________________________\n\n### Get a property\n\nThere are 3 equivalent ways to get a value.\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note');\n\n// Each method returns the same value\necho $note-\u003eid;\necho $note-\u003eget('id');\necho $note-\u003egetId();\n```\n\n________________________________________________________________________\n\n### Set a property\n\nThere are 3 equivalent ways to set a value.\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note');\n\n$note-\u003eid = 'https://example.com/custom-notes/1';\n$note-\u003eset('id', 'https://example.com/custom-notes/1');\n$note-\u003esetId('https://example.com/custom-notes/1');\n\n```\n\nWhenever you assign a value, the format of this value is checked.\n\nThis action is made by a validator. If rules are not respected an\nException is thrown.\n\nWhen a property does not exist, an Exception is thrown in strict mode.\nYou can define 3 different behaviours:\n\n- throw an exception (default=strict)\n- ignore property (ignore)\n- set property (include)\n\n```php\nuse ActivityPhp\\Type;\nuse ActivityPhp\\Type\\TypeConfiguration;\n\n$note = Type::create('Note');\n\n// Ignore mode\nTypeConfiguration::set('undefined_properties', 'ignore');\n$note-\u003eundefinedProperty = 'https://example.com/custom-notes/1';\necho $note-\u003eundefinedProperty; // null\n\n// Include mode\nTypeConfiguration::set('undefined_properties', 'include');\n$note-\u003eundefinedProperty = 'https://example.com/custom-notes/1';\necho $note-\u003eundefinedProperty; // https://example.com/custom-notes/1\n\n// Strict mode\nTypeConfiguration::set('undefined_properties', 'strict');\n$note-\u003eundefinedProperty = 'https://example.com/custom-notes/1'; // Exception\n\n```\n\n________________________________________________________________________\n\n### Set several properties\n\nWith __Type factory__, you can instanciate a type and set several\nproperties.\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note', [\n    'id'   =\u003e 'https://example.com/custom-notes/1',\n    'name' =\u003e 'An important note',\n]);\n\n```\n________________________________________________________________________\n\n### Create a copy\n\nSometimes you may use a copy in order not to affect values of the\noriginal type.\n\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note', ['name' =\u003e 'Original name']);\n\n$copy = $note-\u003ecopy()-\u003esetName('Copy name');\n\necho $copy-\u003ename; // Copy name\necho $note-\u003ename; // Original name\n```\n\nYou can copy and chain methods to affect only values of the copied type.\n\n________________________________________________________________________\n\n### Check if a property exists\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note');\n\necho $note-\u003ehas('id'); // true\necho $note-\u003ehas('anotherProperty'); // false\n\n```\n\n________________________________________________________________________\n\n### Use native types\n\nAll core and extended types are used with a classic instanciation.\n\n```php\nuse ActivityPhp\\Type\\Extended\\Object\\Note;\n\n$note = new Note();\n```\n\nSame way with Type factory:\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('Note');\n```\n\n________________________________________________________________________\n\n\n### Use your own extended types\n\nIf you need some custom attributes, you can extend predefined types.\n\n- Create your custom type:\n```php\nuse ActivityPhp\\Type\\Extended\\Object\\Note;\n\nclass MyNote extends Note\n{\n    // Override basic type\n    protected $type = 'CustomNote';\n\n    // Custom property\n    protected $myProperty;\n}\n```\n\nThere are 2 ways to instanciate a type:\n\n- A classic PHP call:\n\n```php\n$note = new MyNote();\n$note-\u003eid = 'https://example.com/custom-notes/1';\n$note-\u003emyProperty = 'Custom Value';\n\necho $note-\u003egetMyProperty(); // Custom Value\n```\n\n- With the Type factory:\n\n```php\nuse ActivityPhp\\Type;\n\n$note = Type::create('MyNote', [\n    'id' =\u003e 'https://example.com/custom-notes/1',\n    'myProperty' =\u003e 'Custom Value'\n]);\n```\n\nExtending types preserves benefits of getters, setters and\ntheir validators.\n\n________________________________________________________________________\n\n\n### Create your own property validator\n\nUse a custom property validator when you define custom attributes or\nwhen you want to override ActivityPub attribute default validation.\n\nRegarding to previous example with a custom attribute `$myProperty`, if\nyou try to set this property, it would be done without any check on\nvalues you're providing.\n\nYou can easily cope with that implementing a custom validator using\n`Validator`.\n\n```php\nuse ActivityPhp\\Type\\ValidatorInterface;\nuse ActivityPhp\\Type\\Validator;\n\n// Create a custom validator that implements ValidatorInterface\nclass MyPropertyValidator implements ValidatorInterface\n{\n    // A public validate() method is mandatory\n    public function validate($value, $container)\n    {\n        return true;\n    }\n}\n\n// Attach this custom validator to a property\nValidator::add('myProperty', MyPropertyValidator::class);\n\n// Now all values are checked with the validate() method\n// 'myProperty' is passed to the first argument\n// $note is passed to the second one.\n\n$note-\u003emyProperty = 'Custom Value';\n\n```\n\nAn equivalent way is to use Type factory and `addValidator()` method:\n\n```php\nuse ActivityPhp\\Type;\n\n// Attach this custom validator to a property\nType::addValidator('myProperty', MyPropertyValidator::class);\n\n```\n________________________________________________________________________\n\n\nServer\n------\n\nA server instance is an entry point of a federation.\n\nIts purpose is to receive, send and forward activities appropriately.\n\nA minimal approach is:\n\n```php\nuse ActivityPhp\\Server;\n\n$server = new Server();\n```\n\nFor more configuration parameters, [See the full documentation](https://landrok.github.io/activitypub)\n\n### WebFinger\n\nWebFinger is a protocol that allows for discovery of information about\npeople.\n\nGiven a handle, ActivityPub instances can discover profiles using this\nprotocol.\n\n```php\nuse ActivityPhp\\Server;\n\n$server = new Server();\n\n$handle = 'bob@example.org';\n\n// Get a WebFinger instance\n$webfinger = $server-\u003eactor($handle)-\u003ewebfinger();\n```\n\nIn this implementation, we can use an Object Identifier (URI) instead of\na WebFinger handle.\n\n\n```php\nuse ActivityPhp\\Server;\n\n$server = new Server();\n\n$handle = 'https://example.org/users/bob';\n\n// Get a WebFinger instance\n$webfinger = $server-\u003eactor($handle)-\u003ewebfinger();\n```\n________________________________________________________________________\n\n### WebFinger::toArray()\n\nGet all WebFinger data as an array.\n\n```php\nuse ActivityPhp\\Server;\n\n$server = new Server();\n\n$handle = 'bob@example.org';\n\n// Get a WebFinger instance\n$webfinger = $server-\u003eactor($handle)-\u003ewebfinger();\n\n// Dumps all properties\nprint_r($webfinger-\u003etoArray());\n\n// A one line call\nprint_r(\n    $server-\u003eactor($handle)-\u003ewebfinger()-\u003etoArray()\n);\n```\n\nWould output something like:\n\n```\nArray\n(\n    [subject] =\u003e acct:bob@example.org\n    [aliases] =\u003e Array\n        (\n            [0] =\u003e http://example.org/users/bob\n        )\n    [links] =\u003e Array\n        (\n            [0] =\u003e Array\n                (\n                    [rel] =\u003e self\n                    [type] =\u003e application/activity+json\n                    [href] =\u003e http://example.org/users/bob\n                )\n        )\n)\n```\n________________________________________________________________________\n\n### WebFinger::getSubject()\n\nGet a WebFinger resource.\n\n```php\necho $webfinger-\u003egetSubject();\n\n// Would output 'acct:bob@example.org'\n```\n________________________________________________________________________\n\n### WebFinger::getProfileId()\n\nGet ActivityPub object identifier (URI).\n\n```php\necho $webfinger-\u003egetProfileId();\n\n// Would output 'http://example.org/users/bob'\n```\n________________________________________________________________________\n\n### WebFinger::getHandle()\n\nGet a profile handle.\n\n```php\necho $webfinger-\u003egetHandle();\n\n// Would output 'bob@example.org'\n```\n________________________________________________________________________\n\n### WebFinger::getAliases()\n\nGet all aliases entries for this profile.\n\n```php\nprint_r(\n    $webfinger-\u003egetAliases()\n);\n```\n\nWould output something like:\n\n```\nArray\n(\n    [0] =\u003e http://example.org/users/bob\n)\n```\n\n________________________________________________________________________\n\n### WebFinger::getLinks()\n\nGet all links entries for this profile.\n\n```php\n\nprint_r(\n    $webfinger-\u003egetLinks()\n);\n\n```\n\nWould output something like:\n\n```\nArray\n(\n    [0] =\u003e Array\n        (\n            [rel] =\u003e self\n            [type] =\u003e application/activity+json\n            [href] =\u003e http://example.org/users/bob\n        )\n)\n\n```\n________________________________________________________________________\n\n\nMore\n----\n\n- [See the full documentation](https://landrok.github.io/activitypub/)\n\n- To discuss new features, make feedback or simply to share ideas, you\n  can contact me on Mastodon at [https://phpc.social/@landrok](https://phpc.social/@landrok)\n- [ActivityPub](https://www.w3.org/TR/activitypub/)\n- [ActivityStreams 2.0](https://www.w3.org/TR/activitystreams-core/)\n- [JSON-LD](https://www.w3.org/TR/json-ld/)\n- [WebFinger](https://tools.ietf.org/html/rfc7033)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandrok%2Factivitypub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flandrok%2Factivitypub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandrok%2Factivitypub/lists"}