Php check private ip address

...my 5 cents:

IMHO the underlying question is just "how to check if an IP address belongs to a network?".

The answer is simple binary: IP_address AND network_mask EQUALS network_address.

For example, Does IP address 10.1.2.3 belongs to network 10.0.0.0 with netmask 255.0.0.0? 10.1.2.3 & 255.0.0.0 is 10.0.0.0, so the answer is: yes it does.

Easier to see it in binary:

  00001010 00000001 00000010 00000011 ( 10.1.2.3) ip address
& 11111111 00000000 00000000 00000000 (255.0.0.0) network mask
= 00001010 00000000 00000000 00000000 ( 10.0.0.0) network address

Just need to check that for the netwoks you need (including or not loopback, link-local, etc. ):

function _isPrivate($long_ip) {
    return ( ($long_ip & 0xFF000000) === 0x0A000000 ) || //Private A network: 00001010 ....
           ( ($long_ip & 0xFFF00000) === 0xAC100000 ) || //Private B network: 10101100 0001....
           ( ($long_ip & 0xFFFF0000) === 0xC0A80000 ) || //Private C network: 11000000 10101000 ....
           //Link-local and loopback are NOT private range, so the function in the question yield right results to "is in private range?". Seems it was not the desired behaviour... Those cases can also be checked:
           ( ($long_ip & 0xFFFF0000) === 0xA9FE0000 ) || //Link-local       : 10101001 11111110 ....
           ( ($long_ip & 0xFFFF0000) === 0x7F000000 ) || //Loopback         : 01111111 ....
         //...and add all the fancy networks that you want...
           ( ($long_ip & 0xFFFFFF00) === 0xC0AF3000 ) || //Direct Delegation AS112 Service 192.175.48.0/24...
           ( ($long_ip & 0xF0000000) === 0xF0000000 ); //Reserved 240.0.0.0/4
}

The interesting point is the negation of the returned value. The returned value does not really means that the given IP is in a private network, but it's negation does really means that the given IP is a "public IP address" (a common/normal IP address) as the solution by user4880112 makes clear.

IPv6

The same works for IPv6. The "private network" adresses (formally "Unique-Local", RFC 4193 ) are "fc00::/7". So, ip_address & 0xFE00.. === 0xFC00.. is "private network"

Adopting the mentioned answer and including up-to-date information from IANA...

http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml

...we can make a bit more general function like this:

function isPublicAddress($ip) {
  // returns false on failure.
  // negative if it's a private or special address (-4:IPv4, -16:IPv6)
  // positive if it's a common IP public address (4:IPv4, 16:IPv6)

  $networks = array(
    '4' => array('0.0.0.0/8',
      '10.0.0.0/8',
      '100.64.0.0/10',
      '127.0.0.0/8',
      '169.254.0.0/16',
      '172.16.0.0/12',
      '192.0.0.0/24',
      '192.0.0.0/29',
      '192.0.0.8/32',
      '192.0.0.9/32',
      '192.0.0.170/32',
      '192.0.0.170/32',
      '192.0.2.0/24',
      '192.31.196.0/24',
      '192.52.193.0/24',
      '192.88.99.0/24',
      '192.168.0.0/16',
      '192.175.48.0/24',
      '198.18.0.0/15',
      '198.51.100.0/24',
      '203.0.113.0/24',
      '240.0.0.0/4',
      '255.255.255.255/32')
    ,
    '16' => array('::1/128',
      '::/128',
      '::ffff:0:0/96',
      '64:ff9b::/96',
      '100::/64',
      '2001::/23',
      '2001::/32',
      '2001:1::1/128',
      '2001:2::/48',
      '2001:3::/32',
      '2001:4:112::/48',
      '2001:5::/32',
      '2001:10::/28',
      '2001:20::/28',
      '2001:db8::/32',
      '2002::/16',
      '2620:4f:8000::/48',
      'fc00::/7',
      'fe80::/10') 
    );

    $ip = inet_pton($ip);
    if( $ip === false ) return false;

    $space='16';
    if (strlen($ip) === 4) { 
      $space='4';
    }

    //Is the IP in a private or special range?
    foreach($networks[$space] as $network) {
      //split $network in address and mask
      $parts=explode('/',$network);
      $network_address = inet_pton($parts[0]);
      $network_mask    = inet_pton( _mask( $ip , $parts[1] ) );
      if (($ip & $network_mask) === $network_address){
        return -1*$space;
      }
    }
    //Success!
    return $space;
}

function _mask($ip,$nbits){
  $mask='';
  $nibble=array('0','8','C','E');
  $f_s= $nbits >> 2 ;
  if( $f_s > 0 ) $mask.=str_repeat('F',$f_s);
  if( $nbits % 4 ) $mask.= $nibble[$nbits % 4];
  if( strlen($ip) === 4 ){
    if( strlen($mask) < 8 ) $mask.=str_repeat('0', 8 - strlen($mask) );
    long2ip('0x'.$mask);
    $mask=long2ip('0x'.$mask);
  }else{
    if( strlen($mask) < 32 ) $mask.=str_repeat('0', 32 - strlen($mask) );
    $mask=rtrim(chunk_split($mask,4,':'),':');
  }
  return $mask;
}

What I'm wondering now is: an IPv6 address in "IPv4-mapped Address" is a "special" address in IPv6 even if it was a "normal" ip address in IPv4. Should we consider "private use" the subnets in ::ffff:0:0/96 that match IPv4 private use networks?

EDIT to explain the last coment:

The IPv6 network ::ffff:0:0/96 maps to an IPv6 address every IPv4 address. Those IPv6 address are in a single set in the IANA registry ("Special-Purpose"), but the mapped IPv4 address are in all kind of sets in IPv4 (private netwok, loopback, broadcast, public... ) A "common IPv4 address" is always a "special IPv6 address". If we set up a network using IPv6 address in ::ffff:0:0/96 range that match IPv4 private networks... Are we using a private network address?

How do I know if my IP address is private?

An IP address is considered private if the number falls within one of the IP address ranges reserved for private networks such as a Local Area Network (LAN)..
Class A — 10.0. 0.0 — 10.255. 255.255 (16,777,216 total hosts).
Class B — 172.16. 0.0 — 172.31. ... .
Class C — 192.168. 0.0 — 192.168..

How validate IP in PHP?

The FILTER_VALIDATE_IP filter validates an IP address. Possible flags: FILTER_FLAG_IPV4 - The value must be a valid IPv4 address. FILTER_FLAG_IPV6 - The value must be a valid IPv6 address.

Can you trace a private IP address?

Can I Track Someone's IP Address? Yes. As long as the device is on, connected to yours and doesn't have a proxy server or VPN obscuring it, you can track the IP address. If you want to find the IP of a device you're connected to, you can use the “netstat -an” command in the command prompt.

How do I find my localhost IP in PHP?

The simplest way to collect the visitor IP address in PHP is the REMOTE_ADDR. Pass the 'REMOTE_ADDR' in PHP $_SERVER variable. It will return the IP address of the visitor who is currently viewing the webpage.