php php中的短唯一ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/307486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:19:12  来源:igfitidea点击:

Short unique id in php

phpuniqueidentifierunique-index

提问by Antti

I want to create a unique id but uniqid()is giving something like '492607b0ee414'. What i would like is something similar to what tinyurl gives: '64k8ra'. The shorter, the better. The only requirements are that it should not have an obvious order and that it should look prettier than a seemingly random sequence of numbers. Letters are preferred over numbers and ideally it would not be mixed case. As the number of entries will not be that many (up to 10000 or so) the risk of collision isn't a huge factor.

我想创建一个唯一的 id 但uniqid()正在提供类似'492607b0ee414'. 我想要的是类似于 tinyurl 给出的内容:'64k8ra'. 越短越好。唯一的要求是它不应该有明显的顺序,并且它应该看起来比看似随机的数字序列更漂亮。字母优先于数字,理想情况下不会混合大小写。由于条目的数量不会那么多(最多 10000 个左右),因此碰撞风险并不是一个很大的因素。

Any suggestions appreciated.

任何建议表示赞赏。

采纳答案by lpfavreau

Make a small function that returns random letters for a given length:

制作一个小函数,返回给定长度的随机字母:

<?php
function generate_random_letters($length) {
    $random = '';
    for ($i = 0; $i < $length; $i++) {
        $random .= chr(rand(ord('a'), ord('z')));
    }
    return $random;
}

Then you'll want to call that until it's unique, in pseudo-code depending on where you'd store that information:

然后你会想要调用它直到它是唯一的,在伪代码中取决于你存储该信息的位置:

do {
    $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

You might also want to make sure the letters do not form a word in a dictionnary. May it be the whole english dictionnary or just a bad-word dictionnary to avoid things a customer would find of bad-taste.

您可能还想确保这些字母不会构成字典中的单词。可能是整个英文词典,或者只是一个不好的词词典,以避免客户会发现不好的东西。

EDIT: I would also add this only make sense if, as you intend to use it, it's not for a big amount of items because this could get pretty slow the more collisions you get (getting an ID already in the table). Of course, you'll want an indexed table and you'll want to tweak the number of letters in the ID to avoid collision. In this case, with 6 letters, you'd have 26^6 = 308915776 possible unique IDs (minus bad words) which should be enough for your need of 10000.

编辑:我也会添加这仅在您打算使用它时才有意义,因为它不适用于大量项目,因为您获得的碰撞越多(在表中获得一个 ID),这可能会变得非常慢。当然,您需要一个索引表,并且需要调整 ID 中的字母数以避免冲突。在这种情况下,使用 6 个字母,您将有 26^6 = 308915776 个可能的唯一 ID(减去坏词),这应该足以满足您 10000 的需求。

EDIT: If you want a combinations of letters and numbers you can use the following code:

编辑:如果您想要字母和数字的组合,您可以使用以下代码:

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));

回答by Corelgott

@gen_uuid() by gord.

@gen_uuid() 来自 gord。

preg_replace got some nasty utf-8 problems, which causes the uid somtimes to contain "+" or "/". To get around this, you have to explicitly make the pattern utf-8

preg_replace 遇到了一些令人讨厌的 utf-8 问题,这会导致 uid 有时包含“+”或“/”。为了解决这个问题,你必须明确地使模式 utf-8

function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}

Took me quite a while to find that, perhaps it's saves somebody else a headache

我花了很长时间才发现,也许它可以为其他人省去头疼的麻烦

回答by Nico Schefer

You can achieve that with less code:

你可以用更少的代码来实现:

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

Result (examples):

结果(示例):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi
  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi

回答by Chris

There are two ways to obtain a reliably unique ID: Make it so long and variable that the chances of a collision are spectacularly small (as with a GUID) or store all generated IDs in a table for lookup (either in memory or in a DB or a file) to verify uniqueness upon generation.

有两种方法可以获取可靠的唯一 ID:使其长且可变,以致发生冲突的可能性非常小(与 GUID 一样)或将所有生成的 ID 存储在表中以供查找(在内存中或在数据库中)或文件)以在生成时验证唯一性。

If you're really asking how you can generate such a short key and guarantee its uniqueness without some kind of duplicate check, the answer is, you can't.

如果您真的要问如何生成如此短的密钥并保证其唯一性而不进行某种重复检查,那么答案是,您不能。

回答by gord

Here's the routine I use for random base62s of any length...

这是我用于任意长度的随机 base62 的例程...

Calling gen_uuid()returns strings like WJX0u0jV, E9EMaZ3Petc.

调用gen_uuid()返回字符串等WJX0u0jV, E9EMaZ3P

By default this returns 8 digits, hence a space of 64^8 or roughly 10^14, this is often enough to make collisions quite rare.

默认情况下,这将返回 8 位数字,因此空间为 64^8 或大约 10^14,这通常足以使碰撞非常罕见。

For a larger or smaller string, pass in $len as desired. No limit in length, as I append until satisfied [up to safety limit of 128 chars, which can be removed].

对于更大或更小的字符串,根据需要传入 $len。长度没有限制,因为我会追加直到满意 [最多 128 个字符的安全限制,可以删除]。

Note, use a random salt insidethe md5 [or sha1 if you prefer], so it cant easily be reverse-engineered.

注意,使用随机盐的MD5 [或SHA1如果你喜欢],所以它不能很容易被反向工程。

I didn't find any reliable base62 conversions on the web, hence this approach of stripping chars from the base64 result.

我没有在网上找到任何可靠的 base62 转换,因此这种从 base64 结果中剥离字符的方法。

Use freely under BSD licence, enjoy,

在 BSD 许可下自由使用,享受,

gord

戈德

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}

回答by Adcuz

Really simple solution:

非常简单的解决方案:

Make the unique ID with:

使用以下命令制作唯一 ID:

$id = 100;
base_convert($id, 10, 36);

Get the original value again:

再次获取原始值:

intval($str,36);

Can't take credit for this as it's from another stack overflow page, but I thought the solution was so elegant and awesome that it was worth copying over to this thread for people referencing this.

不能因为它来自另一个堆栈溢出页面而对此表示赞赏,但我认为该解决方案非常优雅和出色,值得复制到此线程供人们参考。

回答by AJD

I came up with what I think is a pretty cool solution doing this without a uniqueness check. I thought I'd share for any future visitors.

我想出了一个我认为非常酷的解决方案,无需进行唯一性检查。我想我会分享给任何未来的访客。

A counter is a really easy way to guarantee uniqueness or if you're using a database a primary key also guarantees uniqueness. The problem is it looks bad and and might be vulnerable. So I took the sequence and jumbled it up with a cipher. Since the cipher can be reversed, I know each id is unique while still appearing random.

计数器是保证唯一性的一种非常简单的方法,或者如果您使用的是数据库,主键也可以保证唯一性。问题是它看起来很糟糕,而且可能很脆弱。所以我把这个序列和一个密码混为一谈。由于密码可以反转,我知道每个 id 都是唯一的,同时仍然出现随机。

It's python not php, but I uploaded the code here: https://github.com/adecker89/Tiny-Unique-Identifiers

它是 python 不是 php,但我在这里上传了代码:https: //github.com/adecker89/Tiny-Unique-Identifiers

回答by OIS

You could use the Id and just convert it to base-36 number if you want to convert it back and forth. Can be used for any table with an integer id.

如果您想来回转换,您可以使用 Id 并将其转换为 base-36 数字。可用于任何具有整数 ID 的表。

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

Smart people can probably figure it out with enough id examples. Dont let this obscurity replace security.

聪明的人可能可以通过足够的 id 示例来弄清楚。不要让这种默默无闻取代安全性。

回答by RJHunter

Letters are pretty, digits are ugly. You want random strings, but don't want "ugly" random strings?

字母很漂亮,数字很丑。您想要随机字符串,但不想要“丑陋”的随机字符串?

Create a random number and print it in alpha-style(base-26), like the reservation "numbers" that airlines give.

创建一个随机数并以alpha 样式base-26)打印,就像航空公司提供的预订“数字”一样。

There's no general-purpose base conversion functions built into PHP, as far as I know, so you'd need to code that bit yourself.

据我所知,PHP 中没有内置的通用基本转换函数,因此您需要自己编写代码。

Another alternative: use uniqid()and get rid of the digits.

另一种选择:使用uniqid()并删除数字。

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

Or replace them with letters:

或者用字母替换它们:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}

回答by Aldee

You can also do it like tihs:

你也可以这样做:

public static function generateCode($length = 6)
    {
        $az = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $azr = rand(0, 51);
        $azs = substr($az, $azr, 10);
        $stamp = hash('sha256', time());
        $mt = hash('sha256', mt_rand(5, 20));
        $alpha = hash('sha256', $azs);
        $hash = str_shuffle($stamp . $mt . $alpha);
        $code = ucfirst(substr($hash, $azr, $length));
        return $code;
    }