Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

php: ip2long returning negative val

Tags:

php

ip

function ip_address_to_number($IPaddress) { 
     if(!$IPaddress) {
      return false;
     } else {
      $ips = split('\.',$IPaddress);
      return($ips[3] + $ips[2]*256 + $ips[1]*65536 + $ips[0]*16777216);
     }
}

that function executes the same code as the php bundled function ip2long. however, when i print these 2 values, i get 2 different returns. why? (im using php 5.2.10 on a wamp environment).

ip2long('200.117.248.17'); //returns **-931792879**

ip_address_to_number('200.117.248.17'); // returns **3363174417**

Applied and continued here: Showing my country based on my IP, mysql optimized

like image 433
Andres SK Avatar asked Jun 17 '10 15:06

Andres SK


4 Answers

Try this instead:

$ip = sprintf('%u', ip2long($_SERVER['REMOTE_ADDR']));

sprintf will then write it as an unsigned integer.

like image 55
webbiedave Avatar answered Nov 09 '22 09:11

webbiedave


glopes@nebm:~$ php -r "printf('%u', -931792879);"
3363174417

There you go. My guess is that you are on a system with 32-bit ints and your ip_address_to_number is actually returning a float.

You see, with 32-bit ints, your maximum positive integer is (2^31) - 1 = 2 147 483 647, so the integer wraps around.

If you want to mimic the behaviour of the PHP function, do:

function ip_address_to_number($IPaddress) { 
 if(!$IPaddress) {
  return false;
 } else {
  $ips = split('\.',$IPaddress);
  return($ips[3] | $ips[2] << 8 | $ips[1] << 16 | $ips[0] << 24);
 }
}

(by the way, split has been deprecated)

like image 32
Artefacto Avatar answered Nov 09 '22 09:11

Artefacto


  $ips[3]                             = 17
+ $ips[2] * 256 = 248 * 256           = 63488
+ $ips[1] * 65536 = 117 * 65536       = 7667712
+ $ips[0] * 16777216 = 200 * 16777216 = 3355443200
                                      = 3363174417

PHP max integer value (32-bit) is 2147483647, which is < 3363174417

Quoting from the ip2long() PHP manual page

Note: Because PHP's integer type is signed, and many IP addresses will result in negative integers, you need to use the "%u" formatter of sprintf() or printf() to get the string representation of the unsigned IP address.

like image 6
Mark Baker Avatar answered Nov 09 '22 09:11

Mark Baker


You can use -

// IP Address to Number
function inet_aton($ip)
{
    $ip = trim($ip);
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return 0;
    return sprintf("%u", ip2long($ip));  
}

// Number to IP Address
function inet_ntoa($num)
{
    $num = trim($num);
    if ($num == "0") return "0.0.0.0";
    return long2ip(-(4294967295 - ($num - 1))); 
}
like image 1
user2253362 Avatar answered Nov 09 '22 11:11

user2253362