Генератор случайного кода на PHP
Генерация случайной строки в программировании — популярная тема. Это связано с тем, что таким образом ресурсы можно защитить или сделать уникальными. В большинстве технологий есть готовые решения, позволяющие, например, генерировать UUID или другие типы идентификаторов. Очень полезная вещь.
Однако иногда возникает потребность в чем-то более конкретном. Я имею в виду более короткие случайные строки . Они могут действовать как, например, коды доступа, пин-коды или просто пароли.
<?php class CodeGenerator { public const DEFAULT_LENGTH = 10; public const DEFAULT_CHARACTERS = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVwWxXyYzZ0123456789'; private CodeRepository $codeRepository; public function __construct(CodeRepository $codeRepository) { $this->codeRepository = $codeRepository; } public function generate( int $length = self::DEFAULT_LENGTH, string $allowedCharacters = self::DEFAULT_CHARACTERS ): string { if ($length < 3) { throw new \InvalidArgumentException('Code cannot be shorter than 3 chars'); } $code = ''; $allowedCharactersLength = mb_strlen($allowedCharacters); $codeLength = $length; while ($codeLength !== 0) { $randomIndex = mt_rand(0, $allowedCharactersLength - 1); $code .= $allowedCharacters[$randomIndex]; $codeLength--; } if (!$this->codeRepository->isCodeUnique($code)) { return $this->generate($length, $allowedCharacters); } return $code; } } ?>
<?php interface CodeRepository { public function isCodeUnique(string $code): bool; } ?>
<?php class CodeGeneratorTest extends TestCase { public function testCannotGenerateNonUniqueCode(): void { $codeRepository = $this->prophesize(CodeRepository::class); $codeRepository ->isCodeUnique(Argument::type('string')) ->willReturn(false, false, true) ->shouldBeCalledTimes(3); $codeGenerator = new CodeGenerator($codeRepository->reveal()); $codeGenerator->generate(); } public function testCanGenerateCodeWithDefaultLength(): void { $codeRepository = $this->prophesize(CodeRepository::class); $codeRepository ->isCodeUnique(Argument::type('string')) ->willReturn(true); $codeGenerator = new CodeGenerator($codeRepository->reveal()); $code = $codeGenerator->generate(); $this->assertEquals(CodeGenerator::DEFAULT_LENGTH, strlen($code)); } public function testCanGenerateCodeWithOtherLengthThanDefault(): void { $codeRepository = $this->prophesize(CodeRepository::class); $codeRepository ->isCodeUnique(Argument::type('string')) ->willReturn(true); $codeGenerator = new CodeGenerator($codeRepository->reveal()); $code = $codeGenerator->generate(6); $this->assertSame(strlen($code), 6); } /** @dataProvider provideWrongCodeLength */ public function testCannotGenerateCodeWithLengthLessThanThree(int $length): void { $codeRepository = $this->prophesize(CodeRepository::class); $codeGenerator = new CodeGenerator($codeRepository->reveal()); $this->expectException(\InvalidArgumentException::class); $codeGenerator->generate($length); } public function testCannotGenerateCodeThatContainsOtherCharsThanSpecified() { $codeRepository = $this->prophesize(CodeRepository::class); $codeRepository ->isCodeUnique(Argument::type('string')) ->willReturn(true); $codeGenerator = new CodeGenerator($codeRepository->reveal()); $allowedChars = 'aB0'; $code = $codeGenerator->generate(20, $allowedChars); $regexChars = '/[^' . $allowedChars . ']/i'; $this->assertEquals(0, preg_match($regexChars, $code)); } public function provideWrongCodeLength(): array { return [ 'Length -1000' => [ 'length' => -1000 ], 'Length -1' => [ 'length' => -1 ], 'Length 0' => [ 'length' => 0 ], 'Length 1' => [ 'length' => 1 ], 'Length 2' => [ 'length' => 2 ] ]; } } ?>
Вариант 2.
<?php // Generate a Random String function random_string( $length = 6 ) { $conso = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; $vowels = array( "a", "e", "i", "o", "u" ); $string = ""; srand( (double)microtime()*1000000 ); for ( $i = 1; $i <= $length; $i++ ) { $string .=$conso[rand()%strlen( $conso )]; } return $string; } echo random_string( 10 ); ?>