Dns   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 9
dl 0
loc 156
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A for() 0 4 1
A __construct() 0 6 1
A useNameserver() 0 6 1
A allowedRecordTypes() 0 4 1
A resolveNameserver() 0 4 2
A sanitizeDomain() 0 10 2
A records() 0 28 2
A addResult() 0 18 4
A resolveTypes() 0 20 5
A getNameserver() 0 4 1
A getDomain() 0 4 1
1
<?php
2
3
namespace Gemz\Dns;
4
5
use React\Dns\Model\Record;
6
use React\Dns\Query\CoopExecutor;
7
use React\Dns\Query\Query;
8
use React\Dns\Query\TimeoutExecutor;
9
use React\EventLoop\Factory;
10
use React\Dns\Model\Message;
11
use Gemz\Dns\Exceptions\InvalidArgument;
12
use React\Dns\Query\TcpTransportExecutor;
13
14
class Dns
15
{
16
    /** @var string */
17
    protected $domain;
18
19
    /** @var string */
20
    protected $nameserver;
21
22
    /** @var array */
23
    protected $result;
24
25
    /** @var string */
26
    protected $defaultNameserver = '8.8.8.8';
27
28
    /** @var float */
29
    protected $timeout = 3.0;
30
31
    /** @var array */
32
    protected $recordTypes = [
33
        'A' => Message::TYPE_A,
34
        'CAA' => Message::TYPE_CAA,
35
        'CNAME' => Message::TYPE_CNAME,
36
        'SOA' => Message::TYPE_SOA,
37
        'TXT' => Message::TYPE_TXT,
38
        'MX' => Message::TYPE_MX,
39
        'AAAA' => Message::TYPE_AAAA,
40
        'SRV' => Message::TYPE_SRV,
41
        'NS' => Message::TYPE_NS,
42
        'PTR' => Message::TYPE_PTR,
43
        'SSHFP' => Message::TYPE_SSHFP,
44
    ];
45
46
    public static function for(string $domain, string $nameserver = ''): self
47
    {
48
        return new self($domain, $nameserver);
49
    }
50
51
    public function __construct(string $domain, string $nameserver = '')
52
    {
53
        $this->domain = $this->sanitizeDomain($domain);
54
55
        $this->nameserver = $this->resolveNameserver($nameserver);
56
    }
57
58
    public function useNameserver(string $nameserver): self
59
    {
60
        $this->nameserver = $this->resolveNameserver($nameserver);
61
62
        return $this;
63
    }
64
65
    public function allowedRecordTypes(): array
66
    {
67
        return array_keys($this->recordTypes);
68
    }
69
70
    protected function resolveNameserver(string $nameserver): string
71
    {
72
        return empty($nameserver) ? $this->defaultNameserver : $nameserver;
73
    }
74
75
    protected function sanitizeDomain(string $domain): string
76
    {
77
        if (empty($domain)) {
78
            throw InvalidArgument::domainIsNotValid($domain);
79
        }
80
81
        $domain = str_replace(['http://', 'https://'], '', $domain);
82
83
        return strtolower($domain);
84
    }
85
86
    /**
87
     * @param string|array ...$types
88
     *
89
     * @return array
90
     */
91
    public function records(...$types): array
92
    {
93
        $types = $this->resolveTypes($types);
94
95
        $loop = Factory::create();
96
97
        foreach ($types as $type) {
98
            $query = new Query($this->domain, $this->recordTypes[$type], Message::CLASS_IN);
99
100
            $executor = new CoopExecutor(
101
                new TimeoutExecutor(
102
                    new TcpTransportExecutor($this->nameserver, $loop),
103
                    $this->timeout,
104
                    $loop
105
                )
106
            );
107
108
            $executor
109
                ->query($query)
110
                ->then(function (Message $message) use ($type) {
111
                    $this->addResult($type, $message->answers);
112
                });
113
        }
114
115
        $loop->run();
116
117
        return $this->result;
118
    }
119
120
    protected function addResult(string $type, array $values): void
121
    {
122
        if (empty($values)) {
123
            $this->result[$type] = [];
124
        }
125
126
        foreach ($values as $value) {
127
            if ($value instanceof Record) {
128
                $this->result[$type][] = [
129
                    'ttl' => $value->ttl,
130
                    'data' => $value->data
131
                ];
132
                continue;
133
            }
134
135
            $this->result[$type][] = $value;
136
        }
137
    }
138
139
    protected function resolveTypes(array $types = []): array
140
    {
141
        if (empty($types)) {
142
            $types = array_keys($this->recordTypes);
143
        }
144
145
        $types = is_array($types[0] ?? null)
146
            ? $types[0]
147
            : $types;
148
149
        $types = array_map('strtoupper', $types);
150
151
        foreach ($types as $type) {
152
            if (! array_key_exists($type, $this->recordTypes)) {
153
                throw InvalidArgument::typeIsNotValid($type, $this->recordTypes);
154
            }
155
        }
156
157
        return $types;
158
    }
159
160
    public function getNameserver(): string
161
    {
162
        return $this->nameserver;
163
    }
164
165
    public function getDomain(): string
166
    {
167
        return $this->domain;
168
    }
169
}
170