2009-12-10 35 views
6

我有一個腳本可以轉換爲基礎62(A-Za-z0-9),但是如何從MD5中獲取數字?將MD5轉換爲base62的URL

我讀過很多地方,因爲從MD5的數字大於PHP可以作爲一個整數處理它將是不準確的......因爲我想要一個簡短的URL,並沒有計劃使用整個散列,也許只是8個字符...

所以我的問題是如何獲得一部分MD5哈希的數量?

也只是使用部分MD5散列是一個壞主意?

+0

md5散列不是一個數字,那麼「部分數字」是什麼意思? – 2009-12-10 10:51:28

+5

md5是一個以base36編碼表示的數字,我認爲... – Mark 2009-12-10 10:53:37

+1

你是一半的權利,md5散列是以16爲底的數字(a-f0-9)表示的十六進制數。 – 2009-12-10 10:57:22

回答

6

我要在這裏建議一個不同的東西..既然你只是在使用md5散列的小數部分感興趣,爲什麼不使用任何其他的短數字散列如CRC32Adler?這裏是一個例子:

$hash = sprintf('%u', crc32('your string here')); 

這將產生一個8位數的字符串散列。

編輯:我想我誤解了你,here are some functions that provide conversions to and from bases up to 62

EDIT(再次):要使用任意長度的數字工作,你必須使用bc_math或GMP擴展,here is a function that uses the bc_math extension and can also convert from base 2 up to base 62。你應該使用這樣的:

echo bc_base_convert(md5('your url here'), 16, 62); // public base 62 hash 

和逆:

echo bc_base_convert('base 62 encoded value here', 62, 16); // private md5 hash 

希望它能幫助。 =)

+0

是否可以計算出什麼進入散列?只是我在想,如果我只展示過散列的一部分,它就會讓它更難以鍛鍊它是如何產生的......對嗎? – Mark 2009-12-10 11:32:35

+0

沒錯,但它不會是真正意義上的散列,也可能發生碰撞。 – 2009-12-10 11:50:15

1

你可以做到這一點是這樣的:(並非所有的步驟都在PHP中,它一直是我已經使用了很長一段時間)

只使用md5的幾個位沒有風險。所有這些變化都是碰撞的危險。

+0

不錯的鏈接,謝謝。 – 2009-12-10 11:23:34

0

你可以使用一個稍加修改基地64 -_,而不是+/

function base64_url_encode($str) { 
    return strtr(base64_encode($str), array('+'=>'-', '/'=>'_')); 
} 
function base64_url_decode($str) { 
    return base64_decode(strtr($str, array('-'=>'+', '_'=>'/'))); 
} 

此外,你可以刪除尾隨填充=字符。

而獲得的原始MD5值(二進制字符串),設置第二個參數(手冊中提及$raw_output)至

$raw_md5 = md5($str, true); 
+0

檢查此問題http://stackoverflow.com/questions/352434/base-conversion-of-arbitrary-sized-numbers-php/1743486#1743486 – 2009-12-10 11:47:22

+0

有什麼問題?爲什麼倒票? – Gumbo 2009-12-10 14:09:32

3

如果有可能,我建議不使用哈希值爲您的網址。最終你會遇到碰撞...特別是如果你截斷散列。如果你繼續實施一個基於ID的系統,每個項目都有一個唯一的ID,那麼頭痛就會少得多。第一項是1,第二項是2等---如果你使用的是MySQL,只需要輸入一個自動增量列。

作一個簡短的ID:

//the basic example 
$sid = base_convert($id, 10, 36); 

//if you're going to be needing 64 bit numbers converted 
//on a 32 bit machine, use this instead 
$sid = gmp_strval(gmp_init($id, 10), 36); 

作一個簡短的ID回基地10 ID:

//the basic example 
$id = base_convert($id, 36, 10); 

//if you're going to be needing 64 bit numbers 
//on a 32 bit machine, use this instead 
$id = gmp_strval(gmp_init($shortid, 36)); 

希望這有助於!

如果你想真正基地62(不能用gmpbase_convert來完成),檢查了這一點: http://snipplr.com/view/22246/base62-encode--decode/

+0

GMP,不錯! =) – 2009-12-10 11:22:46

+0

對不起,也許我沒有讓自己清楚,md5沒有發揮作爲一個id ...只是作爲一種方法來阻止用戶猜測下一個url ...所以url是id = 1&md5 = dsf213sfe。無論如何謝謝 – Mark 2009-12-10 11:29:54

+0

夠公平!我的錯。別介意我:) – brianreavis 2009-12-10 11:43:22

0

你可以做這樣的事情,

$hash = md5("The data to be hashed", true); 
$ints = unpack("L*num", $hash); 

$hash_str = base62($ints['num1']) . base62($ints['num2']) . base62($ints['num3']) . base62($ints['num4']) 
0

有實際上是一個你可能會提取的Java實現。這是一個名爲Pulse的開源CMS解決方案。

這裏尋找代碼toBase62()fromBase62()

http://pulse.torweg.org/javadoc/src-html/org/torweg/pulse/util/StringUtils.java.html

唯一依賴於StringUtils是生命週期類,它提供一種方式來獲得一個鹽醃哈希值,你甚至可以忽略一起或剛剛超過複製方法,以您的副本StringUtils的字符串。瞧。

0

從PHP 5.3.2起,GMP支持的基數可達62(以前只有36),所以brianreavis的建議非常接近。我認爲你的問題最簡單的答案是這樣的:

function base62hash($source, $chars = 22) { 
    return substr(gmp_strval(gmp_init(md5($source), 16), 62), 0, $chars); 
} 

從base-16轉換爲base-62顯然有空間的好處。正常的128位MD5哈希是十六進制的32個字符,但是在基數爲62的情況下它只有22個。如果將哈希存儲在數據庫中,則可以將它們轉換爲原始二進制,並節省更多空間(16字節MD5)。

由於生成的哈希值只是一個字符串表示形式,所以如果您只需要一小部分(如函數那樣)就可以使用substr。

0

你可以嘗試base62x以獲得安全和兼容的編碼表示。

Here is for more information about base62x,或簡單-base62x-NatureDNS

shell> ./base62x -n 16 -enc 16AF 
1Ql 
shell> ./base62x -n 16 -dec 1Ql 
16AF 

shell> ./base62x 
Usage: ./base62x [-v] [-n <2|8|10|16|32>] <-enc|dec> string 
Version: 0.60