Completed
Push — master ( cc9218...491824 )
by Christian
08:17 queued 10s
created

Dig::doQuery()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 1
b 0
f 0
nc 5
nop 2
dl 0
loc 17
rs 9.9332
1
<?php
2
3
namespace RemotelyLiving\PHPDNS\Resolvers;
4
5
use RemotelyLiving\PHPDNS\Entities\DNSRecordCollection;
6
use RemotelyLiving\PHPDNS\Entities\DNSRecordType;
7
use RemotelyLiving\PHPDNS\Entities\Hostname;
8
use RemotelyLiving\PHPDNS\Factories\SpatieDNS;
9
use RemotelyLiving\PHPDNS\Mappers\Dig as DigMapper;
10
use RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure;
11
12
class Dig extends ResolverAbstract
13
{
14
    public const SUPPORTED_QUERY_TYPES = [
15
        DNSRecordType::TYPE_A,
16
        DNSRecordType::TYPE_AAAA,
17
        DNSRecordType::TYPE_CNAME,
18
        DNSRecordType::TYPE_NS,
19
        DNSRecordType::TYPE_SOA,
20
        DNSRecordType::TYPE_MX,
21
        DNSRecordType::TYPE_SRV,
22
        DNSRecordType::TYPE_TXT,
23
        DNSRecordType::TYPE_CAA,
24
        DNSRecordType::TYPE_NAPTR,
25
    ];
26
27
    /**
28
     * @var \RemotelyLiving\PHPDNS\Factories\SpatieDNS
29
     */
30
    private $spatieDNSFactory;
31
32
    /**
33
     * @var \RemotelyLiving\PHPDNS\Mappers\Dig
34
     */
35
    private $mapper;
36
37
    /**
38
     * @var \RemotelyLiving\PHPDNS\Entities\Hostname|null
39
     */
40
    private $nameserver;
41
42
    public function __construct(
43
        SpatieDNS $spatieDNSFactory = null,
44
        DigMapper $mapper = null,
45
        Hostname $nameserver = null
46
    ) {
47
        $this->spatieDNSFactory = $spatieDNSFactory ?? new SpatieDNS();
48
        $this->mapper = $mapper ?? new DigMapper();
49
        $this->nameserver = $nameserver;
50
    }
51
52
    protected function doQuery(Hostname $hostname, DNSRecordType $type): DNSRecordCollection
53
    {
54
        if (!self::isSupportedQueryType($type)) {
55
            return new DNSRecordCollection();
56
        }
57
58
        $dig = $this->spatieDNSFactory->createResolver($hostname, $this->nameserver);
59
60
        try {
61
            $response = ($type->equals(DNSRecordType::createANY()))
62
                ? $dig->getRecords(...self::SUPPORTED_QUERY_TYPES)
63
                : $dig->getRecords((string) $type);
64
        } catch (\Throwable $e) {
65
            throw new QueryFailure($e->getMessage(), 0, $e);
66
        }
67
68
        return $this->mapResults($this->mapper, self::parseDigResponseToRows($response));
69
    }
70
71
    private static function parseDigResponseToRows(string $digResponse): array
72
    {
73
        $rows = [];
74
        foreach (explode(PHP_EOL, self::normalizeColumns($digResponse)) as $line) {
75
            if (!trim($line)) {
76
                continue;
77
            }
78
79
            $columns = explode(' ', $line);
80
            $rows[] = [$columns[0], $columns[1], $columns[2], $columns[3], implode(' ', array_slice($columns, 4))];
81
        }
82
83
        return $rows;
84
    }
85
86
    private static function normalizeColumns(string $response): string
87
    {
88
        $keysRemoved = preg_replace('/;(.*)/m', ' ', trim($response));
89
        $tabsRemoved = preg_replace('/(\t)/m', ' ', (string) $keysRemoved);
90
        $breaksRemoved = preg_replace('/\s\s/m', '', (string) $tabsRemoved);
91
        return (string) preg_replace('/(\(\s|(\s\)))/m', '', (string) $breaksRemoved);
92
    }
93
94
    private static function isSupportedQueryType(DNSRecordType $type): bool
95
    {
96
        if ($type->isA(DNSRecordType::TYPE_ANY)) {
97
            return true;
98
        }
99
100
        foreach (self::SUPPORTED_QUERY_TYPES as $queryType) {
101
            if ($type->isA($queryType)) {
102
                return true;
103
            }
104
        }
105
106
        return false;
107
    }
108
}
109