php 中的短唯一 ID
我想创建一个唯一的 ID,但 uniqid()
给出的内容类似于 '492607b0ee414'
。 我想要的是类似于tinyurl给出的内容:'64k8ra'
。 越短越好。 唯一的要求是它不应该有明显的顺序,并且它应该看起来比看似随机的数字序列更漂亮。 字母优先于数字,并且最好不要混合大小写。 由于条目数量不会那么多(最多 10000 个左右),因此碰撞风险并不是一个大因素。
任何建议表示赞赏。
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.
Any suggestions appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
制作一个返回给定长度的随机字母的小函数:
然后您需要调用它,直到它是唯一的,以伪代码形式取决于您存储该信息的位置:
您可能还想确保字母不在字典中形成一个单词。 可能是整本英语词典,也可能只是一本脏词词典,以避免顾客觉得内容不好。
编辑:我还要补充一点,只有当您打算使用它时,它不适用于大量项目,因为您获得的碰撞越多,这可能会变得非常慢(在表中已经获取了ID)。 当然,您需要一个索引表,并且需要调整 ID 中的字母数量以避免冲突。 在这种情况下,如果有 6 个字母,您将有 26^6 = 308915776 个可能的唯一 ID(减去坏词),这应该足以满足您 10000 个的需求。
编辑:
如果您想要字母和数字的组合,可以使用以下代码:
Make a small function that returns random letters for a given length:
Then you'll want to call that until it's unique, in pseudo-code depending on where you'd store that information:
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.
EDIT:
If you want a combinations of letters and numbers you can use the following code:
@gen_uuid() 作者:gord。
preg_replace 遇到了一些讨厌的 utf-8 问题,这导致 uid 有时包含“+”或“/”。
为了解决这个问题,你必须明确地使用 utf-8 模式,
我花了很长时间才发现这一点,也许这可以让其他人头痛
@gen_uuid() by 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
Took me quite a while to find that, perhaps it's saves somebody else a headache
您可以用更少的代码实现这一点:
结果(示例):
You can achieve that with less code:
Result (examples):
有两种方法可以获取可靠的唯一 ID:将其设置得足够长且可变,这样发生冲突的机会就会非常小(就像 GUID 一样),或者将所有生成的 ID 存储在表中以供查找(在内存中或在数据库中)或文件)以在生成时验证唯一性。
如果您真的想知道如何生成这样一个短密钥并保证其唯一性而不进行某种重复检查,那么答案是,您不能。
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.
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.
这是我用于任意长度的随机 base62 的例程...
调用
gen_uuid()
返回诸如WJX0u0jV、E9EMaZ3P
等字符串。默认情况下,这会返回 8 位数字,因此会出现一个空格64^8 或大约 10^14,
这通常足以使碰撞变得非常罕见。
对于更大或更小的字符串,请根据需要传入 $len。 长度没有限制,因为我会追加直到满足[最多 128 个字符的安全限制,可以删除]。
请注意,在 md5 内部使用随机盐(如果您愿意,可以使用 sha1),因此不容易对其进行逆向工程。
我在网络上没有找到任何可靠的 Base62 转换,因此采用了从 Base64 结果中剥离字符的方法。
在 BSD 许可下自由使用,
享受吧,
上帝
Here's the routine I use for random base62s of any length...
Calling
gen_uuid()
returns strings likeWJX0u0jV, E9EMaZ3P
etc.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.
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].
Note, use a random salt inside the md5 [or sha1 if you prefer], so it cant easily be reverse-engineered.
I didn't find any reliable base62 conversions on the web, hence this approach of stripping chars from the base64 result.
Use freely under BSD licence,
enjoy,
gord
非常简单的解决方案:
使用以下方法创建唯一 ID:
再次获取原始值:
不能将此归功于它,因为它来自另一个堆栈溢出页面,但我认为该解决方案非常优雅且很棒,值得复制到该线程供参考此内容的人使用。
Really simple solution:
Make the unique ID with:
Get the original value again:
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.
如果您想来回转换它,您可以使用 Id 并将其转换为基数 36 数字。 可用于任何具有整数 id 的表。
聪明人可能可以通过足够的 id 示例来弄清楚。 不要让这种默默无闻取代安全性。
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.
Smart people can probably figure it out with enough id examples. Dont let this obscurity replace security.
我想出了一个我认为非常酷的解决方案,无需进行唯一性检查。 我想我会为未来的访客分享。
计数器是保证唯一性的一种非常简单的方法,或者如果您使用数据库,主键也可以保证唯一性。 问题是它看起来很糟糕并且可能很脆弱。 所以我把这个序列和密码混在一起。 由于密码可以逆转,我知道每个 id 都是唯一的,同时仍然显示为随机的。
它是 python 而不是 php,但我在这里上传了代码:
https://github.com/adecker89/Tiny-Unique-Identifiers
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.
It's python not php, but I uploaded the code here:
https://github.com/adecker89/Tiny-Unique-Identifiers
字母很漂亮,数字很丑。
您想要随机字符串,但又不想“丑陋”的随机字符串?
创建一个随机数并以 alpha 样式 (base-26) 打印,就像航空公司提供的预订“号码”一样。
据我所知,PHP 中没有内置通用的基本转换函数,因此您需要自己编写代码。
另一种选择:使用
uniqid()
并去掉数字。或者用字母替换它们:
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.
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.
Another alternative: use
uniqid()
and get rid of the digits.Or replace them with letters:
你也可以这样做:
You can also do it like tihs:
您可以以干净且易于阅读的方式做到这一点,而无需使用循环、字符串连接或多次调用 rand() 等不干净/昂贵的东西。 另外,最好使用 mt_rand() :
如果您需要字符串在任何情况下都具有精确的长度,只需用零填充十六进制数字:
“理论回撤”是,您是仅限于 PHP 的功能 - 但在这种情况下,这更像是一个哲学问题;)无论如何,让我们看一下:
$length <= 8
至少,其中 PHP 对此的限制应该是 4.294.967.295 。mt_rand()
至少,它应该是 2.147.483.647回到主题 - 直观的
do { (generate ID) } while { (id is not uniqe) } (insert id)
有一个缺点和一个可能的缺陷,可能会让您陷入黑暗。 ..缺点:验证是悲观的。 这样做总是需要检查数据库。 拥有足够的密钥空间(例如 10k 条目的长度为 5)不太可能经常导致冲突,因为仅尝试存储数据并仅在出现以下情况时重试可能会消耗较少的资源。唯一密钥错误。
缺陷:用户 A 检索到的 ID 经验证尚未被占用。 然后代码将尝试插入数据。 但与此同时,用户 B 进入了相同的循环,不幸的是检索到了相同的随机数,因为用户 A 尚未存储,并且该 ID 仍然是空闲的。 现在,系统存储用户 B 或用户 A,并且当尝试存储第二个用户时,同时已经存在另一个用户 - 具有相同的 ID。
无论如何,您都需要处理该异常,并且需要使用新创建的 ID 重新尝试插入。 在保持悲观检查循环(您需要重新输入)的同时添加此内容将导致代码非常丑陋且难以遵循。 幸运的是,解决这个问题的方法与解决缺点的方法相同:首先就尝试存储数据。 如果出现 UNIQUE KEY 错误,只需使用新 ID 重试。
You can do that without unclean/costy stuff like loops, String concatenations or multiple calls to rand(), in a clean and easy to read way. Also, it is better to use
mt_rand()
:If you need the String to have the exact length in any case, just pad the hex number with zeros:
The "theoretical backdraw" is, that you are limited to PHPs capabilities - but this is more a philosophical issue in that case ;) Let's go through it anyways:
$length <= 8
at least on a 32bit system, where PHPs limitation for this should be 4.294.967.295 .mt_rand()
at least on a 32bit system, it should be 2.147.483.647Coming back to the topic - the intuitive
do { (generate ID) } while { (id is not uniqe) } (insert id)
has one drawback and one possible flaw that might drive you straight to darkness...Drawback: The validation is pessimistic. Doing it like this always requires a check at the database. Having enough keyspace (for example length of 5 for your 10k entries) will quite unlikely cause collisions as often, as it might be comparably less resource consuming to just try to store the data and retry only in case of a UNIQUE KEY error.
Flaw: User A retrieves an ID that gets verified as not taken yet. Then the code will try to insert the data. But in the meantime, User B entered the same loop and unfortunately retrieves the same random number, because User A is not stored yet and this ID was still free. Now the system stores either User B or User A, and when attempting to store the second User, there already is the other one in the meantime - having the same ID.
You would need to handle that exception in any case and need to re-try the insertion with a newly created ID. Adding this whilst keeping the pessimistic checking loop (that you would need to re-enter) will result in quite ugly and hard to follow code. Fortunately the solution to this is the same like the one to the drawback: Just go for it in the first place and try to store the data. In case of a UNIQUE KEY error just retry with a new ID.
看看这篇文章
它解释了如何从您的 bdd id 生成简短的唯一 id,就像 youtube 那样。
实际上,文章中的函数与php函数base_convert非常相关,将一个数字从一个基数转换为另一个基数(但最多只能到 36 基数)。
Take a lookt at this article
It explains how to generate short unique ids from your bdd ids, like youtube does.
Actually, the function in the article is very related to php function base_convert which converts a number from a base to another (but is only up to base 36).
10 个字符:
5 个二进制字符:
8 个 base64 字符:
10 chars:
5 binary chars:
8 base64 chars:
如果您确实喜欢更长版本的唯一 ID,请使用此:
$uniqueid = sha1(md5(time()));
If you do like a longer version of unique Id use this:
$uniqueid = sha1(md5(time()));
最佳答案:给定唯一数据库 ID 的最小唯一“散列式”字符串 - PHP 解决方案,没有第三个需要派对库。
这是代码:
Best Answer Yet: Smallest Unique "Hash Like" String Given Unique Database ID - PHP Solution, No Third Party Libraries Required.
Here's the code: