本文目录导读:

我来详细讲解 PHP 项目中 DNSLink 的概念、原理和实现方法。
DNSLink 简介
DNSLink 是一种利用 DNS TXT 记录将域名映射到 IPFS 内容的机制,它允许使用域名来访问 IPFS 上的内容,而不需要直接使用哈希地址。
工作原理
- 使用
dnslink=前缀的 TXT 记录 - 格式:
dnslink=/ipfs/<CID>或dnslink=/ipns/<domain>
基础实现
1 获取 DNSLink 记录
<?php
class DNSLinkResolver {
/**
* 获取域名的 DNSLink TXT 记录
*/
public function getDNSLinkRecords($domain) {
try {
$records = dns_get_record($domain, DNS_TXT);
$dnslinkRecords = [];
foreach ($records as $record) {
if (strpos($record['txt'], 'dnslink=') === 0) {
$dnslinkRecords[] = $record['txt'];
}
}
return $dnslinkRecords;
} catch (Exception $e) {
throw new Exception("DNS 查询失败: " . $e->getMessage());
}
}
/**
* 解析 DNSLink 记录获取 CID
*/
public function resolveCID($domain) {
$records = $this->getDNSLinkRecords($domain);
if (empty($records)) {
return null;
}
// 解析第一条有效的 dnslink 记录
foreach ($records as $record) {
if (preg_match('/^dnslink=\/ipfs\/(.+)$/', $record, $matches)) {
return [
'type' => 'ipfs',
'path' => $matches[1]
];
} elseif (preg_match('/^dnslink=\/ipns\/(.+)$/', $record, $matches)) {
return [
'type' => 'ipns',
'path' => $matches[1]
];
}
}
return null;
}
}
2 完整的 DNSLink 解析器
<?php
class DNSLinkManager {
private $ipfsGateway = 'https://ipfs.io/ipfs/';
private $ipnsGateway = 'https://ipfs.io/ipns/';
/**
* 设置自定义网关
*/
public function setGateway($ipfsGateway, $ipnsGateway = null) {
$this->ipfsGateway = $ipfsGateway;
$this->ipnsGateway = $ipnsGateway ?? str_replace('/ipfs/', '/ipns/', $ipfsGateway);
}
/**
* 解析域名获取内容
*/
public function resolveContent($domain) {
try {
// 获取 dnslink 记录
$result = $this->resolveCID($domain);
if (!$result) {
return [
'success' => false,
'error' => '未找到 DNSLink 记录'
];
}
// 构建完整 URL
$url = $this->buildURL($result);
// 获取内容
$content = $this->fetchContent($url);
return [
'success' => true,
'content' => $content,
'url' => $url,
'type' => $result['type'],
'path' => $result['path']
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* 构建访问 URL
*/
private function buildURL($result) {
if ($result['type'] === 'ipfs') {
return $this->ipfsGateway . $result['path'];
} else {
return $this->ipnsGateway . $result['path'];
}
}
/**
* 获取远程内容
*/
private function fetchContent($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true
]);
$content = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("获取内容失败,HTTP 状态码: " . $httpCode);
}
return $content;
}
private function resolveCID($domain) {
$records = dns_get_record($domain, DNS_TXT);
foreach ($records as $record) {
if (strpos($record['txt'], 'dnslink=') === 0) {
$value = substr($record['txt'], 8); // 移除 'dnslink='
if (strpos($value, '/ipfs/') === 0) {
return [
'type' => 'ipfs',
'path' => substr($value, 6)
];
} elseif (strpos($value, '/ipns/') === 0) {
return [
'type' => 'ipns',
'path' => substr($value, 6)
];
}
}
}
return null;
}
}
高级功能实现
1 缓存机制
<?php
class CachedDNSLinkResolver extends DNSLinkManager {
private $cache = [];
private $cacheTime = 300; // 5分钟缓存
/**
* 带缓存的解析
*/
public function resolveWithCache($domain) {
$cacheKey = md5($domain);
// 检查缓存
if (isset($this->cache[$cacheKey])) {
$cached = $this->cache[$cacheKey];
if (time() - $cached['time'] < $this->cacheTime) {
return $cached['data'];
}
}
// 解析并缓存
$result = $this->resolveContent($domain);
$this->cache[$cacheKey] = [
'time' => time(),
'data' => $result
];
return $result;
}
/**
* 清除缓存
*/
public function clearCache($domain = null) {
if ($domain) {
unset($this->cache[md5($domain)]);
} else {
$this->cache = [];
}
}
}
2 多记录处理
<?php
class MultiDNSLinkResolver {
/**
* 处理多条 DNSLink 记录(负载均衡)
*/
public function resolveWithFallback($domains) {
foreach ($domains as $domain) {
try {
$resolver = new DNSLinkManager();
$result = $resolver->resolveContent($domain);
if ($result['success']) {
return $result;
}
} catch (Exception $e) {
continue; // 尝试下一个域名
}
}
return [
'success' => false,
'error' => '所有域名解析失败'
];
}
/**
* 获取所有关联的 CID
*/
public function getAllCIDs($domain) {
$cids = [];
$records = dns_get_record($domain, DNS_TXT);
foreach ($records as $record) {
if (strpos($record['txt'], 'dnslink=') === 0) {
$value = substr($record['txt'], 8);
if (strpos($value, '/ipfs/') === 0) {
$cids[] = [
'type' => 'ipfs',
'cid' => substr($value, 6)
];
}
}
}
return $cids;
}
}
Web 应用集成
1 中间件实现
<?php
class DNSLinkMiddleware {
/**
* 处理请求,自动解析 DNSLink
*/
public function handle($request, $next) {
$domain = $request->getHost();
$path = $request->getPath();
$resolver = new DNSLinkManager();
$result = $resolver->resolveContent($domain . $path);
if ($result['success']) {
// 设置响应头
header('X-DNSLink-Content-Type: ' . $result['type']);
header('X-DNSLink-Hash: ' . $result['path']);
// 输出内容
echo $result['content'];
exit;
}
return $next($request);
}
}
// 在框架中使用示例
// Slim Framework
$app->add(new DNSLinkMiddleware());
// Laravel
// app/Http/Kernel.php
protected $middleware = [
\App\Http\Middleware\DNSLinkMiddleware::class,
];
2 RESTful API
<?php
class DNSLinkAPI {
/**
* API 端点:解析 DNSLink
*/
public function resolveEndpoint($request) {
$domain = $request->getParam('domain');
if (!$domain) {
return $this->jsonResponse([
'error' => '缺少 domain 参数'
], 400);
}
$resolver = new DNSLinkManager();
$result = $resolver->resolveContent($domain);
return $this->jsonResponse($result);
}
/**
* API 端点:验证 DNSLink 配置
*/
public function verifyEndpoint($request) {
$domain = $request->getParam('domain');
try {
$resolver = new DNSLinkResolver();
$records = $resolver->getDNSLinkRecords($domain);
return $this->jsonResponse([
'domain' => $domain,
'has_dnslink' => !empty($records),
'records' => $records,
'valid' => $this->validateRecords($records)
]);
} catch (Exception $e) {
return $this->jsonResponse([
'error' => $e->getMessage()
], 500);
}
}
private function validateRecords($records) {
foreach ($records as $record) {
if (preg_match('/^dnslink=\/(ipfs|ipns)\/.+/', $record)) {
return true;
}
}
return false;
}
private function jsonResponse($data, $status = 200) {
http_response_code($status);
header('Content-Type: application/json');
return json_encode($data, JSON_PRETTY_PRINT);
}
}
实用工具函数
<?php
/**
* 检查域名是否有有效的 DNSLink 记录
*/
function hasDNSLink($domain) {
$records = @dns_get_record($domain, DNS_TXT);
if (!$records) return false;
foreach ($records as $record) {
if (strpos($record['txt'], 'dnslink=') === 0) {
return true;
}
}
return false;
}
/**
* 批量检查 DNSLink
*/
function batchCheckDNSLink($domains) {
$results = [];
foreach ($domains as $domain) {
$results[$domain] = hasDNSLink($domain);
}
return $results;
}
/**
* 生成 DNSLink TXT 记录值
*/
function generateDNSLinkRecord($cid, $type = 'ipfs') {
return "dnslink=/{$type}/{$cid}";
}
/**
* 从 URL 提取 DNSLink 信息
*/
function extractDNSLinkFromURL($url) {
$parts = parse_url($url);
if (!isset($parts['host'])) {
return null;
}
$resolver = new DNSLinkResolver();
return $resolver->resolveCID($parts['host']);
}
使用示例
<?php
// 基础使用
$resolver = new DNSLinkManager();
$result = $resolver->resolveContent('example.com');
if ($result['success']) {
echo "内容类型: " . $result['type'] . "\n";
echo "内容哈希: " . $result['path'] . "\n";
echo "访问 URL: " . $result['url'] . "\n";
echo "内容长度: " . strlen($result['content']) . " 字节\n";
}
// 带缓存的使用
$cachedResolver = new CachedDNSLinkResolver();
$result = $cachedResolver->resolveWithCache('ipfs.io');
// API 使用
$api = new DNSLinkAPI();
echo $api->resolveEndpoint(['domain' => 'example.com']);
// 工具函数
if (hasDNSLink('example.com')) {
echo "域名已配置 DNSLink\n";
$record = generateDNSLinkRecord('Qm...', 'ipfs');
echo "生成的记录: " . $record . "\n";
}
注意事项
- DNS 缓存:DNS 记录有 TTL,修改后需要等待传播
- 安全性:验证 DNSLink 记录的来源,防止 DNS 劫持
- 错误处理:DNS 查询可能失败,需要适当的异常处理
- 性能优化:使用缓存减少 DNS 查询次数
- 网关选择:选择可靠且快速的 IPFS 网关
这个实现提供了完整的 DNSLink 解析功能,可以根据项目需求选择合适的组件使用。