如何确保UUID不重复

时间:2013-09-09 23:17:34

标签: php

我正在制作一个视频分享项目,我希望为每个视频生成“字符”ID,类似于youtube的工作方式。例如tgax-1sCgIs

使用以下函数生成UUID是否安全,如果我有100000000个视频,我需要添加新的uuid,我怎么能确定它不重复?

function generateRandomString($length = 11) {
    $characters = '0123456789abcdefghijklm-_nopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

3 个答案:

答案 0 :(得分:1)

如果您使用的是数据库,则可以选择以下几种方法:

  1. 只需使用您要存储视频的表格的自动增量列。该数字将始终是唯一的。

  2. 每次生成id时,请检查数据库以查看它是否存在。如果存在,请重新运行该函数以生成新的uuid并再次检查数据库。在查询数据库之前执行此操作,并且不返回具有该id的行。

  3. 您应该看一些其他帖子,这些帖子有更好的方法来生成真正的uuid:

答案 1 :(得分:1)

以下严格解决UUIDs Youtube使用的网址不是 UUID,无法进行比较。它们要小得多(超过2 93 次小!)并且没有像UUID这样的非常庞大的域的相同保证。在这种情况下(对于“短哈希标签”),必须使用重复检查 - 但它不需要与任何其他类型的重复检查不同。


如果您从适当的生成器(例如随机UUIDv4生成器)创建UUID,那么您可以确信重复的概率为"so low that it just doesn't matter"

因此,虽然我通常建议检查重复的UUID,但有时这样做是恰当的:

  1. 重新合并期间(即循环合并操作),其中预期会发生先前数据的重复
  2. ;
  3. UUID来自不受信任的生成器(即攻击者或其他人工干预会破坏/注入UUID值);
  4. 如果用作SQL列/索引,则没有理由不应用Unique Constraint,因为无论如何都需要它来保持适当的多重性。
  5. 另一方面,虽然我发现UUID 非常适合跨边界识别(例如在系统之间传输信息或提供“长”唯一资源句柄),但我发现UUID 非常穷人用作标准数据库“记录标识符”。在我需要代理PK的地方,我只使用传统的自动增量列,它在物理布局上更容易。 (SQL Server提供了一个特殊的UUID生成器,它比索引更好 - 但安全性低于真正随机的v4 UUID。)

    不幸的是,PHP标准uniqid(“自定义”格式?)函数不能提供最佳保证。在任何情况下,请参阅显示UUIDv4(-ish?)实现的PHP function to generate v4 UUID 比发布的代码更好,因为它们符合常见的生成技术使用更高等级的随机源。 (但是,请参阅答案中有关mt_rand播种方式或播种方式的评论。)

答案 2 :(得分:1)

我很确定YouTube只是在base-X系统中编码整数ID。有这么多,它们创建得如此之快,以至于似乎随机。

代码看起来像:

<?php

$base_str = '0123456789abcdefghijklmnopqrstuvwxyz-_';
$base = strlen($base_str);

// generate a number if no input
if( ! isset($argv[1]) ) {
    $number = rand(1000,1000000);
} else {
    $number = intval($argv[1]);
}

printf("Input: %d\n", $number);
printf("Base: %d\n", $base);

// will hold the base-X encoded representation of the number
$repr = '';

for( $i=$number; $i>0; ) {
    $remainder = $i % $base;
    $digit_repr = substr($base_str, $remainder, 1);
    $repr = $digit_repr . $repr;

    printf("Rem: %2d  Repr: %s  Cur: %16d  Progress: %s\n", $remainder, $digit_repr, $i, $repr);

    $i = ($i - $remainder) / $base;
}

示例输出:

Input: 2000000
Base: 38
Rem: 22  Repr: m  Cur:          2000000  Progress: m
Rem:  1  Repr: 1  Cur:            52631  Progress: 1m
Rem: 17  Repr: h  Cur:             1385  Progress: h1m
Rem: 36  Repr: -  Cur:               36  Progress: -h1m

如果你想在ID 看起来的方式中引入更多“随机性”,你可以随时加扰$base_str。请记住,在开始编码ID之前,您只能将其一次加扰。

解码

我想这很重要,对吧?

<?php

$base_str = '0123456789abcdefghijklmnopqrstuvwxyz-_';
$base = strlen($base_str);

if( ! isset($argv[1]) ) {
    $input = '-h1m';
} else {
    $input = $argv[1];
}

printf("Input: %s\n", $input);
printf("Base: %d\n", $base);

$repr = str_split($input);
$number = 0;

for( $i=0; $i<count($repr); $i++) {
    $number = $number * $base;
    $value = strpos($base_str, $repr[$i]);
    $number += $value;
    printf("Char: %s  Value: %2d  Cur: %12d\n", $repr[$i], $value, $number);
}

示例输出:

Input: -h1m
Base: 38
Char: -  Value: 36  Cur:           36
Char: h  Value: 17  Cur:         1385
Char: 1  Value:  1  Cur:        52631
Char: m  Value: 22  Cur:      2000000