Issues (37)

src/Range/AbstractRange.php (2 issues)

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 242
    public function getRangeType()
23
    {
24 242
        if ($this->rangeType === null) {
25 242
            $addressType = $this->getAddressType();
26 242
            if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) {
27 9
                $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
            } else {
29 233
                switch ($addressType) {
30
                    case AddressType::T_IPv4:
31 170
                        $defaultType = IPv4::getDefaultReservedRangeType();
32 170
                        $reservedRanges = IPv4::getReservedRanges();
33 170
                        break;
34
                    case AddressType::T_IPv6:
35 63
                        $defaultType = IPv6::getDefaultReservedRangeType();
36 63
                        $reservedRanges = IPv6::getReservedRanges();
37 63
                        break;
38
                    default:
39
                        throw new \Exception('@todo'); // @codeCoverageIgnore
40
                }
41 233
                $rangeType = null;
42 233
                foreach ($reservedRanges as $reservedRange) {
43 233
                    $rangeType = $reservedRange->getRangeType($this);
44 233
                    if ($rangeType !== null) {
45 198
                        break;
46
                    }
47
                }
48 233
                $this->rangeType = $rangeType === null ? $defaultType : $rangeType;
49
            }
50
        }
51
52 242
        return $this->rangeType === false ? null : $this->rangeType;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     *
58
     * @see \IPLib\Range\RangeInterface::getAddressAtOffset()
59
     */
60 15
    public function getAddressAtOffset($n)
61
    {
62 15
        if (!is_int($n)) {
63 2
            return null;
64
        }
65
66 13
        $address = null;
67 13
        if ($n >= 0) {
68 8
            $start = Factory::parseAddressString($this->getComparableStartString());
69 8
            $address = $start->getAddressAtOffset($n);
70
        } else {
71 5
            $end = Factory::parseAddressString($this->getComparableEndString());
72 5
            $address = $end->getAddressAtOffset($n + 1);
73
        }
74
75 13
        if ($address === null) {
76 1
            return null;
77
        }
78
79 12
        return $this->contains($address) ? $address : null;
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     *
85
     * @see \IPLib\Range\RangeInterface::contains()
86
     */
87 271
    public function contains(AddressInterface $address)
88
    {
89 271
        $result = false;
90 271
        if ($address->getAddressType() === $this->getAddressType()) {
91 271
            $cmp = $address->getComparableString();
92 271
            $from = $this->getComparableStartString();
93 271
            if ($cmp >= $from) {
94 266
                $to = $this->getComparableEndString();
95 266
                if ($cmp <= $to) {
96 222
                    $result = true;
97
                }
98
            }
99
        }
100
101 271
        return $result;
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     *
107
     * @see \IPLib\Range\RangeInterface::containsRange()
108
     */
109 89
    public function containsRange(RangeInterface $range)
110
    {
111 89
        $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 51
                $myEnd = $this->getComparableEndString();
117 51
                $itsEnd = $range->getComparableEndString();
118 51
                if ($itsEnd <= $myEnd) {
119 21
                    $result = true;
120
                }
121
            }
122
        }
123
124 89
        return $result;
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     *
130
     * @see \IPLib\Range\RangeInterface::split()
131
     */
132 65
    public function split($networkPrefix, $forceSubnet = false)
133
    {
134 65
        $networkPrefix = (int) $networkPrefix;
135 65
        $myNetworkPrefix = $this->getNetworkPrefix();
136 65
        if ($networkPrefix === $myNetworkPrefix) {
137
            return array(
138 18
                $forceSubnet ? $this->asSubnet() : $this,
139
            );
140
        }
141 47
        if ($networkPrefix < $myNetworkPrefix) {
142 16
            throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be smaller than the network prefix of the range ({$myNetworkPrefix})");
143
        }
144 31
        $startIp = $this->getStartAddress();
145 31
        $maxPrefix = $startIp::getNumberOfBits();
146 31
        if ($networkPrefix > $maxPrefix) {
147 13
            throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be larger than the maximum network prefix of the range ({$maxPrefix})");
148
        }
149 18
        if ($startIp instanceof IPv4) {
150 14
            $one = IPv4::fromBytes(array(0, 0, 0, 1));
151 4
        } elseif ($startIp instanceof IPv6) {
152 4
            $one = IPv6::fromBytes(array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1));
153
        }
154 18
        $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 18
        $result = array();
156 18
        while (true) {
157 18
            $range = Subnet::parseString("{$startIp}/{$networkPrefix}");
158 18
            if (!$forceSubnet && $this instanceof Pattern) {
159 6
                $range = $range->asPattern() ?: $range;
160
            }
161 18
            $result[] = $range;
162 18
            $startIp = $startIp->add($delta);
163 18
            if ($startIp === null || !$this->contains($startIp)) {
164 18
                break;
165
            }
166
        }
167
168 18
        return $result;
169
    }
170
}
171