mydomain.com/show/?id=sf32JFSVANMfaskjfh
通常我只是產生一個25個字符的隨機字符串,並以這種方式訪問我的文章。但在今天這個詞裏,短網址是必要的。如何爲我的數據庫中的每篇文章創建一個簡短的唯一ID?
如果我想讓這個ID有3-5個字母......我不能只是產生隨機字符。它有時會發生衝突。
我該怎麼辦?
mydomain.com/show/?id=sf32JFSVANMfaskjfh
通常我只是產生一個25個字符的隨機字符串,並以這種方式訪問我的文章。但在今天這個詞裏,短網址是必要的。如何爲我的數據庫中的每篇文章創建一個簡短的唯一ID?
如果我想讓這個ID有3-5個字母......我不能只是產生隨機字符。它有時會發生衝突。
我該怎麼辦?
如果您的每個帖子都已經有一個ID,並且它是數字,您可以使用任意的基礎對它們進行編碼。覺得有點像六角但較大的數字..
看看這個網址由利·卡爾弗...
http://blog.leahculver.com/2008/06/tiny-urls-based-on-pk.html
一些更多的想法。過去我已經使用過它,它運行良好。在leah的帖子中,它的基數是56,所以只需把你的主鍵(Integer)編碼到你的新基地56中,然後你就完成了。
爲什麼不只是使用自動增量的數字,如5836?每次插入新行時,該列都會加1。例如,如果最新的行是5836,則下一行將是5837等。
只需使用長度爲15的INT類型列。或者,如果它不是將由常規成員添加的行類型,請使用小型int或中型int類型。
的NOID: Nice Opaque Identifier (Minter and Name Resolver)意在爲圖書館系統
做到這一點,但它的基本設計是,它使一個ID,並檢查它是否被使用,如果沒有,那麼它可以在後臺使用生成和分配的ID給用戶可以避免創建它們的開銷
我會說你必須看到外部和內部的一面。您只能使用「僅3個」字母,或者至少短時間不能擁有唯一的數字。所以你可以使用內部的長標識符,例如使用UUIDS,然後你必須弄清楚如何用這樣的UUIDS製作漂亮和可讀的URL。例如,如果我們看帖子如 YYYY.mm.dd.nnn可能會做。我建議查看REST方法......
作爲一般規則,較短的哈希將導致較高的衝突率。較長的哈希也可能導致衝突,但是這種情況的可能性會變小。
如果你想縮短哈希值,你應該實現一個衝突解決策略。
PHP:
運行:
rand_uniqid(9007199254740989);
會返回PpQXn7COf'和:
rand_uniqid( 'PpQXn7COf',真);
將返回 '9007199254740989'
如果你想在rand_uniqid至少爲6信長,使用$ pad_up = 6說法
你甚至可以支持更多的字符(使得生成的rand_uniqid更小),方法是在函數體頂部的$ index var處添加字符。
<?php
function rand_uniqid($in, $to_num = false, $pad_up = false, $passKey = null)
{
$index = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if ($passKey !== null) {
// Although this function's purpose is to just make the
// ID short - and not so much secure,
// you can optionally supply a password to make it harder
// to calculate the corresponding numeric ID
for ($n = 0; $n<strlen($index); $n++) {
$i[] = substr($index,$n ,1);
}
$passhash = hash('sha256',$passKey);
$passhash = (strlen($passhash) < strlen($index))
? hash('sha512',$passKey)
: $passhash;
for ($n=0; $n < strlen($index); $n++) {
$p[] = substr($passhash, $n ,1);
}
array_multisort($p, SORT_DESC, $i);
$index = implode($i);
}
$base = strlen($index);
if ($to_num) {
// Digital number <<-- alphabet letter code
$in = strrev($in);
$out = 0;
$len = strlen($in) - 1;
for ($t = 0; $t <= $len; $t++) {
$bcpow = bcpow($base, $len - $t);
$out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
}
if (is_numeric($pad_up)) {
$pad_up--;
if ($pad_up > 0) {
$out -= pow($base, $pad_up);
}
}
$out = sprintf('%F', $out);
$out = substr($out, 0, strpos($out, '.'));
} else {
// Digital number -->> alphabet letter code
if (is_numeric($pad_up)) {
$pad_up--;
if ($pad_up > 0) {
$in += pow($base, $pad_up);
}
}
$out = "";
for ($t = floor(log($in, $base)); $t >= 0; $t--) {
$bcp = bcpow($base, $t);
$a = floor($in/$bcp) % $base;
$out = $out . substr($index, $a, 1);
$in = $in - ($a * $bcp);
}
$out = strrev($out); // reverse
}
return $out;
}
echo rand_uniqid(1);
?>
的PostgreSQL:
<?php
CREATE OR REPLACE FUNCTION string_to_bits(input_text TEXT)
RETURNS TEXT AS $$
DECLARE
output_text TEXT;
i INTEGER;
BEGIN
output_text := '';
FOR i IN 1..char_length(input_text) LOOP
output_text := output_text || ascii(substring(input_text FROM i FOR 1))::bit(8);
END LOOP;
return output_text;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION id_to_sid(id INTEGER)
RETURNS TEXT AS $$
DECLARE
output_text TEXT;
i INTEGER;
index TEXT[];
bits TEXT;
bit_array TEXT[];
input_text TEXT;
BEGIN
input_text := id::TEXT;
output_text := '';
index := string_to_array('0,d,A,3,E,z,W,m,D,S,Q,l,K,s,P,b,N,c,f,j,5,I,t,C,i,y,o,G,2,r,x,h,V,J,k,-,T,w,H,L,9,e,u,X,p,U,a,O,v,4,R,B,q,M,n,g,1,F,6,Y,_,8,7,Z', ',');
bits := string_to_bits(input_text);
IF length(bits) % 6 <> 0 THEN
bits := rpad(bits, length(bits) + 6 - (length(bits) % 6), '0');
END IF;
FOR i IN 1..((length(bits)/6)) LOOP
IF i = 1 THEN
bit_array[i] := substring(bits FROM 1 FOR 6);
ELSE
bit_array[i] := substring(bits FROM 1 + (i - 1) * 6 FOR 6);
END IF;
output_text := output_text || index[bit_array[i]::bit(6)::integer + 1];
END LOOP;
return output_text;
END;
$$ LANGUAGE plpgsql;
?>
的JavaScript:
<script>
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, newcap: true, immed: true */
/*global Crypto:true */
if (typeof Crypto === 'undefined') {
Crypto = {};
}
Crypto.random = (function() {
var index = [
'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
'n', 'p', 'q', 'r', 't', 'v', 'w', 'x', 'y', 'z',
'_', '-', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'V', 'W', 'X',
'Y', 'Z'
], base = index.length;
return {
encode: function (i) {
var out = [],
t = Math.floor(Math.log(i)/Math.log(base)),
bcp,
a;
while (t >= 0) {
bcp = Math.pow(base, t);
a = Math.floor(i/bcp) % base;
out[out.length] = index[a];
i -= a * bcp;
t -= 1;
}
return out.reverse().join('');
},
decode: function (i) {
var chars = i.split(''),
out = 0,
el;
while (typeof (el = chars.pop()) !== 'undefined') {
out += index.indexOf(el) * Math.pow(base, chars.length);
}
return out;
}
};
}());
</script>
實施例:
<script>
alert(Crypto.random.encode(101010101));
alert(Crypto.random.decode('XMzNr'));
</script>
請注意,如果您有小ID,隨機唯一ID也會保持較小:-)如果您需要另一種語言的解決方案,請告訴我。 – 2010-12-01 06:09:31
隨機生成的ID要麼較短,要麼相當可能是唯一的 - 但不能同時使用。隨着其他海報的建議,順序生成並轉換到更高的基礎是一個更好的主意。 – 2010-12-02 00:18:50
短網址是必要
真的?爲什麼?你打算讓你的用戶手動鍵入它們嗎?
我認爲,因爲他們幾乎肯定會從其他地方的鏈接,URL的大小是大多不相關。
擔心用於查看帖子的URL大小的用戶正在浪費時間。無論如何,如果你願意,可以將一個大整數編碼爲base64或類似的東西,但我個人認爲這是浪費時間,因爲「有可能你會做的事情會有更大的投資回報」。
再次在Twitter上你的評論,我只是分配順序的25個字符(或者更短,如果你願意的話)的實際職位ID作爲你們現在乾的,然後使用一個縮短的版本,你需要更少的一個URL。例如,該25個字符的ID的最後4個字符。
然後將該4個字符的ID映射到最近的等效的25個字符的ID(表示有兩個URL(短和長)可以到達該帖子)。這意味着你的消息將有效,直到你翻過來,但仍然給你大量的活動的(在base64,64 或超過一千六百萬消息)。
而且,全尺寸的URL將能夠永久保留(有效地,因爲25個字符會給你提供約10 消息)。
AFAIK大多數語言都有自己的做法。例如在PHP中,可以使用內置函數uniqid()。 然而,使用這種方法,您還必須將生成的uniqid保存到數據庫中,以便您可以在SQL的「where」子句中使用它。據我所知,沒有辦法解密這些所謂的GUID,因此他們不會告訴你任何有關何時做出的事情。
<?php
//For a basic unique id based on the current microtime:
$uniq_id = uniqid();
//If you want it to be even more uniq, you can play around with rand().
function rlyUniqId(){
$letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghyjklmnopqursuvwxyz1234567890";
$letter_count = strlen($letters);
$prefix_letter_count = rand(1,4);
for($i=1;$i<=$prefix_letter_count;$i++){
$letter_pos = rand(0,$letter_count)-1;
$prefix .= substr($letters,$letter_pos);
}
return uniqid($prefix);
}
$rly_uniq_id = rlyUniqId();
?>
較早這裏提到的另一項建議,是使用標準的生成自動遞增的ID,然後在Base64編碼的URL編碼,所以看起來會顯得花哨。這可以再次解碼,這意味着你只需要解碼url中的id來調用你的數據庫中的id。另一方面,任何人都可以這樣做,所以如果要隱藏實際的ID,這種方式絕不是理想的。此外,如果您有時需要手動編碼鏈接,有時這種方法有點煩人。 好處在於,它比前面提到的uniqid()提供了更短的url。
<?php
$data_from_db = array("id"=>14,"title"=>"Some data we got here, huh?");
$url_id = base64_encode($data_from_db["id"]);
echo '<a href="readmore.php?id='.$url_id.'>'.$data_from_db["title"].'</a>';
//when reading the link, simply do:
$original_id = base64_decode($url_id);
?>
我知道這是有點晚了,但我希望這將有一天幫助別人的地方:P GL HF!
您可以通過有效地將其轉換爲base-64(使用所有大寫和小寫字母,例如0-9,+和/)來進一步壓縮此數字。 http://en.wikipedia.org/wiki/Base64 – 2010-12-01 05:57:16