2015-05-27 53 views
4

我需要生成相同的由PHP生成的adler32哈希,但使用Python。不幸的是,標準實現不同。有任何想法嗎?如何在Python中獲得相同的PHP adler32哈希值?

$ php -r 'print hash("adler32", "bla") . "\n";' 
02620130 

$ python -c 'import zlib; print zlib.adler32("bla");' 
39977264 

(我使用PHP 5.5.9和Python 2.7.6)

在我使出

def php_adler32(string): 
    phpcode = """print hash("adler32", "%s");""" % string 
    try: 
     rv = subprocess.check_output(['php','-r',phpcode], shell=False) 
    except subprocess.CalledProcessError as e: 
     raise RuntimeError("Could not compute adler32 through php: %s" % e) 
    return rv 

的時刻,但恐怕要結束了對dailywtf.com與此代碼。

回答

1

簡而言之,pyton會給出十進制的結果,PHP會以十六進制給出結果。所以轉換如下:

php -r 'print hexdec(hash("adler32", "bla")) . "\n";' 

應該給你一個結果與python一致。

較長答案

阿德勒32滾動散列由一個A和B的值。 a值從1開始,並在零上的字符模65521. b值開始的值增加和對當前A值模數65521增加了,所以對於BLA我們:

Character Decimal Adler_A Adler_B 
         1  0 
     'b'  98  99  99 
     'l'  108  207 306 
     'a'  97  304 610 

所以整個字符串的最終adler32 A和B值分別爲Adler_A = 304Adler_B = 610,它們在轉換爲big-endian十六進制時爲Adler_A = 0130Adler_B = 0262。所以你可以看到PHP的散列給你一個Adler_B的後端表示,後面跟着Adler_A,01300262。將這個十六進制值轉換爲十進制給出39977264,這是你從python獲得的。

+0

謝謝!爲了將來的參考,這相當於PHP:'「%08d」%int(hex(adler32('bla'))[2:]' – Willem

1

從環顧四周,我相信PHP的實現返回不正確的值。 (https://github.com/Sembiance/mhash/issues/6

當使用PHP使用的較舊的mhash庫(現在被hash不贊成使用)進行測試時,我們可以看到與當前哈希庫相同的結果。

define('MOD_ADLER', 65521); 
// Wikipedia Implimentation for testing. 
function adler32($data) { 
    $a = 1; 
    $b = 0; 
    $len = strlen($data); 
    for ($index = 0; $index < $len; ++$index) { 
     $a = ($a + $data[$index]) % MOD_ADLER; 
     $b = ($b + $a) % MOD_ADLER; 
    } 
    return ($b << 16) | $a; 
} 
echo "programed version: " . adler32("bla") . "<br>"; 
echo "php version: " . hash("adler32", "bla") . "<br>"; 
echo "mhash version: " .bin2hex(mhash(MHASH_ADLER32, "bla")); 

最終結果變成了這樣:

programed version: 196609 (I'm not quite sure why this occured to be honest) 
php version: 02620130 
mhash version: 02620130 

我們可以看到,PHP(散)和土豆泥版本產生相同的結果,雖然在mhash函數返回一個十六進制數。

zlib python結果將被證明是最可靠的輸出。