преобразование хеширующей функции C в PHP: ezmlm_hash - PullRequest
0 голосов
/ 30 июня 2010

Я пытаюсь обновить PHP 5.2.x до 5.3.2 на моем сервере.Проблема в том, что я опираюсь на неработающую реализацию PHP-функции ezmlm_hash () (ошибка описана здесь: http://bugs.php.net/bug.php?id=47969).

Моей первой мыслью было переписать сломанную версию нативной функции PHP(который написан на C) сам на PHP и использую его в своем коде, вместо изменения исходного кода PHP и необходимости компилировать PHP из исходного кода.

Вот версия кода на C:

PHP_FUNCTION(ezmlm_hash)
{
    char *str = NULL;
    unsigned int h = 5381L;
    int j, str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
                              &str, &str_len) == FAILURE) {
        return;
    }

    for (j = 0; j < str_len; j++) {
        h = (h + (h << 5)) ^ (unsigned long) (unsigned char) tolower(str[j]);
    }

    h = (h % 53);

    RETURN_LONG((int) h);
}

вот что я написал в PHP:

function ezmlm_hash_mine($email_address){
    $h = 5381;
    $email_length = strlen($email_address);
    for($x=0;$x<$email_length;$x++){
        $chr = strtolower($email_address[$x]);
        $h = ($h + ($h << 5)) ^ ( ord($chr) );
    }

    $h = $h % 53;
    return $h;
}

Я использую 64-битную машину. Две функции выдают разные результаты:

$email_addresses = array(
    'test@example.com',
    'mike@example.com',
);

print('<PRE>');

foreach($email_addresses as $email_address){
    print(ezmlm_hash($email_address).PHP_EOL);
    print(ezmlm_hash_mine($email_address).PHP_EOL.PHP_EOL);
}

output:

23
-52

15
-21

Я знаю, что у меня, возможно, есть проблемы с точностью или типизацией, но я просто не знаю, как это исправить. Любая помощь будет принята с благодарностью!

ОБНОВЛЕНИЕ

Когда я запускаю код на 32-битных машинах, они оба выводят новые исправленные значения:

12
12

45
45

Я думаю, это как-то связано с оператором по модулю... кто-нибудь знает PHP эквивалент оператора C по модулю?% в PHP bПо-разному!

ОБНОВЛЕНИЕ 2

Кажется, что это невозможно с ванильным PHP, так как его арифметика с плавающей запятой не имеет достаточной точности, и странность в,Я должен установить либо BCMath, либо GMP.Спасибо всем за понимание.

Ответы [ 2 ]

1 голос
/ 30 июня 2010

попробуйте это РЕДАКТИРОВАТЬ до 32 бит после вычисления:

function ezmlm_hash_mine($email_address){
    $h = gmp_init(5381);
    $d = gmp_setbit(0, 64);
    $d32 = gmp_setbit(0, 32);
    $email_length = strlen($email_address);

    $chr = strtolower($email_address);

    for($x=0;$x<$email_length;$x++){    
        $h = gmp_mod(gmp_xor(gmp_mod(gmp_add($h, gmp_mod(gmp_mul($h, "32"), $d)), $d), ord($chr[$x])), $d32);
    }

    $h = gmp_mod($h, 53);
    return gmp_intval($h);
}
0 голосов
/ 30 июня 2010

Проблема, вероятно, в этой строке $ h = ($ h + ($ h << 5)) ^ (ord ($ chr)); </p>

В C перед применением xor один символ приводится к длине 4 байта. Хотя я не уверен, что возвращает тип ord, попробуйте разбить выражение на меньшее выражение и проверить, ведут ли они себя одинаково в C и PHP

подобно h + (h << 5) должно вести себя одинаково в C и PHP для каждого h. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...