Subnet::fromContainedAddressCidr()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * Copyright (c) 2018 Mattheu Racine
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace mracine\IPTools\IPv4;
10
11
use OutOfBoundsException;
12
use RangeException;
13
use BadMethodCallException;
14
use InvalidArgumentException;
15
16
use mracine\IPTools\Iterators\SubnetIterator;
17
use mracine\IPTools\IPv4\Address;
18
use mracine\IPTools\IPv4\Netmask;
19
use mracine\IPTools\IPVersion;
20
/**
21
 * Class Subnet represents an IPv4 IP address with a netmask to specify a subnet
22
 *
23
 * Subnet implements :
24
 *  * Countable : number of addresses
25
 *  * ArrayAccess : Address can be acceesed by offset (ex : $range[10])
26
 *  * IteratorAggregate :   range can be itrated (foreach)
27
28
 * @package IPTools
29
 */
30
class Subnet extends Range
31
{
32
    /**
33
     * @var Netmask $netmask 
34
     */
35
    protected $netmask;
36
37
     /**
38
     * Creates an IP Subnet from a an IP network addresses and a netamsk
39
     *
40
     * @param Address $baseAddress the first address of the range
41
     * @param int $count the number  other bound
42
     * @param bool $strict if true $network
43
     */
44 9
    public function __construct(Address $network, Address $netmask, bool $strict=true)
45
    {
46 9
        $finalNetmask = clone($netmask);
47 9
        if (!($netmask instanceof Netmask))
48
        {
49 2
            $finalNetmask = Netmask::fromAddress($netmask);  
50
        }
51
        
52
        // Verify parameters validity
53 9
        if( (($network->int() & $finalNetmask->int()) != $network->int()) && $strict)
54
        {
55 1
            throw new RangeException(sprintf("Invalid network adress %s, this address is not usable with the netmask %s", (string)$network, (string)$finalNetmask));
56
        }
57
58 8
        $finalNetwork = new Address($network->int() & $finalNetmask->int());
59
60 8
        parent::__construct($finalNetwork, $finalNetwork->shift(count($finalNetmask)-1));
0 ignored issues
show
Bug introduced by
It seems like $finalNetmask can also be of type mracine\IPTools\IPv4\Address; 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

60
        parent::__construct($finalNetwork, $finalNetwork->shift(count(/** @scrutinizer ignore-type */ $finalNetmask)-1));
Loading history...
61 8
        $this->netmask = $finalNetmask;
62 8
    }
63
64
   /**
65
     * Construct an IPv4 Subnet from a CIDR notation (#.#.#.#/#)
66
     *
67
     * @param Address $network the network base address  of the subnet
68
     * @param int $cidr the CIDR notation of the netmask
69
     * @param bool $strict 
70
     * @throws OutOfBoundsException when $cidr is negatve or greater than 32
71
     * @throws RangeException when network address and netmask does not form a valid subnet 
72
     * @return Subnet
73
     */
74 7
    public static function fromCidr(Address $network, int $cidr, bool $strict=true)
75
    {
76
        // Ensure CIDR is valid, use Address::fromCidr to have validation logic in only one place 
77 7
        $netmask = Netmask::fromCidr($cidr);
78 7
        return new static($network, $netmask, $strict);
79
    }
80
81
    /**
82
     * Return a subnet from an addresss and a CIDR form netmask, the addresscan be within the subnet, not only the network address
83
     *
84
     * @deprecated use $strict parameter of Subnet::fromCidr
85
     * @see Subnet::fromCidr
86
     * @param Address $address an address within the desired subnet
87
     * @param int $cidr the CIDR notation of the netmask
88
     * @return Subnet
89
     */
90 5
    public static function fromContainedAddressCidr(Address $address, int $cidr)
91
    {
92 5
        @trigger_error(
93
            'The fromContainedAddressCidr functon is deprecated and will be removed soon.'
94 5
            .' Use fromCidr with strict parameter set to false instead.',
95 5
        E_USER_DEPRECATED
96
    );
97 5
        return static::fromCidr($address, $cidr, false);
98
    }
99
100
    /**
101
     * Construct a subnet from string
102
     * 
103
     * @param string $subnet a CIDR formated or netmask representtation of the subnet : x.x.x.x/24 or x.x.x.x/255.255.255.0
104
     * @param bool $strict if true address must be a netwoek bound, else an be an address within the range
105
     * @throws InvaidArgumentException when provided sting cannot be converted to a valid subnet
106
     * @return Subnet
107
     */
108 25
    public static function fromString(string $subnet, bool $strict=true)
109
    {
110 25
        @list($address, $netmask, $trash) = explode('/', $subnet);
111 25
        if (!is_null($trash) || is_null($netmask))
0 ignored issues
show
introduced by
The condition is_null($trash) is always false.
Loading history...
112
        {
113 11
            throw new InvalidArgumentException(sprintf("%s cannot be converted to subnet. Valid formats are : x.x.x.x/cidr or x.x.x.x/y.y.y.y", $subnet));
114
        }
115
116 14
        if(ctype_digit($netmask))
117
        {
118 6
            return static::fromCidr(Address::fromString($address), (int)$netmask, $strict);
119
        }
120 8
        return new static(Address::fromString($address), Netmask::fromString($netmask), $strict);
121
    }
122
123
    /**
124
     * Retrun a string representing the Subnet un DotQuad notation and CIDR
125
     * 
126
     * ex: 192.168.0.0/24
127
     *
128
     * @param string $separator The separator used between network an CIDR, defaults to /
129
     * @return string
130
     */
131 3
    public function asDotQuadAndCidr(string $separator='/')
132
    {
133 3
        return (string)$this->getNetworkAddress() . $separator . (string)$this->getNetmaskAddress()->asCidr();
134
    }
135
136
    /**
137
     * Get the network address
138
     *
139
     * NOICE : return a fresh instance of address
140
     *
141
     * @return Address
142
     */
143 4
    public function getNetworkAddress()
144
    {
145 4
        return $this->getLowerBound();
146
    }
147
148
    /**
149
     * Get the netmask address 
150
     *
151
     * @return Netmask
152
     */
153 4
    public function getNetmaskAddress()
154
    {
155 4
        return $this->netmask;
156
    }
157
    /**
158
     * Get the broadcast address 
159
     *
160
     * @return Address
161
     */
162 6
    public function getBroadcastAddress()
163
    {
164 6
        return $this->getUpperBound();
165
    }
166
167
    /**
168
     * Returns a Subnet shifted by an amount of units (count)
169
     *
170
     * Need explain...
171
     *
172
     * @param int $offset
173
     * @throws OutOfBounsException when the resulting subet is invalid
174
     * @return Subnet
175
     */  
176 2
    public function shift(int $offset)
177
    {
178 2
        return static::fromCidr(
179 2
            $this->getNetworkAddress()->shift($offset*count($this)),
180 2
            $this->getNetmaskAddress()->asCidr()
181
         );
182
    }
183
184
    /*
185
     * interface IteratorAggregate
186
     */
187
188
    /**
189
     * Obtain an iterator to traverse the Subnet
190
     *
191
     * Allows to iterate in the subnet with foreach ($subnet as $address) {...} )
192
     *
193
     * @return SubnetIterator
194
     */
195 1
    public function getIterator()
196
    {
197 1
        return new SubnetIterator($this);
198
    }
199
}
200