Skip to content

Commit

Permalink
Improve base32 package implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Feb 27, 2024
1 parent 01d2ce0 commit 6a7c76f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 32 deletions.
46 changes: 19 additions & 27 deletions Base32.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,23 @@
final class Base32
{
private readonly string $alphabet;
private readonly string $padding;

private function __construct(
string $alphabet,
private readonly string $padding,
) {
if (1 !== strlen($this->padding)) {
throw new ValueError('The padding character must be one byte long.');
}

if (in_array($this->padding, ["\r", "\n"], true)) {
throw new ValueError('The padding character is invalid.');
}

if (32 !== count(array_unique(str_split($alphabet)))) {
throw new ValueError('The alphabet must be 32 bytes long string containing unique characters.');
}

if (
str_contains($alphabet, "\r") ||
str_contains($alphabet, "\n") ||
str_contains($alphabet, $this->padding)
) {
throw new ValueError('The alphabet contains an invalid character.');
}

$this->alphabet = strtoupper($alphabet);
private function __construct(string $alphabet, string $padding)
{
$alphabet = strtoupper($alphabet);

[$this->alphabet, $this->padding] = match (true) {
1 !== strlen($padding) => throw new ValueError('The padding character must a single character.'),
"\r" === $padding => throw new ValueError('The padding character can not be the carriage return character.'),
"\n" === $padding => throw new ValueError('The padding character can not be the newline escape sequence.'),
32 !== strlen($alphabet) => throw new ValueError('The alphabet must be a 32 bytes long string.'),
32 !== count(array_unique(str_split($alphabet))) => throw new ValueError('The alphabet must contain unique characters.'),
str_contains($alphabet, "\r") => throw new ValueError('The alphabet can not contain the carriage return character.'),
str_contains($alphabet, "\n") => throw new ValueError('The alphabet can not contain the newline escape sequence.'),
str_contains($alphabet, strtoupper($padding)) => throw new ValueError('The alphabet can not contain the padding character.'),
default => [$alphabet, $padding],
};
}

public static function new(string $alphabet, string $padding): self
Expand All @@ -49,11 +40,12 @@ public function decode(string $encoded, bool $strict = false): string
return '';
}

$encoded = str_replace(["\r", "\n"], [''], $encoded);
if (!$strict) {
$encoded = strtoupper($encoded);
$encoded = str_replace(strtoupper($this->padding), $this->padding, strtoupper($encoded));
}

if (strtoupper($encoded) !== $encoded) {
if (str_replace(strtoupper($this->padding), $this->padding, strtoupper($encoded)) !== $encoded) {
throw new RuntimeException('The encoded data contains non uppercased characters.');
}

Expand Down
28 changes: 23 additions & 5 deletions Base32Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ public function it_will_base32_encode_and_decode(string $string): void
self::assertSame($string, base32_decode(base32_encode($string, PHP_BASE32_HEX), PHP_BASE32_HEX));
}

#[Test]
public function it_will_base32_decode_multiline_data(): void
{
$base32 = <<<BASE
89GMSPRL
D4yyyyyy
BASE;
self::assertSame('Bangui', base32_decode($base32, PHP_BASE32_HEX, 'y', true));
}


#[DataProvider('invalidDecodingSequence')]
#[Test]
public function it_will_return_false_from_invalid_encoded_string_with_base32_decode_function(
Expand Down Expand Up @@ -209,35 +220,42 @@ public static function invalidDecodingSequence(): iterable

yield 'invalid alphabet length' => [
'sequence' => 'A',
'message' => 'The alphabet must be 32 bytes long string containing unique characters.',
'message' => 'The alphabet must be a 32 bytes long string.',
'alphabet' => '1234567890asdfghjklzxcvbnm',
'padding' => '=',
];

yield 'the padding character is contained within the alphabet' => [
'sequence' => 'A',
'message' => 'The alphabet contains an invalid character.',
'message' => 'The alphabet can not contain the padding character.',
'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII),
'padding' => '*',
];

yield 'the padding character is contained within the alphabet is case insensitive' => [
'sequence' => 'A',
'message' => 'The alphabet can not contain the padding character.',
'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII),
'padding' => 'a',
];

yield 'the padding character is different than one byte' => [
'sequence' => 'A',
'message' => 'The padding character must be one byte long.',
'message' => 'The padding character must a single character.',
'alphabet' => PHP_BASE32_ASCII,
'padding' => 'yo',
];

yield 'the padding character can not contain "\r"' => [
'sequence' => 'A',
'message' => 'The padding character is invalid.',
'message' => 'The padding character can not be the carriage return character.',
'alphabet' => PHP_BASE32_ASCII,
'padding' => "\r",
];

yield 'the padding character can not contain "\n"' => [
'sequence' => 'A',
'message' => 'The padding character is invalid.',
'message' => 'The padding character can not be the newline escape sequence.',
'alphabet' => PHP_BASE32_ASCII,
'padding' => "\n",
];
Expand Down

0 comments on commit 6a7c76f

Please sign in to comment.