2

"B"Perl 代码中的这条pack语句做了什么?

$hce_hash=pack('B*', $hce_hash);

PHP中是否有等效的功能?

4

3 回答 3

2

pack 'B*', $s返回由 of 的字符串表示的字节01组成字符串 in 的字符$s。的值$s在必要时用零填充到可被 8 整除的长度。

例如,

pack 'B*', '0100101000110101'

结果是

chr(0b01001010) . chr(0b00110101);
于 2013-03-07T16:23:14.717 回答
2

PHPpack不支持 的格式B*,但支持H*. 在 Perl 中,你可以用

sub pack_Bstar {
  my($bits) = @_;
  my $Hstar;

  my $nybble = 0;
  for (my $i = 0; $i < length $bits; ++$i) {
    $nybble *= 2;
    $nybble += int substr($bits, $i, 1);
    if ($i % 4 == 3) {
      $Hstar .= sprintf "%x", $nybble;
      $nybble = 0;
    }
  }

  my $pad = 4 - length($bits) % 4;
  if ($pad != 4) {
    $nybble = ($nybble << $pad);
    $Hstar .= sprintf "%x", $nybble;
  }

  pack "H*", $Hstar;
}

上面的代码不是惯用的 Perl,但转换为 PHP 应该很简单。

H*格式首先需要一个具有高 nybble(4 位)的十六进制字符串。上面的代码一次咀嚼四个位来计算每个 nybble 值。例如,对于 的位串1011,跟踪算法给出

  1. nybble = 0
  2. nybble = 2 * 0 + 1 = 1
  3. nybble = 2 * 1 + 0 = 2
  4. nybble = 2 * 2 + 1 = 5
  5. nybble = 2 * 5 + 1 = 11

1011 2确实是 11 10,也就是 b 16。如果最后一个 nybble 不完整(在 1 到 3 位之间),我们将该位左移适当的位数。这具有在右侧填充零的效果。

测试:

my @tests = (
  ["01001010011101010111001101110100"                               => "Just"],
  ["0110000101101110011011110111010001101000011001010111001"        => "another"],
  ["01010000010010000101000000101111010100000110010101110010011011" => "PHP/Perl"],
  ["01101000011000010110001101101011011001010111001000101100"       => "hacker,"],
);

for (@tests) {
  my($input,$expect) = @$_;
  my $got = pack_Bstar $input;
  print "$input: ", ($got eq $expect ? "PASS" : "FAIL"), " ($got)\n";
}

输出:

01001010011101010111001101110100:通过(仅)
0110000101101110011011110111010001101000011001010111001:通过(另一个)
01010000010010000101000000101111010100000110010101110010011011:通过(PHP / Perl)
01101000011000010110001101101011011001010111001000101100:通过(黑客,)
于 2013-03-07T17:32:31.843 回答
2

正如其他人所指出的那样,PHP 的pack()不支持B模板,它在 Perl 的pack()中将一个位串(表示为01字符的文字串)转换为每个字节 8 位的压缩字节串。

然而,由于 PHP 的 pack() 确实支持H模板,除了十六进制数字而不是位之外,它的功能相同,我们可以B在 PHP 中模拟 Perl 的模板,首先使用base_convert()将位转换为十六进制数字,然后将它们打包:

function pack_B( $bits, $len = false ) {
    // truncate input to desired length, if given:
    if ( $len === false ) $len = strlen( $bits );
    else $bits = substr( $bits, 0, $len );

    // pad input with zeros to next multiple of 4 above $len:
    $hexlen = (int)( ($len + 3) / 4 );
    $bits = str_pad( $bits, 4*$hexlen, "0" );

    // split input into chunks of 4 bits, convert each to hex and pack them:
    $nibbles = str_split( $bits, 4 );
    foreach ( $nibbles as $i => $nibble ) {
        $nibbles[$i] = base_convert( $nibble, 2, 16 );
    }
    return pack( "H*", implode( "", $nibbles ) );
}

(我们不能只将整个输入字符串提供给 base_convert() 的原因是它将中间结果存储为 PHP 浮点数,因此对于太大而无法用浮点数准确表示的数字不会产生正确的结果。做但是,一次一个十六进制数字可以正常工作。)

于 2013-03-07T19:39:33.543 回答