Я хочу создать уникальный идентификатор, но 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);
Вы также можете убедиться, что буквы не образуют слово в словарной. Пусть это будет весь английский словарь или просто дурной словарь, чтобы избежать вещей, которые клиент мог бы найти в плохом вкусе.
EDIT: Я бы также добавил, что это имеет смысл только в том случае, если вы собираетесь использовать его, это не для большого количества предметов, потому что это может стать довольно медленным, чем больше коллизий вы получаете (получение идентификатора уже в таблице). Конечно, вам понадобится индексированная таблица, и вы захотите настроить количество букв в ID, чтобы избежать столкновения. В этом случае с 6 буквами у вас будет 26 ^ 6 = 308915776 возможных уникальных идентификаторов (минус плохие слова), которых должно быть достаточно для вашей потребности в 10000.
EDIT: если вам нужны комбинации букв и цифр, вы можете использовать следующий код:
$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
@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); }
Мне потребовалось довольно много времени, чтобы найти это, возможно, это избавляет кого-то еще от головной боли
Вы можете добиться этого с меньшим количеством кода:
function gen_uid($l=10){ return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l); }
Результат (примеры):
Существует два способа получения достоверно уникального идентификатора: сделайте его настолько длинным и переменным, что вероятность столкновения впечатляюще мала (как с GUID) или хранит все сгенерированные идентификаторы в таблице для поиска (либо в памяти, либо в БД или файл), чтобы проверить уникальность при генерации.
Если вы действительно спрашиваете, как вы можете создать такой короткий ключ и гарантировать его уникальность без какой-либо дублирующей проверки, ответ на этот вопрос вы не можете.
Действительно простое решение:
Сделайте уникальный идентификатор:
$id = 100; base_convert($id, 10, 36);
Получите исходное значение еще раз:
intval($str,36);
Не могу взять на себя ответственность за это, поскольку это из другой страницы переполнения стека, но я думал, что решение было настолько изящным и удивительным, что стоило копировать этот поток для людей, ссылающихся на это.
Вот рутина, которую я использую для случайных base62s любой длины …
Вызов 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); }
Я придумал то, что я думаю, это довольно крутое решение, делающее это без проверки уникальности. Я думал, что поделюсь с будущими посетителями.
Счетчик – действительно простой способ гарантировать уникальность, или если вы используете базу данных, первичный ключ также гарантирует уникальность. Проблема в том, что она выглядит плохо и может быть уязвимой. Поэтому я взял последовательность и перепутал ее с помощью шифрования. Поскольку шифр можно изменить, я знаю, что каждый идентификатор является уникальным, но все еще кажется случайным.
Это python, а не php, но я загрузил код здесь: https://github.com/adecker89/Tiny-Unique-Identifiers
Вы можете использовать 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
Умные люди, вероятно, могут понять это с достаточным количеством примеров. Не позволяйте этой безвестности заменить безопасность.
Письма довольно, цифры уродливые. Вы хотите случайные строки, но не хотите «уродливых» случайных строк?
Создайте случайное число и напечатайте его в альфа-стиле (base-26), например, «цифры» резервирования, которые предоставляют авиакомпании.
Насколько я знаю, нет никаких функций преобразования базы общего назначения, которые, как я знаю, так что вам нужно будет закодировать этот бит самостоятельно.
Другая альтернатива: используйте uniqid () и избавьтесь от цифр.
function strip_digits_from_string($string) { return preg_replace('/[0-9]/', '', $string); }
Или замените их на буквы:
function replace_digits_with_letters($string) { return strtr($string, '01234567890', 'abcdefghij'); }
Вы также можете сделать это как 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; }
Вы можете сделать это без нечистых / дорогих вещей, таких как циклы, конкатенации строк или множественные вызовы 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, но в этом случае это скорее философская проблема;) Давайте все равно пройдем:
$length <= 8
по крайней мере, в 32-битной системе, где ограничение PHP для этого должно быть 4.294.967.295. mt_rand()
по крайней мере, в 32-битной системе, она должна быть 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 просто повторите попытку с новым идентификатором.
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); }
Если вы используете более длинную версию уникального Id, используйте это:
$ uniqueid = sha1 (md5 (time ()));
Взгляните на эту статью
В нем объясняется, как генерировать короткие уникальные идентификаторы из ваших идентификаторов bdd, например, youtube.
Фактически, функция в статье очень связана с php-функцией base_convert, которая преобразует число из базы в другую (но только до основания 36).
Лучший ответ: наименьшая уникальная строка «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; } ?>