PHP의 짧은 고유 ID
-
08-07-2019 - |
문제
고유 한 ID를 만들고 싶지만 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);
또한 문자가 사전에 단어를 형성하지 않도록 할 수도 있습니다. 고객이 나쁜 지시로 찾을 수있는 것들을 피하기 위해 전체 영어 사전 또는 나쁜 단어 사전 일 수 있습니다.
편집 : 나는 또한 당신이 그것을 사용하려고하려면, 많은 양의 항목에 대한 것이 아니라면 더 많은 충돌이 느려질 수 있기 때문에 (이미 테이블에서 ID를 얻는) 더 느리게 될 수 있기 때문에 이것을 추가 할 것입니다. 물론, 인덱스 된 테이블을 원하고 충돌을 피하기 위해 ID의 문자 수를 조정하고 싶을 것입니다. 이 경우 6 개의 글자를 사용하면 26^6 = 308915776 가능한 고유 ID (마이너스 나쁜 단어)가있어 10000이 필요하기에 충분해야합니다.
편집 : 문자와 숫자의 조합을 원한다면 다음 코드를 사용할 수 있습니다.
$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
다른 팁
@gen_uuid () by 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);
}
결과 (예제) :
- CJNP56BRDY
- 9d5uv84zfa
- IH162LRYEZ
- ri4ocf6tkj
- XJ04S83EGI
안정적으로 고유 한 ID를 얻는 방법에는 두 가지가 있습니다. 너무 길고 가변적으로 만들어 충돌 가능성이 훌륭하게 작아 지거나 (안내서와 같이) 모든 생성 된 ID를 검색을 위해 테이블에 저장하십시오 (메모리 또는 DB. 또는 파일) 세대에 고유성을 확인합니다.
실제로 그러한 짧은 열쇠를 생성하고 어떤 종류의 중복 점검없이 고유성을 보장 할 수있는 방법을 묻는다면, 대답은 할 수 없다는 것입니다.
다음은 길이의 임의의 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를 만듭니다.
$id = 100;
base_convert($id, 10, 36);
원래 값을 다시 받으십시오.
intval($str,36);
다른 스택 오버 플로우 페이지에서 이에 대한 신용을 얻을 수는 없지만 솔루션이 너무 우아하고 굉장하다고 생각하여 사람들이 이것을 참조하는 사람들을 위해이 스레드에 복사 할 가치가 있다고 생각했습니다.
ID를 사용하여 앞뒤로 변환하려면 ID를 기본 36 번호로 변환 할 수 있습니다. 정수 ID가있는 모든 테이블에 사용할 수 있습니다.
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 예제로 그것을 알아낼 수 있습니다. 이 모호함이 보안을 대체하지 마십시오.
나는 고유성 검사없이 이것을하는 꽤 멋진 솔루션이라고 생각하는 것을 생각해 냈습니다. 나는 미래의 방문객들에게 공유 할 것이라고 생각했다.
카운터는 고유성을 보장하는 정말 쉬운 방법입니다. 또는 데이터베이스를 사용하는 경우 기본 키도 고유성을 보장합니다. 문제는 나쁘게 보이고 취약 할 수 있다는 것입니다. 그래서 나는 시퀀스를 가져 와서 암호로 뒤죽박죽을 달렸다. 암호를 뒤집을 수 있기 때문에 각 ID가 독특하다는 것을 알고 있습니다.
PHP가 아닌 파이썬이지만 여기에 코드를 업로드했습니다.https://github.com/adecker89/tiny-unique-identifiers
글자는 예쁘고 숫자는 못 생겼습니다. 당신은 임의의 문자열을 원하지만 "못생긴"임의의 문자열을 원하지 않습니까?
랜덤 숫자를 만들고 인쇄하십시오 알파 스타일 (베이스 -26), 항공사가 제공하는 예약 "숫자"처럼.
내가 아는 한 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');
}
당신은 또한 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);
}
어떤 경우에도 정확한 길이를 갖기 위해 문자열이 필요한 경우, 16 진수를 0으로 채우십시오.
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는 다음과 같이하는 16 진수로 표현할 수있는 것이 제한됩니다. 이것은 될 것입니다
$length <= 8
적어도 32 비트 시스템에서 PHPS 제한은 4.294.967.295 여야합니다. - PHPS Random Number Generator도 최대 값을 갖습니다. 을 위한
mt_rand()
적어도 32 비트 시스템에서는 2.147.483.647이어야합니다 - 따라서 이론적으로 2.147.483.647 ID로 제한됩니다.
주제로 돌아 오는 것 - 직관적 do { (generate ID) } while { (id is not uniqe) } (insert id)
한 가지 단점과 하나의 가능한 결함이있어 당신을 곧바로 어둠으로 이끌 수 있습니다 ...
약점: 검증은 비관적입니다. 이렇게하는 것 언제나 데이터베이스에서 확인해야합니다. 충분한 키 공간 (예 : 10k 항목의 길이 5)을 갖는 것은 자주 충돌을 일으킬 가능성이 거의 없습니다. 비슷하게 고유 한 키 오류가 발생한 경우에만 데이터를 저장하고 다시 시도하려는 리소스 소비가 적습니다.
결함: 사용자 a 아직 복용하지 않은 것으로 확인되는 ID를 검색합니다. 코드는 데이터를 삽입하려고합니다. 그러나 그 동안 사용자 b 동일한 루프를 입력하고 불행히도 동일한 임의 번호를 검색합니다. 사용자 a 아직 저장되지 않았 으며이 ID는 여전히 무료였습니다. 이제 시스템은 저장합니다 사용자 b 또는 사용자 a, 두 번째 사용자를 저장하려고 할 때 이미 동일한 ID를 가진 다른 사용자가 있습니다.
어쨌든 해당 예외를 처리해야하며 새로 생성 된 ID로 삽입을 다시 트리해야합니다. 비관적 검사 루프를 유지하는 동안 (다시 입력 해야하는) 코드를 따르기가 상당히 추악하고 어려워집니다. 다행히도 이것에 대한 해결책은 단점과 동일합니다. 처음에 가서 데이터를 저장하십시오. 고유 한 키 오류의 경우 새 ID로 다시 시도하십시오.
이 기사를 살펴보십시오
YouTube와 같이 BDD ID에서 짧은 고유 ID를 생성하는 방법을 설명합니다.
실제로 기사의 기능은 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);
}
더 긴 버전의 고유 ID를 좋아하는 경우 다음을 사용하십시오.
$ cightiid = sha1 (md5 (time ());
아직 베스트 답변 : 가장 작은 고유 한 "해시"문자열이 주어진 고유 한 데이터베이스 ID -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;
}
?>