Короткий уникальный идентификатор в php
Я хочу создать уникальный идентификатор, но uniqid()
дает что-то вроде '492607b0ee414'
. То, что я хотел бы, похоже на то, что дает tinyurl: '64k8ra'
. Чем короче, тем лучше. Единственные требования заключаются в том, что он не должен иметь очевидного порядка и что он должен выглядеть красивее, чем кажущаяся случайная последовательность чисел. Письма предпочтительнее номеров, и в идеале это не будет смешанный случай. Поскольку количество записей не будет таким большим (до 10000 или около того), риск столкновения не является огромным фактором.
Любые предложения оценены.
Ответы
Ответ 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;
}
?>