@@ -67,39 +67,130 @@ public static function cidrMaskToNetMask($cidrMask)
6767 return long2ip (-1 << (32 - (int ) $ cidrMask ));
6868 }
6969
70+ public static function cidrMaskToBinary ($ cidrMask , $ IPv )
71+ {
72+ if ($ IPv === 4 ) {
73+ return (~((1 << (32 - $ cidrMask )) - 1 ));
74+ }
75+ elseif ($ IPv === 6 )
76+ {
77+ $ netMask = str_repeat ("f " , $ cidrMask / 4 );
78+
79+ switch ($ cidrMask % 4 )
80+ {
81+ case 0 :
82+ break ;
83+ case 1 :
84+ $ netMask .= "8 " ;
85+ break ;
86+ case 2 :
87+ $ netMask .= "c " ;
88+ break ;
89+ case 3 :
90+ $ netMask .= "e " ;
91+ break ;
92+ }
93+
94+ $ netMask = str_pad ($ netMask , 32 , '0 ' );
95+ $ binMask = pack ("H* " , $ netMask );
96+
97+ return $ binMask ;
98+ }
99+
100+ return false ;
101+ }
102+
70103 public static function netMaskToCidr ($ netMask )
71104 {
72105 $ longMask = ip2long ($ netMask );
73106 $ longBase = ip2long ('255.255.255.255 ' );
74107 return 32 - log (($ longMask ^ $ longBase )+1 , 2 );
75108 }
76109
77- public static function networkIp ($ ip , $ mask )
110+ public static function firstSubnetIp ($ ip , $ mask )
78111 {
79- if (Tools::is ('int&&>0 ' , $ mask )) {
80- $ mask = self ::cidrMaskToNetMask ($ mask );
112+ if (($ isIPv4 = Tools::is ('ipv4 ' , $ ip )) === true || ($ isIPv6 = Tools::is ('ipv6 ' , $ ip )) === true )
113+ {
114+ if (Tools::is ('int&&>0 ' , $ mask )) {
115+ $ IPv = ($ isIPv4 ) ? (4 ) : (6 );
116+ $ mask = self ::cidrMaskToBinary ($ mask , $ IPv );
117+ }
118+ elseif (defined ('AF_INET6 ' )) {
119+ $ mask = inet_pton ($ mask );
120+ }
121+ else {
122+ return false ;
123+ }
124+
125+ // IPv4 & IPv6 compatible
126+ if (defined ('AF_INET6 ' )) {
127+ $ ip = inet_pton ($ ip );
128+ return inet_ntop ($ ip & $ mask );
129+ }
130+ // IPv4 only
131+ elseif ($ isIPv4 ) {
132+ $ netIp = (ip2long ($ ip ) & $ mask );
133+ return long2ip ($ netIp );
134+ }
81135 }
82136
83- $ netIp = (ip2long ($ ip ) & ip2long ($ mask ));
84- return long2ip ($ netIp );
137+ return false ;
85138 }
86139
87- public static function broadcastIp ($ ip , $ mask )
140+ public static function lastSubnetIp ($ ip , $ mask )
88141 {
89- if (Tools::is ('int&&>0 ' , $ mask )) {
90- $ mask = self ::cidrMaskToNetMask ($ mask );
142+ if (($ isIPv4 = Tools::is ('ipv4 ' , $ ip )) === true || ($ isIPv6 = Tools::is ('ipv6 ' , $ ip )) === true )
143+ {
144+ if (Tools::is ('int&&>0 ' , $ mask )) {
145+ $ IPv = ($ isIPv4 ) ? (4 ) : (6 );
146+ $ mask = self ::cidrMaskToBinary ($ mask , $ IPv );
147+ }
148+ elseif (defined ('AF_INET6 ' )) {
149+ $ mask = inet_pton ($ mask );
150+ }
151+ else {
152+ return false ;
153+ }
154+
155+ // IPv4 et IPv6 compatible
156+ if (defined ('AF_INET6 ' )) {
157+ $ ip = inet_pton ($ ip );
158+ return inet_ntop ($ ip | ~ $ mask );
159+ }
160+ // IPv4 only
161+ elseif ($ isIPv4 ) {
162+ $ bcIp = (ip2long ($ ip ) | (~ $ mask ));
163+ return long2ip ($ bcIp );
164+ }
91165 }
92166
93- $ bcIp = (ip2long ($ ip ) | (~ ip2long ($ mask )));
94- return long2ip ($ bcIp );
167+ return false ;
168+ }
169+
170+ public static function networkIp ($ ip , $ mask )
171+ {
172+ return self ::firstSubnetIp ($ ip , $ mask );
173+ }
174+
175+ public static function broadcastIp ($ ip , $ mask )
176+ {
177+ if (Tools::is ('ipv4 ' , $ ip )) {
178+ return self ::lastSubnetIp ($ ip , $ mask );
179+ }
180+ elseif (Tools::is ('ipv6 ' , $ ip )) {
181+ return 'ff02::1 ' ;
182+ }
183+ else {
184+ return false ;
185+ }
95186 }
96187
97188 public static function networkSubnet ($ cidrSubnet )
98189 {
99190 $ subnetPart = explode ('/ ' , $ cidrSubnet );
100191
101192 if (count ($ subnetPart ) === 2 ) {
102- $ networkIp = self ::networkIp ($ subnetPart [0 ], $ subnetPart [1 ]);
193+ $ networkIp = self ::firstSubnetIp ($ subnetPart [0 ], $ subnetPart [1 ]);
103194 return $ networkIp .'/ ' .$ subnetPart [1 ];
104195 }
105196 else {
0 commit comments