Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9f8878f

Browse files
committed
[String] allow passing a string of custom characters to ByteString::fromRandom
1 parent4d8a4b6 commit9f8878f

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

‎src/Symfony/Component/String/ByteString.php

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,58 @@
2525
*/
2626
class ByteStringextends AbstractString
2727
{
28+
privateconstALPHABET_ALPHANUMERIC ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
29+
2830
publicfunction__construct(string$string ='')
2931
{
3032
$this->string =$string;
3133
}
3234

33-
publicstaticfunctionfromRandom(int$length =16):self
35+
publicstaticfunctionfromRandom(int$length =16,string$alphabet =null):self
3436
{
35-
$string ='';
37+
if (0 ===$length) {
38+
returnnewstatic('');
39+
}
40+
41+
if ($length <0) {
42+
thrownew \RuntimeException(sprintf('Expected positive length value, got "%d".',$length));
43+
}
44+
45+
$alphabet =$alphabet ??self::ALPHABET_ALPHANUMERIC;
46+
$alphabet_size =\strlen($alphabet);
47+
$bits = (int)ceil(log($alphabet_size,2.0));
48+
if ($bits <=0 ||$bits >56) {
49+
thrownew \RuntimeException('Expected $alphabet\'s length to be in [2^1, 2^56].');
50+
}
3651

37-
do {
38-
$string .=str_replace(['/','+','='],'',base64_encode(random_bytes($length)));
39-
}while (\strlen($string) <$length);
52+
$ret ='';
53+
while ($length >0) {
54+
$urandom_length = (int)ceil(2 *$length *$bits /8.0);
55+
$data =random_bytes($urandom_length);
56+
$unpacked_data =0;
57+
$unpacked_bits =0;
58+
for ($i =0;$i <$urandom_length &&$length >0; ++$i) {
59+
// Unpack 8 bits
60+
$unpacked_data = ($unpacked_data <<8) |\ord($data[$i]);
61+
$unpacked_bits +=8;
62+
63+
// While we have enough bits to select a character from the alphabet, keep
64+
// consuming the random data
65+
for (;$unpacked_bits >=$bits &&$length >0;$unpacked_bits -=$bits) {
66+
$index = ($unpacked_data & ((1 <<$bits) -1));
67+
$unpacked_data >>=$bits;
68+
// Unfortunately, the alphabet size is not necessarily a power of two.
69+
// Worst case, it is 2^k + 1, which means we need (k+1) bits and we
70+
// have around a 50% chance of missing as k gets larger
71+
if ($index <$alphabet_size) {
72+
$ret .=$alphabet[$index];
73+
--$length;
74+
}
75+
}
76+
}
77+
}
4078

41-
returnnewstatic(substr($string,0,$length));
79+
returnnewstatic($ret);
4280
}
4381

4482
publicfunctionbytesAt(int$offset):array

‎src/Symfony/Component/String/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ CHANGELOG
1212
depending of the input string UTF-8 compliancy
1313
* added`$cut` parameter to`Symfony\Component\String\AbstractString::truncate()`
1414
* added`AbstractString::containsAny()`
15+
* allow passing a string of custom characters to ByteString::fromRandom
1516

1617
5.0.0
1718
-----

‎src/Symfony/Component/String/Tests/ByteStringTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespaceSymfony\Component\String\Tests;
1313

1414
useSymfony\Component\String\AbstractString;
15+
usefunctionSymfony\Component\String\b;
1516
useSymfony\Component\String\ByteString;
1617

1718
class ByteStringTestextends AbstractAsciiTestCase
@@ -21,6 +22,47 @@ protected static function createFromString(string $string): AbstractString
2122
returnnewByteString($string);
2223
}
2324

25+
publicfunctiontestFromRandom():void
26+
{
27+
$random = ByteString::fromRandom(32);
28+
29+
self::assertSame(32,$random->length());
30+
foreach ($random->chunk()as$char) {
31+
self::assertNotNull(b('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')->indexOf($char));
32+
}
33+
}
34+
35+
publicfunctiontestFromRandomWithSpecificChars():void
36+
{
37+
$random = ByteString::fromRandom(32,'abc');
38+
39+
self::assertSame(32,$random->length());
40+
foreach ($random->chunk()as$char) {
41+
self::assertNotNull(b('abc')->indexOf($char));
42+
}
43+
}
44+
45+
publicfunctiontestFromRandomEarlyReturnForZeroLength():void
46+
{
47+
self::assertSame('', ByteString::fromRandom(0));
48+
}
49+
50+
publicfunctiontestFromRandomThrowsForNegativeLength():void
51+
{
52+
$this->expectException(\RuntimeException::class);
53+
$this->expectExceptionMessage('Expected positive length value, got -1');
54+
55+
ByteString::fromRandom(-1);
56+
}
57+
58+
publicfunctiontestFromRandomAlphabetMin():void
59+
{
60+
$this->expectException(\RuntimeException::class);
61+
$this->expectExceptionMessage('Expected $alphabet\'s length to be in [2^1, 2^56]');
62+
63+
ByteString::fromRandom(32,'a');
64+
}
65+
2466
publicstaticfunctionprovideBytesAt():array
2567
{
2668
returnarray_merge(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp