Ve skutečnosti je sloupec celé číslo bez znaménka již tím nejefektivnějším způsobem, jak hledat shodu na částečných IP adresách! Prosím, neplýtvejte svou energií ani časem CPU převodem zpět na tečkovaný zápis nebo hledáním LIKE v nějakém řetězci.
Existuje několik způsobů, jak zapsat částečnou IP adresu, ale nakonec se všechny sníží na základní IP s maskou sítě. Také za předpokladu, že částečným, máte na mysli všechny IP adresy se společnou předponou, pak je to také ekvivalentní zadání rozsahu IP adres.
V každém případě je částečná specifikace IP adresy popsána jako dvě 32bitová celá čísla bez znaménka zakódovaná ve stejném formátu jako sloupec databáze. Buď máte počáteční ip a koncovou ip, nebo máte základní ip a masku. Tato celá čísla lze použít přímo v dotazu SQL k efektivnímu získávání shod. Ještě lepší je, když použijete přístup s rozsahem ip, pak bude motor schopen využít uspořádaný index ve sloupci ip. Nemůžete očekávat nic lepšího.
Jak tedy vybudovat rozsah IP? To bude záležet na tom, jak byly vaše dílčí adresy specifikovány na prvním místě, ale za předpokladu, že znáte masku sítě, pak počáteční adresa je rovna (základní ip a maska sítě) a koncová adresa je ((základní ip &maska sítě) | (~maska sítě)), kde &, | a ~ znamená bitově-a, bitově-nebo a bitově-ne.
Aktualizovat
Zde je ukázkový kód pro aplikaci strategie, kterou jsem popsal.
Nyní je to již velmi dlouho, co jsem naposledy psal kód PHP, a následující nebylo nikdy provedeno, takže prosím omluvte jakoukoli chybu, kterou jsem mohl uvést. Také jsem se záměrně rozhodl „rozšířit“ každý scénář zápisu, aby byl srozumitelnější, než abych je všechny vtěsnal do jediného, velmi složitého regulárního výrazu.
if (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [/] (\d{1,2}) $/x', $input, $r)) {
// Four-dotted IP with number of significant bits: 123.45.67.89/24
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = intval($r[5]);
} elseif (preg_match(' /^ (\d{1,3}) (?: [.] [*0] [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with three-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 8 bits)
$a = intval($r[1]);
$b = 0;
$c = 0;
$d = 0;
$mask = 8;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with two-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 16 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = 0;
$d = 0;
$mask = 16;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with last number missing, or equals to 0 or *:
// 123.45.67, 123.45.67.0, 123.45.67.* (assume netmask of 24 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = 0;
$mask = 24;
} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) $/x', $input, $r)) {
// Four-dotted IP: 123.45.67.89 (assume netmask of 32 bits)
$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = 32;
} else {
throw new Exception('...');
}
if ($a < 0 || $a > 255) { throw new Exception('...') };
if ($b < 0 || $b > 255) { throw new Exception('...') };
if ($c < 0 || $c > 255) { throw new Exception('...') };
if ($d < 0 || $d > 255) { throw new Exception('...') };
if ($mask < 1 || $mask > 32) { throw new Exception('...') };
$baseip = ($a << 24) + ($b << 16) + ($c << 8) + ($d);
$netmask = (1 << (32 - $mask)) - 1;
$startip = $baseip & netmask;
$endip = ($baseip & netmask) | (~netmask);
// ...
doSql( "SELECT ... FROM ... WHERE ipaddress >= ? && ipaddress <= ?", $startip, $endip);
// or
doSql( "SELECT ... FROM ... WHERE ((ipaddress & ?) = ?)", $netmask, $startip);