it-swarm.com.de

Wie prüfe ich, ob eine IP-Adresse in PHP in einem Bereich von zwei IP-Adressen liegt?

Ich habe eine IP-Adresse und ich habe zwei andere IP-Adressen erhalten, die zusammen einen IP-Bereich bilden. Ich möchte überprüfen, ob die erste IP-Adresse in diesem Bereich liegt. Wie kann ich das in PHP herausfinden?

46
guitarlass

Mit ip2long() können Sie Ihre Adressen leicht in Zahlen umwandeln. Danach müssen Sie nur noch prüfen, ob die Nummer im Bereich liegt:

if ($ip <= $high_ip && $low_ip <= $ip) {
  echo "in range";
}
58
oezi

Diese Website bietet einen hervorragenden Leitfaden und Code , um dies zu tun (was das erste Ergebnis einer Google-Suche nach dieser Frage war)

<?php

/*
 * ip_in_range.php - Function to determine if an IP is located in a
 *                   specific range as specified via several alternative
 *                   formats.
 *
 * Network ranges can be specified as:
 * 1. Wildcard format:     1.2.3.*
 * 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
 * 3. Start-End IP format: 1.2.3.0-1.2.3.255
 *
 * Return value BOOLEAN : ip_in_range($ip, $range);
 *
 * Copyright 2008: Paul Gregg <[email protected]>
 * 10 January 2008
 * Version: 1.2
 *
 * Source website: http://www.pgregg.com/projects/php/ip_in_range/
 * Version 1.2
 *
 * This software is Donationware - if you feel you have benefited from
 * the use of this tool then please consider a donation. The value of
 * which is entirely left up to your discretion.
 * http://www.pgregg.com/donate/
 *
 * Please do not remove this header, or source attibution from this file.
 */


// decbin32
// In order to simplify working with IP addresses (in binary) and their
// netmasks, it is easier to ensure that the binary strings are padded
// with zeros out to 32 characters - IP addresses are 32 bit numbers
Function decbin32 ($dec) {
  return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
}

// ip_in_range
// This function takes 2 arguments, an IP address and a "range" in several
// different formats.
// Network ranges can be specified as:
// 1. Wildcard format:     1.2.3.*
// 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
// 3. Start-End IP format: 1.2.3.0-1.2.3.255
// The function will return true if the supplied IP is within the range.
// Note little validation is done on the range inputs - it expects you to
// use one of the above 3 formats.
Function ip_in_range($ip, $range) {
  if (strpos($range, '/') !== false) {
    // $range is in IP/NETMASK format
    list($range, $netmask) = explode('/', $range, 2);
    if (strpos($netmask, '.') !== false) {
      // $netmask is a 255.255.0.0 format
      $netmask = str_replace('*', '0', $netmask);
      $netmask_dec = ip2long($netmask);
      return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
    } else {
      // $netmask is a CIDR size block
      // fix the range argument
      $x = explode('.', $range);
      while(count($x)<4) $x[] = '0';
      list($a,$b,$c,$d) = $x;
      $range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
      $range_dec = ip2long($range);
      $ip_dec = ip2long($ip);

      # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
      #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));

      # Strategy 2 - Use math to create it
      $wildcard_dec = pow(2, (32-$netmask)) - 1;
      $netmask_dec = ~ $wildcard_dec;

      return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
    }
  } else {
    // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
    if (strpos($range, '*') !==false) { // a.b.*.* format
      // Just convert to A-B format by setting * to 0 for A and 255 for B
      $lower = str_replace('*', '0', $range);
      $upper = str_replace('*', '255', $range);
      $range = "$lower-$upper";
    }

    if (strpos($range, '-')!==false) { // A-B format
      list($lower, $upper) = explode('-', $range, 2);
      $lower_dec = (float)sprintf("%u",ip2long($lower));
      $upper_dec = (float)sprintf("%u",ip2long($upper));
      $ip_dec = (float)sprintf("%u",ip2long($ip));
      return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
    }

    echo 'Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format';
    return false;
  }

}
?>
30
John Conde

Ich habe diese kleine Gist .__ gefunden, die eine einfachere/kürzere Lösung hat als bereits erwähnt. 

Das zweite Argument (Bereich) kann entweder eine statische IP wie 127.0.0.1 oder ein Bereich wie 127.0.0.0/24 sein.

/**
 * Check if a given ip is in a network
 * @param  string $ip    IP to check in IPV4 format eg. 127.0.0.1
 * @param  string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
 * @return boolean true if the ip is in this range / false if not.
 */
function ip_in_range( $ip, $range ) {
    if ( strpos( $range, '/' ) == false ) {
        $range .= '/32';
    }
    // $range is in IP/CIDR format eg 127.0.0.1/24
    list( $range, $netmask ) = explode( '/', $range, 2 );
    $range_decimal = ip2long( $range );
    $ip_decimal = ip2long( $ip );
    $wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
    $netmask_decimal = ~ $wildcard_decimal;
    return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
}
11
codefreak
if(version_compare($low_ip, $ip) + version_compare($ip, $high_ip) === -2) {
    echo "in range";
}
2
Bas

Ich würde immer ip2long vorschlagen, aber manchmal müssen Sie Netzwerke überprüfen usw. Ich habe in der Vergangenheit eine IPv4-Netzwerkklasse erstellt, die Sie hier auf HighOnPHP finden.

Das Schöne an der Arbeit mit IP-Adressierung ist ihre Flexibilität, insbesondere bei der Verwendung von BITWISE-Operatoren. AND'ing, OR'ing und BitShifting funktionieren wie ein Zauber.

2
Mike Mackintosh

Hier ist meine Herangehensweise an das Thema.

function validateIP($whitelist, $ip) {

    // e.g ::1
    if($whitelist == $ip) {
        return true;
    }

    // split each part of the IP address and set it to an array
    $validated1 = explode(".", $whitelist);
    $validated2 = explode(".", $ip);

    // check array index to avoid undefined index errors
    if(count($validated1) >= 3 && count($validated2) == 4) {

        // check that each value of the array is identical with our whitelisted IP,
        // except from the last part which doesn't matter
        if($validated1[0] == $validated2[0] && $validated1[1] == $validated2[1] && $validated1[2] == $validated2[2]) {
            return true;
        }   

    }

    return false;
}
0
user8581607

Übrigens, falls Sie mehrere Bereiche gleichzeitig prüfen müssen, können Sie dem Code einige Zeilen hinzufügen, um ein Array von Bereichen zu übergeben. Das zweite Argument kann ein Array oder eine Zeichenfolge sein:

public static function ip_in_range($ip, $range) {
      if (is_array($range)) {
          foreach ($range as $r) {
              return self::ip_in_range($ip, $r);
          }
      } else {
          if ($ip === $range) { // in case you have passed a static IP, not a range
             return TRUE;
          }
      } 
      // The rest of the code follows here..
      // .........
}
0
Vlado

Vergleich innerhalb des Bereichs (einschließlich Ipv6-Unterstützung)

Die folgenden zwei Funktionen wurden in PHP 5.1.0, inet_pton und inet_pton eingeführt. Sie dienen dazu, vom Menschen lesbare IP-Adressen in ihre gepackte in_addr-Darstellung umzuwandeln. Da das Ergebnis nicht rein binär ist, müssen Sie die Funktion unpack verwenden, um bitweise Operatoren anzuwenden.

Beide Funktionen unterstützen sowohl IPv6 als auch IPv4. Der einzige Unterschied besteht darin, wie Sie die Adresse aus den Ergebnissen auspacken. Mit IPv6 entpacken Sie Inhalte mit A16 und mit IPv4 entpacken Sie mit A4.

Um das Vorhergehende in eine Perspektive zu bringen, ist hier eine kleine Beispielausgabe zur Verdeutlichung:

// Our Example IP's
$ip4= "10.22.99.129";
$ip6= "fe80:1:2:3:a:bad:1dea:dad";


// ip2long examples
var_dump( ip2long($ip4) ); // int(169239425)
var_dump( ip2long($ip6) ); // bool(false)


// inet_pton examples
var_dump( inet_pton( $ip4 ) ); // string(4)
var_dump( inet_pton( $ip6 ) ); // string(16)

Wir zeigen oben, dass die inet_ * -Familie sowohl IPv6 als auch v4 unterstützt. Als nächsten Schritt wird das gepackte Ergebnis in eine nicht gepackte Variable übersetzt.

// Unpacking and Packing
$_u4 = current( unpack( "A4", inet_pton( $ip4 ) ) );
var_dump( inet_ntop( pack( "A4", $_u4 ) ) ); // string(12) "10.22.99.129"


$_u6 = current( unpack( "A16", inet_pton( $ip6 ) ) );
var_dump( inet_ntop( pack( "A16", $_u6 ) ) ); //string(25) "fe80:1:2:3:a:bad:1dea:dad"

Anmerkung: Die aktuelle Funktion gibt den ersten Index eines Arrays zurück. Es ist gleichbedeutend mit $ array [0].

Nach dem Auspacken und Verpacken sehen wir, dass wir das gleiche Ergebnis wie bei der Eingabe erzielen. Dies ist ein einfacher Proof-of-Concept, um sicherzustellen, dass keine Daten verloren gehen.

Schließlich verwenden,

if ($ip <= $high_ip && $low_ip <= $ip) {
  echo "in range";
}

Referenz: php.net

0