Skip to content

Commit

Permalink
Merge pull request #5 from petrknap/refactor
Browse files Browse the repository at this point in the history
Refactoring
  • Loading branch information
petrknap committed Apr 3, 2024
2 parents 39adf3d + f0f0472 commit 8a3e38d
Show file tree
Hide file tree
Showing 48 changed files with 919 additions and 716 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Library for work with binaries
# Library for work with binary data and objects

Library for basic work with binary data in PHP.
See the examples below for more information, or check out [`CoderInterface`](./src/CoderInterface.php) and [`SerializerInterface`](./src/SerializerInterface.php).
Simple library for work with binary data and objects in PHP.
See the examples below for more information, or check out [`Encoder`](./src/Encoder.php), [`Decoder`](./src/Decoder.php) and [`Serializer`](./src/Serializer.php).

```php
use PetrKnap\Binary\Binary;
Expand Down
20 changes: 11 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"allow-plugins": false,
"sort-packages": true
},
"description": "Library for work with binaries",
"description": "Library for work with binary data and objects",
"funding": [
{
"type": "other",
Expand All @@ -23,21 +23,23 @@
],
"homepage": "https://github.com/petrknap/php-binary",
"keywords": [
"binary",
"helper",
"base64",
"encoder",
"decoder",
"binary",
"checksum",
"zlib",
"compression",
"decompression"
"decoder",
"decompression",
"encoder",
"helper",
"igbinary",
"serializer",
"zlib"
],
"license": "LGPL-3.0-or-later",
"name": "petrknap/binary",
"require": {
"petrknap/shorts": "^1.4",
"php": ">=8.1"
"php": ">=8.1",
"petrknap/shorts": "^1.5"
},
"require-dev": {
"ext-mbstring": "*",
Expand Down
13 changes: 2 additions & 11 deletions src/Binary.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,11 @@ public static function decode(string $data): Decoder

public static function serialize(mixed $data): string
{
return self::getSerializer()->serialize(serializable: $data);
return (new Serializer())->serialize(serializable: $data);
}

public static function unserialize(string $data): mixed
{
return self::getSerializer()->unserialize(serialized: $data);
}

private static function getSerializer(): Serializer
{
static $serializer;
return $serializer ??= new Serializer(
new Encoder(),
new Decoder(),
);
return (new Serializer())->unserialize(serialized: $data);
}
}
11 changes: 5 additions & 6 deletions src/Coder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@

namespace PetrKnap\Binary;

use PetrKnap\Shorts\Exception;

/**
* @internal please use subclass
*
* @phpstan-consistent-constructor override {@see self::create()} if not
*
* @implements CoderInterface<Exception\CouldNotCodeData>
* @implements CoderInterface<Exception\CouldNotProcessData>
*/
abstract class Coder implements CoderInterface
{
protected const BASE64_URL_SAFE_MAP = [
['+', '/', '='],
['-', '_', ''],
];

public function __construct(
protected readonly string $data = '',
) {
Expand Down
47 changes: 47 additions & 0 deletions src/Coder/Base64.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder;

/**
* @see base64_encode()
* @see base64_decode()
*/
final class Base64 extends Coder
{
public const URL_SAFE = false;
private const URL_REPLACE_TABLE = [
['+', '/', '='],
['-', '_', ''],
];

private bool $urlSafe;

public function encode(string $decoded, ?bool $urlSafe = null): string
{
$this->urlSafe = $urlSafe ?? self::URL_SAFE;
return parent::encode($decoded);
}

protected function doEncode(string $decoded): string
{
$encoded = base64_encode($decoded);
if ($this->urlSafe) {
$encoded = str_replace(self::URL_REPLACE_TABLE[0], self::URL_REPLACE_TABLE[1], $encoded);
}
return $encoded;
}

protected function doDecode(string $encoded): string
{
$decoded = base64_decode(
str_replace(self::URL_REPLACE_TABLE[1], self::URL_REPLACE_TABLE[0], $encoded),
strict: true,
);
if ($decoded === false) {
throw new Exception\CouldNotDecodeData(__METHOD__, $encoded);
}
return $decoded;
}
}
60 changes: 60 additions & 0 deletions src/Coder/Checksum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder;

use PetrKnap\Binary\HasRequirementsTrait;
use PetrKnap\Shorts\HasRequirements;

/**
* @see hash()
*
* @link https://en.wikipedia.org/wiki/Checksum
*/
final class Checksum extends Coder implements HasRequirements
{
use HasRequirementsTrait;

public const ALGORITHM = 'crc32';
private const REQUIRED_FUNCTIONS = [
'mb_strlen',
'mb_strcut',
];

private string $algorithm;

public function __construct()
{
self::checkRequirements();
}

public function encode(string $decoded, ?string $algorithm = null): string
{
$this->algorithm = $algorithm ?? self::ALGORITHM;
return parent::encode($decoded);
}

public function decode(string $encoded, ?string $algorithm = null): string
{
$this->algorithm = $algorithm ?? self::ALGORITHM;
return parent::decode($encoded);
}

protected function doEncode(string $decoded): string
{
$checksum = hash($this->algorithm, $decoded, binary: true);
return $decoded . $checksum;
}

protected function doDecode(string $encoded): string
{
$checksumLength = mb_strlen(hash($this->algorithm, '', binary: true), encoding: '8bit');
$dataLength = mb_strlen($encoded, encoding: '8bit') - $checksumLength;
$decoded = mb_strcut($encoded, 0, $dataLength, encoding: '8bit');
if ($this->doEncode($decoded) !== $encoded) {
throw new Exception\CouldNotDecodeData(__METHOD__, $encoded);
}
return $decoded;
}
}
44 changes: 44 additions & 0 deletions src/Coder/Coder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder;

use Throwable;

abstract class Coder implements CoderInterface
{
public function encode(string $decoded): string
{
try {
return $this->doEncode($decoded);
} catch (Throwable $reason) {
if ($reason instanceof Exception\CouldNotEncodeData) {
throw $reason;
}
throw new Exception\CouldNotEncodeData(__METHOD__, $decoded, $reason);
}
}

public function decode(string $encoded): string
{
try {
return $this->doDecode($encoded);
} catch (Throwable $reason) {
if ($reason instanceof Exception\CouldNotDecodeData) {
throw $reason;
}
throw new Exception\CouldNotDecodeData(__METHOD__, $encoded, $reason);
}
}

/**
* @throws Throwable
*/
abstract protected function doEncode(string $decoded): string;

/**
* @throws Throwable
*/
abstract protected function doDecode(string $encoded): string;
}
18 changes: 18 additions & 0 deletions src/Coder/CoderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder;

interface CoderInterface
{
/**
* @throws Exception\CouldNotEncodeData
*/
public function encode(string $decoded): string;

/**
* @throws Exception\CouldNotDecodeData
*/
public function decode(string $encoded): string;
}
11 changes: 11 additions & 0 deletions src/Coder/Exception/CoderException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder\Exception;

use PetrKnap\Binary\Exception\BinaryException;

interface CoderException extends BinaryException
{
}
14 changes: 14 additions & 0 deletions src/Coder/Exception/CouldNotDecodeData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder\Exception;

use PetrKnap\Shorts\Exception\CouldNotProcessData;

/**
* @extends CouldNotProcessData<string>
*/
final class CouldNotDecodeData extends CouldNotProcessData implements CoderException
{
}
14 changes: 14 additions & 0 deletions src/Coder/Exception/CouldNotEncodeData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder\Exception;

use PetrKnap\Shorts\Exception\CouldNotProcessData;

/**
* @extends CouldNotProcessData<string>
*/
final class CouldNotEncodeData extends CouldNotProcessData implements CoderException
{
}
60 changes: 60 additions & 0 deletions src/Coder/Zlib.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Binary\Coder;

use PetrKnap\Binary\HasRequirementsTrait;
use PetrKnap\Shorts\HasRequirements;

/**
* @see zlib_encode()
* @see zlib_decode()
*/
final class Zlib extends Coder implements HasRequirements
{
use HasRequirementsTrait;

public const ENCODING = ZLIB_ENCODING_RAW;
public const LEVEL = -1;
public const MAX_LENGTH = 0;
private const REQUIRED_FUNCTIONS = [
'zlib_encode',
'zlib_decode',
];

private int $encoding;
private int $level;
private int $maxLength;

public function encode(string $decoded, ?int $encoding = null, ?int $level = null): string
{
$this->encoding = $encoding ?? self::ENCODING;
$this->level = $level ?? self::LEVEL;
return parent::encode($decoded);
}

public function decode(string $encoded, ?int $maxLength = null): string
{
$this->maxLength = $maxLength ?? self::MAX_LENGTH;
return parent::decode($encoded);
}

protected function doEncode(string $decoded): string
{
$encoded = zlib_encode($decoded, $this->encoding, $this->level);
if ($encoded === false) {
throw new Exception\CouldNotEncodeData(__METHOD__, $decoded);
}
return $encoded;
}

protected function doDecode(string $encoded): string
{
$decoded = zlib_decode($encoded, $this->maxLength);
if ($decoded === false) {
throw new Exception\CouldNotDecodeData(__METHOD__, $encoded);
}
return $decoded;
}
}
Loading

0 comments on commit 8a3e38d

Please sign in to comment.