This file contains multiple functions. I normally avoid having multiple functions in a scriptlet. However they were so closely intertwined that it just made sense. These functions basically accomplish an IP calculator for PHP. They include functions to turn an IP into a binary string, and vice-versa along with functions for calculating the network and broadcast address of a particular network. There’s also a function to check whether a particular IP exists in a given network.
I’ll admit readily that I’d much rather have used binary arithmetic to work these functions. After all that would make sense. However PHP unfortunately does not support unsigned integers (at this time and I could find no reference to them extending their variable capabilities.) As a result, these functions are a slight bit slower than I would like. They have to do a string-based binary comparison to ensure that all IPs in the top end of the 32bits are covered. Some additional performance improvements could be made in two regards right now, but they aren’t of priority.
- Add a function to detect the submitted parameter so that in_network could avoid doing the binary calculation on the netmasks three times (once in subcalls to broadcast() and network() and of course once directly to get the netmasks’s binary equivalent.
- Change the whole thing into a class that caches its previous calculations for subsequent calls.
Of course, when I do code these features I’ll update this page.
Example:
include 'network.inc'; ip2bin('192.168.90.5'); // returns 11000000101010000101101000000101 bin2ip('11000000101010000101101000000101'); // returns 192.168.90.5 network('192.168.90.5', '255.255.248.0'); // returns 192.168.88.0 broadcast('192.168.90.5', '255.255.248.0'); // returns 192.168.95.255 in_network('192.168.50.4', '192.168.90.5', '255.255.248.0'); // returns -1 (not present) in_network('192.168.94.4', '192.168.90.5', '255.255.248.0'); // returns 1 (present)
<?php // Copyright (C) 2005 James Bly // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. function ip2bin($ip) { $ret = ''; if(!preg_match("/^\d+\.\d+\.\d+\.\d+$/", $ip)) return -1; foreach(explode(".", $ip) as $a) { if(!is_numeric($a)) return -1; $ret .= str_pad(decbin($a), 8, 0, STR_PAD_LEFT); } return $ret; } function cidr($ip) { if(preg_match("/^(\d+.\d+.\d+.\d+)\/(\d+)$/", $ip, $matches)) { return array($matches[1], bin2ip(netmask($matches[2]))); } else { return false; } } function bin2ip($bits) { if(!preg_match("/^([0-9]{8})([0-9]{8})([0-9]{8})([0-9]{8})$/", $bits, $matches)) return -1; return sprintf("%s.%s.%s.%s", bindec($matches[1]), bindec($matches[2]), bindec($matches[3]), bindec($matches[4])); } function bitmask($mask) { $bits = ip2bin($mask); if(preg_match("/^(1+)(0+)$/", $bits, $matches)) return strlen($matches[1]); else return -1; } function netmask($bits) { $ret = ''; if(!preg_match("/^\d+$/", $bits)) return -1; for($i = 0; $i < 32; $i++) $ret .= ($bits > $i)?1:0; return $ret; } function network($ip, $mask) { $ret = ''; $bitip = ip2bin($ip); $bitmask = ip2bin($mask); for($i = 0; $i < 32; $i++) { if($bitmask{$i} == '1') $ret .= $bitip{$i}; else $ret .= '0'; } return bin2ip($ret); } function broadcast($ip, $mask) { $ret = ''; $bitip = ip2bin($ip); $bitmask = ip2bin($mask); for($i = 0; $i < 32; $i++) { if($bitmask{$i} == '1') $ret .= $bitip{$i}; else $ret .= '1'; } return bin2ip($ret); } function in_network($check, $network, $netmask) { $c = ''; $b = ''; $cip = ip2bin($check); $nip = ip2bin(network($network, $netmask)); $bip = ip2bin(broadcast($network, $netmask)); $bitmask = ip2bin($netmask); for($i = 0; $i < 32; $i++) { if($bitmask{$i}) if($cip{$i} != $nip{$i}) return false; else { $c .= $cip{$i}; $b .= $bip{$i}; } } if(bindec($c) > bindec($b)) return false; else return 1; } ?>