1

我正在做一个视频共享项目,我想为每个视频生成“字符”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;
}
4

3 回答 3

2

以下严格处理UUIDYoutube 使用的 URL不是UUID,因此无法进行比较。它们要小得多(超过 2 93倍!),并且不能像 UUID 那样保证如此巨大的域。在这种情况下(对于“短哈希标签”),必须使用重复检查 - 但它不需要与任何其他类型的重复检查不同。


如果您从适当的生成器(例如随机UUIDv4生成器)创建 UUID ,那么您可以放心,重复的概率“低到无所谓”

因此,虽然我通常建议不要检查重复的 UUID,但在某些情况下这样做是相关的:

  1. 重新合并(即循环合并操作)期间,预期会出现先前数据的重复;
  2. UUID 来自不受信任的生成器(即 UUID 值被攻击者破坏/注入或来自其他人工干预);
  3. 如果用作 SQL 列/索引,则没有理由不应用唯一约束,因为无论如何都需要保持适当的多重性。

另一方面,虽然我发现 UUID非常适合跨边界识别(例如在系统之间传输信息或提供“长”唯一资源句柄),但我发现 UUID很难用作标准数据库“记录标识符”。在需要代理 PK 的地方,我只使用传统的自增列,这在物理布局上要容易得多。(SQL Server 提供了一个特殊的 UUID 生成器,它比真正随机的 v4 UUID 更适合索引 - 但安全性较低。)

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

于 2013-09-09T23:27:39.217 回答
1

如果您使用的是数据库,您有几个选择:

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

  2. 每次生成 id 时,检查数据库是否存在。如果存在,则重新运行该函数以生成新的 uuid 并再次检查数据库。执行此操作,直到您查询数据库并且没有返回具有该 ID 的行。

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

于 2013-09-09T23:24:55.397 回答
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
于 2013-09-09T23:53:18.547 回答