IP::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace devtoolboxuk\internetaddress;
4
5
class IP
6
{
7
8
    use IpTrait;
9
    /**
10
     * @var string
11
     */
12
    public $in_addr;
13
14
    /**
15
     * @param string ip
16
     * @throws \Exception
17
     */
18
    public function __construct($ip)
19
    {
20
        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
21
            throw new \Exception("Invalid IP address format");
22
        }
23
        $this->in_addr = inet_pton($ip);
24
    }
25
26
    public static function parse($ip)
27
    {
28
29
        if (is_numeric($ip)) {
30
            return IPv4::parse($ip);
31
        }
32
33
        return new self($ip);
34
    }
35
36
    public static function parseHex($hexIP)
37
    {
38
        if (!preg_match('/^([0-9a-fA-F]{8}|[0-9a-fA-F]{32})$/', $hexIP)) {
39
            throw new \Exception("Invalid hexadecimal IP address format");
40
        }
41
        return new self(inet_ntop(pack('H*', $hexIP)));
42
    }
43
44
45
    /**
46
     * @param string $binIP
47
     * @throws \Exception
48
     * @return IP
49
     */
50
    public static function parseBin($binIP)
51
    {
52
        if (!preg_match('/^([0-1]{32}|[0-1]{128})$/', $binIP)) {
53
            throw new \Exception("Invalid binary IP address format");
54
        }
55
56
        $in_addr = '';
57
        foreach (array_map('bindec', str_split($binIP, 8)) as $char) {
58
            $in_addr .= pack('C*', $char);
59
        }
60
61
        return new self(inet_ntop($in_addr));
62
    }
63
64
    public static function parseInAddr($inAddr)
65
    {
66
        return new self(inet_ntop($inAddr));
67
    }
68
69
    public static function parseRange($data)
70
    {
71
        return Network::parse($data);
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    public function __toString()
78
    {
79
        return inet_ntop($this->in_addr);
80
    }
81
82
    /**
83
     * @return int
84
     */
85
    public function getMaxPrefixLength()
86
    {
87
        return $this->getVersion() === IPv4::version
88
            ? IPv4::length
89
            : IPv6::length;
90
    }
91
92
    /**
93
     * @return string
94
     */
95
    public function getVersion()
96
    {
97
        if (filter_var(inet_ntop($this->in_addr), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
98
            return IPv6::version;
99
        }
100
101
        return IPv4::version;
102
    }
103
104
    /**
105
     * @return int
106
     */
107
    public function getOctetsCount()
108
    {
109
        return $this->getVersion() === IPv4::version
110
            ? IPv4::octets
111
            : IPv6::octets;
112
    }
113
114
    /**
115
     * @return string
116
     */
117
    public function inAddr()
118
    {
119
        return $this->in_addr;
120
    }
121
122
    public function toHex()
123
    {
124
        return bin2hex($this->in_addr);
125
    }
126
127
    /**
128
     * @return string
129
     */
130
    public function toBin()
131
    {
132
        $binary = array();
133
        foreach (unpack('C*', $this->in_addr) as $char) {
134
            $binary[] = str_pad(decbin($char), 8, '0', STR_PAD_LEFT);
135
        }
136
137
        return implode($binary);
138
    }
139
140
141
    /**
142
     * @return string
143
     */
144
    public function toLong()
145
    {
146
147
        if ($this->getVersion() === IPv6::version) {
148
            return IPv6::getLong($this->in_addr);
0 ignored issues
show
Bug Best Practice introduced by
The method devtoolboxuk\internetaddress\IPv6::getLong() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

148
            return IPv6::/** @scrutinizer ignore-call */ getLong($this->in_addr);
Loading history...
149
        }
150
        return IPv4::getLong($this->in_addr);
151
    }
152
153
    /**
154
     * @param int $next
155
     * @return IP
156
     * @throws \Exception
157
     */
158
    public function next($next = 1)
159
    {
160
        if ($next < 0) {
161
            throw new \Exception("Number must be greater than 0");
162
        }
163
164
        $unpacked = unpack('C*', $this->in_addr);
165
166
        for ($i = 0; $i < $next; $i++) {
167
            for ($byte = count($unpacked); $byte >= 0; --$byte) {
0 ignored issues
show
Bug introduced by
It seems like $unpacked can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            for ($byte = count(/** @scrutinizer ignore-type */ $unpacked); $byte >= 0; --$byte) {
Loading history...
168
                if ($unpacked[$byte] < 255) {
169
                    $unpacked[$byte]++;
170
                    break;
171
                }
172
173
                $unpacked[$byte] = 0;
174
            }
175
        }
176
177
        return new self(inet_ntop(call_user_func_array('pack', array_merge(array('C*'), $unpacked))));
0 ignored issues
show
Bug introduced by
It seems like $unpacked can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

177
        return new self(inet_ntop(call_user_func_array('pack', array_merge(array('C*'), /** @scrutinizer ignore-type */ $unpacked))));
Loading history...
178
    }
179
180
    /**
181
     * @param int $next
182
     * @return IP
183
     * @throws \Exception
184
     */
185
    public function prev($next = 1)
186
    {
187
188
        if ($next < 0) {
189
            throw new \Exception("Number must be greater than 0");
190
        }
191
192
        $unpacked = unpack('C*', $this->in_addr);
193
194
        for ($i = 0; $i < $next; $i++) {
195
            for ($byte = count($unpacked); $byte >= 0; --$byte) {
0 ignored issues
show
Bug introduced by
It seems like $unpacked can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
            for ($byte = count(/** @scrutinizer ignore-type */ $unpacked); $byte >= 0; --$byte) {
Loading history...
196
                if ($unpacked[$byte] === 0) {
197
                    $unpacked[$byte] = 255;
198
                } else {
199
                    $unpacked[$byte]--;
200
                    break;
201
                }
202
            }
203
        }
204
        return new self(inet_ntop(call_user_func_array('pack', array_merge(array('C*'), $unpacked))));
0 ignored issues
show
Bug introduced by
It seems like $unpacked can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

204
        return new self(inet_ntop(call_user_func_array('pack', array_merge(array('C*'), /** @scrutinizer ignore-type */ $unpacked))));
Loading history...
205
    }
206
}
207