Есть функция преобразования строки IP-адреса в число, и есть функция преобразования обратно.
function ipstr2num($str)
{
$res = 0;
$str = explode(".", $str);
$res = ($str[0] << 24) + ($str[1] << 16) + ($str[2] << 8) + $str[3];
return $res;
}function ipnum2str($num)
{
$res = "";
$res .= ($num & 0xFF000000) >> 24;
$res .= ".";
$res .= ($num & 0x00FF0000) >> 16;
$res .= ".";
$res .= ($num & 0x0000FF00) >> 8;
$res .= ".";
$res .= ($num & 0x000000FF);
return $res;
}После преобразования число получается 10 десятичных разрядов и число превращается в отрицательное. Пишу его в базу с помошью форматирования sprintf("%u",ipstr2num($IP)) и значение сохраняется нормально. А проблема получается в том, что когда пытаюсь преобразовать его обратно первый октет никак не получается больше 127, соответственно остальные тоже неправильно.
Вопрос - какие возможности PHP мне использовать для работы с большими числами ?!
>Есть функция преобразования строки IP-адреса в число, и есть функция преобразования обратно.
>
>function ipstr2num($str)
>{
> $res = 0;
> $str = explode(".", $str);
> $res = ($str[0] << 24) + ($str[1] <<
>16) + ($str[2] << 8) + $str[3];
> return $res;
>}
>
>function ipnum2str($num)
>{
> $res = "";
> $res .= ($num & 0xFF000000) >> 24;
> $res .= ".";
> $res .= ($num & 0x00FF0000) >> 16;
> $res .= ".";
> $res .= ($num & 0x0000FF00) >> 8;
> $res .= ".";
> $res .= ($num & 0x000000FF);
> return $res;
>}
>
>После преобразования число получается 10 десятичных разрядов и число превращается в отрицательное.
>Пишу его в базу с помошью форматирования sprintf("%u",ipstr2num($IP)) и значение сохраняется
>нормально. А проблема получается в том, что когда пытаюсь преобразовать его
>обратно первый октет никак не получается больше 127, соответственно остальные тоже
>неправильно.
>Вопрос - какие возможности PHP мне использовать для работы с большими числами
>?!
это не столько вопрос больших чисел, сколько вопрос битовых операций.
попробуйте провести битовую операцию сдвига влево числа, большего 127 (возьмем 128) вручную (24 раза умножить на два) и с помощью битовой операции php. получите разные числа. Битовая операция php затронет знаковый разряд и получится отрицательное число (в двоичном виде получится 10101000000000000000000000000000 - неверно). умножение же даст 10000000000000000000000000000000 - верно.
см мануал по битовым операциям - Don't left shift in case it results to number longer than 32 bits.
вот тут-то и порылась собака.решение вытекает из вышеизложенного (сорри, нет времени набросать - убегаю домой).
Сделал так
function ipstr2num($str)
{
$res = 0;
$str = explode(".", $str);
$res = ($str[0] * 16777216) + ($str[1] * 65536) + ($str[2] * 256) + $str[3];
print $res;
return $res;
}
, но число получается тем же, соответственно результат никакой..
>Сделал так
>function ipstr2num($str)
>{
> $res = 0;
> $str = explode(".", $str);
> $res = ($str[0] * 16777216) + ($str[1] *
>65536) + ($str[2] * 256) + $str[3];
> print $res;
> return $res;
>}
>, но число получается тем же, соответственно результат никакой..вот так будут выглядеть функции для хранения ip в числовом виде, если учитывать единицу в знаковом разряде:
function ipstr2num($str)
{
$res = 0;
$str = explode(".", $str);
$res = ((int)$str[0] << 24) + ((int)$str[1] << 16) + ((int)$str[2] << 8) + (int)$str[3];
return $res;
}function ipnum2str($num)
{
$res = "";
$res .= (($num & 0xFF000000) >> 24)<0?(256+(($num & 0xFF000000)>>24)):(($num & 0xFF000000) >> 24);
$res .= ".";
$res .= ($num & 0x00FF0000) >> 16;
$res .= ".";
$res .= ($num & 0x0000FF00) >> 8;
$res .= ".";
$res .= ($num & 0x000000FF);
return $res;
}
Спасибо, совет частично помог, а именно число из строки стало выходить точным, но обратно........................
Я тут сижу и понимаю, что проблема в битовой операции "И".
Для примера возьмем подсеть "192.168.0.0". Набираем в виндовском калькуляторе 192, сдвигаем влево на 8, прибавляем 168, и еще сдвигаем на 16. Получается 3232235520 (это же число дает функция преобразования строки в число), в битах 11000000101010000000000000000000. После операции ($num & 0xFF000000) калькулятор показывает 3221225472, в битах 11000000000000000000000000000000, что верно, а у PHP получается 2130706432, в битах 01111111000000000000000000000000, что после сдвига вправо дает 127..
Только не могу понять как решить проблему..
>Спасибо, совет частично помог, а именно число из строки стало выходить точным,
>но обратно........................
>Я тут сижу и понимаю, что проблема в битовой операции "И".
>Для примера возьмем подсеть "192.168.0.0". Набираем в виндовском калькуляторе 192, сдвигаем влево
>на 8, прибавляем 168, и еще сдвигаем на 16. Получается 3232235520
>(это же число дает функция преобразования строки в число), в битах
>11000000101010000000000000000000. После операции ($num & 0xFF000000) калькулятор показывает 3221225472, в битах
>11000000000000000000000000000000, что верно, а у PHP получается 2130706432, в битах 01111111000000000000000000000000,
>что после сдвига вправо дает 127..
>Только не могу понять как решить проблему..Хм, а у меня нормально работает и туда и обратно. при тех функциях, что я дал, действительно получается отрицательные числа при переводе ip в число (используется знаковый разряд), но это учитывается при переводу обратно и все отрабатывает нормально.
вот, можно посмотреть здесь http://demo.xmlsapiens.org/ip.php
>Есть функция преобразования строки IP-адреса в число, и есть функция преобразования обратно.
>
>function ipstr2num($str)
>{
> $res = 0;
> $str = explode(".", $str);
> $res = ($str[0] << 24) + ($str[1] <<
>16) + ($str[2] << 8) + $str[3];
> return $res;
>}
>
>function ipnum2str($num)
>{
> $res = "";
> $res .= ($num & 0xFF000000) >> 24;
> $res .= ".";
> $res .= ($num & 0x00FF0000) >> 16;
> $res .= ".";
> $res .= ($num & 0x0000FF00) >> 8;
> $res .= ".";
> $res .= ($num & 0x000000FF);
> return $res;
>}
>
>После преобразования число получается 10 десятичных разрядов и число превращается в отрицательное.
>Пишу его в базу с помошью форматирования sprintf("%u",ipstr2num($IP)) и значение сохраняется
>нормально. А проблема получается в том, что когда пытаюсь преобразовать его
>обратно первый октет никак не получается больше 127, соответственно остальные тоже
>неправильно.
>Вопрос - какие возможности PHP мне использовать для работы с большими числами
>?!
а http://ru2.php.net/ip2long не подойдет?
Спасибо всем за помощь!!! Я нашел решение!!!
Заглянул в исходники на Перле и понял, что эта проблема не только у РНР!.
Число у меня извлекалось из базы данных и сразу передавалось функции - ipnum2str($res["IP"]). Когда я проверил число в массиве, то обнаружил, что уже в нём обрезан крайний бит. В Перле, при каждом вызове функции, сделано сложение с нулем - ipstr2num($ip)+0.
Теперь я делаю так $res["IP"] += 0 и всё работает!!
Поздравляю всех и себя =)