2013-08-16 14 views
11

in IPv4 possiamo usare ip2long per convertirlo in numero,Php convertire ipv6 al numero

come convertire ipv6 compressa per il numero in PHP?

Ho provato inet_pton e non funziona.

$ip_1='2001:0db8:85a3:0000:0000:8a2e:0370:7334'; 
$ip_2='2001:11ff:ffff:f';//Compressed 
echo inet_pton($ip_1); 
//OUTPUT ИЃ.ps4 
echo inet_pton($ip_2); 
//OUTPUT Warning: inet_pton(): Unrecognized address 2001:11ff:ffff:f 
+0

Cosa uscita vuoi arrivare, eventuali errori? – Halcyon

+3

Il PHP ha un tipo di dati a 128 bit? – SLaks

+0

1o ottengo testo strano 2o uno comprime ottengo l'errore – Ben

risposta

7

$ IP_2 non è un indirizzo IPv6 valido. Hai bisogno di "::" da qualche parte lì dentro, per indicare il punto zero di omissione.

Se si dispone come una delle

$ip_2='2001::11ff:ffff:f'; 
$ip_2='2001:11ff::ffff:f'; 
$ip_2='2001:11ff:ffff::f'; 

poi inet_pton() dovrebbe funzionare bene.

Come già accennato, PHP non dispone di un tipo intero 128, quindi la cosa migliore che si può ottenere è una stringa numerica fuori dalla stringa binaria inet_pton() ti dà ... sì, questo è quello che è, ed è per questo che sembra strano Se guardi i pezzi di quelle stringhe, vedrai che sono esattamente ciò che ti aspetteresti.

Ecco come espandere la stringa binaria in una stringa numerica (argomento "0" che mancava da str_pad() in origine):

/** 
* @param string $ip A human readable IPv4 or IPv6 address. 
* @return string Decimal number, written out as a string due to limits on the size of int and float. 
*/ 
function ipv6_numeric($ip) { 
    $binNum = ''; 
    foreach (unpack('C*', inet_pton($ip)) as $byte) { 
     $binNum .= str_pad(decbin($byte), 8, "0", STR_PAD_LEFT); 
    } 
    return base_convert(ltrim($binNum, '0'), 2, 10); 
} 
+0

quindi cosa dovrei memorizzare questo in Banca dati? Cerco di trovare la posizione IP da db, qualcosa come INET_ATON ("123.243.51.83") TRA INET_ATON (ip_start) E INET_ATON (ip_end) – Ben

+0

@ Ben. Dipende, dipende. Si può semplicemente memorizzare la stringa binaria da inet_pton(). La stringa numerica è davvero utile solo se è necessario eseguire un po 'di "matematica" sull'indirizzo. Se stai semplicemente canonizzando le notazioni IP, il confronto tra l'output di inet_pton() di due notazioni è sufficiente. –

+0

@Ben Oh, quindi vuoi controllare gli intervalli ... beh, questa è una specie di "matematica", quindi sì. Potresti voler usare una funzione come la precedente, e poi passare i risultati a qualcosa di simile alle funzioni GMP per fare la matematica. –

0

Prova questa

function inet6_to_int64($addr) 
{ 
    /* Expand the address if necessary */ 
    if (strlen($addr) != 39) { 
     $addr = inet6_expand($addr); 
     if ($addr == false) return false; 
    } // if 
    $addr = str_replace(':', '', $addr); 
    $p1 = '0x' . substr($addr, 0, 16); 
    $p2 = '0x' . substr($addr, 16); 
    $p1 = gmp_init($p1); 
    $p2 = gmp_init($p2); 
    $result = array(gmp_strval($p1), gmp_strval($p2)); 
    return $result; 
} // inet6_to_int64() 

Per ulteriori funzioni o informazioni si prega di visitare http://www.soucy.org/project/inet6/

+0

ottenuto errore irreversibile: chiamata a funzione non definita gmp_init() – Ben

+1

http://www.php.net/manual/en/gmp.installation.php –

+0

verifica supporto GMP è abilitato –

1

OK, alcune rivelazioni da chiacchierata con Ben Wong ... The REAL problema sta ottimizzando le ricerche in un DB su un servizio geoIP.

Il layout DB offerto da this geoIP database è troppo lento per avere solo OL 'BETWEEN applicato all'inizio e alla fine, anche se lo spazio di archiviazione è il più economico possibile.

La proposta che ho descritto per primo nella chat era frammentare l'indirizzo IP in 4 ints che sono confrontati in sequenza, ma al secondo però potrebbe non essere sufficiente, dal momento che stai ancora cercando l'intero DB, che è oltre 1 milione di righe. Ho anche avuto l'idea di fare corrispondenze con le maschere di sottorete, ma dato che alcuni intervalli non sono all'interno di maschere di grandi dimensioni, fare questo potrebbe, ancora una volta, non essere sufficiente.

Vedrò cosa posso fare e modificheremo questa risposta. Ma sto postando questo nel frattempo per chiunque sia disposto ad aiutare in questo.

9

Usa:

$ip = 'fe80:0:0:0:202:b3ff:fe1e:8329'; 
$dec = ip2long_v6($ip); 
$ip2 = long2ip_v6($dec); 

// $ip = fe80:0:0:0:202:b3ff:fe1e:8329 
// $dec = 338288524927261089654163772891438416681 
// $ip2 = fe80::202:b3ff:fe1e:8329 

Funzioni:

Con abilitato GMP o BCMATH estensione.

function ip2long_v6($ip) { 
    $ip_n = inet_pton($ip); 
    $bin = ''; 
    for ($bit = strlen($ip_n) - 1; $bit >= 0; $bit--) { 
     $bin = sprintf('%08b', ord($ip_n[$bit])) . $bin; 
    } 

    if (function_exists('gmp_init')) { 
     return gmp_strval(gmp_init($bin, 2), 10); 
    } elseif (function_exists('bcadd')) { 
     $dec = '0'; 
     for ($i = 0; $i < strlen($bin); $i++) { 
      $dec = bcmul($dec, '2', 0); 
      $dec = bcadd($dec, $bin[$i], 0); 
     } 
     return $dec; 
    } else { 
     trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); 
    } 
} 

function long2ip_v6($dec) { 
    if (function_exists('gmp_init')) { 
     $bin = gmp_strval(gmp_init($dec, 10), 2); 
    } elseif (function_exists('bcadd')) { 
     $bin = ''; 
     do { 
      $bin = bcmod($dec, '2') . $bin; 
      $dec = bcdiv($dec, '2', 0); 
     } while (bccomp($dec, '0')); 
    } else { 
     trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); 
    } 

    $bin = str_pad($bin, 128, '0', STR_PAD_LEFT); 
    $ip = array(); 
    for ($bit = 0; $bit <= 7; $bit++) { 
     $bin_part = substr($bin, $bit * 16, 16); 
     $ip[] = dechex(bindec($bin_part)); 
    } 
    $ip = implode(':', $ip); 
    return inet_ntop(inet_pton($ip)); 
} 

demo

3

Si noti che tutte le risposte si tradurrà in risultati non corretti per i grandi indirizzi IP o stanno attraversando un processo altamente complicato per ricevere i numeri reali. Recuperare il valore intero effettivo da un indirizzo IPv6 richiede due cose:

  1. supporto IPv6
  2. GMP extension (--with-gmp)

Con entrambi prerequisiti luogo conversione è semplice come:

$ip = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'; 
$int = gmp_import(inet_pton($ip)); 

echo $int; // 340282366920938463463374607431768211455 

L' la rappresentazione numerica binaria in_addr che viene restituita da inet_pton è già un numero intero e può direttamente b e importato in GMP, come illustrato sopra. Non c'è bisogno di conversioni speciali o altro.

Si noti che il contrario è altrettanto semplice:

$int = '340282366920938463463374607431768211455'; 
$ip = inet_ntop(str_pad(gmp_export($int), 16, "\0", STR_PAD_LEFT)); 

echo $ip; // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 

Di qui la costruzione delle due funzioni desiderate è semplice come:

function ipv6_to_integer($ip) { 
    return (string) gmp_import(inet_pton($ip)); 
} 

function ipv6_from_integer($integer) { 
    return inet_ntop(str_pad(gmp_export($integer), 16, "\0", STR_PAD_LEFT)); 
}