本文目录导读:

在 PHP 中实现去中心化标识符(DID,Decentralized Identifier)并不是一个简单的单一函数调用,而是一个涉及密钥生成、DID 文档构建、签名验证以及与区块链或分布式账本交互的完整流程。
由于 PHP 在区块链生态中的原生库不如 JavaScript/Node.js 或 Rust 丰富,主要有两种实现路径:
直接使用 PHP 原生库(适合学习或简单场景)
这种方式不依赖外部区块链网络,仅通过密码学技术生成密钥对并构建符合 DID Core 规范的标识符和文档。
安装依赖库
推荐使用 web3p 或 simplito/elliptic-php 进行椭圆曲线加密(DID 常用 secp256k1 或 ed25519),以及 mlively/php-jwt 进行签名。
composer require simplito/elliptic-php composer require mlively/php-jwt
实现 DID 生成与验证示例
<?php
use Elliptic\EC;
use kornrunner\Keccak;
class SimpleDID {
private $privateKey;
private $publicKey;
// 生成基于 secp256k1 的密钥对
public function __construct() {
$ec = new EC('secp256k1');
$this->privateKey = $ec->genKeyPair();
$this->publicKey = $this->privateKey->getPublic();
}
// 创建 DID 标识符(格式:did:example:<公钥指纹>)
public function getDID(): string {
// 获取未压缩的公钥(前导字节 0x04)
$pubKeyHex = $this->publicKey->encode('hex');
// 生成方法特定标识符(例如使用 Keccak-256 哈希)
$hash = Keccak::hash(hex2bin($pubKeyHex), 256);
$fingerprint = substr($hash, 0, 40); // 取前 40 位
return "did:example:{$fingerprint}";
}
// 构建 DID 文档
public function getDocument(): array {
$did = $this->getDID();
$pubKeyHex = $this->publicKey->encode('hex');
return [
"@context" => "https://www.w3.org/ns/did/v1",
"id" => $did,
"verificationMethod" => [
[
"id" => $did . "#keys-1",
"type" => "EcdsaSecp256k1VerificationKey2019",
"controller" => $did,
"publicKeyHex" => $pubKeyHex
]
],
"authentication" => [
$did . "#keys-1"
]
];
}
// 使用私钥对数据进行签名
public function sign($data): string {
$signature = $this->privateKey->sign(Keccak::hash($data, 256));
return $signature->toDER('hex');
}
// 验证签名
public function verify($data, $signatureHex): bool {
$ec = new EC('secp256k1');
$signature = $ec->signatureFromDER(hex2bin($signatureHex));
$hash = Keccak::hash($data, 256);
return $this->publicKey->verify($hash, $signature);
}
}
// 使用示例
$didObj = new SimpleDID();
echo "DID: " . $didObj->getDID() . "\n";
print_r($didObj->getDocument());
$testData = "hello_decentralized_world";
$sig = $didObj->sign($testData);
echo "签名验证: " . ($didObj->verify($testData, $sig) ? "有效" : "无效") . "\n";
通过 API 集成 DIF 通用解析器(生产环境推荐)
生产环境通常不需要自己实现密码学细节,而是通过 HTTP API 调用一个DID 通用解析器(Universal Resolver)来解析或注册 DID。
使用 Guzzle 与 Universal Resolver 交互
composer require guzzlehttp/guzzle
解析任何 DID 的 PHP 实现
<?php
use GuzzleHttp\Client;
function resolveDID(string $did): array {
$client = new Client([
'base_uri' => 'https://dev.uniresolver.io',
'timeout' => 10.0,
]);
try {
$response = $client->get("/1.0/identifiers/{$did}");
return json_decode($response->getBody(), true);
} catch (\Exception $e) {
return ['error' => $e->getMessage()];
}
}
// 使用示例:解析一个已知的 did:ethr
$didResult = resolveDID('did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a');
print_r($didResult);
集成具体 DID 方法的 PHP SDK
不同去中心化网络(如 Ethereum、IPFS、Sovrin)有不同的 did:method,需要对应的 SDK。
示例:创建 did:ethr 的方法标识
Ethereum 的 DID 方法是基于以太坊地址的。
<?php
use kornrunner\Keccak;
use Symfony\Component\Process\Process;
class EthrDID {
// 从私钥生成 did:ethr
public static function fromPrivateKey(string $privateKeyHex): string {
// 这里需要集成 ethereum 库(如 php-ethereum/ethereum)
// 简化示例:假设已有以太坊地址
$ethAddress = '0xb9c5714089478a327f09197987f16f9e5d936e8a';
// did:ethr 格式:did:ethr:<网络ID>:<地址>
// 主网无网络ID
return "did:ethr:{$ethAddress}";
}
// 注册到链上(需要与以太坊节点交互)
public static function registerOnChain(string $did, array $didDocument): bool {
// 调用以太坊智能合约 EthrDID Registry
// 需要 ethr-did-registry 的合约地址和 RPC 调用代码
return false; // 简化处理
}
}
核心架构对比与选择建议
| 方案 | 适用场景 | 开发复杂度 | 去中心化程度 |
|---|---|---|---|
| 纯密码学生成 | 原型验证、后端服务内生成、离线签名 | 中等(需懂椭圆曲线) | 局部(需自行管理密钥) |
| Universal Resolver | 解析已有DID,不负责创建 | 低(HTTP调用) | 依赖于解析器节点 |
| 特定方法SDK | 需读写区块链(如 Ethereum / Bitcoin / Hyperledger) | 高(需链交互) | 完全去中心化 |
注意事项
- 密钥管理:不要将私钥硬编码或存储在数据库,生产环境使用 HSM(硬件安全模块) 或 密钥管理服务(KMS) 如 AWS KMS / Azure Key Vault。
- ID 规范:PHP 实现的 DID 必须遵循 W3C DID Core 1.0 规范,特别是
@context和verificationMethod字段。 - Web5 / TBD 生态:如果面向未来 Web5 生态,PHP 目前支持较弱,建议考虑与 Node.js 微服务集成(通过消息队列或 REST API)。
- 性能:椭圆曲线签名在 PHP 中较慢(相比 C 扩展),推荐使用
sodium扩展(Sodium::crypto_sign)实现基于 Ed25519 的 DID(如did:key):
// 使用 libsodium 实现 did:key 的快速版本
$keyPair = sodium_crypto_sign_keypair();
$publicKey = sodium_crypto_sign_publickey($keyPair);
$privateKey = sodium_crypto_sign_secretkey($keyPair);
// did:key 的生成方式(参考 did:key 规范)
$fingerprint = base58_encode(multibase_encode(0xed, $publicKey));
$did = "did:key:{$fingerprint}";
- 快速验证:用 PHP 原生椭圆曲线 +
did:example方法(路径一)。 - 生产解析:调用 Universal Resolver API(路径二)。
- 链上交互:针对特定 DID 方法,在 PHP 中调用对应区块链 RPC 或通过 PHP 扩展(如
ethr-did的实现)。
对于 PHP 开发者,最佳实践是将加密和链交互部分封装成独立的 Trait 或抽象类,对外提供统一的 createDID()、sign()、verify() 接口。