Unsigned int для подписания в php

Похоже, что в 32-битной ОС ip2long возвращает подписанный int, а в 64-битной ОС возвращается unsigned int.

Мое приложение работает на 10 серверах, а некоторые из них 32 бит, а некоторые из них 64 бит, поэтому мне нужно, чтобы все они работали одинаково.

В документации PHP есть трюк, чтобы сделать этот результат всегда неподписанным, но поскольку я получил свою базу данных, уже заполненную данными, я хочу, чтобы она была подписана.

Итак, как изменить unsigned int в подписанный в PHP?

PHP не поддерживает целые числа без знака как тип, но то, что вы можете сделать, просто превратить результат ip2long в строку unsigned int, если sprintf интерпретирует значение как unsigned с %u :

  $ip="128.1.2.3"; $signed=ip2long($ip); // -2147417597 in this example $unsigned=sprintf("%u", $signed); // 2147549699 in this example 

Edit, так как вы действительно хотели, чтобы его подписали даже на 64-битных системах – вот как вы конвертируете значение 64 бит + ve в 32-разрядный эквивалент:

 $ip = ip2long($ip); if (PHP_INT_SIZE == 8) { if ($ip>0x7FFFFFFF) { $ip-=0x100000000; } } 

Fwiw, если вы используете MySQL, это обычно намного проще и чище, если вы просто передаете IP-адреса в виде строк в базу данных и позволяете MySQL делать преобразование с использованием INET_ATON () (при INSERTING / UPDAT (E)) и INET_NTOA () (при выборе). У MySQL нет каких-либо проблем, описанных здесь.

Примеры:

 SELECT INET_NTOA(ip_column) FROM t; INSERT INTO t (ip_column) VALUES (INET_ATON('10.0.0.1')); 

Запросы также более читабельны.

Обратите внимание, что вы не можете смешивать INET_NTOA () / INET_ATON () в MySQL с ip2long () / long2ip () в PHP, поскольку MySQL использует тип данных INT UNSIGNED, в то время как PHP использует целое число со знаком. Смешивание целых чисел с подписью и без знака серьезно испортит ваши данные!

интерпретируя целочисленное значение как подписанное int в 32 и 64-битных системах:

 function signedint32($value) { $i = (int)$value; if (PHP_INT_SIZE > 4) // eg php 64bit if($i & 0x80000000) // is negative return $i - 0x100000000; return $i; } 

-Понятая проблема, см. Ответ Пола Диксона выше.


64-битные целые числа без знака технически не поддерживаются в PHP5. Он будет использовать собственный тип. Чтобы преобразовать в 32-битный подписанный int из 64-битного подписанного int, не теряя высокий бит, вы можете замаскировать и затем набрать команду output:

 $ip_int = ip2long($ip); if (PHP_INT_SIZE == 8) // 64bit native { $temp_int = (int)(0x7FFFFFFF & $ip_int); $temp_int |= (int)(0x80000000 & ($ip_int >> 32)); $ip_int = $temp_int; } 

В 64-битной системе печать этого значения ($ ip_int) отобразит целое число без знака, так как мы удалили высокий бит. Однако это должно позволить вам делать вывод и хранить его, как вы пожелаете.