Práce s IPv4 a IPv6 adresami v PHP
S rozvojem IPv6 začínají zastarávat funkce v PHP pro práci s IP adresami, proto pokud potřebujete někde v PHP pracovat se šestkovou adresou, nezbývá než si pomoct vlastními funkcemi. Ale i zabudované funkce pro IPv4 nejsou zdaleka všemocné, takže si myslím že se bude spoustě programátorů hodit následující knihovna pro práci a výpočty s IP adresami, zejména funkce pro výpočty adresy sítě, broadcast adresy a masky sítě, které nativní PHP knihovna postrádá.
Nejprve musíme převést IPv6 adresy do formátu ve kterém se s nimi bude v PHP lépe pracovat. Podobnou funkcionalitu u IPv4 adres řeší funkce ip2long() a zpětně long2ip(). Funkce sice podle jména vypadají že konvertují stejně jako původní zabudované v PHP datový typ long (který je u PHP ve skutečnosti ale signed int), ale do něj se IPv6 adresa ani zdaleka nevejde, takže je použita knihovna gmp (GNU Multiple Precission), která umí pracovat s dostatečně velkou přesností.
function ip2long6($ipv6) {
$ip_n = @inet_pton($ipv6);
if($ip_n==false) return false;
$bits = 15; // 16 x 8 bit = 128bit
$ipv6long = '';
while ($bits >= 0) {
$bin = sprintf("%08b",(ord($ip_n[$bits])));
$ipv6long = $bin.$ipv6long;
$bits--;
}
return gmp_strval(gmp_init($ipv6long,2),10);
}
function long2ip6($ipv6long) {
$bin = gmp_strval(gmp_init($ipv6long,10),2);
if (strlen($bin) < 128) {
$pad = 128 - strlen($bin);
for ($i = 1; $i <= $pad; $i++)
$bin = "0".$bin;
}
$bits = 0;
$ipv6 = '';
while ($bits<=7) {
$bin_part = substr($bin,($bits*16),16);
$ipv6 .= dechex(bindec($bin_part)).":";
$bits++;
}
return inet_ntop(inet_pton(substr($ipv6,0,-1)));
}
Následně se budou hodit funkce které zjistí jestli zadaná IP adresa je IPv4 nebo IPv6.
function is_ipv4($ip) {
return ip2long($ip) && true;
}
function is_ipv6($ip) {
return !ip2long($ip) && @inet_pton($ip) && true;
}
Teď si můžeme ze zadané adresy spočítat adresu sítě, broadcast adresu a síťovou masku. A to jak pro IPv4 tak IPv6 adresy.
function ipcalc4($in_net_addr) {
$x = explode('/',$in_net_addr);
$ip = gmp_init(ip2long($x[0]));
$prefix = $x[1];
unset($x);
$netmask = gmp_init(0);
$neg_netmask = gmp_init(0);
for($bits=1; $bits< =32; $bits++) {
$bits<=$prefix && gmp_setbit($netmask, 32-$bits);
gmp_setbit($neg_netmask, $bits-1);
}
$neg_netmask = gmp_xor($netmask, $neg_netmask);
$broadcast = gmp_or($ip, $neg_netmask);
$network = gmp_and($ip, $netmask); # IP AND NETMASK
return array(gmp_strval($ip), (string)$prefix, gmp_strval($netmask), gmp_strval($network), gmp_strval($broadcast));
}
function ipcalc6($in_net_addr) {
$x = explode('/', $in_net_addr);
$ip = gmp_init(ip2long6($x[0]));
$prefix = $x[1];
unset($x);
$netmask = gmp_init(0);
$neg_netmask = gmp_init(0);
for($bits=1; $bits<=128; $bits++) {
$bits<=$prefix && gmp_setbit($netmask, 128-$bits);
gmp_setbit($neg_netmask, $bits-1);
}
$neg_netmask = gmp_xor($netmask, $neg_netmask);
$broadcast = gmp_or($ip, $neg_netmask);
$network = gmp_and($ip, $netmask);
return array(gmp_strval($ip), (string)$prefix, gmp_strval($netmask), gmp_strval($network), gmp_strval($broadcast));
}
Poslední částí této knihovny je porovnání IPv4 a IPv6 adresy jestli se vejde do zadaného rozsahu.
function ip_in_subnet4($subnet, $ip) {
$ip = gmp_init(ip2long($ip));
$subnet = ipcalc4($subnet);
return gmp_cmp($ip, gmp_init($subnet[3]))>=0 && gmp_cmp($ip, gmp_init($subnet[4]))< =0;
}
function ip_in_subnet6($subnet, $ip) {
$ip = gmp_init(ip2long6($ip));
$subnet = ipcalc6($subnet);
return gmp_cmp($ip, gmp_init($subnet[3]))>=0 && gmp_cmp($ip, gmp_init($subnet[4]))< =0;
}
Tímto je definice funkcí knihovny kompletní a na závěr tedy malá ukázka práce s touto knihovnou.
$ipv4 = ipcalc4('81.0.225.64/26');
$ipv6 = ipcalc6('2001:1528:124:1::1/64');
print 'IP : '.long2ip($ipv4[0])."\n";
print 'Mask : '.long2ip($ipv4[2])."\n";
print 'Network : '.long2ip($ipv4[3])."\n";
print 'Broadcast : '.long2ip($ipv4[4])."\n";
print "\n";
print 'IP : '.long2ip6($ipv6[0])."\n";
print 'Mask : '.long2ip6($ipv6[2])."\n";
print 'Network : '.long2ip6($ipv6[3])."\n";
print 'Broadcast : '.long2ip6($ipv6[4])."\n";
print ip_in_subnet4('81.0.225.64/26', '81.0.225.127');
print ip_in_subnet6('2001:1528:124:100::/64', '2001:1528:124:100::225:103');
Pokud chcete tuto knihovnu využívat, je publikována pod MIT licencí která umožňuje tuto knihovnu libovolně šířit a začleňovat do dalších aplikací.
Download: http://glux.org/download/iplib-1-0.zip
Dobrý den, chtěl jsem se zeptat, zda by jste mi mohl poskytou nějaký ucelený příklad s celým porgramem na webu tj, i s formálařeme pro vstupy dat. Prostě ucelený funkční celek. Děuji
Prominte, ale davam k dispozici knihovnu poskytujici zakladni funkce. Myslim si ze i pro prumerneho progamatora je popis vice ne dostacujici. Pokud Vam to nestaci, zaplatte si nejaky kurz programovani nebo neco podobneho.
Parada, zrovna jsem neco podobneho potreboval resit, tak jsem rad ze to nemusim psat odznova. Diky moc!