本文目录导读:

在 PHP 中实现智能 DNS 解析,主要包含两个方面:DNS 解析库和智能路由逻辑,下面我给你一套完整的方案。
基础 DNS 解析
<?php
// 基础DNS解析
class BasicDNS {
// 标准解析
public function resolve($domain) {
$records = dns_get_record($domain, DNS_A | DNS_AAAA);
return $records;
}
// 获取所有记录类型
public function getAllRecords($domain) {
$types = [
DNS_A, DNS_AAAA, DNS_MX, DNS_NS,
DNS_TXT, DNS_CNAME, DNS_SOA
];
$all = [];
foreach ($types as $type) {
$records = dns_get_record($domain, $type);
if ($records) {
$all = array_merge($all, $records);
}
}
return $all;
}
}
智能 DNS 解析器
<?php
class SmartDNS {
private $geoIP;
private $cache;
private $config;
public function __construct($config = []) {
$this->config = array_merge([
'cache_ttl' => 300, // 缓存时间
'fallback_ttl' => 60, // 降级缓存
'timeout' => 5, // 超时时间
'enable_cache' => true,
'enable_ipv6' => false
], $config);
$this->initCache();
$this->initGeoIP();
}
/**
* 智能解析主入口
*/
public function resolve($domain, $clientIP = null) {
// 1. 获取客户端IP
$clientIP = $clientIP ?: $this->getClientIP();
// 2. 检查缓存
$cacheKey = md5($domain . '|' . $clientIP);
if ($cached = $this->getCache($cacheKey)) {
return $cached;
}
// 3. 获取用户地理位置
$location = $this->getGeoLocation($clientIP);
// 4. 获取DNS记录
$records = $this->fetchDNSRecords($domain);
// 5. 智能选择最佳IP
$bestIP = $this->smartSelect($records, $location);
// 6. 缓存结果
$result = [
'ip' => $bestIP,
'location' => $location,
'query_time' => time(),
'ttl' => $this->config['cache_ttl']
];
$this->setCache($cacheKey, $result);
return $result;
}
/**
* 智能选择IP
*/
private function smartSelect($records, $location) {
// 按地理位置分组
$grouped = [];
foreach ($records as $record) {
if (!isset($record['ip'])) continue;
$ipLocation = $this->getGeoLocation($record['ip']);
$distance = $this->calculateDistance($location, $ipLocation);
$record['distance'] = $distance;
$record['score'] = $this->calculateScore($record);
$grouped[] = $record;
}
// 排序并选择最佳
usort($grouped, function($a, $b) {
return $b['score'] - $a['score'];
});
return !empty($grouped) ? $grouped[0]['ip'] : false;
}
/**
* 计算IP评分
*/
private function calculateScore($record) {
$score = 100;
// 距离扣分(越远分越低)
$score -= $record['distance'] * 0.1;
// 响应时间扣分
if (isset($record['response_time'])) {
$score -= $record['response_time'] * 10;
}
// 负载扣分
if (isset($record['load'])) {
$score -= $record['load'] * 20;
}
return max(0, $score);
}
/**
* 计算两点距离(简化版)
*/
private function calculateDistance($loc1, $loc2) {
$earth_radius = 6371;
$lat1 = deg2rad($loc1['lat'] ?? 0);
$lng1 = deg2rad($loc1['lng'] ?? 0);
$lat2 = deg2rad($loc2['lat'] ?? 0);
$lng2 = deg2rad($loc2['lng'] ?? 0);
$dLat = $lat2 - $lat1;
$dLng = $lng2 - $lng1;
$a = sin($dLat/2) * sin($dLat/2) +
cos($lat1) * cos($lat2) *
sin($dLng/2) * sin($dLng/2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $earth_radius * $c;
}
/**
* 获取DNS记录(带缓存)
*/
private function fetchDNSRecords($domain) {
$records = dns_get_record($domain, DNS_A | DNS_AAAA);
// 添加健康检查
foreach ($records as &$record) {
if (isset($record['ip'])) {
$record['response_time'] = $this->checkLatency($record['ip']);
$record['load'] = 0; // 可从监控系统获取
}
}
return $records;
}
/**
* 延迟测试
*/
private function checkLatency($ip, $port = 80) {
$start = microtime(true);
$conn = @fsockopen($ip, $port, $errno, $errstr, 2);
if ($conn) {
fclose($conn);
return microtime(true) - $start;
}
return 999; // 不可达
}
/**
* 获取地理位置(使用纯真IP库或MaxMind)
*/
private function getGeoLocation($ip) {
// 这里使用简单的IP段映射作为示例
// 实际应使用 GeoIP2 或 ip2region 库
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
// 简化的地理位置判断
if (strpos($ip, '61.') === 0 || strpos($ip, '120.') === 0) {
return ['lat' => 39.9042, 'lng' => 116.4074, 'city' => '北京'];
} elseif (strpos($ip, '113.') === 0 || strpos($ip, '116.') === 0) {
return ['lat' => 22.5431, 'lng' => 114.0579, 'city' => '深圳'];
}
}
return ['lat' => 0, 'lng' => 0, 'city' => 'unknown'];
}
/**
* 获取客户端IP
*/
private function getClientIP() {
$keys = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_REAL_IP',
'HTTP_CLIENT_IP',
'REMOTE_ADDR'
];
foreach ($keys as $key) {
if (isset($_SERVER[$key]) && filter_var($_SERVER[$key], FILTER_VALIDATE_IP)) {
return $_SERVER[$key];
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
// 缓存方法
private function initCache() {
// 可以使用 Redis/Memcached/文件缓存
$this->cache = [];
}
private function getCache($key) {
if (!$this->config['enable_cache']) return false;
if (isset($this->cache[$key])) {
$data = $this->cache[$key];
if (time() - $data['query_time'] < $data['ttl']) {
return $data;
}
}
return false;
}
private function setCache($key, $data) {
if ($this->config['enable_cache']) {
$this->cache[$key] = $data;
}
}
}
使用示例
<?php
// 1. 基础使用
$dns = new SmartDNS();
$result = $dns->resolve('example.com');
echo "最佳IP: " . $result['ip'] . "\n";
echo "所在位置: " . $result['location']['city'] . "\n";
// 2. 指定客户端IP
$clientIP = '61.135.169.121'; // 北京IP
$result = $dns->resolve('example.com', $clientIP);
// 3. 自定义配置
$config = [
'cache_ttl' => 600,
'timeout' => 3,
'enable_ipv6' => true
];
$dns = new SmartDNS($config);
高级功能:多区域负载均衡
<?php
class SmartDNSEnhanced extends SmartDNS {
private $serviceNodes;
public function __construct($config = []) {
parent::__construct($config);
// 配置多区域节点
$this->serviceNodes = [
'北京' => [
'servers' => ['202.106.0.20', '210.75.1.10'],
'weight' => 50,
'region' => '华北'
],
'上海' => [
'servers' => ['61.129.42.10', '218.75.50.10'],
'weight' => 30,
'region' => '华东'
],
'深圳' => [
'servers' => ['113.108.10.20', '119.147.15.10'],
'weight' => 20,
'region' => '华南'
]
];
}
public function smartResolve($domain, $clientIP) {
// 获取用户位置
$userLocation = $this->getGeoLocation($clientIP);
// 根据位置选择最优区域
$bestRegion = $this->selectBestRegion($userLocation);
// 在区域内进行负载均衡
$targetServer = $this->loadBalance($bestRegion);
return [
'domain' => $domain,
'client_ip' => $clientIP,
'target_ip' => $targetServer,
'region' => $bestRegion,
'timestamp' => time()
];
}
private function selectBestRegion($location) {
$minDistance = PHP_INT_MAX;
$bestRegion = null;
foreach ($this->serviceNodes as $region => $node) {
$regionLoc = $this->getRegionalLocation($region);
$distance = $this->calculateDistance($location, $regionLoc);
if ($distance < $minDistance) {
$minDistance = $distance;
$bestRegion = $region;
}
}
return $bestRegion;
}
private function loadBalance($region) {
$nodes = $this->serviceNodes[$region]['servers'];
$totalWeight = $this->serviceNodes[$region]['weight'];
$random = mt_rand(1, 100);
if ($random <= $totalWeight) {
return $nodes[0]; // 主节点
}
return $nodes[1]; // 备节点
}
}
集成第三方库
<?php
// 使用 Composer 安装 GEOIP 库
require 'vendor/autoload.php';
use GeoIp2\Database\Reader;
class CommercialDNS extends SmartDNS {
private $geoReader;
public function __construct($config = []) {
parent::__construct($config);
// 初始化 GeoIP
$this->geoReader = new Reader('/path/to/GeoLite2-City.mmdb');
}
protected function getGeoLocation($ip) {
try {
$record = $this->geoReader->city($ip);
return [
'lat' => $record->location->latitude,
'lng' => $record->location->longitude,
'city' => $record->city->name,
'country' => $record->country->name
];
} catch (Exception $e) {
return ['lat' => 0, 'lng' => 0, 'city' => 'unknown'];
}
}
}
性能优化建议
<?php
// 使用Redis缓存
class RedisDNS extends SmartDNS {
private $redis;
public function __construct($config = []) {
parent::__construct($config);
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
protected function getCache($key) {
$data = $this->redis->get($key);
return $data ? json_decode($data, true) : false;
}
protected function setCache($key, $data, $ttl = 300) {
$this->redis->set($key, json_encode($data), $ttl);
}
// 批量查询优化
public function batchResolve($domains, $clientIP) {
$pipe = $this->redis->multi();
foreach ($domains as $domain) {
$key = md5($domain . '|' . $clientIP);
$cached = $this->redis->get($key);
if (!$cached) {
$result = $this->resolve($domain, $clientIP);
$pipe->set($key, json_encode($result), $this->config['cache_ttl']);
}
}
$pipe->exec();
}
}
注意事项
- 安全考虑:防止 DNS 投毒,使用 DNS over HTTPS (DoH) 或 DNS over TLS (DoT)
- 性能优化:使用缓存、CDN、边缘计算
- 数据更新:定期更新 IP 地理位置库
- 监控告警:对 DNS 解析成功率、延迟进行监控
- 降级机制:主 DNS 失败时自动切换到备用 DNS
这个方案可以很好地满足大多数智能 DNS 需求,你可以根据实际场景调整和扩展。