如何创建YouTube等唯一ID?

时间:2009-07-02 19:00:26

标签: php database

我一直想知道他们为何以及为何这样做......例如:http://youtube.com/watch?v=DnAMjq0haic

如何生成这些ID,以便没有重复项,这比使用简单的自动递增数字ID有什么优势呢?

如何保持简短但仍然保持其独特性? uniqid创建的字符串非常长。

14 个答案:

答案 0 :(得分:19)

Kevin van Zonneveld撰写了一篇优秀的article,其中包含一个PHP函数来完成这项工作。他的方法是我在研究这个主题时发现的最好的方法。

他的功能非常聪明。它使用固定的$ index变量,因此可以删除有问题的字符(例如元音,或避免O和0混淆)。它还可以选择对id进行模糊处理,以便它们不易被猜测。

答案 1 :(得分:18)

试试这个:http://php.net/manual/en/function.uniqid.php

  

uniqid - 生成唯一ID ...

     

根据当前时间(以微秒为单位)获取带前缀的唯一标识符。

     
    

<强>注意     此函数不会生成加密安全值,也不应用于加密目的。如果您需要加密安全值,请考虑改用random_int()random_bytes()openssl_random_pseudo_bytes()

         

警告     此功能不保证返回值的唯一性。由于大多数系统通过NTP等调整系统时钟,因此系统时间会不断变化。因此,该函数可能不返回进程/线程的唯一ID。使用more_entropy增加唯一性的可能性......

  

答案 2 :(得分:9)

base62或base64对主键的值进行编码,然后将其存储在另一个字段中。

示例base62用于主键12443 = 3eH

节省了一些空间,这就是为什么我确定youtube正在使用它。

对您的PK或唯一标识符执行base62(A-Za-z0-9)编码将防止必须检查密钥是否已存在的开销:)

答案 3 :(得分:8)

我有一个类似的问题 - 我在数据库中有主要ID,但我不想将它们暴露给用户 - 相反,显示某种哈希会好得多。所以,我写了一些哈希。

文档:http://www.hashids.org/php/

Souce:https://github.com/ivanakimov/hashids.php

使用此类创建的哈希值是唯一且可解密的。你可以提供一个自定义的盐值,这样其他人就无法解密你的哈希值(不是说这是一个大问题,但仍然是“有益的”)。

要加密数字,您可以这样做:

require('lib/Hashids/Hashids.php');

$hashids = new Hashids\Hashids('this is my salt');
$hash = $hashids->encrypt(123);

您的$hash现在是: YDx

您还可以将最小哈希长度设置为构造函数的第二个参数,这样您的哈希值可以更长。或者,如果您有一个复杂的集群系统,您甚至可以将多个数字加密为一个哈希值:

$hash = $hashids->encrypt(2, 456); /* aXupK */

(例如,如果群组 2 中的用户和主ID为 456 的对象),解密的工作方式相同:

$numbers = $hashids->decrypt('aXupK');

$numbers将是:[2, 456]

关于这一点的好处是你甚至不必将这些哈希值存储在数据库中。一旦请求进入并动态解密,您就可以从url获取哈希值 - 然后从数据库中提取主ID(这显然是速度上的优势)。

与输出相同 - 你可以在出路时加密id,并向用户显示哈希值。

修改

  1. 更改了网址以包含文档网站和代码来源
  2. 更改了示例代码以适应主要的lib更新(当前的PHP lib版本为0.3.0 - 感谢所有开源社区改进了lib)

答案 4 :(得分:4)

可以轻松抓取自动递增功能。这些无法预测,因此无法顺序爬行。

我建议使用双网址格式(类似于SO网址):

yoursite.com/video_idkey/url_friendly_video_title

如果您同时需要网址中的ID和标题,则可以使用简单的数字,如0001,0002,0003等。

生成这些键非常简单。您可以使用PHP中的uniqid()函数生成13个字符,或23个具有更多熵的字符。

答案 5 :(得分:3)

如果您想要短网址和可预测性不是问题,可以convert the auto-incrementing ID to a higher base

答案 6 :(得分:3)

这是一个小函数,每次都会随机生成唯一的密钥。重复相同的唯一ID的机会很少。

function uniqueKey($limit = 10) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randstring = '';
    for ($i = 0; $i < $limit; $i++) {
        $randstring .= $characters[rand(0, strlen($characters))];
    }
    return $randstring;
}

来源:generate random unique IDs like YouTube or TinyURL in PHP

答案 7 :(得分:2)

一种方法是通过每次都有唯一输入的哈希函数。

示例(您已使用php therfore标记了问题):

$uniqueID = null
do {
  $uniqueID = sha1( $fileName + date() );
} while ( !isUnique($uniqueID) )

答案 8 :(得分:2)

考虑使用以下内容:

$ id = base64_encode(md5(uniqid(),true));

uniqid会为您提供唯一标识符。 MD5会扩散它,给你一个128位的结果。 Base 64编码,在标识符中为每个字符提供6位,适合在Web上使用,重约23个字符,计算难以猜测。如果你想从md5到sha1或更高级别更加偏执狂。

答案 9 :(得分:1)

应该有一个PHP库来生成这些ID。如果没有,实施它并不困难。

优点是,当您尝试重新组织或合并不同的服务器资源时,您将不会遇到名称冲突。使用数字ID,您必须更改其中一些以解决冲突,这将导致Url更改导致SEO命中。

答案 10 :(得分:1)

这很大程度上取决于你需要做什么。 “独特”有多独特?您是否提供了唯一的ID,它们是否意味着您的数据库中存在某些内容?如果是这样,顺序#可能没问题。

另一方面,如果你使用顺序#,有人可以通过迭代数字系统地窃取你的内容。

有文件系统命令会生成唯一的文件名 - 您可以使用它们。

或GUID's。

答案 11 :(得分:1)

SHA-1或MD5和GUID之类的散列函数的结果往往变得很长,这可能是您不想要的。 (你已经特别提到YouTube作为一个例子:即使他们正在托管的大量视频,他们的标识符仍然相对较短。)

这就是为什么您可能希望将您在幕后使用的数字ID转换为将其放入URL时的另一个基础。 Flickr例如使用Base58作为其规范的短URL。有关详细信息,请访问:http://www.flickr.com/groups/api/discuss/72157616713786392/。如果您正在寻找通用解决方案,请查看PEAR包Mathe_Basex。

请注意,即使在其他基础中,仍可以从应用程序外部预测ID。

答案 12 :(得分:0)

我没有公式但是我们在我正在进行的项目上这样做。 (我无法分享)。但我们基本上一次生成一个字符并附加字符串。

一旦我们有一个完整的字符串,我们就会对数据库进行检查。如果没有别的,我们就去吧。如果它是重复的,我们就开始这个过程。不是很复杂。

优点是,我想是GUID

答案 13 :(得分:0)

这是非PHP ,但可以转换为php或者它是Javascript&amp;所以clinetside不需要减慢服务器的速度..它可以用来发布任何需要一个唯一的ID到您的PHP。

这是一种创建仅限于

的唯一ID的方法
9 007 199 254 740 992 unique id's

它总是会返回9个字符。

其中iE2XnNGpF9 007 199 254 740 992

您可以对长Number进行编码,然后解码生成的{4} String 它返回数字。

基本上这个函数使用62base索引Math.log()和Math.Power来根据数字得到正确的索引..我会解释更多关于这个函数的信息,但是前一段时间它已经找不到了我已经花了很长时间才知道它是如何工作的...无论如何我从0改写了这个函数......这个比我发现的快2-3倍。 我通过1000万次检查这个数字是否与enc dec进程相同,并且用这个数字为33秒,另一个为90秒。

var UID={
 ix:'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
 enc:function(N){
  N<=9007199254740992||(alert('OMG no more uid\'s'));
  var M=Math,F=M.floor,L=M.log,P=M.pow,r='',I=UID.ix,l=I.length,i;
  for(i=F(L(N)/L(l));i>=0;i--){
   r+=I.substr((F(N/P(l,i))%l),1)
  };
  return UID.rev(new Array(10-r.length).join('a')+r)
 },
 dec:function(S){
  var S=UID.rev(S),r=0,i,l=S.length,I=UID.ix,j=I.length,P=Math.pow;
  for(i=0;i<=(l-1);i++){r+=I.indexOf(S.substr(i,1))*P(j,(l-1-i))};
  return r
 },
 rev:function(a){return a.split('').reverse().join('')}
};

因为我想要一个9个字符的字符串,我还在生成的字符串a上添加了0

要对数字进行编码,您需要传递Number而不是字符串。

var uniqueId=UID.enc(9007199254740992);

要再次解码数字,您需要传递9char生成的String

var id=UID.dec(uniqueId);

这里有一些数字

console.log(UID.enc(9007199254740992))//9 biliardi o 9 milioni di miliardi
console.log(UID.enc(1)) //baaaaaaaa 
console.log(UID.enc(10)) //kaaaaaaaa 
console.log(UID.enc(100)) //Cbaaaaaaa 
console.log(UID.enc(1000)) //iqaaaaaaa 
console.log(UID.enc(10000)) //sBcaaaaaa 
console.log(UID.enc(100000)) //Ua0aaaaaa 
console.log(UID.enc(1000000)) //cjmeaaaaa
console.log(UID.enc(10000000)) //u2XFaaaaa
console.log(UID.enc(100000000)) //o9ALgaaaa 
console.log(UID.enc(1000000000)) //qGTFfbaaa
console.log(UID.enc(10000000000)) //AOYKUkaaa 
console.log(UID.enc(100000000000)) //OjO9jLbaa
console.log(UID.enc(1000000000000)) //eAfM7Braa 
console.log(UID.enc(10000000000000)) //EOTK1dQca
console.log(UID.enc(100000000000000)) //2ka938y2a

正如你所看到的那样,a有很多,而且你不希望这样......所以从一个很高的数字开始。 假设您的数据库ID为1 ..只需添加100000000000000即可100000000000001

并且您的唯一ID看起来像youtube的ID 3ka938y2a

我认为实现其他8907199254740992唯一ID

并不容易