我试图在PHP中创建一个随机字符串,我得到绝对没有输出:

<?php
    function RandomString()
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randstring = '';
        for ($i = 0; $i < 10; $i++) {
            $randstring = $characters[rand(0, strlen($characters))];
        }
        return $randstring;
    }

    RandomString();
    echo $randstring;

我做错了什么?


当前回答

我已经测试了那里最流行的函数的性能,在我的盒子上生成1 000 000个32个符号的字符串所需的时间是:

2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);

请注意,它到底有多长并不重要,重要的是哪个更慢,哪个更快,因此您可以根据您的要求进行选择,包括密码准备等。

如果需要小于32个字符的字符串,则在MD5周围添加substr()以保证准确性。

为了回答:字符串没有被连接,而是被覆盖,函数的结果没有被存储。

其他回答

function getRandomString($length) {
  $salt = array_merge(range('a', 'z'), range(0, 9));
  $maxIndex = count($salt) - 1;

  $result = '';
  for ($i = 0; $i < $length; $i++) {
    $index = mt_rand(0, $maxIndex);
    $result .= $salt[$index];
  }
  return $result
}

请尝试这个函数来生成一个自定义的随机字母数字字符串:

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = random_int(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
?>

你可以通过将字符串的长度传递给函数来调整结果,如下所示:

  $test_with_50_items = random_alphanumeric(50); // 50 characters
  echo $test_with_50_items;

示例(test_with_50_items): Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86

如果你需要超过50个字符或更少,只需按你喜欢的方式调用函数:

  $test_with_27_items = random_alphanumeric(27); // 27 characters
  echo $test_with_27_items;

如果你需要两个或更多唯一的字符串,你可以使用while循环,这样你肯定会得到两个唯一的字符串…你可以用更多的弦做同样的事情,唯一的限制是你的幻想……

  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  while ($string_1 == $string_2) {
    $string_1 = random_alphanumeric(50);
    $string_2 = random_alphanumeric(50);
    if ($string_1 != $string_2) {
       break;
    }
  }
  echo $string_1;
  echo "<br>\n";
  echo $string_2;

$string_1: KkvUwia8rbDEV2aChWqm3AgeUZqyrRbUx2AxVhx5s4TSJ2VwA4

$string_2: XraO85YfxBBCInafvwipSOJwLmk6JMWiuWOxYQDnXohcn2D8K6

根据PHP 8.3, random_int()是“默认安全的”

我已经测试了那里最流行的函数的性能,在我的盒子上生成1 000 000个32个符号的字符串所需的时间是:

2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);

请注意,它到底有多长并不重要,重要的是哪个更慢,哪个更快,因此您可以根据您的要求进行选择,包括密码准备等。

如果需要小于32个字符的字符串,则在MD5周围添加substr()以保证准确性。

为了回答:字符串没有被连接,而是被覆盖,函数的结果没有被存储。

一个完整的解决方案(课程加测试),部分基于上面的一些建议…

class TokenFactory
{
    private const LENGTH = 12;
    private const ALLOWED = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ~!@#$%^&*{}';
    private const MIN_NUMBER_OF_DIGITS = 1;
    private const MIN_NUMBER_OF_CAPS = 1;
    private const MIN_NUMBER_OF_SPECIALS = 1;
    private const MIN_NUMBER_OF_LETTERS = 1;

    /**
     * @return string
     * @throws \Exception
     */
    public function make(): string
    {
        $pass = $this->generateToken();

        if ($this->isTokenValid($pass)) {
            return $pass;
        } else {
            return $this->make();
        }
    }

    /**
     * @return string
     * @throws \Exception
     */
    private function generateToken(): string
    {
        $allowedCharacters = self::ALLOWED;
        $token              = '';
        $max               = mb_strlen($allowedCharacters, '8bit') - 1;
        for ($i = 0; $i < self::LENGTH; ++$i) {
            $token .= $allowedCharacters[random_int(0, $max)];
        }
        return $token;
    }

    /**
     * @param $token
     * @return bool
     */
    private function isTokenValid($token): bool
    {
        $numberOfDigits   = preg_match_all("/[0-9]/", $token);
        $numberOfCaps     = preg_match_all("/[A-Z]/", $token);
        $numberOfSpecials = preg_match_all("/[~!@#\$%^&*{}]/", $token);
        $numberOfLetters  = preg_match_all("/[a-z]/", $token);

        return
            $numberOfDigits > self::MIN_NUMBER_OF_DIGITS
            && $numberOfCaps > self::MIN_NUMBER_OF_CAPS
            && $numberOfSpecials > self::MIN_NUMBER_OF_SPECIALS
            && $numberOfLetters > self::MIN_NUMBER_OF_LETTERS
            ;
    }
}

class TokenFactoryTest
{
    public function test_correct_syntax()
    {
        /**
         * Arrange
         */
        $length = 12;
        $numberOfChecks = 1000;

        /**
         * Act & Assert
         */
        $class = new TokenFactory();

        $i = 0;
        while ($i < $numberOfChecks) {
            $generatedToken = $class->make();

            $numberOfDigits = preg_match_all( "/[0-9]/", $generatedToken );
            $numberOfCaps = preg_match_all( "/[A-Z]/", $generatedToken );
            $numberOfSpecials   = preg_match_all("/[~!@#\$%^&*{}]/", $generatedToken);
            $numberOfLetters   = preg_match_all("/[a-z]/", $generatedToken);

            Assert::assertEquals($length, strlen($generatedToken));
            Assert::assertTrue($numberOfDigits >= 1, 'Digit error: ' . $generatedToken);
            Assert::assertTrue($numberOfCaps >= 1, 'Caps error: ' . $generatedToken);
            Assert::assertTrue($numberOfSpecials >= 1, 'Specials error: ' . $generatedToken);
            Assert::assertTrue($numberOfLetters >= 1, 'Letters error: ' . $generatedToken);

            $i++;
        }
    }
}

顺便说一句,请确保在适合您需要的地方捕获该异常!

如果您使用的是PHP 7 +

public function generateRandom(){

$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars

// OR

$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+

// or

$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+

// or

$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f

}