如何在PHP 7.2中生成64位Murmur哈希v2?

时间:2018-07-25 18:35:52

标签: php c++ mysql murmurhash

我有一个MySQL数据库,该数据库具有一些Murmur2散列(作为无符号的64位整数),这些散列是通过与Percona UDF一起生成的,该数据库是在https://github.com/percona/build-test/blob/master/plugin/percona-udf/murmur_udf.cc处找到的MySQL数据库的Percona子束中的

我的问题是,现在我需要在PHP端生成这些相同的哈希,但是我似乎无法找到或调整任何现有的东西来为相同的输入工作/输出相同的输出。

我尝试过的事情:

  1. 将Percona UDF中的C ++函数复制到此PHP扩展的派生版本中,该版本最初产生32位int哈希https://github.com/StirlingMarketingGroup/php_murmurhash。这几乎可以正常工作,就像在编译时一样,但是当我在PHP中执行该功能时,apache服务器因段错误而崩溃,并且我对C ++和PHP扩展尚不熟悉,无法对其进行调试

段错误是由我运行此功能引起的

var_dump(murmurhash('Hello World'));

当我下载https://github.com/kibae/php_murmurhash(原始的32位,产生哈希的扩展名)并按照说明进行操作时,可以正常工作,但是一旦我替换了函数(仅在MurmurHash2.cpp文件中将其编辑为{{3} })相同的函数调用会使PHP脚本崩溃。

  1. 尝试将Percona UDF C ++函数移植到PHP。我不太确定我的PHP函数在尝试解决指针增加时是否100%准确,但我怀疑更多,因此我在PHP版本中获得完全不同的输出的原因与PHP不支持无符号整数有关。

这是我作为Percona C ++函数的端口编写的PHP函数

function murmurhash2(string $s) : int {
    $len = strlen($s);
    $seed = 0;

    $m = 0x5bd1e995;
    $r = 24;

    $h1 = $seed ^ $len;
    $h2 = 0;

    $i = 0;

    while ($len >= 8) {
        $k1 = ord($s[$i++]);
        $k1 *= $m; $k1 ^= $k1 >> $r; $k1 *= $m;
        $h1 *= $m; $h1 ^= $k1;
        $len -= 4;

        $k2 = ord($s[$i++]);
        $k2 *= $m; $k2 ^= $k2 >> $r; $k2 *= $m;
        $h2 *= $m; $h2 ^= $k2;
        $len -= 4;
    }

    if ($len >= 4) {
        $k1 = ord($s[$i++]);
        $k1 *= $m; $k1 ^= $k1 >> $r; $k1 *= $m;
        $h1 *= $m; $h1 ^= $k1;
        $len -= 4;
    }

    switch ($len) {
        case 3: $h2 ^= ord($s[2]) << 16;
        case 2: $h2 ^= ord($s[1]) << 8;
        case 1: $h2 ^= ord($s[0]);
                $h2 *= $m;
    };

    $h1 ^= $h2 >> 18; $h1 *= $m;
    $h2 ^= $h1 >> 22; $h2 *= $m;
    $h1 ^= $h2 >> 17; $h1 *= $m;

    $h = $h1;

    $h = ($h << 32) | $h2;
    return $h;
}

在MySQL中,我得到了

select murmur_hash('Hello World'), cast(murmur_hash('Hello World')as unsigned), CONV(cast(murmur_hash('Hello World')as unsigned), 10, 16);
-- -8846466548632298438 9600277525077253178 853B098B6B655C3A

在PHP中,我得到

var_dump(murmurhash2('Hello World'));
// int(5969224437940092928)

因此,查看MySQL和PHP结果,有符号和无符号都不匹配我的PHP输出。

我的前两种方法是否可以解决某些问题,或者可以替代使用一种已经有效的方法?

1 个答案:

答案 0 :(得分:0)

我已经通过将Percona哈希函数直接移植到PHP扩展MySQL来解决了这个问题。

安装和使用说明发布在此处https://github.com/StirlingMarketingGroup/php-murmur-hash


示例输出

在MySQL中,Percona扩展名的用法类似于

select`murmur_hash`('Yeet')
-- -7850704420789372250

在PHP中

php -r 'echo murmur_hash("Yeet");'
// -7850704420789372250

请注意,两种环境都将它们视为有符号整数,您可以使用cast(`murmur_hash`('Yeet')as unsigned)在MySQL中解决这些问题,但是PHP不支持无符号整数。