Failed Conditions
Branch master (51f507)
by Arnold
05:21
created

server_functions.php ➔ ipv4_to_ipv6()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 4
nop 1
dl 0
loc 16
ccs 7
cts 7
cp 1
crap 6
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Jasny;
4
5
/**
6
 * Convert an IPv4 address or CIDR into an IP6 address or CIDR.
7
 * 
8
 * @param string $ip
9
 * @return string
10
 * @throws \InvalidArgumentException if ip isn't valid
11
 */
12
function ipv4_to_ipv6($ip)
13
{
14 6
    if ($ip === '0.0.0.0/0') {
15 1
        return '::';
16
    }
17
18 5
    list($address, $mask) = explode('/', $ip, 2) + [null, null];
19
20 5
    if (!filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || (isset($mask) && !ctype_digit($mask))) {
21 2
        throw new \InvalidArgumentException("'$ip' is not a valid IPv4 address or cidr");
22
    }
23
    
24 3
    $bytes = array_map('dechex', explode('.', $address));
25
    
26 3
    return vsprintf('0:0:0:0:0:ffff:%02s%02s:%02s%02s', $bytes) . (isset($mask) ? '/' . ($mask + 96) : '');
27
}
28
29
/**
30
 * Check if IP address is in CIDR block
31
 * 
32
 * @param string $ip     An IPv4 or IPv6
33
 * @param string $cidr   An IPv4 CIDR block or IPv6 CIDR block
34
 * @return boolean
35
 */
36
function ip_in_cidr($ip, $cidr)
37
{
38 37
    if ($cidr === '0.0.0.0/0' || $cidr === '::/0' || $cidr === '::') {
39 4
        return true;
40
    }
41
    
42 33
    $ipv = strpos($ip, ':') === false ? 4 : 6;
43 33
    $cidrv = strpos($cidr, ':') === false ? 4 : 6;
44
    
45
    try {
46 33
        if ($ipv < $cidrv) {
47 5
            $ip = ipv4_to_ipv6($ip);
48 4
            $ipv = 6;
49 28
        } elseif ($ipv > $cidrv) {
50 32
            $cidr = ipv4_to_ipv6($cidr);
51
        }
52 2
    } catch (\InvalidArgumentException $e) {
53 2
        return false;
54
    }
55
    
56 31
    $fn = __NAMESPACE__ . "\\ipv{$ipv}_in_cidr";
57 31
    return $fn($ip, $cidr);
58
}
59
60
/**
61
 * Check if IPv4 address is in CIDR block
62
 * 
63
 * @param string $ip
64
 * @param string $cidr
65
 * @return boolean
66
 */
67
function ipv4_in_cidr($ip, $cidr)
68
{
69 13
    list($subnet, $mask) = explode('/', $cidr, 2) + [null, '32'];
70
    
71
    if (
72 13
        !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ||
73 13
        !filter_var($subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
74
    ) {
75 3
        return false;
76
    }
77
    
78 10
    $ipLong = ip2long($ip);
79 10
    $subnetLong = ip2long($subnet);
80
    
81 10
    $ipMasked = $ipLong & ~((1 << (32 - $mask)) - 1);
82 10
    $subnetMasked = $subnetLong & ~((1 << (32 - $mask)) - 1);
83
    
84 10
    return $ipMasked == $subnetMasked;
85
}
86
87
/**
88
 * Check if IPv6 address is in CIDR block
89
 * 
90
 * @param string $ip
91
 * @param string $cidr
92
 * @return boolean
93
 */
94
function ipv6_in_cidr($ip, $cidr)
95
{
96 14
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
97 2
        return false;
98
    }
99
    
100 12
    $inetIp = inet_pton($ip);
101 12
    $binaryIp = inet_to_bits($inetIp);
102
103 12
    if (strpos($cidr, '/') === false) {
104 3
        $net = $cidr;
105 3
        $mask = $cidr === '::' ? 0 : substr_count(rtrim($cidr, ':'), ':') * 16;
106
    } else {
107 9
        list($net, $mask) = explode('/', $cidr, 2);
108
    }
109
110 12
    if (!filter_var($net, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
111 1
        return false;
112
    }
113
        
114 11
    $inetNet = inet_pton($net);
115 11
    $binaryNet = inet_to_bits($inetNet);
116
117 11
    $ipNetBits = substr($binaryIp, 0, $mask);
118 11
    $netBits = substr($binaryNet, 0, $mask);
119
120 11
    return $ipNetBits === $netBits;
121
}
122
123
/**
124
 * Converts inet_pton output to string with bits.
125
 *
126
 * @param string $inet
127
 * @return string
128
 */
129
function inet_to_bits($inet)
130
{
131 12
    $unpackedArr = unpack('A16', $inet);
132 12
    $unpacked = str_split($unpackedArr[1]);
133
    
134 12
    $binaryip = '';
135
136 12
    foreach ($unpacked as $char) {
137 12
        $binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
138
    }
139
140 12
    return str_pad($binaryip, 128, '0', STR_PAD_RIGHT);
141
}
142
143