2010-12-01 26 views
1
mydomain.com/show/?id=sf32JFSVANMfaskjfh 

通常我只是產生一個25個字符的隨機字符串,並以這種方式訪問​​我的文章。但在今天這個詞裏,短網址是必要的。如何爲我的數據庫中的每篇文章創建一個簡短的唯一ID?

如果我想讓這個ID有3-5個字母......我不能只是產生隨機字符。它有時會發生衝突。

我該怎麼辦?

回答

1

如果您的每個帖子都已經有一個ID,並且它是數字,您可以使用任意的基礎對它們進行編碼。覺得有點像六角但較大的數字..

看看這個網址由利·卡爾弗...

http://blog.leahculver.com/2008/06/tiny-urls-based-on-pk.html

一些更多的想法。過去我已經使用過它,它運行良好。在leah的帖子中,它的基數是56,所以只需把你的主鍵(Integer)編碼到你的新基地56中,然後你就完成了。

2

爲什麼不只是使用自動增量的數字,如5836?每次插入新行時,該列都會加1。例如,如果最新的行是5836,則下一行將是5837等。

只需使用長度爲15的INT類型列。或者,如果它不是將由常規成員添加的行類型,請使用小型int或中型int類型。

+1

您可以通過有效地將其轉換爲base-64(使用所有大寫和小寫字母,例如0-9,+和/)來進一步壓縮此數字。 http://en.wikipedia.org/wiki/Base64 – 2010-12-01 05:57:16

0

NOID: Nice Opaque Identifier (Minter and Name Resolver)意在爲圖書館系統

做到這一點,但它的基本設計是,它使一個ID,並檢查它是否被使用,如果沒有,那麼它可以在後臺使用生成和分配的ID給用戶可以避免創建它們的開銷

0

我會說你必須看到外部和內部的一面。您只能使用「僅3個」字母,或者至少短時間不能擁有唯一的數字。所以你可以使用內部的長標識符,例如使用UUIDS,然後你必須弄清楚如何用這樣的UUIDS製作漂亮和可讀的URL。例如,如果我們看帖子如 YYYY.mm.dd.nnn可能會做。我建議查看REST方法......

1

作爲一般規則,較短的哈希將導致較高的衝突率。較長的哈希也可能導致衝突,但是這種情況的可能性會變小。

如果你想縮短哈希值,你應該實現一個衝突解決策略。

4

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> 
+0

請注意,如果您有小ID,隨機唯一ID也會保持較小:-)如果您需要另一種語言的解決方案,請告訴我。 – 2010-12-01 06:09:31

+0

隨機生成的ID要麼較短,要麼相當可能是唯一的 - 但不能同時使用。隨着其他海報的建議,順序生成並轉換到更高的基礎是一個更好的主意。 – 2010-12-02 00:18:50

1

短網址是必要

真的?爲什麼?你打算讓你的用戶手動鍵入它們嗎?

我認爲,因爲他們幾乎肯定會從其他地方的鏈接,URL的大小是大多不相關。

擔心用於查看帖子的URL大小的用戶正在浪費時間。無論如何,如果你願意,可以將一個大整數編碼爲base64或類似的東西,但我個人認爲這是浪費時間,因爲「有可能你會做的事情會有更大的投資回報」。


再次在Twitter上你的評論,我只是分配順序的25個字符(或者更短,如果你願意的話)的實際職位ID作爲你們現在乾的,然後使用一個縮短的版本,你需要更少的一個URL。例如,該25個字符的ID的最後4個字符。

然後將該4個字符的ID映射到最近的等效的25個字符的ID(表示有兩個URL(短和長)可以到達該帖子)。這意味着你的消息將有效,直到你翻過來,但仍然給你大量的活動的(在base64,64 或超過一千六百萬消息)。

而且,全尺寸的URL將能夠永久保留(有效地,因爲25個字符會給你提供約10 消息)。

0

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!

相關問題