sql >> Database >  >> RDS >> Mysql

Zoeken op gedeeltelijke IP-adressen die zijn opgeslagen als gehele getallen

Eigenlijk is de unsigned integer-kolom al de meest efficiënte manier om te zoeken naar overeenkomsten op gedeeltelijke ip-adressen! Verspil alsjeblieft geen energie of CPU-tijd aan het terug converteren naar gestippelde notatie of het zoeken naar een LIKE op een soort stringkolom.

Er zijn verschillende manieren om een ​​gedeeltelijk IP-adres op te schrijven, maar uiteindelijk komen ze allemaal neer op een basis-ip met een netmasker. Ook, ervan uitgaande dat u met gedeeltelijk alle IP's met een gemeenschappelijk voorvoegsel bedoelt, dan is dit ook gelijk aan het specificeren van een reeks IP's.

Hoe dan ook, de gedeeltelijke IP-adresspecificatie wordt uiteindelijk beschreven als twee 32-bits, niet-ondertekende gehele getallen, gecodeerd in hetzelfde formaat als uw databasekolom. Of je hebt een start-ip en een eind-ip, of je hebt een basis-ip en een masker. Deze gehele getallen kunnen direct in uw SQL-query worden gebruikt om efficiënt overeenkomsten te verkrijgen. Nog beter, als u de ip-bereikbenadering gebruikt, kan de engine profiteren van een geordende index op uw ip-kolom. Je kunt niet beter verwachten.

Dus hoe het IP-bereik te bouwen? We zullen dat afhankelijk zijn van hoe uw gedeeltelijke adressen in de eerste plaats zijn opgegeven, maar ervan uitgaande dat u het netmasker kent, dan is het startadres gelijk aan (base ip &net mask), en het eindadres is ((base ip &netmask) | (~netmask)), waar &, | en ~ betekent respectievelijk bitsgewijze-en, bitsgewijze-of en bitsgewijze-niet.

Bijwerken

Hier is een voorbeeldcode om de door mij beschreven strategie toe te passen.

Nu is het heel lang geleden dat ik voor het laatst PHP-code heb geschreven en het volgende is nooit uitgevoerd, dus excuseer me voor eventuele fouten die ik heb geïntroduceerd. Ik heb er ook bewust voor gekozen om elk notatiescenario "uit te breiden" om ze gemakkelijker te begrijpen te maken, in plaats van ze allemaal in een enkele, zeer complexe regex te persen.

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);


  1. Oracle PL/SQL:Dynamisch SQL-voorbeeld met Execute Immediate

  2. Een een-op-veel-relatie toevoegen aan een zelfverwijzende ouder/kind

  3. mysql-achtige zoekopdracht getallen uitsluiten

  4. Zoeken naar databaseobjecten en tabelgegevens in SQL Server