1

I have some strange behavior with the unpack function. I have a packed string, stored as longblob in a mysql database. When I read that string and unpack it, it gives me an array, so far so good. But when I run this on another machine some of the values in the array are different.

When I dump the data from mysql, they are equal on both machines.

Unpacking is done this way:

$array = unpack("N*", $packed); 

$array should then be like this (and it is on one machine)

Array
(
    [1]  => 179848175
    [2]  => -16214255
    [3]  => 179848175
    [4]  => -16214255
    [5]  => 179848175
    [6]  => -16214255
    [7]  => 179999949
    [8]  => -16152916
    [9]  => 179999277
    [10] => -16168574
...
)

But on the other machine it is like this:

Array
(
    [1]  => 179848175
    [2]  => 427853622
    [3]  => 179848175
    [4]  => 427853622
    [5]  => 179848175
    [6]  => 427853622
    [7]  => 179999949
    [8]  => 427853423
    [9]  => 179999277
    [10] => 427853341
...
)

Every second value seems to be different.

I have tested this on three different machines, on two everything was fine, but on that one machine I get that weird output.

One machine is running PHP 5.6.3 (here it is ok), two machines are running PHP 5.5.14 (on one it is ok, on the other not)

j08691
  • 204,283
  • 31
  • 260
  • 272
Ben
  • 21
  • 5
  • 2
    Is one machine running 32-bit PHP and the other running 64-bit PHP? – Mark Baker Jul 13 '15 at 18:16
  • 1
    not sure about this, uname -a brings me "x86_64" on both machines. Would there be a way, in case one is 32 the other is 64? – Ben Jul 13 '15 at 18:18
  • `echo PHP_INT_SIZE * 8;` – AbraCadaver Jul 13 '15 at 18:22
  • Just check the value of the constants `PHP_INT_MAX` (a value of 2147483647 indicates 32-bit) or `PHP_INT_SIZE` (a value of 4 indicates 32-bit, 8 is 64-bit) from within a PHP script... just because an operating system is 64-bit, doesn't mean that the PHP that it's running is 64-bit – Mark Baker Jul 13 '15 at 18:22
  • ok, just did it on the machines where it works, there `echo PHP_INT_SIZE` shows 4. Unfortunately I cannot check on the non working machine right now, as I have no access to it until tomorrow. In case it is 64bit PHP, is there a way to handle that? – Ben Jul 13 '15 at 18:25
  • I think there is an answer in this one: [php 64 bit with php_int_max = 2147483647][1] [1]: http://stackoverflow.com/questions/17837157/php-64-bit-with-php-int-max-2147483647 – DTH Jul 13 '15 at 18:28
  • thanks, I will try to understand that, though it seems to be vice versa. Otherwise I would try to deinstall php and install a 32bit Version (?)... – Ben Jul 13 '15 at 18:35

1 Answers1

3

The pack format N means unsigned long, which means it can't be negative. However, you are storing negative values, and they are the ones that aren't being unpacked the way you want. PHP does not have a pack format for machine-independent signed longs; it only supports packing them in machine byte order, which may not be compatible from machine to machine. Thus you'll have to make the values signed yourself.

To convert your array items into signed values:

for ($i = 1; $i <= count($array); $i++) {
    // Check for a greater-than-32-bit environment,
    // and check if the number should be negative
    // (i.e., if the high bit is set in 32-bit notation).
    if (PHP_INT_SIZE > 4 && $array[$i] & 0x80000000) {
        // A negative number was unpacked as an unsigned
        // long in a greater-than-32-bit environment.
        // Subtract the appropriate amount (max 32-bit
        // unsigned long + 1) to convert it to negative.
        $array[$i] = $array[$i] - 0x100000000;
    }
}

var_dump($array);
Lithis
  • 1,327
  • 8
  • 14