Странное поведение в PHP и Apache2: разные выходные данные на разных серверах

Я испытываю разные результаты в PHP-коде, работающем в Mac и Linux.

У меня есть 2 сервера, на которых запущен следующий код:

$ltt = ((ord($str[7]) << 24) | (ord($str[8]) << 16) | (ord($str[9]) << 8) | (ord($str[10]))) / 1000000; 

Даже выходы ord(str[ ]) одинаковы:

 [7] = 254 [8] = 26 [9] = 22 [10] = 216 

Но в стеке MAMP (Mac), работающем под php 5.3.6, если изначально предполагается, что $ ltt является отрицательным числом, он возвращает 4263.12265 (неверно).

В стеке LAMP (Ubuntu), выполняющем ту же самую версию php, он вернет точное отрицательное значение -31.84465 .

Это происходит только с отрицательными номерами.

Обновить добавление. Информация:

  • Дамп var дает þØçï_Kstring(25) "þØçï_K"
  • bin2hex дает 000e1b00000000fe1a16d806e707ef0000045f0000004b0000

Для того чтобы функция включала только числовые входы, выход по- прежнему отличается :

 $ltt = (254 << 24 | 26 << 16 | 22 << 8 | 216)/ 1000000; 

4263.12265 на MAMP и -31.84465 на -31.84465

Это 32-разрядная 64-разрядная проблема.

Поскольку ваш самый старший байт составляет> 127, на 32-битной платформе это интерпретируется как отрицательное значение из-за целочисленного переполнения – устанавливается самый старший бит. На 64-битной платформе это не так.

Решение состоит в том, чтобы использовать pack() и unpack() чтобы вы могли указать, что целое число должно быть подписано. EDIT Исправлен этот пример кода. См. Edit 2

 $packed = pack('C*', ord($str[7]), ord($str[8]), ord($str[9]), ord($str[10])); $unpacked = unpack('l', $packed); $lat = current($unpacked); 

… однако вы также должны осознавать, что это не будет работать на архитектуре little-endian, потому что порядок байтов будет неправильным. Вы можете просто отменить порядок упакованных байтов, чтобы обойти это, но я просто пытаюсь обернуть голову вокруг решения для всей работы.

EDIT 2

Хорошо, мне потребовалось некоторое время, чтобы обмануть голову, но мы пришли туда, в конце:

Вам нужно сделать, если установлен самый старший бит, ИЛИ результат с номером, где минимально значимые 32 бита не установлены, а остальные. Итак, следующее работает как на 32, так и на 64 бит:

 <?php // The input bytes as ints $bytes = array(254, 26, 22, 216); // The operand to OR with at the end $op = $bytes[0] & 0x80 ? (~0 << 16) << 16 : 0; // Do the bitwise thang $lat = (($bytes[0] << 24) | ($bytes[1] << 16) | ($bytes[2] << 8) | $bytes[3]) | $op; // Convert to float for latitude $lat /= 1000000; echo $lat;