Вопрос

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

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

Это было полезно?

Решение

Создайте небольшую функцию, которая возвращает случайные буквы заданной длины:

<?php
function generate_random_letters($length) {
    $random = '';
    for ($i = 0; $i < $length; $i++) {
        $random .= chr(rand(ord('a'), ord('z')));
    }
    return $random;
}

Затем вы захотите вызывать это до тех пор, пока оно не станет уникальным, в псевдокоде, в зависимости от того, где вы будете хранить эту информацию:

do {
    $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

Возможно, вы также захотите убедиться, что буквы не образуют слова в словаре.Это может быть весь словарь английского языка или просто словарь плохих слов, чтобы избежать того, что клиент сочтет безвкусицей.

Редактировать:Я бы также добавил, что это имеет смысл только в том случае, если, поскольку вы собираетесь его использовать, это не для большого количества элементов, потому что это может стать довольно медленным, чем больше столкновений вы получите (получение идентификатора уже в таблице).Конечно, вам понадобится индексированная таблица, и вы захотите изменить количество букв в идентификаторе, чтобы избежать коллизии.В этом случае, имея 6 букв, вы получили бы 26 ^ 6 = 308915776 возможных уникальных идентификаторов (за вычетом плохих слов), которых должно быть достаточно для вашей потребности в 10000.

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

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));

Другие советы

@gen_uuid () от gord.

preg_replace получил несколько неприятных проблем с utf-8, из-за которых в uid иногда содержится " + " или " / " ;. Чтобы обойти это, вы должны явно сделать шаблон utf-8

function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}

Мне потребовалось немало времени, чтобы понять, что, возможно, это избавит кого-то еще от головной боли

Вы можете достичь этого с меньшим количеством кода:

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

Результат (примеры):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi

Существует два способа получения надежно уникального идентификатора: сделать его настолько длинным и переменным, чтобы шансы на столкновение были невероятно маленькими (как с GUID), или сохранить все сгенерированные идентификаторы в таблице для поиска (в памяти или в БД или в файл) для проверки уникальности при генерации.

Если вы действительно спрашиваете, как вы можете сгенерировать такой короткий ключ и гарантировать его уникальность без какой-либо повторной проверки, ответ - вы не можете.

Вот процедура, которую я использую для случайных base62 любой длины ...

Вызов gen_uuid() возвращает такие строки, как WJX0u0jV, E9EMaZ3P и т. д.

По умолчанию это возвращает 8 цифр, следовательно, пробел 64 ^ 8 или примерно 10 ^ 14, этого достаточно, чтобы столкновения происходили довольно редко.

Для большей или меньшей строки передайте $ len по желанию. Никаких ограничений по длине, как я добавляю, пока не будет выполнено [до предела безопасности 128 символов, который можно удалить].

Обратите внимание, используйте случайную соль внутри md5 [или sha1, если вы предпочитаете], чтобы ее нельзя было легко перепроектировать.

Я не нашел надежных преобразований base62 в Интернете, поэтому этот подход позволяет отделить символы от результата base64.

Свободно использовать по лицензии BSD, наслаждаться,

Горд

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}

Действительно простое решение:

Создайте уникальный идентификатор с помощью:

$id = 100;
base_convert($id, 10, 36);

Получите исходное значение еще раз.

intval($str,36);

Не могу взять на себя ответственность за это, так как это с другой страницы переполнения стека, но я подумал, что решение было настолько элегантным и удивительным, что стоило скопировать в этот поток для людей, ссылающихся на это.

Вы можете использовать Id и просто конвертировать его в число base-36, если хотите конвертировать его туда и обратно. Может использоваться для любой таблицы с целочисленным идентификатором.

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

Умные люди, вероятно, могут понять это с помощью достаточного количества примеров идентификаторов. Не позволяйте этой безвестности заменить безопасность.

Я придумал довольно крутое решение, которое делает это без проверки уникальности. Я думал, что поделюсь для любых будущих посетителей.

Счетчик - это действительно простой способ гарантировать уникальность или, если вы используете базу данных, первичный ключ также гарантирует уникальность. Проблема в том, что это выглядит плохо и может быть уязвимо. Поэтому я взял последовательность и перемешал ее с шифром. Поскольку шифр можно перевернуть, я знаю, что каждый идентификатор уникален, хотя и выглядит случайным.

Это python, а не php, но я загрузил код здесь: https://github.com/adecker89/Tiny-Unique-Identifiers

Буквы красивые, цифры некрасивые. Вы хотите случайные строки, но не хотите & Quot; ugly & Quot; случайные строки?

Создайте случайное число и распечатайте его в альфа-стиле ( base-26 ), например, как оговорка " numbers " что авиакомпании дают.

Насколько я знаю, в PHP нет встроенных базовых функций преобразования общего назначения, поэтому вам придется кодировать их самостоятельно.

Другой вариант: используйте uniqid() и избавьтесь от цифр.

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

Или замените их буквами:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}

Вы также можете сделать это следующим образом:

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;
    }

Ты можешь это сделать без нечистые / дорогостоящие вещи, такие как циклы, конкатенации строк или множественные вызовы 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);
}

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

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

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

Недостаток: Оценка пессимистична.Делаю это вот так всегда требуется проверка в базе данных.Наличие достаточного пространства ключей (например, длиной 5 для ваших записей 10k) вряд ли будет вызывать коллизии так часто, как могло бы быть сравнительно меньше ресурсов уходит на то, чтобы просто попытаться сохранить данные и повторить попытку только в случае ошибки УНИКАЛЬНОГО КЛЮЧА.

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

Вам нужно будет обработать это исключение в любом случае и повторить попытку вставки с вновь созданным идентификатором.Добавление этого при сохранении пессимистичного цикла проверки (который вам нужно будет ввести повторно) приведет к довольно уродливому и сложному для понимания коду. К счастью, решение этой проблемы такое же, как и решение проблемы с недостатком: Просто сделайте это в первую очередь и попробуйте сохранить данные.В случае ошибки с УНИКАЛЬНЫМ КЛЮЧОМ просто повторите попытку с новым идентификатором.

Взгляните на эту статью

В нем объясняется, как генерировать короткие уникальные идентификаторы из ваших bdd-идентификаторов, как это делает YouTube.

На самом деле, функция, описанная в статье, очень связана с php-функция base_convert (базовое преобразование) который преобразует число из базового в другое (но только до базового 36).

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);
}

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

Лучший ответ пока что: Самый маленький уникальный " 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;

}

?>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top