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

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

    RandomString();
    echo $randstring;

我做错了什么?


当前回答

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

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++;
        }
    }
}

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

其他回答

函数作用域中的$randstring与调用它的作用域不相同。你必须把返回值赋给一个变量。

$randstring = RandomString();
echo $randstring;

或者直接回显返回值:

echo RandomString();

另外,在函数中有一个小错误。在for循环中,您需要使用.=,以便每个字符都被追加到字符串中。通过使用=,您将用每个新字符覆盖它,而不是追加。

$randstring .= $characters[rand(0, strlen($characters))];

以前的答案会生成不安全或难以输入的密码。

这是安全的,并且提供了用户更有可能实际使用的密码,而不是因为一些薄弱的东西而被丢弃。

// NOTE: On PHP 5.x you will need to install https://github.com/paragonie/random_compat

/**
 * Generate a password that can easily be typed by users.
 *
 * By default, this will sacrifice strength by skipping characters that can cause
 * confusion. Set $allowAmbiguous to allow these characters.
 */
static public function generatePassword($length=12, $mixedCase=true, $numericCount=2, $symbolCount=1, $allowAmbiguous=false, $allowRepeatingCharacters=false)
{
  // sanity check to prevent endless loop
  if ($numericCount + $symbolCount > $length) {
    throw new \Exception('generatePassword(): $numericCount + $symbolCount are too high');
  }

  // generate a basic password with just alphabetic characters
  $chars  = 'qwertyupasdfghjkzxcvbnm';
  if ($mixedCase) {
    $chars .= 'QWERTYUPASDFGHJKZXCVBNML';
  }
  if ($allowAmbiguous) {
    $chars .= 'iol';
    if ($mixedCase) {
      $chars .= 'IO';
    }
  }

  $password = '';
  foreach (range(1, $length) as $index) {
    $char = $chars[random_int(0, strlen($chars) - 1)];

    if (!$allowRepeatingCharacters) {
      while ($char == substr($password, -1)) {
        $char = $chars[random_int(0, strlen($chars) - 1)];
      }
    }

    $password .= $char;
  }


  // add numeric characters
  $takenSubstitutionIndexes = [];

  if ($numericCount > 0) {
    $chars = '23456789';
    if ($allowAmbiguous) {
      $chars .= '10';
    }

    foreach (range(1, $numericCount) as $_) {
      $index = random_int(0, strlen($password) - 1);
      while (in_array($index, $takenSubstitutionIndexes)) {
        $index = random_int(0, strlen($password) - 1);
      }

      $char = $chars[random_int(0, strlen($chars) - 1)];
      if (!$allowRepeatingCharacters) {
        while (substr($password, $index - 1, 1) == $char || substr($password, $index + 1, 1) == $char) {
          $char = $chars[random_int(0, strlen($chars) - 1)];
        }
      }

      $password[$index] = $char;
      $takenSubstitutionIndexes[] = $index;
    }
  }

  // add symbols
  $chars = '!@#$%&*=+?';
  if ($allowAmbiguous) {
    $chars .= '^~-_()[{]};:|\\/,.\'"`<>';
  }

  if ($symbolCount > 0) {
    foreach (range(1, $symbolCount) as $_) {
      $index = random_int(0, strlen($password) - 1);
      while (in_array($index, $takenSubstitutionIndexes)) {
        $index = random_int(0, strlen($password) - 1);
      }

      $char = $chars[random_int(0, strlen($chars) - 1)];
      if (!$allowRepeatingCharacters) {
        while (substr($password, $index - 1, 1) == $char || substr($password, $index + 1, 1) == $char) {
          $char = $chars[random_int(0, strlen($chars) - 1)];
        }
      }

      $password[$index] = $char;
      $takenSubstitutionIndexes[] = $index;
    }
  }

  return $password;
}

这一个是从管理员来源:

/** Get a random string
* @return string 32 hexadecimal characters
*/
function rand_string() {
    return md5(uniqid(mt_rand(), true));
}

管理员,用PHP编写的数据库管理工具。

function generateRandomString($length = 10, $hasNumber = true, $hasLowercase = true, $hasUppercase = true): string
{
    $string = '';
    if ($hasNumber)
        $string .= '0123456789';
    if ($hasLowercase)
        $string .= 'abcdefghijklmnopqrstuvwxyz';
    if ($hasUppercase)
        $string .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    return substr(str_shuffle(str_repeat($x = $string, ceil($length / strlen($x)))), 1, $length);
}

和使用:

echo generateRandomString(32);

我已经测试了那里最流行的函数的性能,在我的盒子上生成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()以保证准确性。

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