Den osignerade heltalskolumnen är faktiskt redan det mest effektiva sättet att söka efter matchningar på partiella ip-adresser! Slösa inte din energi eller CPU-tid på att konvertera tillbaka till prickad notation eller göra en LIKE-sökning på någon form av strängkolumn.
Det finns flera sätt att skriva ned partiell IP-adress, men i slutändan kommer de alla ner till en bas-ip med en nätmask. Om du också antar att du med partiell menar alla IP-adresser med ett gemensamt prefix, så motsvarar detta också att ange ett intervall av IP-adresser.
Hur som helst, slutar den partiella IP-adressspecifikationen med att beskrivas som två 32 bitar, osignerade heltal, kodade i samma format som din databaskolumn. Antingen har du en start-ip och en slut-ip, eller så har du en bas-ip och en mask. Dessa heltal kan användas direkt i din SQL-fråga för att få matchningar effektivt. Ännu bättre, om du använder tillvägagångssättet ip range, då kommer motorn att kunna dra fördel av ett ordnat index på din ip kolumn. Du kan inte förvänta dig bättre.
Så hur bygger man IP-intervallet? Vi kommer att det beror på hur dina partiella adresser specificerades från början, men om du antar att du känner till nätmasken, då är startadressen lika med (bas ip &nätmask), och slutadressen är ((bas ip) &nätmask) | (~nätmask)), där &, | och ~ betyder bitvis-och, bitvis-eller och bitvis-inte.
Uppdatera
Här är en exempelkod för att tillämpa strategin jag beskrev.
Nu har det gått väldigt länge sedan jag skrev PHP-kod senast, och följande har aldrig körts, så ursäkta alla fel jag kan ha introducerat. Jag valde också medvetet att "expandera" varje notationsscenario för att göra dem lättare att förstå, snarare än att klämma ihop dem alla i ett enda, mycket komplext 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);