Completed
Branch phpstan (92b7c6)
by Sam
03:09
created

Toolbox::expandIpv6()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 6
cts 7
cp 0.8571
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3.0261
1
<?php
2
3
/*
4
 * This file is part of Badcow DNS Library.
5
 *
6
 * (c) Samuel Williams <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Badcow\DNS\Ip;
13
14
use Badcow\DNS\Validator;
15
16
class Toolbox
17
{
18
    /**
19
     * Expands an IPv6 address to its full, non-shorthand representation.
20
     *
21
     * E.g. 2001:db8:9a::42 -> 2001:0db8:009a:0000:0000:0000:0000:0042
22
     *
23
     * @param string $ip IPv6 address
24
     *
25
     * @throws \InvalidArgumentException
26
     *
27
     * @return string
28
     */
29 10
    public static function expandIpv6(string $ip): string
30
    {
31 10
        if (!Validator::ipv6($ip)) {
32 2
            throw new \InvalidArgumentException(sprintf('"%s" is not a valid IPv6 address.', $ip));
33
        }
34
35 9
        if (false === $packed = inet_pton($ip)) {
36
            throw new \InvalidArgumentException(sprintf('"%s" is not a valid IPv6 address.', $ip));
37
        }
38
39 9
        $hex = unpack('H*hex', $packed);
40
41 9
        return implode(':', str_split($hex['hex'], 4));
42
    }
43
44
    /**
45
     * This function will expand in incomplete IPv6 address.
46
     * An incomplete IPv6 address is of the form `2001:db8:ff:abcd`
47
     * i.e. one where there is less than eight hextets.
48
     *
49
     * @param string $ip IPv6 address
50
     *
51
     * @return string Expanded incomplete IPv6 address
52
     */
53 2
    public static function expandIncompleteIpv6(string $ip): string
54
    {
55
        $hextets = array_map(function ($hextet) {
56 2
            return str_pad($hextet, 4, '0', STR_PAD_LEFT);
57 2
        }, explode(':', $ip));
58
59 2
        return implode(':', $hextets);
60
    }
61
62
    /**
63
     * Takes a valid IPv6 address and contracts it
64
     * to its shorter version.
65
     *
66
     * E.g.: 2001:0000:0000:acad:0000:0000:0000:0001 -> 2001:0:0:acad::1
67
     *
68
     * Note: If there is more than one set of consecutive hextets, the function
69
     * will favour the larger of the sets. If both sets of zeroes are the same
70
     * the first will be favoured in the omission of zeroes.
71
     *
72
     * E.g.: 2001:0000:0000:ab80:2390:0000:0000:000a -> 2001:0:0:ab80:2390::a
73
     *
74
     * @param string $ip IPv6 address
75
     *
76
     * @throws \InvalidArgumentException
77
     *
78
     * @return string Contracted IPv6 address
79
     */
80 11
    public static function contractIpv6(string $ip): string
81
    {
82 11
        $packed = inet_pton($ip);
83
84 11
        if (!Validator::ipv6($ip) || false === $packed) {
85 1
            throw new \InvalidArgumentException(sprintf('"%s" is not a valid IPv6 address.', $ip));
86
        }
87
88 10
        $unpacked = inet_ntop($packed);
89
90 10
        if (false === $unpacked) {
91
            throw new \InvalidArgumentException(sprintf('"%s" could not be contracted.', $ip));
92
        }
93
94 10
        return $unpacked;
95
    }
96
97
    /**
98
     * Creates a reverse IPv4 address.
99
     *
100
     * E.g. 192.168.1.213 -> 213.1.168.192.in-addr.arpa.
101
     *
102
     * @param string $ip Valid IPv4 address
103
     *
104
     * @return string Reversed IP address appended with ".in-addr.arpa."
105
     */
106 2
    public static function reverseIpv4(string $ip): string
107
    {
108 2
        $octets = array_reverse(explode('.', $ip));
109
110 2
        return implode('.', $octets).'.in-addr.arpa.';
111
    }
112
113
    /**
114
     * Creates a reverse IPv6 address.
115
     *
116
     * E.g. 2001:db8::567:89ab -> b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
117
     *
118
     * @param string $ip           A full or partial IPv6 address
119
     * @param bool   $appendSuffix Whether or not to append ".ip6.arpa.' suffix.
120
     *
121
     * @return string The reversed address appended with ".ip6.arpa."
122
     */
123 2
    public static function reverseIpv6(string $ip, bool $appendSuffix = true): string
124
    {
125
        try {
126 2
            $ip = self::expandIpv6($ip);
127 2
        } catch (\InvalidArgumentException $e) {
128 2
            $ip = self::expandIncompleteIpv6($ip);
129
        }
130
131 2
        $ip = str_replace(':', '', $ip);
132 2
        $ip = strrev($ip);
133 2
        $ip = implode('.', str_split($ip));
134 2
        $ip .= $appendSuffix ? '.ip6.arpa.' : '';
135
136 2
        return $ip;
137
    }
138
}
139