문제

고유 한 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;

}

?>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top