Подтвердить что ты не робот

Короткий уникальный идентификатор в php

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

Любые предложения оценены.

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

@gen_uuid() от gord.

preg_replace получил некоторые неприятные проблемы utf-8, что заставляет uid somtimes содержать "+" или "/". Чтобы обойти это, вы должны явно сделать шаблон 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);
}

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

Ответ 3

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

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

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

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi

Ответ 4

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

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

Ответ 5

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

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

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

Получить исходное значение снова:

intval($str,36);

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

Ответ 6

Здесь подпрограмма я использую для случайных base62s любой длины...

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

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

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

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

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

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

gord

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

Ответ 7

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

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

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

Ответ 8

Вы можете использовать Id и просто преобразовать его в номер базы 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

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

Ответ 9

Буквы красивы, цифры уродливы. Вы хотите случайные строки, но не хотите "уродливых" случайных строк?

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

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

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

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

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

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

Ответ 10

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

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

Ответ 11

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

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

  • PHP ограничен в том, что он может представлять как шестнадцатеричное число, выполняющее его так. Это будет $length <= 8 по крайней мере в 32-битной системе, где ограничение PHP для этого должно быть 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 для ваших записей 10 тыс.) Вряд ли вызовет столкновения так часто, как это может быть сравнительно меньше ресурсов, чтобы просто попытаться сохранить данные и повторить попытку только в случае ошибки UNIQUE KEY.

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

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

Ответ 12

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

Ответ 13

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

Ответ 14

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

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

Собственно, функция в статье очень связана с php function base_convert, которая преобразует число из базы в другую (но только вверх к основанию 36).

Ответ 15

Лучший ответ: Самая маленькая уникальная строка типа "Хеш" с уникальным идентификатором базы данных - решение для 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 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;

}

?>