Skip to content

Commit e988f0f

Browse files
authored
[9.x] Allow random string generation to be controlled (#42669)
* Allow random string generation to be controlled * Fix typo * style ci
1 parent b7a1b92 commit e988f0f

File tree

2 files changed

+119
-8
lines changed

2 files changed

+119
-8
lines changed

src/Illuminate/Support/Str.php

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ class Str
4444
*/
4545
protected static $uuidFactory;
4646

47+
/**
48+
* The callback that should be used to generate random strings.
49+
*
50+
* @var callable|null
51+
*/
52+
protected static $randomStringFactory;
53+
4754
/**
4855
* Get a new stringable object from the given string.
4956
*
@@ -655,17 +662,74 @@ public static function pluralStudly($value, $count = 2)
655662
*/
656663
public static function random($length = 16)
657664
{
658-
$string = '';
665+
return (static::$randomStringFactory ?? function ($length) {
666+
$string = '';
659667

660-
while (($len = strlen($string)) < $length) {
661-
$size = $length - $len;
668+
while (($len = strlen($string)) < $length) {
669+
$size = $length - $len;
662670

663-
$bytes = random_bytes($size);
671+
$bytes = random_bytes($size);
664672

665-
$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
666-
}
673+
$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
674+
}
675+
676+
return $string;
677+
})($length);
678+
}
679+
680+
/**
681+
* Set the callable that will be used to generate random strings.
682+
*
683+
* @param callable|null $factory
684+
* @return void
685+
*/
686+
public static function createRandomStringsUsing(callable $factory = null)
687+
{
688+
static::$randomStringFactory = $factory;
689+
}
667690

668-
return $string;
691+
/**
692+
* Set the sequence that will be used to generate random strings.
693+
*
694+
* @param array $sequence
695+
* @param callable|null $whenMissing
696+
* @return void
697+
*/
698+
public static function createRandomStringsUsingSequence(array $sequence, $whenMissing = null)
699+
{
700+
$next = 0;
701+
702+
$whenMissing ??= function ($length) use (&$next) {
703+
$factoryCache = static::$randomStringFactory;
704+
705+
static::$randomStringFactory = null;
706+
707+
$randomString = static::random($length);
708+
709+
static::$randomStringFactory = $factoryCache;
710+
711+
$next++;
712+
713+
return $randomString;
714+
};
715+
716+
static::createRandomStringsUsing(function ($length) use (&$next, $sequence, $whenMissing) {
717+
if (array_key_exists($next, $sequence)) {
718+
return $sequence[$next++];
719+
}
720+
721+
return $whenMissing($length);
722+
});
723+
}
724+
725+
/**
726+
* Indicate that random strings should be created normally and not using a custom factory.
727+
*
728+
* @return void
729+
*/
730+
public static function createRandomStringsNormally()
731+
{
732+
static::$randomStringFactory = null;
669733
}
670734

671735
/**

tests/Support/SupportStrTest.php

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,53 @@ public function testRandom()
470470
$this->assertIsString(Str::random());
471471
}
472472

473+
public function testRandomStringFactoryCanBeSet()
474+
{
475+
Str::createRandomStringsUsing(fn ($length) => 'length:'.$length);
476+
477+
$this->assertSame('length:7', Str::random(7));
478+
$this->assertSame('length:7', Str::random(7));
479+
480+
Str::createRandomStringsNormally();
481+
482+
$this->assertNotSame('length:7', Str::random());
483+
}
484+
485+
public function testItCanSpecifyASequenceOfRandomStringsToUtilise()
486+
{
487+
Str::createRandomStringsUsingSequence([
488+
0 => 'x',
489+
// 1 => just generate a random one here...
490+
2 => 'y',
491+
3 => 'z',
492+
// ... => continue to generate random strings...
493+
]);
494+
495+
$this->assertSame('x', Str::random());
496+
$this->assertSame(16, mb_strlen(Str::random()));
497+
$this->assertSame('y', Str::random());
498+
$this->assertSame('z', Str::random());
499+
$this->assertSame(16, mb_strlen(Str::random()));
500+
$this->assertSame(16, mb_strlen(Str::random()));
501+
502+
Str::createRandomStringsNormally();
503+
}
504+
505+
public function testItCanSpecifyAFallbackForARandomStringSequence()
506+
{
507+
Str::createRandomStringsUsingSequence([Str::random(), Str::random()], fn () => throw new \Exception('Out of random strings.'));
508+
Str::random();
509+
Str::random();
510+
511+
try {
512+
$this->expectExceptionMessage('Out of random strings.');
513+
Str::random();
514+
$this->fail();
515+
} finally {
516+
Str::createRandomStringsNormally();
517+
}
518+
}
519+
473520
public function testReplace()
474521
{
475522
$this->assertSame('foo bar laravel', Str::replace('baz', 'laravel', 'foo bar baz'));
@@ -933,7 +980,7 @@ public function testItCanFreezeUuidsInAClosure()
933980
Str::createUuidsNormally();
934981
}
935982

936-
public function testItCanSpecifyASquenceOfUuidsToUtilise()
983+
public function testItCanSpecifyASequenceOfUuidsToUtilise()
937984
{
938985
Str::createUuidsUsingSequence([
939986
0 => ($zeroth = Str::uuid()),

0 commit comments

Comments
 (0)