Passed
Pull Request — main (#96)
by Michele
08:00
created

AbstractRange::getAddressAtOffset()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 12
c 0
b 0
f 0
nc 7
nop 1
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 5
rs 9.5555
1
<?php
2
3
namespace IPLib\Range;
4
5
use IPLib\Address\AddressInterface;
6
use IPLib\Address\IPv4;
7
use IPLib\Address\IPv6;
8
use IPLib\Address\Type as AddressType;
9
use IPLib\Factory;
10
use OutOfBoundsException;
11
12
/**
13
 * Base class for range classes.
14
 */
15
abstract class AbstractRange implements RangeInterface
16
{
17
    /**
18
     * {@inheritdoc}
19
     *
20
     * @see \IPLib\Range\RangeInterface::getRangeType()
21
     */
22
    public function getRangeType()
23 242
    {
24
        if ($this->rangeType === null) {
25 242
            $addressType = $this->getAddressType();
26 242
            if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) {
27 242
                $this->rangeType = Factory::getRangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType();
0 ignored issues
show
Bug Best Practice introduced by
The property rangeType does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
28 9
            } else {
29
                switch ($addressType) {
30 233
                    case AddressType::T_IPv4:
31
                        $defaultType = IPv4::getDefaultReservedRangeType();
32 170
                        $reservedRanges = IPv4::getReservedRanges();
33 170
                        break;
34 170
                    case AddressType::T_IPv6:
35
                        $defaultType = IPv6::getDefaultReservedRangeType();
36 63
                        $reservedRanges = IPv6::getReservedRanges();
37 63
                        break;
38 63
                    default:
39
                        throw new \Exception('@todo'); // @codeCoverageIgnore
40
                }
41
                $rangeType = null;
42 233
                foreach ($reservedRanges as $reservedRange) {
43 233
                    $rangeType = $reservedRange->getRangeType($this);
44 233
                    if ($rangeType !== null) {
45 233
                        break;
46 198
                    }
47
                }
48
                $this->rangeType = $rangeType === null ? $defaultType : $rangeType;
49 233
            }
50
        }
51
52
        return $this->rangeType === false ? null : $this->rangeType;
53 242
    }
54
55
    /**
56
     * {@inheritdoc}
57
     *
58
     * @see \IPLib\Range\RangeInterface::getAddressAtOffset()
59
     */
60
    public function getAddressAtOffset($n)
61 15
    {
62
        if (!is_int($n)) {
63 15
            return null;
64 2
        }
65
66
        $address = null;
67 13
        if ($n >= 0) {
68 13
            $start = Factory::parseAddressString($this->getComparableStartString());
69 8
            $address = $start->getAddressAtOffset($n);
70 8
        } else {
71
            $end = Factory::parseAddressString($this->getComparableEndString());
72 5
            $address = $end->getAddressAtOffset($n + 1);
73 5
        }
74
75
        if ($address === null) {
76 13
            return null;
77 1
        }
78
79
        return $this->contains($address) ? $address : null;
80 12
    }
81
82
    /**
83
     * {@inheritdoc}
84
     *
85
     * @see \IPLib\Range\RangeInterface::contains()
86
     */
87
    public function contains(AddressInterface $address)
88 253
    {
89
        $result = false;
90 253
        if ($address->getAddressType() === $this->getAddressType()) {
91 253
            $cmp = $address->getComparableString();
92 253
            $from = $this->getComparableStartString();
93 253
            if ($cmp >= $from) {
94 253
                $to = $this->getComparableEndString();
95 248
                if ($cmp <= $to) {
96 248
                    $result = true;
97 204
                }
98
            }
99
        }
100
101
        return $result;
102 253
    }
103
104
    /**
105
     * {@inheritdoc}
106
     *
107
     * @see \IPLib\Range\RangeInterface::containsRange()
108
     */
109
    public function containsRange(RangeInterface $range)
110 89
    {
111
        $result = false;
112 89
        if ($range->getAddressType() === $this->getAddressType()) {
113 89
            $myStart = $this->getComparableStartString();
114 89
            $itsStart = $range->getComparableStartString();
115 89
            if ($itsStart >= $myStart) {
116 89
                $myEnd = $this->getComparableEndString();
117 51
                $itsEnd = $range->getComparableEndString();
118 51
                if ($itsEnd <= $myEnd) {
119 51
                    $result = true;
120 21
                }
121
            }
122
        }
123
124
        return $result;
125 89
    }
126
127
    /**
128
     * {@inheritdoc}
129
     *
130
     * @see \IPLib\Range\RangeInterface::split()
131
     */
132
    public function split($networkPrefix, $forceSubnet = false)
133 65
    {
134
        $networkPrefix = (int) $networkPrefix;
135 65
        $myNetworkPrefix = $this->getNetworkPrefix();
136 65
        if ($networkPrefix === $myNetworkPrefix) {
137 65
            return array(
138
                $forceSubnet ? $this->asSubnet() : $this,
139 18
            );
140
        }
141
        if ($networkPrefix < $myNetworkPrefix) {
142 47
            throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be smaller than the network prefix of the range ({$myNetworkPrefix})");
143 16
        }
144
        $startIp = $this->getStartAddress();
145 31
        $maxPrefix = $startIp::getNumberOfBits();
146 31
        if ($networkPrefix > $maxPrefix) {
147 31
            throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be larger than the maximum network prefix of the range ({$maxPrefix})");
148 13
        }
149
        if ($startIp instanceof IPv4) {
150
            $one = IPv4::fromBytes(array(0, 0, 0, 1));
151 18
        } elseif ($startIp instanceof IPv6) {
152 18
            $one = IPv6::fromBytes(array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1));
153 18
        }
154 1
        $delta = $one->shift($networkPrefix - $maxPrefix);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $one does not seem to be defined for all execution paths leading up to this point.
Loading history...
155
        $result = array();
156
        while (true) {
157 17
            $range = Subnet::parseString("{$startIp}/{$networkPrefix}");
158 17
            if (!$forceSubnet && $this instanceof Pattern) {
159 17
                $range = $range->asPattern() ?: $range;
160 17
            }
161 17
            $result[] = $range;
162 17
            $startIp = $startIp->add($delta);
163 6
            if ($startIp === null || !$this->contains($startIp)) {
164
                break;
165 17
            }
166 17
        }
167
168
        return $result;
169 17
    }
170
}
171