PHP Pack: 数据类型问题和结果验证问题

3

我是PHP的初学者,我的任务是构建一些命令,这些命令将被发送到一个设备上。我使用的是OSX和PHP 5.5.3.8版本。 为了创建二进制数据,我使用了“pack”函数。以下是我的代码示例:

<?php
$in_1 = 0x3100;
$in_2 = 0031;
echo "Inputs: " . $in_1 . "\t" . $in_2;
$bin = pack("v*", $in_1, $in_2);
echo "\nlength: ". strlen($bin);
printf ("\npacked result: %x \n",$bin);
printf("HEX result %h\n", $bin);
file_put_contents("ausgabe.log", $bin, FILE_APPEND);
?>

我的终端输出为:
Inputs: 12544   25
length: 4
packed result: 0 
HEX result 

我对$in_2的数值25感到困惑。

如果我将0x0031分配给$in_2,那么结果是49。

这里有什么问题吗?

顺带一提:我的最终目标是构建二进制命令,它们在以下方案中恰好占用12个字节(每行作为注释的十进制值):

function set_routing_item ($in_ch, $out_ch, $on_off, $seq)
{
    $command = toggle_two_bytes(37);    // 37 --> 0x2500
    $status = 0x0000;                   // 0 --> 0x0000
    $pos = 4;                           // 4= route item
    $channel_1 = $in_ch;                // 3
    $channel_2 = $out_ch;               // 6
    $preset_no = 0xff;                  // 255
    $value = $on_off;                   // 33145
    $seq = $seq;                        // 35
    // implement building of command using pack here
}

在这种情况下,结果(十六进制)应该是:25 00 00 00 04 03 06 FF 79 81 23 00。
谢谢!

好的,第一件事解决了。PHP将带有前导零的数字解释为八进制数。因此,$a = 0123; 相当于83十进制。示例在这里找到:http://php.net/manual/de/language.types.integer.php - Stefatronik
你能否发布更多关于“toggle_two_bytes”的信息? - alistaircol
当然。虽然我学过使用正确的修饰符“v”在pack()中,但这已经不再必要了... // 切换两个字节的短变量的高低位 function toggle_two_bytes($two_bytes) { $two_bytes = $two_bytes&0xffff; // 限制大小为2个字节 $high =($two_bytes << 8); // 位移 $low =($two_bytes >> 8); $ret =($high | $low); // 或 $ret = $ret&0xffff; // 再次限制为两个字节 return($ret); } - Stefatronik
2个回答

1
我想到了这个方法,但这不是最好的方法,适当的位运算会更快。
我正在使用 sprintf%x 格式说明符将值转换为十六进制值。

每个转换说明符都由百分号(%)组成。

你会看到我使用了 %02x%04x
  • 0 - 在左侧用零填充数字
  • 24 - 宽度,要打印的最小字符数。
  • x - 十六进制说明符,使用 X 代表大写字母。
代码:
<?php
function toggle_two_bytes ($two_bytes)
{
    $two_bytes = $two_bytes & 0xffff;   // limit size to 2 Bytes
    $high = ($two_bytes << 8);          // bit shift
    $low = ($two_bytes >> 8);
    $ret = ($high | $low);              // OR
    $ret = $ret & 0xffff;               // limit (again) to two bytes
    return ($ret);
}


function set_routing_item ($in_ch, $out_ch, $on_off, $seq)
{
    $str  = '';
    $command = toggle_two_bytes(37);
    $str .= sprintf('%04X', $command);

    $status = 0x0000;
    $str .= sprintf('%04X', $status);

    $pos = 4;
    $str .= sprintf('%02X', $pos);

    $str .= sprintf('%02X', $in_ch);

    $str .= sprintf('%02X', $out_ch);

    $preset_no = 0xFF;
    $str .= sprintf('%02X', $preset_no);

    $value = toggle_two_bytes($on_off);
    $str .= sprintf('%04X', $value);

    $seq = toggle_two_bytes($seq);
    $str .= sprintf('%04X', $seq);

    for ($i = 0; $i < strlen($str) - 1; $i += 2) {
      echo $str[$i] . $str[$i+1] . ' ';
    }
}

echo set_routing_item(3, 6, 33145, 35) . PHP_EOL;

输出:

25 00 00 00 04 03 06 FF 79 81 23 00

演示:https://eval.in/793695


谢谢您的启发。我终于让pack()起作用了。其中“魔法”在这里: return pack("vvCCCCvv", $command, $status, $type, $ch, $out_ch, $preset, $value, $seq); 为了查看我的结果,我在二进制字符串上使用了bin2hex()。 干杯!Stefan。 - Stefatronik
顺便说一句,我用Wireshark检查了通过UDP发送的字符串,一切都完美无缺。 - Stefatronik

0

对不起,我的回答格式不好。 这是您要求的代码:

// toggle higher and lower byte of a two-byte short variable
function toggle_two_bytes ($two_bytes)`

{
    $two_bytes = $two_bytes & 0xffff; // limit size to 2 Bytes
    $high = ($two_bytes << 8);          // bit shift
    $low = ($two_bytes >> 8);
    $ret = ($high | $low);              // OR
    $ret = $ret & 0xffff;               // limit (again) to two bytes
    return ($ret);
}

我发现使用pack('v',...)已经不再需要这个了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接