2010-06-30 3 views
0

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

Моя первая мысль заключалась в том, чтобы переписать сломанную версию собственной 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(
    '[email protected]', 
    '[email protected]', 
); 

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); 
} 

выход:

23 
-52 

15 
-21 

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

UPDATE

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

12 
12 

45 
45 

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

UPDATE 2

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

+0

, поведение которых вы были полагаться на? Если это 64-битный, вы не получите этого из кода php, который вы указали, даже игнорируя возможные проблемы с подписанным/unsigned – Spudd86

+0

. Это определенно для меня 64-битная проблема. Запуск этого кода дает одинаковые результаты по моя 32-битная машина. – tplaner

+0

Предполагается, что ezmlm_hash использует 'unsigned int h = 5381;' вместо 'unsigned int h = 5381L;'. Это было исправлено в более поздних версиях PHP. то есть64-битная версия вела себя плохо ... исправление заключалось в том, чтобы всегда делать 32-битные вычисления! Так что теперь я должен подражать неправильной 64-битной версии ... –

ответ

1

попробовать это EDIT отсечение на 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

У меня нет GMP, и, хотя я уверен, что это работает, я пытаюсь не добавлять ничего к моей установке PHP, кроме прямого обновления. +1 хотя. –

+0

К сожалению, я просто попробовал, у него есть ошибка где-то .... – Spudd86

0

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

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

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

+0

Я думал, что это сделал php ord()? Что я должен делать иначе? –

+0

ОК, извините, вы, вероятно, правы, еще одна вещь, которую вы, возможно, захотите изучить, - это то, что PHP не поддерживает целые числа без знака, операции переключения ведут себя по-разному по целым числам без знака и без знака – Ivan

+0

это не сдвиг, левые сдвиги одинаковы для подписанных и unsigned values, это, вероятно, модуль – Spudd86

Смежные вопросы