0

我有一个 MySQL 数据库,其中包含一些 Murmur2 哈希(作为无符号 64 位整数),这些哈希是由 Percona UDF 生成的,该 UDF 附带 MySQL 数据库的 Percona 链,可在此处找到https://github.com/percona/build-test/ blob/master/plugin/percona-udf/murmur_udf.cc

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

我尝试过的事情:

  1. 将 Percona UDF 中的 C++ 函数复制到我最初生成 32 位 int 散列https://github.com/StirlingMarketingGroup/php_murmurhash的 PHP 扩展的分叉版本中。这几乎可以工作,就像在它编译时一样,但是当我在 PHP 中执行函数时,apache 服务器会因段错误而崩溃,而且我对 C++ 和 PHP 扩展还不够熟悉,无法调试它

段错误是由我运行此函数引起的

var_dump(murmurhash('Hello World'));

当我下载https://github.com/kibae/php_murmurhash(原始,32 位,散列生成扩展)并按照说明操作时,它工作正常,但是一旦我替换了函数(仅在 MurmurHash2.cpp 文件中编辑为https ://github.com/StirlingMarketingGroup/php_murmurhash/blob/master/MurmurHash2.cpp)相同的函数调用使 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 输出相匹配。

有什么东西可以用我以前的两种方法中的任何一种来解决,或者我可以使用一种已经有效的方法吗?

4

1 回答 1

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

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

于 2018-07-25T21:43:39.320 回答