【问题标题】:PHP MD5 equivalent to JavaPHP MD5 等价于 Java
【发布时间】:2013-12-09 12:22:55
【问题描述】:

我需要一个 PHP 等效于 Java 的 MD5 功能,它接受一个字节数组并将哈希作为 16 字节数组返回。 我不需要 PHP 的 md5 函数的 Java 等效项。 问题是 PHP 的 md5 函数只接受字符串,而不接受字节数组。

这是 Java 中的预期结果:

// input byte array
// for short: 123456
final byte[] data = new byte[] { (byte) 0x12, (byte) 0x34, (byte) 0x56 };

// expected 16 hash bytes
// for short: ae1fa6209a246b8b2f2cd2d21be8f2e1
final byte[] expectedHash = new byte[] {
        (byte) 0xae, (byte) 0x1f, (byte) 0xa6, (byte) 0x20,
        (byte) 0x9a, (byte) 0x24, (byte) 0x6b, (byte) 0x8b,
        (byte) 0x2f, (byte) 0x2c, (byte) 0xd2, (byte) 0xd2,
        (byte) 0x1b, (byte) 0xe8, (byte) 0xf2, (byte) 0xe1 };

我在 PHP 中的尝试是:

<?php
// input byte array
$data = array(0x12, 0x34, 0x56);

// pack data in a string, becouse md5 can only
// compute a hash for a string
$dataString = pack('C*', $data); // is it the right way?
var_dump($dataString);

// compute the hash and get a string back
$hash = md5($dataString, true);

// expected 16 hash bytes
// for short: ae1fa6209a246b8b2f2cd2d21be8f2e1
$expected = array(
    0xae, 0x1f, 0xa6, 0x20,
    0x9a, 0x24, 0x6b, 0x8b,
    0x2f, 0x2c, 0xd2, 0xd2,
    0x1b, 0xe8, 0xf2, 0xe1);
var_dump($expected);

// convert the string back to a byte array
$actual = unpack('C*', $hash); // is it the right way?
var_dump($actual);

assert($expected == $actual);
?>

$dataString 的长度为 0。所以第一个错误必须在pack 中。但我不知道如何将任意字节数组打包成字符串。你能给我正确的format 论据吗?

【问题讨论】:

  • 您是否尝试过使用implode
  • @Chris:感谢提示,但 implode 没有返回正确的字符串:implode('', array(12, 34, 56)) 返回123456。它只将整数值转换为十进制表示并在那里连接。
  • 您确实意识到在 PHP 中,"\x12" 是一个字节,与 Java 的 0x12 含义完全相同,不是吗?所以“\x12\x34\x56”是字节数组,也是字符串。
  • @SirDarius:'\x12\x34\x56'的解释是什么?一个带有 3 个字符的 ascii 字符串,一个带有 1 1/2 个字符的 utf8 字符串等等?显式字节数组和字符串之间的区别在于我可以在任何位置获取和设置一个字节。我不知道字符串是否有可能在相同的位置获取和设置一个字节(解释为字符),因为字符编码不同。
  • 没有解释,只要您实际上不使用期望给定编码的字符串函数。 PHP 字符串可以包含二进制数据。来自php.net/manual/en/language.types.string.php:“字符串是一系列字符,其中一个字符与一个字节相同。”期间,没有别的了。

标签: java php md5


【解决方案1】:

我知道了:)

<?php
function javaMd5($data) {
    assert(is_array($data));

    $dataString = byteArrayToString($data);

    $hashString = md5($dataString, true);
    assert(strlen($hashString) == 16);

    $hash = stringToByteArray($hashString);

    assert(count($hash) == 16);
    return $hash;
}

function stringToByteArray($s) {
    assert(is_string($s));

    $result = array_fill(0, strlen($s), 0);
    for ($i = 0; $i < strlen($s); $i++) {
        $result[$i] = ord($s[$i]);
    }
    return $result;
}

function byteArrayToString($b) {
    assert(is_array($b));

    $asciiString = '';
    for ($i = 0; $i < count($b); $i++) {
        assert($b[$i] >= 0 && $b[$i] <= 255);
        $asciiString .= chr($b[$i]);
    }

    $utf8String = utf8_encode($asciiString);

    return $utf8String;
}

$data = array(0x12, 0x34, 0x56);

$expected = array(
    0xae, 0x1f, 0xa6, 0x20,
    0x9a, 0x24, 0x6b, 0x8b,
    0x2f, 0x2c, 0xd2, 0xd2,
    0x1b, 0xe8, 0xf2, 0xe1);

$actual = javaMd5($data);

assert($expected == $actual);
?>

我不确定字符串编码,但它可以工作。我没有解释 PHP 使用隐式 xyz 编码字符串而不是像 Java 那样的显式字节数组。手册并没有说明 char 编码。这可能是为什么在 XYZ 语言中如何计算与 PHP 等效的字符串的 md5 存在很多问题的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-27
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 2011-04-02
    • 1970-01-01
    • 2011-03-18
    相关资源
    最近更新 更多