Faktisk er den usignerede heltalskolonne allerede den mest effektive måde at søge efter match på delvise ip-adresser! Spild ikke din energi eller CPU-tid på at konvertere tilbage til prikket notation eller gå til en LIKE-søgning på en slags strengkolonne.
Der findes flere måder at nedskrive delvise IP-adresser på, men i sidste ende kommer de alle ned til en basis-ip med en netmaske. Hvis du også antager, at du med delvis mener alle IP'er med et fælles præfiks, så svarer dette også til at angive en række IP'er.
Uanset hvad ender den delvise IP-adressespecifikation med at blive beskrevet som to 32 bit, usignerede heltal, kodet i samme format som din databasekolonne. Enten har du en start-ip og en slut-ip, eller også har du en base-ip og en maske. Disse heltal kan bruges direkte i din SQL-forespørgsel for at opnå matches effektivt. Endnu bedre, hvis du bruger ip range tilgangen, så vil motoren være i stand til at drage fordel af et ordnet indeks på din ip kolonne. Du kan ikke forvente bedre.
Så hvordan opbygger man IP-området? Det afhænger af, hvordan dine delvise adresser blev specificeret i første omgang, men hvis du antager, at du kender netmasken, så er startadressen lig med (base ip &net mask), og slutadressen er ((base ip) &netmaske) | (~netmaske)), hvor &, | og ~ betyder henholdsvis bitvist-og, bitvist-eller og bitvist-ikke.
Opdater
Her er en prøvekode til at anvende den strategi, jeg beskrev.
Nu er det meget lang tid siden, jeg sidst skrev PHP-kode, og følgende er aldrig blevet udført, så undskyld venligst enhver fejl, jeg måtte have introduceret. Jeg valgte også bevidst at "udvide" hvert notationsscenarie for at gøre dem nemmere at forstå i stedet for at presse dem alle sammen i et enkelt, meget komplekst regex.
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);