Короткий уникальный идентификатор в php - PullRequest
46 голосов
/ 21 ноября 2008

Я хочу создать уникальный идентификатор, но uniqid() дает что-то вроде '492607b0ee414'. То, что я хотел бы, - это что-то похожее на то, что дает tinyurl: '64k8ra'. Чем короче, тем лучше. Единственные требования - чтобы он не имел очевидного порядка и чтобы он выглядел красивее, чем казалось бы случайная последовательность чисел. Буквы предпочтительнее цифр, и в идеале это не смешанный регистр. Поскольку количество записей не будет таким большим (до 10000 или около того), риск столкновения не является огромным фактором.

Любые предложения приветствуются.

Ответы [ 15 ]

1 голос
/ 24 сентября 2013

Вы можете сделать это без нечистых / дорогостоящих вещей, таких как циклы, конкатенации строк или множественные вызовы rand (), простым и понятным способом. Также лучше использовать mt_rand():

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    return dechex($random);
}

Если вам нужна строка для точной длины в любом случае, просто добавьте шестнадцатеричное число с нулями:

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    $number = dechex($random);
    return str_pad($number, $length, '0', STR_PAD_LEFT);
}

«Теоретический отступ» заключается в том, что вы ограничены возможностями PHP - но в этом случае это скорее философский вопрос;) Давайте все равно разберемся:

  • PHP ограничен в том, что он может представлять как шестнадцатеричное число, делая это следующим образом. Это будет $length <= 8 по крайней мере в 32-битной системе, где ограничение PHP должно быть 4.294.967.295.
  • PHP генератор случайных чисел также имеет максимум. Для mt_rand() не менее в 32-битной системе оно должно составлять 2,147,483,647
  • Таким образом, вы теоретически ограничены 2,147.483.647 идентификаторами.

Возвращаясь к теме - интуитивно понятный do { (generate ID) } while { (id is not uniqe) } (insert id) имеет один недостаток и один возможный недостаток, который может привести вас прямо в темноту ...

Недостаток: Проверка является пессимистичной. Для этого всегда требуется проверка в базе данных. Наличие достаточного пространства ключей (например, длины 5 для ваших записей 10 тыс.) Вряд ли вызовет коллизии так часто, поскольку это может быть сравнительно меньше ресурсов, потребляющих просто попытаться сохранить данные и повторить попытку только в случае UNIQUE KEY error.

Недостаток: Пользователь A извлекает идентификатор, который подтвержден как еще не принятый. Затем код попытается вставить данные. Но в то же время Пользователь B вошел в ту же петлю и, к сожалению, получает то же случайное число, потому что Пользователь A еще не сохранен и этот идентификатор все еще свободен. Теперь система хранит либо пользователя B , либо пользователя A , и при попытке сохранить второго пользователя тем временем уже есть другой пользователь с тем же идентификатором.

В любом случае вам нужно будет обработать это исключение, и вам нужно будет повторить попытку вставки с новым идентификатором. Добавление этого при сохранении цикла пессимистической проверки (который вам необходимо будет повторно ввести) приведет к довольно уродливому и трудному для понимания коду. К счастью, решение этой проблемы такое же, как и у недостатка: Просто зайдите в первую очередь и попытайтесь сохранить данные. В случае ошибки UNIQUE KEY просто повторите попытку с новым идентификатором.

1 голос
/ 26 февраля 2013

Вы также можете сделать это, как их:

public static function generateCode($length = 6)
    {
        $az = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $azr = rand(0, 51);
        $azs = substr($az, $azr, 10);
        $stamp = hash('sha256', time());
        $mt = hash('sha256', mt_rand(5, 20));
        $alpha = hash('sha256', $azs);
        $hash = str_shuffle($stamp . $mt . $alpha);
        $code = ucfirst(substr($hash, $azr, $length));
        return $code;
    }
0 голосов
/ 04 августа 2014

Лучший ответ пока: Самая маленькая уникальная строка типа "Hash Like" с уникальным идентификатором базы данных - решение PHP, сторонние библиотеки не требуются.

Вот код:

<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 200 maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1 maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1987645 maps to $base36value\n";

// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
    //DebugBreak();
   global $error;
   $string = null;

   $base = (int)$base;
   if ($base < 2 | $base > 36 | $base == 10) {
      echo 'BASE must be in the range 2-9 or 11-36';
      exit;
   } // if

   // maximum character string is 36 characters
   $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

   // strip off excess characters (anything beyond $base)
   $charset = substr($charset, 0, $base);

   if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
      $error['dec_input'] = 'Value must be a positive integer with < 50 digits';
      return false;
   } // if

   do {
      // get remainder after dividing by BASE
      $remainder = bcmod($decimal, $base);

      $char      = substr($charset, $remainder, 1);   // get CHAR from array
      $string    = "$char$string";                    // prepend to output

      //$decimal   = ($decimal - $remainder) / $base;
      $decimal   = bcdiv(bcsub($decimal, $remainder), $base);

   } while ($decimal > 0);

   return $string;

}

?>
0 голосов
/ 07 августа 2012

Если вам нравится более длинная версия уникального идентификатора, используйте это:
$ uniqueid = sha1 (md5 (time ()));

0 голосов
/ 15 декабря 2008
function rand_str($len = 12, $type = '111', $add = null) {
    $rand = ($type[0] == '1'  ? 'abcdefghijklmnpqrstuvwxyz' : '') .
            ($type[1] == '1'  ? 'ABCDEFGHIJKLMNPQRSTUVWXYZ' : '') .
            ($type[2] == '1'  ? '123456789'                 : '') .
            (strlen($add) > 0 ? $add                        : '');

    if(empty($rand)) $rand = sha1( uniqid(mt_rand(), true) . uniqid( uniqid(mt_rand(), true), true) );

    return substr(str_shuffle( str_repeat($rand, 2) ), 0, $len);
}
...