代码之家  ›  专栏  ›  技术社区  ›  Brian Leishman

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

  •  0
  • Brian Leishman  · 技术社区  · 6 年前

    我有一个MySQL数据库,它有一些杂音2散列(作为无符号64位整数),这些散列是用Percona UDF生成的,Percona UDF来自这里的MySQL数据库的Percona串 https://github.com/percona/build-test/blob/master/plugin/percona-udf/murmur_udf.cc

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

    我尝试过的事情:

    1. 将C++函数从PrCONA UDF复制到PHP扩展的分叉版本中,最初扩展了32位int散列 https://github.com/StirlingMarketingGroup/php_murmurhash . 这几乎是有效的,就像在编译时一样,但是当我在PHP中执行这个函数时,Apache服务器崩溃了,我对C++和PHP扩展调试不够熟悉。

    segfault是由我运行这个函数引起的

    var_dump(murmurhash('Hello World'));
    

    当我下载的时候正常工作 https://github.com/kibae/php_murmurhash (原始的,32位,产生散列的扩展名)并按照说明进行操作,但是一旦我替换了函数(仅在murrushhash2.cpp文件中编辑为 https://github.com/StirlingMarketingGroup/php_murmurhash/blob/master/MurmurHash2.cpp )同一个函数调用会导致PHP脚本崩溃。

    1. 尝试将PelCONA UDF C++函数移植到PHP中。我不确定我的PHP函数是否100%准确地解释了指针递增的原因,但我更怀疑是因为PHP版本的输出与PHP不支持无符号整数有关。

    下面是我从PrCONA 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 回复  |  直到 6 年前
        1
  •  0
  •   Brian Leishman    6 年前

    我自己解决了这个问题,把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不支持无符号整数。