Skip to content

Commit

Permalink
Merge pull request #2 from petrknap/hash
Browse files Browse the repository at this point in the history
Add support for checksums
  • Loading branch information
petrknap committed Mar 31, 2024
2 parents 8152edb + 8d4f1d4 commit 9634cb6
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 5 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ See the sample below for more information, or check out [`CoderInterface`](./src
use PetrKnap\Binary\Binary;

$data = base64_decode('hmlpFnFwbchsoQARSibVpfbWVfuwAHLbGxjFl9eC8fiGaWkWcXBtyGyhABFKJtWl9tZV+7AActsbGMWX14Lx+A==');
$encoded = Binary::encode($data)->zlib()->base64(urlSafe: true)->getData();
$decoded = Binary::decode($encoded)->base64()->zlib()->getData();
$encoded = Binary::encode($data)->checksum()->zlib()->base64(urlSafe: true)->getData();
$decoded = Binary::decode($encoded)->base64()->zlib()->checksum()->getData();

printf('Data was coded into `%s` %s.', $encoded, $decoded === $data ? 'successfully' : 'unsuccessfully');
```
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"base64",
"encoder",
"decoder",
"checksum",
"zlib",
"compression",
"decompression"
Expand All @@ -38,6 +39,7 @@
"php": ">=8.1"
},
"require-dev": {
"ext-mbstring": "*",
"ext-zlib": "*",
"nunomaduro/phpinsights": "^2.11",
"petrknap/shorts": "^1.3",
Expand All @@ -59,6 +61,7 @@
]
},
"suggest": {
"ext-mbstring": "Required to check checksum",
"ext-zlib": "Required to compress data"
}
}
15 changes: 13 additions & 2 deletions src/CoderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
*/
interface CoderInterface
{
public const CHECKSUM_ALGORITHM = 'crc32';

public function getData(): string;

/**
* {@see base64_encode()}/{@see base64_decode()} data
* {@see base64_encode()}/{@see base64_decode()} the data
*
* @link https://en.wikipedia.org/wiki/Base64
*
Expand All @@ -21,7 +23,16 @@ public function getData(): string;
public function base64(): static;

/**
* {@see zlib_encode()}/{@see zlib_decode()} data
* Encodes/decodes the data {@see hash()} into the data
*
* @link https://en.wikipedia.org/wiki/Checksum
*
* @throws TExceptionCouldNotCodeData
*/
public function checksum(string $algorithm = self::CHECKSUM_ALGORITHM): static;

/**
* {@see zlib_encode()}/{@see zlib_decode()} the data
*
* @link https://en.wikipedia.org/wiki/Zlib
*
Expand Down
15 changes: 15 additions & 0 deletions src/Decoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ public function base64(): static
}
}

public function checksum(string $algorithm = self::CHECKSUM_ALGORITHM): static
{
try {
$checksumLength = mb_strlen(hash($algorithm, '', binary: true), encoding: '8bit');
$dataLength = mb_strlen($this->data, encoding: '8bit') - $checksumLength;
$data = mb_strcut($this->data, 0, $dataLength, encoding: '8bit');
if ((new Encoder($data))->checksum($algorithm)->getData() !== $this->data) {
throw new Exception\CouldNotDecodeData($this, __METHOD__);
}
return static::create($this, $data);
} catch (Throwable $reason) {
throw new Exception\CouldNotDecodeData($this, __METHOD__, $reason);
}
}

public function zlib(int $maxLength = self::ZLIB_MAX_LENGTH): static
{
try {
Expand Down
10 changes: 10 additions & 0 deletions src/Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ public function base64(bool $urlSafe = self::BASE64_URL_SAFE): static
}
}

public function checksum(string $algorithm = self::CHECKSUM_ALGORITHM): static
{
try {
$checksum = hash($algorithm, $this->data, binary: true);
return static::create($this, $this->data . $checksum);
} catch (Throwable $reason) {
throw new Exception\CouldNotEncodeData($this, __METHOD__, $reason);
}
}

public function zlib(int $encoding = self::ZLIB_ENCODING, int $level = self::ZLIB_LEVEL): static
{
try {
Expand Down
9 changes: 9 additions & 0 deletions tests/CoderTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public static function dataBase64(): array
];
}

public static function dataChecksum(): array
{
$data = base64_decode(self::DATA_BASE64);
return [
'crc32' => [$data, $data . hex2bin('95a41ef8'), 'crc32'],
'sha1' => [$data, $data . hex2bin('d0dc1cf9bf61884f8e7982e0b1b87954bd9ee9c7'), 'sha1'],
];
}

public static function dataZlib(): array
{
$data = base64_decode(self::DATA_BASE64);
Expand Down
28 changes: 28 additions & 0 deletions tests/DecoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,34 @@ public static function dataBase64Throws(): array
];
}

#[DataProvider('dataChecksum')]
public function testDecodesChecksum(string $decoded, string $encoded, string $algorithm): void
{
self::assertSame(
$decoded,
(new Decoder($encoded))->checksum($algorithm)->getData(),
);
}

#[DataProvider('dataChecksumThrows')]
public function testChecksumThrows(string $data, string $algorithm): void
{
self::expectException(Exception\CouldNotDecodeData::class);

(new Decoder($data))->checksum($algorithm);
}

public static function dataChecksumThrows(): array
{
$dataSet = self::dataChecksum()[CoderInterface::CHECKSUM_ALGORITHM];
return [
'wrong algorithm' => [$dataSet[1], '?'],
'short data' => ['?', CoderInterface::CHECKSUM_ALGORITHM],
'wrong data' => [$dataSet[0], CoderInterface::CHECKSUM_ALGORITHM],
'wrong checksum' => ['?' . $dataSet[1], CoderInterface::CHECKSUM_ALGORITHM],
];
}

#[DataProvider('dataZlib')]
public function testDecodesZlib(string $decoded, string $encoded): void
{
Expand Down
24 changes: 24 additions & 0 deletions tests/EncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ public function testEncodesBase64(string $decoded, string $encoded, bool $urlSaf
);
}

#[DataProvider('dataChecksum')]
public function testEncodesChecksum(string $decoded, string $encoded, string $algorithm): void
{
self::assertSame(
$encoded,
(new Encoder($decoded))->checksum($algorithm)->getData(),
);
}

#[DataProvider('dataChecksumThrows')]
public function testChecksumThrows(string $algorithm): void
{
self::expectException(Exception\CouldNotEncodeData::class);

(new Encoder(''))->checksum($algorithm);
}

public static function dataChecksumThrows(): array
{
return [
'wrong algorithm' => ['?'],
];
}

#[DataProvider('dataZlib')]
public function testEncodesZlib(string $decoded, string $encoded, int $encoding, int $level): void
{
Expand Down
2 changes: 1 addition & 1 deletion tests/ReadmeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static function getPathToMarkdownFile(): string
public static function getExpectedOutputsOfPhpExamples(): iterable
{
return [
'coders' => 'Data was coded into `a8vMFCssyD2Rs5BB0Evt6tJv10J_b2Aoui0tcXT69aaPP9oIyAMA` successfully.',
'coders' => 'Data was coded into `a8vMFCssyD2Rs5BB0Evt6tJv10J_b2Aoui0tcXT69aaPP9oIyB-fLeAHAA` successfully.',
];
}
}

0 comments on commit 9634cb6

Please sign in to comment.