在 php 中生成唯一 id(用于 url 缩短器)

Posted

技术标签:

【中文标题】在 php 中生成唯一 id(用于 url 缩短器)【英文标题】:generating unique id's in php (for url shortener) 【发布时间】:2011-06-26 00:40:52 【问题描述】:

如何使用 (0 - 9)、(a - z) 和 (A - Z) 在 php 中生成最多 6 个字符的唯一组合?有多少种可能的组合? (例如 AAaa 将不同于 Aaaa)?

【问题讨论】:

uniqid() nz.php.net/manual/en/function.uniqid.php 问题不在于生成它们,而在于确保它们保持唯一性。您打算如何存储它们? 如果生成了id还是需要每次都检查一遍,确保之前没有生成过,如果使用uniquid(),就不用每次都检查了。跨度> 谢谢。 @Gordon,是的,我的下一个关注点是如何将诸如 AAaa 之类的词存储在数据库中以及如何将它们分开。如果您有任何建议,请告诉我。 @Dagon OP 正在寻找一个 6 个字符的字符串,而 uniqid 将生成一个 13 个字符的字符串。如果你在任何地方截断它,你也必须检查唯一性。 【参考方案1】:

我的建议(特别是如果您使用数据库来存储它们)是让数据库使用数据库中的自动增量编号生成唯一的行 ID,然后将该数字转换为您的代码,这保证是独一无二,因为它是由数据库生成的。

在从数字生成代码方面,我的建议是一个简单的替换,所以创建一个包含所有可能字符的字符串并将你的数字转换为基数 62(所有字符的计数)替换一个字母或数字每个。

AaBbCcDd...0123456789

(顺便说一句,我建议删除 lIioO01,因为它们看起来都非常相似)

正如 Dan Grossman 在下面的评论中所建议的那样,以下代码将为您提供一个非常接近您想要的内容。

$code = base_convert($number, 10, 36);

这将为您提供一个基于数字和字母 0-9 和 a-z 的数字。

【讨论】:

$code = base_convert($number, 10, 36); 将使用 0-9 和 a-z。这对他来说应该足够短,你不需要手动编写更高的代码。【参考方案2】:

使用base_convert($number, 10, 36) 不会像问题中指定的那样将a-zA-Z 区别对待。需要自定义函数。

在您的数据库中使用一个 int 列作为插入时自动递增的主键,然后在您的永久链接逻辑中将此 ID 从十进制转换为 base-62(62 允许使用 0-9、az 和 AZ) .

创建新的永久链接时:

<?php

/**
 * Convert decimal int to a base-62 string
 *
 * @param int $dec
 * @returns string
 */
function toBase62 ($dec) 

  // 0 is always 0
  if ($dec == 0)
    return "0";

  // this array maps decimal keys to our base-62 radix digits
  $values = array(
    "0", "1", "2", "3", "4", 
    "5", "6", "7", "8", "9", 
    "A", "B", "C", "D", "E",
    "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O",
    "P", "Q", "R", "S", "T",
    "U", "V", "W", "X", "Y", 
    "Z", "a", "b", "c", "d", 
    "e", "f", "g", "h", "i", 
    "j", "k", "l", "m", "n", 
    "o", "p", "q", "r", "s", 
    "t", "u", "v", "w", "x", 
    "y", "z"
  );

  // convert negative numbers to positive.
  $neg = $dec < 0;
  if ($neg)
    $dec = 0 - $dec;

  // do the conversion:
  $chars = array(); // this will store our base-62 chars

  while ($dec > 0) 

    $val = $dec % 62;

    $chars[] = $values[$val];

    $dec -= $val;
    $dec /= 62;

  

  // add zero-padding:
  while (count($chars) < 6)
    $chars[] = '0';

  // convert to string
  $rv = implode( '' , array_reverse($chars) );

  // if input was negative:
  return $neg ? "-$rv" : $rv;




// Usage example:

// ... do mysql insert here and retrieve new insert_id into var $id ...

$permalink = toBase62($id);

?>

解码请求的永久链接时:

<?php

/**
 * Convert base-62 string to a decimal int
 *
 * @param string $str
 * @returns int on success, FALSE on failure
 */
function base62ToInt ($str) 

  // validate str:
  if ( ! preg_match('/^\-?[0-9A-Za-z]+$/', $str) )
    return FALSE; // not a valid string

  // 0 is always 0
  if ($str == "0" )
    return 0;

  // this array maps decimal keys to our base-62 radix digits
  $values = array(
    "0", "1", "2", "3", "4", 
    "5", "6", "7", "8", "9", 
    "A", "B", "C", "D", "E",
    "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O",
    "P", "Q", "R", "S", "T",
    "U", "V", "W", "X", "Y", 
    "Z", "a", "b", "c", "d", 
    "e", "f", "g", "h", "i", 
    "j", "k", "l", "m", "n", 
    "o", "p", "q", "r", "s", 
    "t", "u", "v", "w", "x", 
    "y", "z"
  );

  // flip $values so it maps base-62 digits to decimal values:
  $values = array_flip($values);

  // get chars from $str:
  $chars = str_split($str);

  // convert negative numbers to positive.
  $neg = $chars[0] == '-';

  if ($neg)
    array_shift($chars);

  // do the conversion:
  $val = 0;
  $i = 0;

  while ( count($chars) > 0 ) 

    $char = array_pop($chars);
    $val += ($values[$char] * pow(62, $i) );
    ++$i;

  

  return $neg ? 0 - $val : $val;



// Usage example:

// ... assuming permalink has been put in a var called $permalink

$id = base62ToInt($permalink);

// ... now look up $id in DB

?>

【讨论】:

以上是关于在 php 中生成唯一 id(用于 url 缩短器)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Dart 中生成唯一 id

如何在javascript中生成唯一ID? [复制]

推特(Twitter)的Snowflake算法——用于生成唯一ID

如何在本机反应中生成唯一ID

在 ruby​​/ActiveRecord 中生成类似 Instagram 或 Youtube 的不可猜测的字符串 ID

如何在 Sails.js 中生成唯一的发票 ID