3

我的任务是将某人用 perl 制作的 crypt 函数转换为 php 代码。一切正常,除了这个:

珀尔:

$wert = Encode::encode( "utf8", $wert );
$len=length $wert;
$pad = ($len % 16)?"0".chr(16 - ($len % 16)):"10";
$fuell = pack( "H*", $pad x (16 - $len % 16));

PHP:

$wert = utf8_encode($wert);
$len = mb_strlen($wert);
$pad = ( $len%16 ) ? '0'.chr(16 - ($len%16)) : '10';
$fuell = pack("H*", str_repeat($pad, (16 - $len % 16)));

php 版本适用于某些字符串。但是当我有类似“2010-01-01T00:00:00.000”的东西时,perl 版本可以正常工作,并且 php 版本会打印“PHP 警告:pack():H 型:非法十六进制数字”。

如果有人能在 php 版本中发现错误,我将不胜感激。

编辑:

这是我必须转换为 php.ini 的完整功能。它是由一家不再为我们工作的公司的程序员制作的,所以我无法真正说出最初的意图是什么。

sub crypt
{
    my $self = shift;
    my ($wert,$pw)= @_;
    $wert = Encode::encode( "utf8", $wert );
    $pw = Encode::encode( "utf8", $pw );
    $len=length $wert;
    $pad = ($len % 16)?"0".chr(16 - ($len % 16)):"10";
    $fuell = pack( "H*", $pad  x (16 - $len % 16));
    $wert=$wert.$fuell;
    $lenpw=length $pw;
    $fuell = ($lenpw % 16)? pack ("H*", "00" x (16 - $lenpw % 16)):"";
    $pw=$pw.$fuell;
    $cipher = new Crypt::Rijndael $pw, Crypt::Rijndael::MODE_CBC;
    $cipher->set_iv($pw);
    $crypted = encode_base64($cipher->encrypt($wert),"");

    return $crypted;
}
4

2 回答 2

7

看起来错误实际上存在于两个版本中。格式代码H查找一个十六进制数字,并且如 PHP 错误中所述,它没有找到(合法的)一个。罪魁祸首似乎是这个表达式:

chr(16 - ($len % 16))

Perl 版本没有抱怨,因为 Perl 版本的 pack 将转换字符,无论它是否是十六进制数字(这可能不是您想要的)。该文档更详细地介绍了实际发生的情况。

为防止该错误,请尝试以下操作:

sprintf('%x', 16 - ($len % 16))

注意:虽然这应该可以解决您遇到的错误,但我不知道这是否是一个可接受的解决方案,因为我不知道 Perl 代码的原始作者的确切意图。

于 2009-11-23T18:37:45.123 回答
6

似乎 Perl 的实现pack()可以容忍输入字符串中的无效十六进制数字,而 PHP 版本显然不能。

考虑:

print pack("H*", "ZZ");

这会在 Perl 中打印3(出于某种原因),但会导致您在 PHP 中提到的错误。

我不确定 Perl 究竟对这些“数字”做了什么,但它绝对与 PHP 不同。

编辑:看起来,Perl 实际上会将十六进制数字域向前“滚动”到字符集中。那是:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ  #-- Give this to Perl...
0123456789ABCDEF0123456789ABCDEF0123  #-- .. and it's treated as this hex digit

因此,“ZZ”与“33”相同,这就是它打印的原因3。请注意,根据文档,此行为未明确定义。因此,Perl 中的原始实现可以被认为是错误的,因为它依赖于未明确定义的行为。

于 2009-11-23T18:33:21.217 回答