"B"
Perl 代码中的这条pack
语句做了什么?
$hce_hash=pack('B*', $hce_hash);
PHP中是否有等效的功能?
pack 'B*', $s
返回由 of 的字符串表示的字节0
和1
组成字符串 in 的字符$s
。的值$s
在必要时用零填充到可被 8 整除的长度。
例如,
pack 'B*', '0100101000110101'
结果是
chr(0b01001010) . chr(0b00110101);
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
,跟踪算法给出
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:通过(黑客,)
正如其他人所指出的那样,PHP 的pack()不支持B
模板,它在 Perl 的pack()中将一个位串(表示为0
和1
字符的文字串)转换为每个字节 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 浮点数,因此对于太大而无法用浮点数准确表示的数字不会产生正确的结果。做但是,一次一个十六进制数字可以正常工作。)