php: ip2long возвращает отрицательное значение - PullRequest
15 голосов
/ 17 июня 2010
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);
     }
}

эта функция выполняет тот же код, что и связанная с php функция ip2long.однако, когда я печатаю эти 2 значения, я получаю 2 разных результата.Зачем?(я использую php 5.2.10 в среде wamp).

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

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

Применяется и продолжает здесь: Показ моей страны на основе моего IP, mysql оптимизирован

Ответы [ 6 ]

32 голосов
/ 17 июня 2010

Попробуйте вместо этого:

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

sprintf запишет его как целое число без знака.

9 голосов
/ 17 июня 2010
glopes@nebm:~$ php -r "printf('%u', -931792879);"
3363174417

Вот, пожалуйста.Я предполагаю, что вы находитесь в системе с 32-разрядными целыми числами, и ваш ip_address_to_number фактически возвращает число с плавающей запятой.

Вы видите, что с 32-разрядными целыми числами ваше максимальное положительное целое число равно (2^31) - 1 = 2 147 483 647, поэтомуцелое число оборачивается.

Если вы хотите имитировать поведение функции PHP, выполните:

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

(кстати, split устарело)

6 голосов
/ 17 июня 2010
  $ips[3]                             = 17
+ $ips[2] * 256 = 248 * 256           = 63488
+ $ips[1] * 65536 = 117 * 65536       = 7667712
+ $ips[0] * 16777216 = 200 * 16777216 = 3355443200
                                      = 3363174417

Макс. Целое значение PHP (32-разрядное): 2147483647, что <3363174417 </p>

Цитирование со страницы руководства PHP ip2long ()

Примечание: поскольку целочисленный тип PHP подписан, и многие IP-адреса будут результат в отрицательные целые числа, вам нужно использовать "% u" форматер sprintf () или printf () чтобы получить строку представление неподписанного IP адрес.

1 голос
/ 08 апреля 2013

Вы можете использовать -

// 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))); 
}
0 голосов
/ 23 июня 2015

Были ли некоторые тесты производительности для сравнения: от ip2long до sprintf против взрыва массива и затем временного или побитового сдвига:

<?php
    header ('Content-Type: text/plain');

    function ip_range($start, $count) {
        $start = ip2long($start);
        return array_map('long2ip', range($start, $start + $count) );
    }

    $iterations = 500000;
    $results = array();
    $ips = ip_range('192.168.1.1', $iterations);
    $time = microtime(true);
    foreach ($ips as $ip) {
        $result = sprintf('%u', ip2long($ip));
    }
    $time = microtime(true) - $time;
    $results['ip2long'] = array ('total' => $time, 'cycles' => $iterations, 'average' => ($time / $iterations) . 's', 'speed' => ($iterations/$time) . ' hashes per second.' );

    $time = microtime(true);
    foreach ($ips as $ip) {
        $aIp = explode('.', $ip);
        if (count($aIp) == 4) {
            $result = /*sprintf('%u',*/ $aIp[0]*16777216 + $aIp[1]*65536 + $aIp[2]*256 + $aIp[3] /*)*/;
        }
        else
        {
            $result = false;
        }
    }
    $time = microtime(true) - $time;
    $results['explode multiple'] = array ('total' => $time, 'cycles' => $iterations, 'average' => ($time / $iterations) . 's', 'speed' => ($iterations/$time) . ' hashes per second.' );

    $time = microtime(true);
    foreach ($ips as $ip) {
        $aIp = explode('.', $ip);
        if (count($aIp) == 4) {
            $result = /*sprintf('%u',*/ $aIp[3] | $aIp[2] << 8 | $aIp[1] << 16 | $aIp[0] << 24 /*)*/;
        }
        else
        {
            $result = false;
        }
    }
    $time = microtime(true) - $time;
    $results['explode bitwise'] = array ('total' => $time, 'cycles' => $iterations, 'average' => ($time / $iterations) . 's', 'speed' => ($iterations/$time) . ' hashes per second.' );


    die(var_dump($results));

Вот результаты:

array(3) {


["ip2long"]=>
  array(4) {
    ["total"]=>
    float(0.92530012130737)
    ["cycles"]=>
    int(500000)
    ["average"]=>
    string(19) "1.8506002426147E-6s"
    ["speed"]=>
    string(34) "540365.21609177 hashes per second."
  }
  ["explode multiple"]=>
  array(4) {
    ["total"]=>
    float(0.91870212554932)
    ["cycles"]=>
    int(500000)
    ["average"]=>
    string(19) "1.8374042510986E-6s"
    ["speed"]=>
    string(34) "544246.04678153 hashes per second."
  }
  ["explode bitwise"]=>
  array(4) {
    ["total"]=>
    float(0.9184091091156)
    ["cycles"]=>
    int(500000)
    ["average"]=>
    string(19) "1.8368182182312E-6s"
    ["speed"]=>
    string(34) "544419.68730197 hashes per second."
  }
}

При обтекании поразрядным и умножением на sprintf они медленнее, чем ip2long, но поскольку это не нужно, они быстрее.

0 голосов
/ 29 декабря 2014
<?php
function _ip2long($input)
{
    $r = null;
    if (is_string($input))
    {
        $_input = trim($input);
        if (filter_var($_input, FILTER_VALIDATE_IP))
        {
            $PRE_r = explode('.', $_input);
            $r = ($PRE_r[0] * pow(256, 3)) + ($PRE_r[1] * pow(256, 2)) + ($PRE_r[2] * 256) + ($PRE_r[0]);
        } else
        { 
            $r = false;
        }
    } else
    {
        $r = false;
    }
    return ($r);
}
$out = _ip2long('127.0.0.1');
if (false === $out)
{
  print('Invalid IP');
} else
{
  print($out);
}
?>
...