swentel / nostr-php

PHP 的 Nostr 辅助库

1.4.1 2024-09-14 20:30 UTC

This package is auto-updated.

Last update: 2024-09-14 20:32:09 UTC


README

CI Packagist PHP Version GitHub contributors GitHub issues GitHub last commit (branch)

这是一个为 Nostr 设计的 PHP 辅助库。有关 Nostr 的更多信息,请参阅:https://github.com/nostr-protocol/nostr

安装

要使用 Composer 在您的 PHP 项目中安装此包

$ composer require swentel/nostr-php

如果您想通过下面的代码示例片段测试/编写一些代码,请安装依赖项。

$ composer install

创建一个事件

这将创建一个包含简短文本消息的事件对象(类型 1)。

use swentel\nostr\Event\Event;

$note = new Event();
$note->setKind(1);
$note->setContent('Hello world!');
$note->setTags([
  ['e', $relayUrl],
  ['p', $public_key, $relayUrl],
  ['r', $relayUrl],
]);
// or use addTag()
$note->addTag(['p', $public_key, $relayUrl]);

签名事件

为事件生成 id 和签名。将 'pubkey'、'id' 和 'sig' 属性添加到事件对象中。

use swentel\nostr\Event\Event;
use swentel\nostr\Sign\Sign;

$note = new Event();
$note->setContent('Hello world!');
$note->setKind(1);

$signer = new Sign();
$signer->signEvent($note, $private_key);

生成消息

生成事件消息:["EVENT", <event JSON as created above with id and sig>]

use swentel\nostr\Sign\Sign;
use swentel\nostr\Message\EventMessage;

$signer = new Sign();
$signer->signEvent($note, $private_key);

$eventMessage = new EventMessage($note);
$message_string = $eventMessage->generate();

将事件发布到中继

发布一个已准备好发送到中继的带注释的事件。

use swentel\nostr\Event\Event;
use swentel\nostr\Message\EventMessage;
use swentel\nostr\Relay\Relay;

$note = new Event();
$note->setContent('Hello world');
$note->setKind(1);

$signer = new Sign();
$signer->signEvent($note, $private_key);

$eventMessage = new EventMessage($note);

$relayUrl = 'wss://nostr-websocket.tld';
$relay = new Relay($relayUrl);
$relay->setMessage($eventMessage);
$result = $relay->send();

如果您想将事件发布到多个中继,可以使用 RelaySet 类。

$relay1 = new Relay(''wss://nostr-websocket1.tld'');
$relay2 = new Relay(''wss://nostr-websocket2.tld'');
$relay3 = new Relay(''wss://nostr-websocket3.tld'');
$relay4 = new Relay(''wss://nostr-websocket4.tld'');
$relaySet = new RelaySet();
$relaySet->setRelays([$relay1, $relay2, $relay3, $relay4]);
$relaySet->setMessage($eventMessage);
$result = $relay->send();

从中继读取事件

从中继获取事件。

$subscription = new Subscription();
$subscriptionId = $subscription->setId();

$filter1 = new Filter();
$filter1->setKinds([1, 3]); // You can add multiple kind numbers
$filter1->setLimit(25); // Limit to fetch only a maximum of 25 events
$filters = [$filter1]; // You can add multiple filters.

$requestMessage = new RequestMessage($subscriptionId, $filters);

$relayUrl = 'wss://nostr-websocket.tld';
$relay = new Relay($relayUrl);
$relay->setMessage($requestMessage);

$request = new Request($relay, $requestMessage);
$response = $request->send();

$response 是一个多维数组,包含每个响应消息(JSON 字符串),从中继解码为数组并按中继排序。输出示例

[
  'wss://nostr-websocket.tld' => [
    0 => [
      "EVENT",
      "A8kWzjCVUHSD1rmuwGqyK2PxsolZMO9YXditbg05fch6p3Q4eT7vRFLEJINBna",
      [
        'id' => '1e8534623845629d40f7761c0577edf10f778c490e7b95a524845d9280c7c25a',
        'kind' => 1,
        'pubkey' => '06639a386c9c1014217622ccbcf40908c4f1a0c33e23f8d6d68f4abf655f8f71',
        'created_at' => 1718723787,
        'content' => 'Losing your social graph can feel the same for some I think 😮 ',
        'tags' => [
          ['e', 'f754a238947b7f32168f872650a8dd0b9376493e58005d7e0b8be52f6f229364', 'wss://nos.lol/', 'root'],
          ['e', 'fe7dd6ba22fa0aa39370aa160226b8bc2413460621c8d67ce862205ad5a02c24', 'wss://nos.lol/', 'reply'],
          ['p', 'fb1366abd5e4c92a8a950791bc72d51bde291a83555cb2c629a92fedd78068ac', '', 'mention']
        ],
        'sig' => '888c9b5d9e0b69eba3510dd2b5d03eddcf0a680ab0e7673820fb36a56448ad80701042a669c7ef9918593c5a41c8b3ccc1d82ade50f32b62dd843144f32df403'
    ],
    1 => [
      "EVENT",
      "A8kWzjCVUHSD1rmuwGqyK2PxsolZMO9YXditbg05fch6p3Q4eT7vRFLEJINBna",
      [
        ...Nostr event
      ]
    ],
    2 => [
      ...
    ],
    3 => [
      ...
    ],
    4 => [
      ...
    ]
  ]
]

从一组中继读取事件

使用 RelaySet 类从一组中继读取事件。它基本上与上面的代码片段相同,只是您创建了一个 RelaySet 类并将其通过 Request 对象传递。

$subscription = new Subscription();
$subscriptionId = $subscription->setId();

$filter1 = new Filter();
$filter1->setKinds([1]);
$filter1->setLimit(5);
$filters = [$filter1];
$requestMessage = new RequestMessage($subscriptionId, $filters);
$relays = [
    new Relay('wss://nostr-websocket-1.tld'),
    new Relay('wss://nostr-websocket-2.tld'),
    new Relay('wss://nostr-websocket-3.tld'),
];
$relaySet = new RelaySet();
$relaySet->setRelays($relays);

$request = new Request($relaySet, $requestMessage);
$response = $request->send();

生成私钥和公钥

use swentel\nostr\Key\Key;

$key = new Key();

$private_key = $key->generatePrivateKey();
$public_key  = $key->getPublicKey($private_key);

转换密钥

将 bech32 编码的密钥(npub、nsec)转换为十六进制。

use swentel\nostr\Key\Key;

$public_key = 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg';
$key = new Key();
$hex = $key->convertToHex($public_key);

将十六进制密钥转换为 bech32(npub、nsec)。

use swentel\nostr\Key\Key;

$public_key = '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e';
$private_key = '67dea2ed018072d675f5415ecfaed7d2597555e202d85b3d65ea4e58d2d92ffa';
$key = new Key();
$bech32_public = $key->convertPublicKeyToBech32($public_key);
$bech32_private = $key->convertPrivateKeyToBech32($private_key);

运行测试

所有测试都在 tests 中。

$ php vendor/bin/phpunit

nostr-php 脚本(命令行客户端)

该库附带了简单的 CLI 客户端(bin/nostr-php),用于将简短文本注释发布到 Nostr 中继。

Usage:
$ bin/nostr-php --content "Hello world!" --key /home/path/to/nostr-private.key --relay wss://nostr.pleb.network

注意:关键参数期望一个包含您私钥的文件!不要在命令行上粘贴您的私钥。

路线图

  • 密钥对生成和验证
    • 从十六进制转换为 bech32 编码的密钥
  • 使用 Schnorr 签名(secp256k1)签名事件
  • 事件验证(问题 #17
  • 支持 NIP-01 基本协议流程描述
    • 发布事件
    • 请求事件(问题 #55,归功于 kriptonix
    • 实现所有类型的中继响应
      • EVENT - 向客户端发送请求的事件
      • OK - 表示接受或拒绝 EVENT 消息
      • EOSE - 存储事件的结束
      • CLOSED - 在服务器端结束订阅
      • NOTICE - 用于向客户端发送人类可读的消息(如错误)
  • 改进中继响应的处理
  • 支持 NIP-19 bech32 编码的标识符
  • 支持 NIP-42 客户端到中继的认证 => AUTH 中继响应
  • 支持 NIP-45 事件计数
  • 支持 NIP-50 搜索功能
  • 支持多线程(异步并发)以同时处理请求
  • 通过bin/nostr-php CLI客户端支持实时(运行时)订阅,以监听中继的新事件

社区

如果您需要任何帮助,请加入这个Telegram群组:https://t.me/nostr_php

资金

2024年5月,OpenSats授予Sebastian Hagens一年内进一步开发这个库的资金。如果您想通过捐赠支持这个项目,可以向sebastian@lnd.sebastix.com发送一些闪电币,或者在链上向bc1p3p6jq2sxsf650lgllv57st9h97xj37fflg5t8d265saz6yqzcdyqd7pzun发送。

维护者

  • @sebastix npub1qe3e5wrvnsgpggtkytxteaqfprz0rgxr8c3l34kk3a9t7e2l3acslezefe
  • @swentel(原始作者,已停用)npub1z8n2zt0vzkefhrhpf60face4wwq2nx87sz7wlgcvuk4adddkkycqknzjk5

贡献者

请参阅https://github.com/nostrver-se/nostr-php/graphs/contributors