mirror of
https://github.com/danog/endtoend-test-psl.git
synced 2024-11-29 20:29:52 +01:00
[Encoding] introduce encoding component
This commit is contained in:
parent
883141b2a4
commit
fa55601439
33
src/Psl/Encoding/Base64/decode.php
Normal file
33
src/Psl/Encoding/Base64/decode.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Base64;
|
||||
|
||||
use Psl\Encoding\Exception;
|
||||
|
||||
use function base64_decode;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Decode a base64-encoded string into raw binary.
|
||||
*
|
||||
* Base64 character set:
|
||||
* [A-Z] [a-z] [0-9] + /
|
||||
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
|
||||
*
|
||||
* @psalm-pure
|
||||
*
|
||||
* @throws Exception\RangeException If the encoded string contains characters outside
|
||||
* the base64 characters range.
|
||||
*/
|
||||
function decode(string $base64): string
|
||||
{
|
||||
if (!preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $base64)) {
|
||||
throw new Exception\RangeException(
|
||||
'The given base64 string contains characters outside the base64 range.'
|
||||
);
|
||||
}
|
||||
|
||||
return (string) @base64_decode($base64, true);
|
||||
}
|
25
src/Psl/Encoding/Base64/encode.php
Normal file
25
src/Psl/Encoding/Base64/encode.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Base64;
|
||||
|
||||
use Psl\Str;
|
||||
|
||||
use function base64_encode;
|
||||
use function pack;
|
||||
use function unpack;
|
||||
|
||||
/**
|
||||
* Convert a binary string into a base64-encoded string.
|
||||
*
|
||||
* Base64 character set:
|
||||
* [A-Z] [a-z] [0-9] + /
|
||||
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
function encode(string $binary): string
|
||||
{
|
||||
return base64_encode($binary);
|
||||
}
|
11
src/Psl/Encoding/Exception/ExceptionInterface.php
Normal file
11
src/Psl/Encoding/Exception/ExceptionInterface.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Exception;
|
||||
|
||||
use Psl\Exception;
|
||||
|
||||
interface ExceptionInterface extends Exception\ExceptionInterface
|
||||
{
|
||||
}
|
9
src/Psl/Encoding/Exception/IncorrectPaddingException.php
Normal file
9
src/Psl/Encoding/Exception/IncorrectPaddingException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Psl\Encoding\Exception;
|
||||
|
||||
use Psl\Exception;
|
||||
|
||||
final class IncorrectPaddingException extends Exception\InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
9
src/Psl/Encoding/Exception/RangeException.php
Normal file
9
src/Psl/Encoding/Exception/RangeException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Exception;
|
||||
|
||||
final class RangeException extends \RangeException implements ExceptionInterface
|
||||
{
|
||||
}
|
39
src/Psl/Encoding/Hex/decode.php
Normal file
39
src/Psl/Encoding/Hex/decode.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Hex;
|
||||
|
||||
use Psl\Encoding\Exception;
|
||||
use Psl\Str;
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal string into a binary string.
|
||||
*
|
||||
* Hex ( Base16 ) character set:
|
||||
* [0-9] [a-f] [A-F]
|
||||
* 0x30-0x39, 0x61-0x66, 0x41-0x46
|
||||
*
|
||||
* @psalm-pure
|
||||
*
|
||||
* @throws Exception\RangeException If the hexadecimal string contains characters outside the base16 range,
|
||||
* or an odd number of characters.
|
||||
*/
|
||||
function decode(string $hexadecimal): string
|
||||
{
|
||||
if (!ctype_xdigit($hexadecimal)) {
|
||||
throw new Exception\RangeException(
|
||||
'The given hexadecimal string contains characters outside the base16 range.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @psalm-suppress MissingThrowsDocblock */
|
||||
$hex_len = Str\length($hexadecimal, '8bit');
|
||||
if (($hex_len & 1) !== 0) {
|
||||
throw new Exception\RangeException(
|
||||
'Expected an even number of hexadecimal characters.',
|
||||
);
|
||||
}
|
||||
|
||||
return hex2bin($hexadecimal);
|
||||
}
|
19
src/Psl/Encoding/Hex/encode.php
Normal file
19
src/Psl/Encoding/Hex/encode.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Encoding\Hex;
|
||||
|
||||
/**
|
||||
* Convert a binary string into a hexadecimal string.
|
||||
*
|
||||
* Hex ( Base16 ) character set:
|
||||
* [0-9] [a-f]
|
||||
* 0x30-0x39, 0x61-0x66
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
function encode(string $binary): string
|
||||
{
|
||||
return bin2hex($binary);
|
||||
}
|
@ -323,6 +323,10 @@ final class Loader
|
||||
'Psl\Password\hash',
|
||||
'Psl\Password\needs_rehash',
|
||||
'Psl\Password\verify',
|
||||
'Psl\Encoding\Base64\encode',
|
||||
'Psl\Encoding\Base64\decode',
|
||||
'Psl\Encoding\Hex\encode',
|
||||
'Psl\Encoding\Hex\decode',
|
||||
];
|
||||
|
||||
public const INTERFACES = [
|
||||
@ -340,6 +344,7 @@ final class Loader
|
||||
'Psl\Observer\SubjectInterface',
|
||||
'Psl\Observer\ObserverInterface',
|
||||
'Psl\Result\ResultInterface',
|
||||
'Psl\Encoding\Exception\ExceptionInterface',
|
||||
];
|
||||
|
||||
public const TRAITS = [
|
||||
@ -379,6 +384,8 @@ final class Loader
|
||||
'Psl\Type\Type',
|
||||
'Psl\Json\Exception\DecodeException',
|
||||
'Psl\Json\Exception\EncodeException',
|
||||
'Psl\Encoding\Exception\IncorrectPaddingException',
|
||||
'Psl\Encoding\Exception\RangeException',
|
||||
];
|
||||
|
||||
private const TYPE_CONSTANTS = 1;
|
||||
|
@ -13,6 +13,8 @@ use Psl\Iter;
|
||||
* @psalm-param (callable(): \Generator<Tk, Tv, mixed, mixed>) $fun
|
||||
*
|
||||
* @psalm-return Iter\Iterator<Tk, Tv>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function lazy_iterator(callable $fun): Iter\Iterator
|
||||
{
|
||||
|
@ -15,6 +15,8 @@ use Psl;
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @throws Psl\Exception\InvariantViolationException If the offset is out-of-bounds.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function validate_offset(int $offset, int $length): int
|
||||
{
|
||||
|
@ -13,6 +13,8 @@ use Psl;
|
||||
* @psalm-pure
|
||||
*
|
||||
* @throws Psl\Exception\InvariantViolationException If $offset is out-of-bounds.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function validate_offset_lower_bound(int $offset, int $length): int
|
||||
{
|
||||
|
36
tests/Psl/Encoding/Base64Test.php
Normal file
36
tests/Psl/Encoding/Base64Test.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Encoding;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Encoding\Base64;
|
||||
use Psl\Encoding\Exception;
|
||||
use Psl\SecureRandom;
|
||||
|
||||
final class Base64Test extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideRandomBytes
|
||||
*/
|
||||
public function testEncodeAndDecode(string $random): void
|
||||
{
|
||||
$encoded = Base64\encode($random);
|
||||
self::assertSame($random, Base64\decode($encoded));
|
||||
}
|
||||
|
||||
public function testDecodeThrowsForCharactersOutsideTheBase64Range(): void
|
||||
{
|
||||
$this->expectException(Exception\RangeException::class);
|
||||
|
||||
Base64\decode('@~==');
|
||||
}
|
||||
|
||||
public function provideRandomBytes(): iterable
|
||||
{
|
||||
for ($i = 1; $i < 128; ++$i) {
|
||||
yield [SecureRandom\bytes($i)];
|
||||
}
|
||||
}
|
||||
}
|
49
tests/Psl/Encoding/HexTest.php
Normal file
49
tests/Psl/Encoding/HexTest.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psl\Tests\Encoding;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psl\Encoding\Hex;
|
||||
use Psl\Encoding\Exception;
|
||||
use Psl\SecureRandom;
|
||||
use Psl\Str;
|
||||
|
||||
use function bin2hex;
|
||||
|
||||
final class HexTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideRandomBytes
|
||||
*/
|
||||
public function testRandom(string $random): void
|
||||
{
|
||||
$enc = Hex\encode($random);
|
||||
self::assertSame($random, Hex\decode($enc));
|
||||
self::assertSame(bin2hex($random), $enc);
|
||||
$enc = Hex\encode($random);
|
||||
self::assertSame($random, Hex\decode($enc));
|
||||
}
|
||||
|
||||
public function testDecodeThrowsForCharactersOutsideTheHexRange(): void
|
||||
{
|
||||
$this->expectException(Exception\RangeException::class);
|
||||
|
||||
Hex\decode('gf');
|
||||
}
|
||||
|
||||
public function testDecodeThrowsForAnOddNumberOfCharacters(): void
|
||||
{
|
||||
$this->expectException(Exception\RangeException::class);
|
||||
|
||||
Hex\decode('f');
|
||||
}
|
||||
|
||||
public function provideRandomBytes(): iterable
|
||||
{
|
||||
for ($i = 1; $i < 128; ++$i) {
|
||||
yield [SecureRandom\bytes($i)];
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user