spatie/dns
Fetch DNS records in PHP using dig. Query domains for A, AAAA, CNAME, MX, TXT, SRV and more, filter by type(s), and get structured record objects with handy accessors for record details.
Installation:
composer require spatie/dns
Ensure dig is installed on your system (Linux/MacOS/Windows with WSL). If not, the package falls back to PHP's dns_get_record().
First Query:
use Spatie\Dns\Dns;
$dns = new Dns();
$records = $dns->getRecords('example.com');
Filter Records:
// Get only A records
$aRecords = $dns->getRecords('example.com', 'A');
// Get multiple types
$aAndMx = $dns->getRecords('example.com', ['A', 'MX']);
Basic DNS Lookup:
$dns = new Dns();
$records = $dns->getRecords('google.com');
foreach ($records as $record) {
echo $record->host() . ' => ' . $record->type() . ': ' . $record->data() . "\n";
}
Handling Specific Record Types:
// SRV records for VoIP services
$srvRecords = $dns->getRecords('example.com', 'SRV');
$srvRecords[0]->target(); // e.g., "sip.example.com"
// TXT records for SPF/DKIM
$txtRecords = $dns->getRecords('example.com', 'TXT');
$txtRecords[0]->content(); // e.g., "v=spf1 include:_spf.example.com ~all"
Custom Nameservers:
$dns->useNameserver('8.8.8.8')->getRecords('example.com');
Retry Logic for Unstable Networks:
$dns->setRetries(3)->setTimeout(2)->getRecords('example.com');
Service Providers:
Bind the Dns instance to the container for global access:
$this->app->singleton(Dns::class, function () {
return new Dns();
});
Artisan Commands: Create a command to debug DNS issues:
use Spatie\Dns\Dns;
class DebugDnsCommand extends Command {
protected $signature = 'dns:debug {domain} {--type=}';
public function handle(Dns $dns) {
$records = $dns->getRecords($this->argument('domain'), $this->option('type'));
$this->table(['Host', 'Type', 'Data'], $records);
}
}
Testing:
Mock the Dns class or use a test nameserver (e.g., 127.0.0.1 with dnsmasq):
$this->mock(Dns::class)->shouldReceive('getRecords')
->once()
->andReturn([new A('example.com', '192.0.2.1')]);
Caching: Cache results for non-critical checks (e.g., TTL-based caching):
$records = Cache::remember("dns_{$domain}_{$type}", now()->addMinutes(5), function () use ($dns, $domain, $type) {
return $dns->getRecords($domain, $type);
});
Missing dig:
CouldNotFetchDns exception with exit code 127.dig (e.g., sudo apt-get install dnsutils on Ubuntu) or ensure PHP’s dns_get_record() is enabled in php.ini (extension=dns).IDN (Internationalized Domain Names):
例.测试) may fail if dig converts them to ASCII.->noIdnOut() to disable IDN conversion:
$dns->noIdnOut()->getRecords('例.测试');
Rate Limiting:
setTimeout() and setRetries() to avoid hammering:
$dns->setTimeout(3)->setRetries(2)->getRecords('example.com');
Record-Specific Quirks:
content() to get the raw string or parse manually.flags(), tag(), and value() for validation:
$caa = $dns->getRecords('example.com', 'CAA')[0];
$caa->tag(); // e.g., "issue"
$caa->value(); // e.g., "letsencrypt.org"
Root/TLD Queries:
. (root) or .com may return unexpected results.$dns->useNameserver('a.root-servers.net')->getRecords('com.');
Verbose Output:
Enable debug mode for dig by extending the Dig handler:
class DebugDigHandler extends \Spatie\Dns\Handlers\Dig {
protected function buildCommand(string $domain, ?string $type = null): string {
return parent::buildCommand($domain, $type) . ' +dnssec +trace';
}
}
$dns->useHandlers([new DebugDigHandler()]);
Exception Handling:
Catch CouldNotFetchDns for graceful degradation:
try {
$records = $dns->getRecords('example.com');
} catch (\Spatie\Dns\Exceptions\CouldNotFetchDns $e) {
Log::warning("DNS lookup failed for example.com: {$e->getExitCode()}");
// Fallback logic
}
Custom Handlers: Implement your own handler for specialized DNS queries (e.g., DNSSEC validation):
class DnssecHandler extends \Spatie\Dns\Handlers\Handler {
public function getRecords(string $domain, ?string $type = null): array {
// Custom logic using `dnssec-dig` or similar
}
}
$dns->useHandlers([new DnssecHandler()]);
Macros for Records: Extend record functionality dynamically:
\Spatie\Dns\Records\Record::macro('isValidIp', function () {
return filter_var($this->ip(), FILTER_VALIDATE_IP) !== false;
});
$aRecord->isValidIp(); // true/false
Factory for Parsing:
Use the Factory to parse raw DNS output (e.g., from logs):
use \Spatie\Dns\Support\Factory;
$record = (new Factory())->guess('example.com. 300 IN A 192.0.2.1');
PHP dns_get_record():
dig for full support.allow_url_fopen in php.ini if using remote nameservers.Nameserver Selection:
8.8.8.8) may throttle requests. Use authoritative nameservers for critical checks:
$dns->useNameserver('ns1.example.com');
TTL Handling:
ttl() in seconds. Account for this in caching strategies:
$ttl = $records[0]->ttl(); // e.g., 3600 (1 hour)
Cache::forever("dns_{$domain}", $records); // Cache until TTL expires
How can I help you explore Laravel packages today?