Domů > PHP > Práce s IPv4 a IPv6 adresami v PHP

Práce s IPv4 a IPv6 adresami v PHP

phpS 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

Tags: , ,
  1. Dominik
    09.10.2011 na 17:34 | #1

    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

  2. 10.10.2011 na 08:55 | #2

    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.

  3. dafodil
    17.11.2011 na 16:32 | #3

    Parada, zrovna jsem neco podobneho potreboval resit, tak jsem rad ze to nemusim psat odznova. Diky moc!

  1. Žádné zpětné odkazy