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 разных результата. Зачем? (im, используя php 5.2.10 в рабочей среде).
ip2long('200.117.248.17'); //returns **-931792879** ip_address_to_number('200.117.248.17'); // returns **3363174417**
Применяется и продолжается здесь: Показывая мою страну на основе моего IP, оптимизирован mysql
glopes @ nebm: ~ $ php -r "printf ('% u', -931792879); 3363174417
Вот так. Я предполагаю, что вы находитесь в системе с 32-битными ints, и ваш ip_address_to_number
фактически возвращает float.
Вы видите, что с 32-битным ints ваше максимальное положительное целое число (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
устарел)
Попробуйте это вместо этого:
$ip = sprintf('%u', ip2long($_SERVER['REMOTE_ADDR']));
Затем sprintf записывает его как целое число без знака.
$ips[3] = 17 + $ips[2] * 256 = 248 * 256 = 63488 + $ips[1] * 65536 = 117 * 65536 = 7667712 + $ips[0] * 16777216 = 200 * 16777216 = 3355443200 = 3363174417
Максимальное целочисленное значение PHP max (32-разрядное) – 2147483647, что составляет <3363174417
Цитирование с страницы руководства ip2long () PHP
Примечание. Поскольку целочисленный тип PHP подписан, а многие IP-адреса приводят к отрицательным целым числам, вам нужно использовать форматирование «% u» sprintf () или printf (), чтобы получить строковое представление неподписанного IP-адреса.
Вы можете использовать –
// 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))); }
<?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); } ?>
ip2long
ли некоторые тесты производительности, чтобы сравнить запуск ip2long
через sprintf
vs array ip2long
а затем раз или побитовое смещение:
<?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
но поскольку они не нужны, они быстрее.