PHP - unpack() uint8_t and uint16_t

2k views Asked by At

This is my first question here - so I apologize in advance for any errors.

I currently work on a project, which includes a C++ program, communicating with a web server running PHP.

I've used PHP's unpack/pack many times, but always with whole bytes, and usually float and int32, and padded strings. But now, to save some bandwidth, we've decided to "compress" the output from C to smaller integers.

Here is my problem:

The data PHP gets from C, looks roughly like this (that 1 byte):

(uint8_t)hc.OnOff << 1
| (uint8_t)hc.No1 << 2
| (uint8_t)hc.No2 << 3
| (uint8_t)hc.No3 << 4
| (uint8_t)hc.No4 << 5
| (uint16_t)hc.No5 << 6;

I've tried to unpack this in many ways. But I don't get proper results. And I know I am just plane stupid when it comes to bits. :)

The closest I've gotten is using something like this:

$bit = unpack('C*', $bit);
$bit = $bit['1'];
$bin = decbin(ord($bit));
$bin = str_pad($bin, 8, 0, STR_PAD_LEFT);

But It's still not the expected result.

Has anyone got some other tips?

And I do apologize for my poor binary knowledge, I do know I have to read some more up on this topic.

2

There are 2 answers

1
Alnitak On BEST ANSWER

Assuming that each value is just a single bit boolean, and without expensive string operations:

$val = ord($bit);

$OnOff = (bool)($val & (1 << 1));
$No1   = (bool)($val & (1 << 2));
... etc

I note that you're apparently not using bit zero?

0
axiac On

pack()/unpack() should be the way to go but I have a different PHP approach that works well: produce the binary representation of the packed value as string, split it in characters (each character will be either 0 or 1), put them in the appropriate variables:

list($No5, $No4, $No3, $No2, $No1, $OnOff, $ignore) =       
    str_split(
        decbin($bit)
    );

Each variable will receive one bit. The last variable ($ignore) receives the value you (did not) put on bit 0 in the pack in the C code.