• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / auth / 22527357078

28 Feb 2026 07:22PM UTC coverage: 63.267% (+0.7%) from 62.568%
22527357078

push

github

daycry
Remove PHP 8.1 from PHPUnit CI matrix

Update .github/workflows/phpunit.yml to drop PHP 8.1 from the test matrix. CI will now run PHPUnit only on PHP 8.2 and 8.3, reducing the matrix to current supported versions.

3064 of 4843 relevant lines covered (63.27%)

41.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.92
/src/Libraries/CheckIpInRange.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Auth.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Auth\Libraries;
15

16
/*
17
 * Network ranges can be specified as:
18
 * 1. Wildcard format:     1.2.3.*
19
 * 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
20
 * 3. Start-End IP format: 1.2.3.0-1.2.3.255
21
 *
22
 * Return value BOOLEAN : ip_in_range($ip, $range);
23
 */
24

25
class CheckIpInRange
26
{
27
    /**
28
     * In order to simplify working with IP addresses (in binary) and their
29
     * netmasks, it is easier to ensure that the binary strings are padded
30
     * with zeros out to 32 characters - IP addresses are 32 bit numbers
31
     *
32
     * @codeCoverageIgnore
33
     *
34
     * @param mixed $dec
35
     */
36
    public static function decbin32($dec)
×
37
    {
38
        return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
×
39
    }
40

41
    /**
42
     * This function takes 2 arguments, an IP address and a "range" in several
43
     * different formats.
44
     * Network ranges can be specified as:
45
     * 1. Wildcard format:     1.2.3.*
46
     * 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
47
     * 3. Start-End IP format: 1.2.3.0-1.2.3.255
48
     * The function will return true if the supplied IP is within the range.
49
     * Note little validation is done on the range inputs - it expects you to
50
     *
51
     * @param mixed $ip
52
     * @param mixed $range
53
     */
54
    public static function ipv4_in_range($ip, $range)
12✔
55
    {
56
        if (str_contains($range, '/')) {
12✔
57
            // $range is in IP/NETMASK format
58
            [$range, $netmask] = explode('/', $range, 2);
8✔
59
            if (str_contains($netmask, '.')) {
8✔
60
                // $netmask is a 255.255.0.0 format
61
                $netmask     = str_replace('*', '0', $netmask);
×
62
                $netmask_dec = ip2long($netmask);
×
63

64
                return (ip2long($ip) & $netmask_dec) === (ip2long($range) & $netmask_dec);
×
65
            }
66
            // $netmask is a CIDR size block
67
            // fix the range argument
68
            $x = explode('.', $range);
8✔
69

70
            while (count($x) < 4) {
8✔
71
                $x[] = '0';
×
72
            }
73
            [$a, $b, $c, $d] = $x;
8✔
74
            $range           = sprintf('%u.%u.%u.%u', $a === '' || $a === '0' ? '0' : $a, $b === '' || $b === '0' ? '0' : $b, $c === '' || $c === '0' ? '0' : $c, $d === '' || $d === '0' ? '0' : $d);
8✔
75
            $range_dec       = ip2long($range);
8✔
76
            $ip_dec          = ip2long($ip);
8✔
77

78
            // Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
79
            // $netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));
80

81
            // Strategy 2 - Use math to create it
82
            $wildcard_dec = 2 ** (32 - (int) $netmask) - 1;
8✔
83
            $netmask_dec  = ~$wildcard_dec;
8✔
84

85
            return ($ip_dec & $netmask_dec) === ($range_dec & $netmask_dec);
8✔
86
        }
87
        // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
88
        if (str_contains($range, '*')) { // a.b.*.* format
8✔
89
            // Just convert to A-B format by setting * to 0 for A and 255 for B
90
            $lower = str_replace('*', '0', $range);
5✔
91
            $upper = str_replace('*', '255', $range);
5✔
92
            $range = "{$lower}-{$upper}";
5✔
93
        }
94

95
        if (str_contains($range, '-')) { // A-B format
8✔
96
            [$lower, $upper] = explode('-', $range, 2);
7✔
97
            $lower_dec       = (float) sprintf('%u', ip2long($lower));
7✔
98
            $upper_dec       = (float) sprintf('%u', ip2long($upper));
7✔
99
            $ip_dec          = (float) sprintf('%u', ip2long($ip));
7✔
100

101
            return ($ip_dec >= $lower_dec) && ($ip_dec <= $upper_dec);
7✔
102
        }
103

104
        return false;
1✔
105
    }
106

107
    /**
108
     * Determine whether the IPV6 address is within range.
109
     * $ip is the IPV6 address in decimal format to check if its within the IP range created by the cloudflare IPV6 address, $range_ip.
110
     * $ip and $range_ip are converted to full IPV6 format.
111
     * Returns true if the IPV6 address, $ip,  is within the range from $range_ip.  False otherwise.
112
     *
113
     * @codeCoverageIgnore
114
     *
115
     * @param mixed $ip
116
     * @param mixed $range_ip
117
     */
118
    public static function ipv6_in_range($ip, $range_ip)
×
119
    {
120
        $pieces     = explode('/', $range_ip, 2);
×
121
        $left_piece = $pieces[0];
×
122

123
        // Extract out the main IP pieces
124
        $ip_pieces     = explode('::', $left_piece, 2);
×
125
        $main_ip_piece = $ip_pieces[0];
×
126
        $last_ip_piece = $ip_pieces[1];
×
127

128
        // Pad out the shorthand entries.
129
        $main_ip_pieces = explode(':', $main_ip_piece);
×
130

131
        foreach (array_keys($main_ip_pieces) as $key) {
×
132
            $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, '0', STR_PAD_LEFT);
×
133
        }
134

135
        // Create the first and last pieces that will denote the IPV6 range.
136
        $first = $main_ip_pieces;
×
137
        $last  = $main_ip_pieces;
×
138

139
        // Check to see if the last IP block (part after ::) is set
140
        $last_piece = '';
×
141
        $size       = count($main_ip_pieces);
×
142
        if (trim($last_ip_piece) !== '') {
×
143
            $last_piece = str_pad($last_ip_piece, 4, '0', STR_PAD_LEFT);
×
144

145
            // Build the full form of the IPV6 address considering the last IP block set
146
            for ($i = $size; $i < 7; $i++) {
×
147
                $first[$i] = '0000';
×
148
                $last[$i]  = 'ffff';
×
149
            }
150
            $main_ip_pieces[7] = $last_piece;
×
151
        } else {
152
            // Build the full form of the IPV6 address
153
            for ($i = $size; $i < 8; $i++) {
×
154
                $first[$i] = '0000';
×
155
                $last[$i]  = 'ffff';
×
156
            }
157
        }
158

159
        // Rebuild the final long form IPV6 address
160
        $first = self::ip2long6(implode(':', $first));
×
161
        $last  = self::ip2long6(implode(':', $last));
×
162

163
        return $ip >= $first && $ip <= $last;
×
164
    }
165

166
    /**
167
     * @codeCoverageIgnore
168
     *
169
     * @param mixed $ip
170
     */
171
    private static function ip2long6($ip)
×
172
    {
173
        if (substr_count($ip, '::') !== 0) {
×
174
            $ip = str_replace('::', str_repeat(':0000', 8 - substr_count($ip, ':')) . ':', $ip);
×
175
        }
176

177
        $ip   = explode(':', $ip);
×
178
        $r_ip = '';
×
179

180
        foreach ($ip as $v) {
×
181
            $r_ip .= str_pad(base_convert($v, 16, 2), 16, '0', STR_PAD_LEFT);
×
182
        }
183

184
        return base_convert($r_ip, 2, 10);
×
185
    }
186

187
    /**
188
     * @codeCoverageIgnore
189
     *
190
     * @param mixed $ip
191
     */
192
    // Get the ipv6 full format and return it as a decimal value.
193
    public static function get_ipv6_full($ip)
×
194
    {
195
        $pieces     = explode('/', $ip, 2);
×
196
        $left_piece = $pieces[0];
×
197

198
        // Extract out the main IP pieces
199
        $ip_pieces     = explode('::', $left_piece, 2);
×
200
        $main_ip_piece = $ip_pieces[0];
×
201
        $last_ip_piece = $ip_pieces[1];
×
202

203
        // Pad out the shorthand entries.
204
        $main_ip_pieces = explode(':', $main_ip_piece);
×
205

206
        foreach (array_keys($main_ip_pieces) as $key) {
×
207
            $main_ip_pieces[$key] = str_pad($main_ip_pieces[$key], 4, '0', STR_PAD_LEFT);
×
208
        }
209

210
        // Check to see if the last IP block (part after ::) is set
211
        $last_piece = '';
×
212
        $size       = count($main_ip_pieces);
×
213
        if (trim($last_ip_piece) !== '') {
×
214
            $last_piece = str_pad($last_ip_piece, 4, '0', STR_PAD_LEFT);
×
215

216
            // Build the full form of the IPV6 address considering the last IP block set
217
            for ($i = $size; $i < 7; $i++) {
×
218
                $main_ip_pieces[$i] = '0000';
×
219
            }
220
            $main_ip_pieces[7] = $last_piece;
×
221
        } else {
222
            // Build the full form of the IPV6 address
223
            for ($i = $size; $i < 8; $i++) {
×
224
                $main_ip_pieces[$i] = '0000';
×
225
            }
226
        }
227

228
        // Rebuild the final long form IPV6 address
229
        $final_ip = implode(':', $main_ip_pieces);
×
230

231
        return self::ip2long6($final_ip);
×
232
    }
233
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc