Completed
Push — master ( ece0e5...b20eda )
by Peter
02:27
created

IPv6Network::getIPMaskFromCIDR()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php
2
3
/**
4
 * GpsLab component.
5
 *
6
 * @author    Peter Gribanov <[email protected]>
7
 * @copyright Copyright (c) 2016, Peter Gribanov
8
 * @license   http://opensource.org/licenses/MIT
9
 */
10
11
namespace GpsLab\Component\Interval\IPv6Network;
12
13
use GpsLab\Component\Interval\Exception\InvalidIntervalFormatException;
14
15
class IPv6Network
16
{
17
    /**
18
     * @var string
19
     */
20
    const CIDR = '(1[0-2][0-9]|[1-9]?[0-9])'; // 0-128
21
22
    /**
23
     * @var string
24
     */
25
    const REGEXP = '/^
26
        \s*
27
        (?<ip>'.IPv6NetworkPoint::IPV6_ADDR.') # IP
28
        \/                                     # separator
29
        (?<cidr>'.self::CIDR.')                # CIDR bit
30
        \s*
31
    $/x';
32
33
    /**
34
     * @var IPv6NetworkPoint
35
     */
36
    private $start;
37
38
    /**
39
     * @var IPv6NetworkPoint
40
     */
41
    private $end;
42
43
    /**
44
     * @var int
45
     */
46
    private $mask;
47
48
    /**
49
     * @var IPv6NetworkComparator
50
     */
51
    private $comparator;
52
53
    /**
54
     * @param IPv6NetworkPoint $ip
55
     * @param int $mask
56
     */
57 17
    private function __construct(IPv6NetworkPoint $ip, $mask)
58
    {
59 17
        $this->start = $ip;
60 17
        $this->mask = $mask;
61 17
        $this->comparator = new IPv6NetworkComparator($this);
62
63
        // calculate end point
64 17
        $end = inet_ntop($ip->value() | ~ inet_pton($this->getIPMaskFromCIDR($mask)));
65 17
        $end = preg_replace('/:(0:)+/', '::', $end, 1); // format end ip
66 17
        $this->end = new IPv6NetworkPoint($end);
67 17
    }
68
69
    /**
70
     * @param int $cidr
71
     *
72
     * @return string
73
     */
74 17
    private function getIPMaskFromCIDR($cidr)
75
    {
76
        // bin mask
77 17
        $bin = str_repeat('1', $cidr).str_repeat('0', 128 - $cidr);
78
79
        // convert bin to hex
80 17
        $hex = [];
81 17
        foreach (str_split($bin, 16) as $octet) {
82 17
            $hex[] = dechex(bindec($octet)) ?: '0000';
83 17
        }
84
85 17
        return implode(':', $hex);
86
    }
87
88
    /**
89
     * @param string $ip
90
     * @param int $cidr
91
     *
92
     * @return IPv6Network
93
     */
94 17
    public static function fromCIDR($ip, $cidr)
95
    {
96 17
        if ($cidr < 0 || $cidr > 128) {
97
            throw InvalidMaskException::create($cidr);
98
        }
99
100 17
        return new self(new IPv6NetworkPoint($ip), $cidr);
101
    }
102
103
104
    /**
105
     * Create network from string.
106
     *
107
     * Example formats of network:
108
     *   2001:db8:d0::/33
109
     *   2001:db8::/64
110
     *
111
     * Spaces are ignored in format.
112
     *
113
     * @param string $string
114
     *
115
     * @return self
116
     */
117 11 View Code Duplication
    public static function fromString($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
    {
119 11
        if (!preg_match(self::REGEXP, $string, $match)) {
120
            $ipv6 = implode(':', array_fill(0, 8, 'ffff'));
121
            throw InvalidIntervalFormatException::create($ipv6.'/128', $string);
122
        }
123
124 11
        return self::fromCIDR($match['ip'], $match['cidr']);
125
    }
126
127
    /**
128
     * Checks if this network is equal to the specified network.
129
     *
130
     * @param IPv6Network $network
131
     *
132
     * @return bool
133
     */
134
    public function equal(IPv6Network $network)
135
    {
136
        return $this->comparator->equal($network);
137
    }
138
139
    /**
140
     * Does this network contain the specified IP.
141
     *
142
     * @param string $point
143
     *
144
     * @return bool
145
     */
146 2
    public function contains($point)
147
    {
148 2
        return $this->comparator->contains(new IPv6NetworkPoint($point));
149
    }
150
151
    /**
152
     * Does this network intersect the specified network.
153
     *
154
     * @param IPv6Network $network
155
     *
156
     * @return bool
157
     */
158 3
    public function intersects(IPv6Network $network)
159
    {
160 3
        return $this->comparator->intersects($network);
161
    }
162
163
    /**
164
     * Does this network abut with the network specified.
165
     *
166
     * @param IPv6Network $network
167
     *
168
     * @return bool
169
     */
170
    public function abuts(IPv6Network $network)
171
    {
172
        return $this->comparator->abuts($network);
173
    }
174
175
    /**
176
     * @param int $step
177
     *
178
     * @return \Generator
179
     */
180 View Code Duplication
    public function iterate($step = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        $end = $this->endPoint()->value();
183
        $ip = $this->startPoint()->value();
184
185
        while ($ip < $end) {
186
            yield long2ip($ip);
187
            $ip += $step;
188
        }
189
    }
190
191
    /**
192
     * @return string
193
     */
194 12
    public function start()
195
    {
196 12
        return (string) $this->start;
197
    }
198
199
    /**
200
     * @return string
201
     */
202 12
    public function end()
203
    {
204 12
        return (string) $this->end;
205
    }
206
207
    /**
208
     * @return int
209
     */
210 12
    public function mask()
211
    {
212 12
        return $this->mask;
213
    }
214
215
    /**
216
     * @return IPv6NetworkPoint
217
     */
218 11
    public function startPoint()
219
    {
220 11
        return $this->start;
221
    }
222
223
    /**
224
     * @return IPv6NetworkPoint
225
     */
226 11
    public function endPoint()
227
    {
228 11
        return $this->end;
229
    }
230
231
    /**
232
     * @return string
233
     */
234
    public function __toString()
235
    {
236
        return $this->start.'/'.$this->mask;
237
    }
238
}
239