Skip to content

Commit 1c06391

Browse files
committed
feat: Adds validation for data decoding in base62.
1 parent a453e68 commit 1c06391

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

src/Base62.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
namespace TinyBlocks\Encoder;
44

5+
use TinyBlocks\Encoder\Internal\Exceptions\InvalidBase62Encoding;
6+
57
final class Base62
68
{
79
private const BASE62_RADIX = 62;
810
private const BASE62_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
9-
private const HEXADECIMAL_RADIX = 16;
11+
private const BASE62_HEXADECIMAL_RADIX = 16;
1012

1113
public static function encode(string $value): string
1214
{
@@ -21,16 +23,20 @@ public static function encode(string $value): string
2123
$base62 = str_repeat(self::BASE62_ALPHABET[0], $bytes);
2224

2325
if (empty($hexadecimal)) {
24-
return strtr($base62, self::BASE62_ALPHABET, self::BASE62_ALPHABET);
26+
return $base62;
2527
}
2628

27-
$base62Conversion = gmp_strval(gmp_init($hexadecimal, self::HEXADECIMAL_RADIX), self::BASE62_RADIX);
29+
$number = gmp_init($hexadecimal, self::BASE62_HEXADECIMAL_RADIX);
2830

29-
return strtr($base62 . $base62Conversion, self::BASE62_ALPHABET, self::BASE62_ALPHABET);
31+
return $base62 . gmp_strval($number, self::BASE62_RADIX);
3032
}
3133

3234
public static function decode(string $value): string
3335
{
36+
if (strlen($value) !== strspn($value, self::BASE62_ALPHABET)) {
37+
throw new InvalidBase62Encoding(value: $value);
38+
}
39+
3440
$bytes = 0;
3541

3642
while (!empty($value) && str_starts_with($value, self::BASE62_ALPHABET[0])) {
@@ -42,9 +48,10 @@ public static function decode(string $value): string
4248
return str_repeat("\x00", $bytes);
4349
}
4450

45-
$hexadecimal = gmp_strval(gmp_init($value, self::BASE62_RADIX), self::HEXADECIMAL_RADIX);
51+
$number = gmp_init($value, self::BASE62_RADIX);
52+
$hexadecimal = gmp_strval($number, self::BASE62_HEXADECIMAL_RADIX);
4653

47-
if (strlen($hexadecimal) % 2 !== 0) {
54+
if (strlen($hexadecimal) % 2) {
4855
$hexadecimal = '0' . $hexadecimal;
4956
}
5057

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace TinyBlocks\Encoder\Internal\Exceptions;
4+
5+
use RuntimeException;
6+
7+
final class InvalidBase62Encoding extends RuntimeException
8+
{
9+
public function __construct(private readonly string $value)
10+
{
11+
$template = 'The value <%s> does not have a valid base62 encoding.';
12+
parent::__construct(message: sprintf($template, $this->value));
13+
}
14+
}

tests/Base62Test.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace TinyBlocks\Encoder;
44

55
use PHPUnit\Framework\TestCase;
6+
use TinyBlocks\Encoder\Internal\Exceptions\InvalidBase62Encoding;
67

78
class Base62Test extends TestCase
89
{
@@ -37,6 +38,17 @@ public function testEncodeAndDecodeWithLeadingZeroBytes(string $value): void
3738
self::assertEquals($value, $actual);
3839
}
3940

41+
public function testWhenInvalidBase62Encoding(): void
42+
{
43+
$value = hex2bin('9850EEEC191BF4FF26F99315CE43B0C8');
44+
$template = 'The value <%s> does not have a valid base62 encoding.';
45+
46+
$this->expectException(InvalidBase62Encoding::class);
47+
$this->expectExceptionMessage(sprintf($template, $value));
48+
49+
Base62::decode(value: $value);
50+
}
51+
4052
public function providerForTestEncode(): array
4153
{
4254
return [

0 commit comments

Comments
 (0)