{"id":13832722,"url":"https://github.com/nostrver-se/nostr-php","last_synced_at":"2026-03-06T20:31:49.840Z","repository":{"id":86096037,"uuid":"606714179","full_name":"nostrver-se/nostr-php","owner":"nostrver-se","description":"PHP helper library for Nostr https://nostr-php.dev","archived":false,"fork":false,"pushed_at":"2026-02-03T11:14:19.000Z","size":537,"stargazers_count":65,"open_issues_count":3,"forks_count":17,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-02-21T21:35:56.559Z","etag":null,"topics":["nostr","php"],"latest_commit_sha":null,"homepage":"https://nostr-php.dev","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/nostrver-se.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-02-26T10:48:12.000Z","updated_at":"2026-02-03T11:13:05.000Z","dependencies_parsed_at":"2023-12-05T16:02:46.655Z","dependency_job_id":"1eb4cfc4-54f8-4674-a211-43c798780fd5","html_url":"https://github.com/nostrver-se/nostr-php","commit_stats":{"total_commits":28,"total_committers":3,"mean_commits":9.333333333333334,"dds":0.1428571428571429,"last_synced_commit":"1163821ba3132a98410c6bc61a9a6af369493417"},"previous_names":["swentel/nostr-php"],"tags_count":35,"template":false,"template_full_name":null,"purl":"pkg:github/nostrver-se/nostr-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrver-se%2Fnostr-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrver-se%2Fnostr-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrver-se%2Fnostr-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrver-se%2Fnostr-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nostrver-se","download_url":"https://codeload.github.com/nostrver-se/nostr-php/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrver-se%2Fnostr-php/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30196173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["nostr","php"],"created_at":"2024-08-04T11:00:28.802Z","updated_at":"2026-03-06T20:31:49.818Z","avatar_url":"https://github.com/nostrver-se.png","language":"PHP","funding_links":[],"categories":["Libraries","PHP"],"sub_categories":["Client reviews and/or comparisons"],"readme":"# nostr-php\n\n![CI](https://github.com/nostrver-se/nostr-php/actions/workflows/ci.yml/badge.svg)\n![Packagist PHP Version](https://img.shields.io/packagist/dependency-v/swentel/nostr-php/php)\n![GitHub contributors](https://img.shields.io/github/contributors/nostrver-se/nostr-php)\n![GitHub issues](https://img.shields.io/github/issues/nostrver-se/nostr-php)\n![GitHub last commit (branch)](https://img.shields.io/github/last-commit/nostrver-se/nostr-php/main)\n\nThis is a PHP Helper library for Nostr.\nMore info about Nostr: https://github.com/nostr-protocol/nostr.\n\n## Installation\n\nTo use the library as a package in your PHP project, you can add it via Composer:\n\n```console\n$ composer require swentel/nostr-php\n```\n\nInstall dependencies if you would like to test / code some things out for yourself with the code example snippets below. \n\n```console\n$ composer install\n```\n\n## Create an event\n\nThis will create an event object with a short text message (kind 1).\n\n```php\nuse swentel\\nostr\\Event\\Event;\n\n$note = new Event();\n$note-\u003esetKind(1);\n$note-\u003esetContent('Hello world!');\n$note-\u003esetTags([\n  ['e', $relayUrl],\n  ['p', $public_key, $relayUrl],\n  ['r', $relayUrl],\n]);\n// or use addTag()\n$note-\u003eaddTag(['p', $public_key, $relayUrl]);\n```\n\n## Signing an event\n\nGenerates the id and signature for an event. The 'pubkey', 'id' and 'sig' \nproperties are added to the event object.\n\n```php\nuse swentel\\nostr\\Event\\Event;\nuse swentel\\nostr\\Sign\\Sign;\n\n$note = new Event();\n$note-\u003esetContent('Hello world!');\n$note-\u003esetKind(1);\n\n$signer = new Sign();\n$signer-\u003esignEvent($note, $private_key);\n```\n\n## Generating a message\n\nGenerate an event message : `[\"EVENT\", \u003cevent JSON as created above with id and sig\u003e]`\n\n```php\nuse swentel\\nostr\\Sign\\Sign;\nuse swentel\\nostr\\Message\\EventMessage;\n\n$signer = new Sign();\n$signer-\u003esignEvent($note, $private_key);\n\n$eventMessage = new EventMessage($note);\n$message_string = $eventMessage-\u003egenerate();\n```\n\n## Publish an event to a relay\n\nPublish an event with a note that has been prepared for sending to a relay.\n\n```php\nuse swentel\\nostr\\Event\\Event;\nuse swentel\\nostr\\Message\\EventMessage;\nuse swentel\\nostr\\Relay\\Relay;\n\n$note = new Event();\n$note-\u003esetContent('Hello world');\n$note-\u003esetKind(1);\n\n$signer = new Sign();\n$signer-\u003esignEvent($note, $private_key);\n\n$eventMessage = new EventMessage($note);\n\n$relayUrl = 'wss://nostr-websocket.tld';\n$relay = new Relay($relayUrl);\n$relay-\u003esetMessage($eventMessage);\n$result = $relay-\u003esend();\n```\n\nIf you would like to publish the event to multiple relays, you can use the `RelaySet` class.\n\n```php\n$relay1 = new Relay(''wss://nostr-websocket1.tld'');\n$relay2 = new Relay(''wss://nostr-websocket2.tld'');\n$relay3 = new Relay(''wss://nostr-websocket3.tld'');\n$relay4 = new Relay(''wss://nostr-websocket4.tld'');\n$relaySet = new RelaySet();\n$relaySet-\u003esetRelays([$relay1, $relay2, $relay3, $relay4]);\n$relaySet-\u003esetMessage($eventMessage);\n$result = $relaySet-\u003esend();\n```\n\n## Read events from a relay\n\nFetch events from a relay. \n\n```php\n$filter1 = new Filter();\n$filter1-\u003esetKinds([1, 3]); // You can add multiple kind numbers\n$filter1-\u003esetLimit(25); // Limit to fetch only a maximum of 25 events\n$filters = [$filter1]; // You can add multiple filters.\n\n$subscription = new Subscription();\n$requestMessage = new RequestMessage($subscription-\u003egetid(), $filters);\n\n$relayUrl = 'wss://nostr-websocket.tld';\n$relay = new Relay($relayUrl);\n$relay-\u003esetMessage($requestMessage);\n\n$request = new Request($relay, $requestMessage);\n$response = $request-\u003esend();\n```\n\n`$response` is a multidimensional array with elements containing each a response message (JSON string) decoded to an array from the relay and sorted by the relay.\nOutput example:\n```php\n[\n  'wss://nostr-websocket.tld' =\u003e [\n    0 =\u003e [\n      \"EVENT\",\n      \"A8kWzjCVUHSD1rmuwGqyK2PxsolZMO9YXditbg05fch6p3Q4eT7vRFLEJINBna\",\n      [\n        'id' =\u003e '1e8534623845629d40f7761c0577edf10f778c490e7b95a524845d9280c7c25a',\n        'kind' =\u003e 1,\n        'pubkey' =\u003e '06639a386c9c1014217622ccbcf40908c4f1a0c33e23f8d6d68f4abf655f8f71',\n        'created_at' =\u003e 1718723787,\n        'content' =\u003e 'Losing your social graph can feel the same for some I think 😮 ',\n        'tags' =\u003e [\n          ['e', 'f754a238947b7f32168f872650a8dd0b9376493e58005d7e0b8be52f6f229364', 'wss://nos.lol/', 'root'],\n          ['e', 'fe7dd6ba22fa0aa39370aa160226b8bc2413460621c8d67ce862205ad5a02c24', 'wss://nos.lol/', 'reply'],\n          ['p', 'fb1366abd5e4c92a8a950791bc72d51bde291a83555cb2c629a92fedd78068ac', '', 'mention']\n        ],\n        'sig' =\u003e '888c9b5d9e0b69eba3510dd2b5d03eddcf0a680ab0e7673820fb36a56448ad80701042a669c7ef9918593c5a41c8b3ccc1d82ade50f32b62dd843144f32df403'\n    ],\n    1 =\u003e [\n      \"EVENT\",\n      \"A8kWzjCVUHSD1rmuwGqyK2PxsolZMO9YXditbg05fch6p3Q4eT7vRFLEJINBna\",\n      [\n        ...Nostr event\n      ]\n    ],\n    2 =\u003e [\n      ...\n    ],\n    3 =\u003e [\n      ...\n    ],\n    4 =\u003e [\n      ...\n    ]\n  ]\n]\n\n```\n\n## Read events from a set of relays\n\nRead events from a set of relays with the `RelaySet` class.\nIt's basically the same snippet as above with the difference you create a `RelaySet` class and pass it through the `Request` object.\n\n```php\n$filter1 = new Filter();\n$filter1-\u003esetKinds([1]);\n$filter1-\u003esetLimit(5);\n$filters = [$filter1];\n$subscription = new Subscription();\n$requestMessage = new RequestMessage($subscription-\u003egetId(), $filters);\n$relays = [\n    new Relay('wss://nostr-websocket-1.tld'),\n    new Relay('wss://nostr-websocket-2.tld'),\n    new Relay('wss://nostr-websocket-3.tld'),\n];\n$relaySet = new RelaySet();\n$relaySet-\u003esetRelays($relays);\n\n$request = new Request($relaySet, $requestMessage);\n$response = $request-\u003esend();\n```\n\n## Generating a private key and a public key\n\n```php\nuse swentel\\nostr\\Key\\Key;\n\n$key = new Key();\n\n$private_key = $key-\u003egeneratePrivateKey();\n$public_key  = $key-\u003egetPublicKey($private_key);\n\n```\n\n## Converting keys\n\nConvert bech32 encoded keys (npub, nsec) to hex.\n\n```php\nuse swentel\\nostr\\Key\\Key;\n\n$public_key = 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg';\n$key = new Key();\n$hex = $key-\u003econvertToHex($public_key);\n```\n\nConvert hex keys to bech32 (npub, nsec).\n\n```php\nuse swentel\\nostr\\Key\\Key;\n\n$public_key = '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e';\n$private_key = '67dea2ed018072d675f5415ecfaed7d2597555e202d85b3d65ea4e58d2d92ffa';\n$key = new Key();\n$bech32_public = $key-\u003econvertPublicKeyToBech32($public_key);\n$bech32_private = $key-\u003econvertPrivateKeyToBech32($private_key);\n```\n\n## Run tests\n\nAll tests can be found in `tests`.\n\n```console\n$ php vendor/bin/phpunit\n```\n\n## Documentation\n\nThere is a comprehensive documentation website for the library: https://nostr-php.dev\n\nAlso, this website is published with nsite on several Blossom servers which can be accessed on the following hosts:\n\n* https://npub1phpdev2d38u5hzs4jrsh360mevh0rjctu9669quy97wu23u8sqdqpfha0j.nsite.lol/\n* https://npub1phpdev2d38u5hzs4jrsh360mevh0rjctu9669quy97wu23u8sqdqpfha0j.nostrdeploy.com/\n\nRepository: https://github.com/nostrver-se/nostr-php.dev\n\n## phpDocumentor documentation\n\nGenerate documentation with [phpDocumentor](https://phpdoc.org/).\n\n```console\n$ phpdoc \n```\n\nAll documentation is saved in the `phpdoc.nostr-php.dev` directory where the `index.html` can be opened in any browser.\nThis directory also serves as the root directory for https://phpdoc.nostr-php.dev. \n\nThe documentation of phpDocumentor can be found at https://docs.phpdoc.org/.\n\n## Roadmap / features\n\n- [x] Keypair generation and validation\n  - [x] Convert from hex to bech32-encoded keys\n- [x] Event signing with Schnorr signatures (`secp256k1`)\n- [x] Event string validation (issue [#17](https://github.com/nostrver-se/nostr-php/issues/17)) + Event object validation (issue [#85](https://github.com/nostrver-se/nostr-php/issues/85))\n- [x] NIP-01 basic protocol flow description\n  - [x] Publish events\n  - [x] Request events (issue [#55](https://github.com/nostrver-se/nostr-php/pull/55) credits to [kriptonix](https://github.com/kriptonix))\n  - [x] Fetch event with a persistent connection (pr [#99](https://github.com/nostrver-se/nostr-php/pull/99))\n  - [x] Implement all types of relay responses \n    - [x] `EVENT` - sends events requested by the client\n    - [x] `OK` - indicate an acceptance or denial of an EVENT message\n    - [x] `EOSE` - end of stored events\n    - [x] `CLOSED` - subscription is ended on the server side\n    - [x] `NOTICE` - used to send human-readable messages (like errors) to clients\n- [x] NIP-04 encrypted direct messages (pr [#84](https://github.com/nostrver-se/nostr-php/pull/84) credits to [dsbaars](https://github.com/dsbaars))\n- [x] NIP-05 mapping Nostr keys to DNS-based internet identifiers (pr [89](https://github.com/nostrver-se/nostr-php/pull/89) credits to [dsbaars](https://github.com/dsbaars))\n- [x] NIP-17 private direct messages (pr [#90](https://github.com/nostrver-se/nostr-php/pull/90) credits to [dsbaars](https://github.com/dsbaars))\n- [x] NIP-19 bech32-encoded identifiers (pr [#68](https://github.com/nostrver-se/nostr-php/pull/68))\n- [x] NIP-24 extra metadata fields and tags (pr [94](https://github.com/nostrver-se/nostr-php/pull/94) credits to [dsbaars](https://github.com/dsbaars))\n- [x] NIP-42 authentication of clients to relays\n- [x] NIP-44 encrypted payloads (pr [#84](https://github.com/nostrver-se/nostr-php/pull/84) credits to [dsbaars](https://github.com/dsbaars))\n- [x] NIP-65 relay list metadata (pr [#100](https://github.com/nostrver-se/nostr-php/pull/100))\n- [ ] Support multi-threading (async concurrency) for handling requests simultaneously\n- [ ] Support NIP-29 relay-based groups (communities)\n- [ ] Support NIP-52 calendar events\n- [ ] Support NIP-46 remote signing initiated by the client (issue [#87](https://github.com/nostrver-se/nostr-php/issues/87)) \n- [ ] Support NIP-45 event counts\n- [ ] Support NIP-50 search capability\n- [ ] Support NIP-03 openTimestamps attestations for events\n- [ ] Support NIP-14 subject tag in text events\n- [ ] Support NIP-40 expiration timestamp\n- [ ] Support NIP-47 Nostr Wallet Connect\n- [ ] Support NIP-49 private key encryption\n- [ ] Support NIP-77 Negentropy syncing\n\n## Community\n\nIf you need any help, please join this Telegram group: https://t.me/nostr_php\n\n## Funding\n\nIn May 2024 OpenSats granted Sebastian Hagens for further development of this library for one year. If you would like to support this project with a donation, you could send some lightning sats to `sebastian@lnd.sebastix.com` or on-chain to `bc1p3p6jq2sxsf650lgllv57st9h97xj37fflg5t8d265saz6yqzcdyqd7pzun`. \n\n## Maintainers\n \n* [@sebastix](https://github.com/Sebastix)  `npub1qe3e5wrvnsgpggtkytxteaqfprz0rgxr8c3l34kk3a9t7e2l3acslezefe`\n* [@swentel](https://github.com/swentel) (original author, inactive)  `npub1z8n2zt0vzkefhrhpf60face4wwq2nx87sz7wlgcvuk4adddkkycqknzjk5`\n\n## Contributors\n\nSee https://github.com/nostrver-se/nostr-php/graphs/contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostrver-se%2Fnostr-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnostrver-se%2Fnostr-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostrver-se%2Fnostr-php/lists"}