如何为数据库中的每个帖子创建一个简短的唯一 ID?

发布于 2024-10-05 07:07:42 字数 192 浏览 0 评论 0 原文

mydomain.com/show/?id=sf32JFSVANMfaskjfh

通常我只是生成一个 25 个字符长的随机字符串并以这种方式访问​​我的帖子。但在今天看来,短网址是必要的。

如果我想要 3-5 个字母作为 ID...我不能只生成随机字符。有时候会发生冲突。

我该怎么办?

mydomain.com/show/?id=sf32JFSVANMfaskjfh

Usually I just generate a random string that's 25 characters long and access my post that way. But in today's word, short URLs are necessary.

If I want 3-5 letters for the ID...I can't just generate random characters. It'll conflict sometime.

What do I do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

怪我闹别瞎闹 2024-10-12 07:07:43

PHP:

运行:

rand_uniqid(9007199254740989);

将返回 'PpQXn7COf' 和:

rand_uniqid('PpQXn7COf', true);

将返回 '9007199254740989'


如果您希望 rand_uniqid 至少有 6 个字母长,请使用 $pad_up = 6 参数


您可以通过向顶部的 $index var 添加字符来支持更多字符(使生成的 rand_uniqid 更小)函数体的。


<?php
function rand_uniqid($in, $to_num = false, $pad_up = false, $passKey = null)
{
    $index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    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>

PHP:

Running:

rand_uniqid(9007199254740989);

will return 'PpQXn7COf' and:

rand_uniqid('PpQXn7COf', true);

will return '9007199254740989'


If you want the rand_uniqid to be at least 6 letter long, use the $pad_up = 6 argument


You can support even more characters (making the resulting rand_uniqid even smaller) by adding characters to the $index var at the top of the function body.


<?php
function rand_uniqid($in, $to_num = false, $pad_up = false, $passKey = null)
{
    $index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    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>

Example:

<script>
alert(Crypto.random.encode(101010101));
alert(Crypto.random.decode('XMzNr'));
</script>
二智少女 2024-10-12 07:07:43

为什么不直接使用自动递增的数字,例如 5836?每次插入新行时,该列都会加一。例如,如果最新行是 5836,则下一行将为 5837,依此类推。

只需使用长度为 15 的 INT 类型列。或者,如果它不是由常规成员添加的行类型,请使用小 int 或中 int 类型。

Why not just use an autoincremented number such as 5836? Every time a new row is inserted, that column will be incremented by one. For example, if the newest row is 5836, the next row will be 5837 and so on.

Just use an INT type column with a length of 15. Or if it's not a type of row that will be added by a regular member, use a small int or medium int type.

嘿嘿嘿 2024-10-12 07:07:43

如果您的每个帖子已经有一个 id,并且它是数字,您可以使用任意基数对它们进行编码。想想有点像十六进制,但数字更大..

看看 leah culver 的这个网址...

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

了解更多想法。我过去用过这个并且效果很好。在 Leah 的帖子中,它是基数 56,因此只需将您的主键(整数)编码为新的基数 56,就可以了。

if each of your posts have an id already, and it is numeric, you can just encode them using an arbitrary base. think kinda like hex but with larger numbers..

check out this url by leah culver...

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

for some more ideas. I've used this in the past and it works well. In leah's post it is base 56, so just take your primary key (Integer) and encode it into your new base 56, and you are all set.

卸妝后依然美 2024-10-12 07:07:43

一般来说,较短的哈希值会导致较高的冲突率。较长的哈希值也可能导致冲突,但发生冲突的概率会变小。

如果您想要更短的哈希值,您应该实施冲突解决策略。

As a general rule, shorter hashes will lead to a higher rate of conflicts. Longer hashes can also lead to conflicts, but the probability of such becomes less.

If you want shorter hashes, you should implement a conflict resolution strategy.

瞄了个咪的 2024-10-12 07:07:43

短网址是必要的

真的吗?为什么?您打算让用户手动输入它们吗?

我认为,由于它们几乎肯定是来自其他地方的链接,因此 URL 的大小基本上是无关紧要的。

担心用于访问帖子的 URL 大小的用户是在浪费时间。无论如何,如果您愿意,可以将大整数编码为 base64 或类似的内容,但我个人认为这是浪费时间,就像“您可能可以做一些事情来获得更大的投资回报”一样。


关于您在 Twitter 上的评论,我只是像您现在一样为实际帖子分配连续的 25 个字符(如果您愿意,可以更短)ID,然后在您需要较少 URL 的地方使用缩短的版本。例如,该 25 个字符的 ID 的最后 4 个字符。

然后将该 4 字符 ID 映射到最新等效的 25 字符 ID(意味着有两个 URL(短和长)可以访问该帖子)。这意味着您的消息将一直有效,直到您滚动,但这仍然会为您提供大量活跃的消息(以 base64、644 或超过 1600 万条消息)。

并且完整大小的 URL 将能够永远访问该帖子(有效,因为 25 个字符可为您提供大约 1045 消息)。

short URLs are necessary

Really? Why? Are you planning to have your users type them in manually?

I would think that, since they're almost certainly going to be links from somewhere else, the size of the URL is mostly irrelevant.

Users who worry about the size of the URL that was used to get to a post are wasting their time. By all means, encode a large integer into base64 or something like that if you wish, but I personally believe it's a waste of time, as in "there are probably things you could be doing that would have a greater return on investment".


Re your comment on Twitter, I'd just allocate sequential 25-character (or shorter if you wish) IDs for the actual posts as you do now, then use a shortened version for where you need less of a URL. For example, the last 4 characters of that 25-character ID.

Then map that 4-character ID to the most recent equivalent 25-character ID (meaning there are two URLs (short and long) which can get to that post). That means your messages will be valid until you roll over but that still gives you a huge number of active ones (at base64, 644 or over sixteen million messages).

And the full-size URL will be able to get to the post (effectively, since 25 characters gives you about 1045 messages) forever.

爱要勇敢去追 2024-10-12 07:07:43

NOID:漂亮的不透明标识符(Minter 和名称解析器) 旨在为库执行此操作系统,

但它的基本设计是它创建一个 id 并检查它是否已被使用,如果没有则可以使用在后台生成并将 id 分发给用户可以避免创建它们的开销

the NOID: Nice Opaque Identifier (Minter and Name Resolver) was meant to do this for library systems

but it's basic design is that it makes a id and checked if it's been used if not then it's available for use generating in the background and distributing ids to the users can avoid the overhead of creating them

红墙和绿瓦 2024-10-12 07:07:43

我想说你必须看到外部和内部。您不能拥有包含“仅 3 个”字母的唯一数字,或者至少在短时间内。因此,您可以使用内部长标识符,我想到的是使用 UUIDS,然后您必须弄清楚如何使具有此类 UUIDS 的 URL 变得漂亮和/或可读。例如,如果我们看类似的帖子
YYYY.mm.dd.nnn 可以。我建议检查 REST 方法......

I'd say you have to see the external side and the internal side. You can not have unique numbers with "just 3 " letters, or at least just for a short time. So you can use internally long identfiers one which come to my mind would be e.g using UUIDS, then you have to figure out how to make URLS with such UUIDS pretty and or readable. E.g If we look at posts something like
YYYY.mm.dd.nnn may do. I suggest checking out the REST approach...

逆光飞翔i 2024-10-12 07:07:43

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,然后在 URL 中对其进行 base64 编码,这样看起来会很漂亮。这可以再次解码,这意味着您只需解码 url 中的 id 即可从数据库中调用 id。另一方面,任何人都可以这样做,所以如果是为了隐藏实际的id,这种方式绝不是理想的。另外,如果您有时必须手动编写链接,则有时此方法有点烦人。
从好的方面来说,它给你的 url 比前面提到的 uniqid() 短得多。

<?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 高频!

AFAIK most languages have their own method of doing this. For instance in PHP, you could use the built in function uniqid().
With this method however, you also have to save the generated uniqid in your database, so you can use it in your "where" clause in SQL. There is no way of decrypting these so called GUID's as far as I am aware, and as such they don't tell you anything about when this was made or anything.

<?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();
?>

Another suggestion mentioned earlier here, is using the standard generated auto-incremented id, and then base64 encoding it in your URL so it will look fancy. This can be decoded again, which means you just decode the id in the url to call on the id from your database. On the other hand, anyone can do this, so if it's to hide the actual id, this way is by no means ideal. Also, sometimes this method is a bit annoying if you sometimes have to handcode a link.
On the upside, it gives you way shorter url's than the earlier mentioned uniqid().

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

I know this is a bit late, but I hope this will some day help someone somewhere :P
GL HF!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文