Как сгенерировать 64-битный хэш Murmur v2 в PHP 7.2?

У меня есть база данных MySQL, в которой есть некоторые хэши Murmur2 (в виде 64-битных целых чисел без знака), которые были сгенерированы с помощью Percona UDF, который поставляется с цепочкой Percona базы данных MySQL, найденной здесь https://github.com/percona/build-test/blob/master/plugin/percona-udf/murmur_udf.cc

Моя проблема в том, что теперь мне нужно сгенерировать те же хэши на стороне PHP, но я не могу найти или настроить что-либо существующее для работы / вывода одного и того же вывода для того же ввода.

Вещи, которые я пробовал:

  1. Копирование функции C++ из Percona UDF в мою разветвленную версию этого расширения 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 на https://github.com/StirlingMarketingGroup/php_murmurhash/blob/master/MurmurHash2.cpp), тот же вызов функции приведет к сбою скрипта PHP.

  1. Попытка перенести функцию Percona UDF C++ на PHP. Я не уверен, что моя функция PHP на 100% точна при попытке учесть увеличение указателя, но я подозреваю, что причина, по которой я получаю совершенно другой вывод с версией PHP, связана с тем, что PHP не поддерживает целые числа без знака.

Вот функция PHP, которую я написал как порт из функции Percona C++.

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.

Есть ли что-то, что можно исправить с помощью любого из моих предыдущих двух подходов, или, может быть, уже работающий подход, который я могу использовать вместо этого?

Порекомендуйте добавить в вопрос, как вы вызываете библиотеку C++ и что вы ей предоставляете. Некоторые умники здесь могут обнаружить, что пошло не так, и избавить от необходимости переносить алгоритм.

user4581301 25.07.2018 20:43

@ user4581301 Я добавил немного больше о том, что я сделал для этого подхода, со ссылками на исходный файл и мой обновленный файл C++.

Brian Leishman 25.07.2018 20:48

@ user4581301 Я создал собственное решение, которое сработало!

Brian Leishman 25.07.2018 23:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
3
1 024
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я сам решил эту проблему, по сути перенеся хеш-функцию 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 не поддерживает целые числа без знака.

Другие вопросы по теме