[php] PHP : 임의의 고유 한 영숫자 문자열을 생성하는 방법?

확인 링크에 사용하기 위해 숫자와 문자를 사용하여 임의의 고유 한 문자열을 생성하는 방법은 무엇입니까? 웹 사이트에서 계정을 만들 때 링크가 포함 된 이메일을 보내면 계정을 확인하려면 해당 링크를 클릭해야합니다.

PHP를 사용하여 그중 하나를 어떻게 생성 할 수 있습니까?

업데이트 : 방금 기억했습니다 uniqid(). 현재 시간 (마이크로 초)을 기반으로 고유 식별자를 생성하는 PHP 함수입니다. 나는 그것을 사용할 것이라고 생각합니다.



답변

보안 공지 :이 솔루션은 임의의 품질이 응용 프로그램의 보안에 영향을 줄 수있는 상황에서는 사용해서는 안됩니다. 특히, rand()uniqid()암호 난수 발생기를 안전하지 않습니다 . 안전한 대안 은 Scott의 답변 을 참조하십시오 .

시간이 지남에 따라 고유해야 할 필요가없는 경우 :

md5(uniqid(rand(), true))

그렇지 않은 경우 (사용자의 고유 한 로그인을 이미 결정한 경우) :

md5(uniqid($your_user_login, true))


답변

나는이 같은 문제를 해결하는 방법을 찾고 있었지만 암호 검색에도 사용할 수있는 토큰을 만드는 기능을 원합니다. 이것은 토큰의 추측 능력을 제한해야 함을 의미합니다. 때문에 uniqid시간에 따라, 그리고 php.net에 따라하고있다 “반환 값은 () microtime에서 약간 다릅니다은” uniqid기준을 충족하지 않습니다. PHP openssl_random_pseudo_bytes()는 암호로 안전한 토큰을 생성하기 위해 대신 사용 하는 것이 좋습니다 .

짧고 간결한 대답은 다음과 같습니다.

bin2hex(openssl_random_pseudo_bytes($bytes))

길이 = $ bytes * 2의 임의의 영숫자 문자열을 생성합니다. 불행히도 이것은 알파벳 만 [a-f][0-9]있지만 작동합니다.


아래는 기준을 만족시킬 수있는 가장 강력한 기능입니다 (이것은 Erik의 답변의 구현 버전입니다).

function crypto_rand_secure($min, $max)
{
    $range = $max - $min;
    if ($range < 1) return $min; // not so random...
    $log = ceil(log($range, 2));
    $bytes = (int) ($log / 8) + 1; // length in bytes
    $bits = (int) $log + 1; // length in bits
    $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
    do {
        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
        $rnd = $rnd & $filter; // discard irrelevant bits
    } while ($rnd > $range);
    return $min + $rnd;
}

function getToken($length)
{
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet); // edited

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
    }

    return $token;
}

crypto_rand_secure($min, $max)rand()또는의 대체품으로 사용됩니다 mt_rand. openssl_random_pseudo_bytes를 사용하여 $ min과 $ max 사이의 난수를 만드는 데 도움이됩니다.

getToken($length)토큰 내에서 사용할 알파벳을 만든 다음 length 문자열을 만듭니다 $length.

편집 : 나는 소스 인용을 소홀히했다-http : //us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

편집 (PHP7) : PHP7 의 출시와 함께 표준 라이브러리에는 위의 crypto_rand_secure 함수를 대체 / 개선 / 단순화 할 수있는 두 가지 새로운 기능이 있습니다. random_bytes($length)random_int($min, $max)

http://php.net/manual/en/function.random-bytes.php

http://php.net/manual/en/function.random-int.php

예:

function getToken($length){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet);

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[random_int(0, $max-1)];
    }

    return $token;
}


답변

가장 투표가 많은 솔루션의 객체 지향 버전

Scott 의 답변을 기반으로 객체 지향 솔루션을 만들었습니다 .

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://stackoverflow.com/a/13733588/1056679
 */
class RandomStringGenerator
{
    /** @var string */
    protected $alphabet;

    /** @var int */
    protected $alphabetLength;


    /**
     * @param string $alphabet
     */
    public function __construct($alphabet = '')
    {
        if ('' !== $alphabet) {
            $this->setAlphabet($alphabet);
        } else {
            $this->setAlphabet(
                  implode(range('a', 'z'))
                . implode(range('A', 'Z'))
                . implode(range(0, 9))
            );
        }
    }

    /**
     * @param string $alphabet
     */
    public function setAlphabet($alphabet)
    {
        $this->alphabet = $alphabet;
        $this->alphabetLength = strlen($alphabet);
    }

    /**
     * @param int $length
     * @return string
     */
    public function generate($length)
    {
        $token = '';

        for ($i = 0; $i < $length; $i++) {
            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);
            $token .= $this->alphabet[$randomKey];
        }

        return $token;
    }

    /**
     * @param int $min
     * @param int $max
     * @return int
     */
    protected function getRandomInteger($min, $max)
    {
        $range = ($max - $min);

        if ($range < 0) {
            // Not so random...
            return $min;
        }

        $log = log($range, 2);

        // Length in bytes.
        $bytes = (int) ($log / 8) + 1;

        // Length in bits.
        $bits = (int) $log + 1;

        // Set all lower bits to 1.
        $filter = (int) (1 << $bits) - 1;

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));

            // Discard irrelevant bits.
            $rnd = $rnd & $filter;

        } while ($rnd >= $range);

        return ($min + $rnd);
    }
}

용법

<?php

use Utils\RandomStringGenerator;

// Create new instance of generator class.
$generator = new RandomStringGenerator;

// Set token length.
$tokenLength = 32;

// Call method to generate random string.
$token = $generator->generate($tokenLength);

맞춤 알파벳

필요한 경우 사용자 정의 알파벳을 사용할 수 있습니다. 지원되는 문자가있는 문자열을 생성자 또는 설정자에게 전달하십시오.

<?php

$customAlphabet = '0123456789ABCDEF';

// Set initial alphabet.
$generator = new RandomStringGenerator($customAlphabet);

// Change alphabet whenever needed.
$generator->setAlphabet($customAlphabet);

출력 샘플은 다음과 같습니다

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

누군가에게 도움이되기를 바랍니다. 건배!


답변

나는 늦었지만 Scott의 답변에서 제공하는 기능을 기반으로 한 좋은 연구 데이터가 있습니다. 그래서이 5 일 동안 자동화 된 테스트를 위해 Digital Ocean 드롭 릿을 설정하고 생성 된 고유 한 문자열을 MySQL 데이터베이스에 저장했습니다.

이 테스트 기간 동안 5 개의 다른 길이 (5, 10, 15, 20, 50)를 사용했으며 각 길이마다 +/- 50 만 개의 레코드가 삽입되었습니다. 내 테스트 중에는 5 백만 길이에서 +/- 3K 복제본 만 0.5 백만을 생성했으며 나머지 길이는 복제본을 생성하지 않았습니다. 따라서 Scott의 함수에 길이가 15 이상인 경우 신뢰성이 높은 고유 한 문자열을 생성 할 수 있습니다. 내 연구 데이터를 보여주는 표는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

업데이트 : 토큰을 JSON 응답으로 반환하는 이러한 함수를 사용하여 간단한 Heroku 앱을 만들었습니다. 앱은 https://uniquestrings.herokuapp.com/api/token?length=15 에서 액세스 할 수 있습니다.

이게 도움이 되길 바란다.


답변

UUID (Universally Unique Identifier)를 사용할 수 있으며 사용자 인증 문자열에서 지불 트랜잭션 ID에 이르기까지 모든 용도로 사용할 수 있습니다.

UUID는 16 옥텟 (128 비트) 숫자입니다. 정식 형식으로 UUID는 32 개의 16 진수로 표시되며 하이픈으로 구분 된 5 개의 그룹으로 표시되며 총 8 자 (32 자의 영숫자 및 4 개의 하이픈)로 8-4-4-4-12 형식으로 하이픈으로 구분됩니다.

function generate_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
        mt_rand( 0, 0xffff ),
        mt_rand( 0, 0x0C2f ) | 0x4000,
        mt_rand( 0, 0x3fff ) | 0x8000,
        mt_rand( 0, 0x2Aff ), mt_rand( 0, 0xffD3 ), mt_rand( 0, 0xff4B )
    );

}

// 전화하기

$transationID = generate_uuid();

일부 출력 예는 다음과 같습니다.

E302D66D-87E3-4450-8CB6-17531895BF14
22D288BC-7289-442B-BEEA-286777D559F2
51B4DE29-3B71-4FD2-9E6C-071703E1FF31
3777C8C6-9FF5-4C78-AAA2-08A47F555E81
54B91C72-2CF4-4501-A6E9-02A60DCBAE4C
60F75C7C-1AE3-417B-82C8-14D456542CD7
8DE0168D-01D3-4502-9E59-10D665CEBCB2

그것이 미래에 누군가를 돕기를 바랍니다 🙂


답변

이 함수는 숫자와 문자를 사용하여 임의의 키를 생성합니다.

function random_string($length) {
    $key = '';
    $keys = array_merge(range(0, 9), range('a', 'z'));

    for ($i = 0; $i < $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}

echo random_string(50);

출력 예 :

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8


답변

나는이 하나의 라이너를 사용합니다 :

base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));

여기서 length는 원하는 문자열의 길이입니다 (4로 나눌 수 있음, 그렇지 않으면 4로 나눌 수있는 가장 가까운 숫자로 내림 됨)