PHP项目DNSLink与解析

wen PHP项目 4

本文目录导读:

PHP项目DNSLink与解析

  1. DNSLink 简介
  2. 基础实现
  3. 高级功能实现
  4. Web 应用集成
  5. 实用工具函数
  6. 使用示例
  7. 注意事项

我来详细讲解 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";
}

注意事项

  1. DNS 缓存:DNS 记录有 TTL,修改后需要等待传播
  2. 安全性:验证 DNSLink 记录的来源,防止 DNS 劫持
  3. 错误处理:DNS 查询可能失败,需要适当的异常处理
  4. 性能优化:使用缓存减少 DNS 查询次数
  5. 网关选择:选择可靠且快速的 IPFS 网关

这个实现提供了完整的 DNSLink 解析功能,可以根据项目需求选择合适的组件使用。

抱歉,评论功能暂时关闭!