Skip to content

Commit 1020f75

Browse files
committed
feat: coders with support for base64 and zlib
1 parent 1da72db commit 1020f75

20 files changed

+504
-5
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,20 @@
1-
# php-binary
1+
# Library for work with binaries
2+
3+
Library for basic work with binary data in PHP.
4+
See the sample below for more information, or check out [`CoderInterface`](./src/CoderInterface.php).
5+
6+
```php
7+
use PetrKnap\Binary\Binary;
8+
9+
$data = base64_decode('hmlpFnFwbchsoQARSibVpfbWVfuwAHLbGxjFl9eC8fiGaWkWcXBtyGyhABFKJtWl9tZV+7AActsbGMWX14Lx+A==');
10+
$encoded = Binary::encode($data)->zlib()->base64(urlSafe: true)->getData();
11+
$decoded = Binary::decode($encoded)->base64()->zlib()->getData();
12+
13+
printf('Data was coded into `%s` %s.', $encoded, $decoded === $data ? 'successfully' : 'unsuccessfully');
14+
```
15+
16+
---
17+
18+
Run `composer require petrknap/binary` to install it.
19+
You can [support this project via donation](https://petrknap.github.io/donate.html).
20+
The project is licensed under [the terms of the `LGPL-3.0-or-later`](./COPYING.LESSER).

composer.json

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"WARNING": "This file is updated automatically. All keys will be overwritten, except of 'conflict', 'keywords', 'require', 'require-dev' and 'scripts'.",
2+
"WARNING": "This file is updated automatically. All keys will be overwritten, except of 'conflict', 'keywords', 'require', 'require-dev', 'scripts' and 'suggest'.",
33
"autoload": {
44
"psr-4": {
55
"PetrKnap\\Binary\\": "src"
@@ -14,7 +14,7 @@
1414
"allow-plugins": false,
1515
"sort-packages": true
1616
},
17-
"description": "Simple util for work with binary in PHP",
17+
"description": "Library for work with binaries",
1818
"funding": [
1919
{
2020
"type": "other",
@@ -24,16 +24,21 @@
2424
"homepage": "https://github.com/petrknap/php-binary",
2525
"keywords": [
2626
"binary",
27+
"helper",
28+
"base64",
2729
"encoder",
2830
"decoder",
29-
"helper"
31+
"zlib",
32+
"compression",
33+
"decompression"
3034
],
3135
"license": "LGPL-3.0-or-later",
3236
"name": "petrknap/binary",
3337
"require": {
3438
"php": ">=8.1"
3539
},
3640
"require-dev": {
41+
"ext-zlib": "*",
3742
"nunomaduro/phpinsights": "^2.11",
3843
"petrknap/shorts": "^1.3",
3944
"phpstan/phpstan": "^1.10",
@@ -46,11 +51,14 @@
4651
"phpcs --colors --standard=PSR12 --exclude=PSR12.Files.OpenTag,PSR12.Files.FileHeader,Generic.Files.LineLength src tests",
4752
"phpstan analyse --level max src",
4853
"phpstan analyse --level 5 tests",
49-
"phpinsights analyse src"
54+
"phpinsights analyse src --ansi --no-interaction"
5055
],
5156
"ci-script": [
5257
"@validate",
5358
"@test"
5459
]
60+
},
61+
"suggest": {
62+
"ext-zlib": "Required to compress data"
5563
}
5664
}

src/Binary.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
final class Binary
8+
{
9+
public static function encode(string $data): Encoder
10+
{
11+
return new Encoder($data);
12+
}
13+
14+
public static function decode(string $data): Decoder
15+
{
16+
return new Decoder($data);
17+
}
18+
}

src/Coder.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
/**
8+
* @phpstan-consistent-constructor override {@see self::create()} if not
9+
*
10+
* @implements CoderInterface<Exception\CouldNotCodeData>
11+
*/
12+
abstract class Coder implements CoderInterface
13+
{
14+
protected const BASE64_URL_SAFE_MAP = [
15+
['+', '/', '='],
16+
['-', '_', ''],
17+
];
18+
19+
public function __construct(
20+
protected readonly string $data,
21+
) {
22+
}
23+
24+
public function getData(): string
25+
{
26+
return $this->data;
27+
}
28+
29+
protected static function create(self $coder, string $data): static
30+
{
31+
return new static($data);
32+
}
33+
}

src/CoderInterface.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
/**
8+
* @template TExceptionCouldNotCodeData of Exception\CouldNotCodeData
9+
*/
10+
interface CoderInterface
11+
{
12+
public function getData(): string;
13+
14+
/**
15+
* {@see base64_encode()}/{@see base64_decode()} data
16+
*
17+
* @link https://en.wikipedia.org/wiki/Base64
18+
*
19+
* @throws TExceptionCouldNotCodeData
20+
*/
21+
public function base64(): static;
22+
23+
/**
24+
* {@see zlib_encode()}/{@see zlib_decode()} data
25+
*
26+
* @link https://en.wikipedia.org/wiki/Zlib
27+
*
28+
* @throws TExceptionCouldNotCodeData
29+
*/
30+
public function zlib(): static;
31+
}

src/Decoder.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
use Throwable;
8+
9+
class Decoder extends Coder implements DecoderInterface
10+
{
11+
public function base64(): static
12+
{
13+
try {
14+
$decoded = base64_decode(
15+
str_replace(self::BASE64_URL_SAFE_MAP[1], self::BASE64_URL_SAFE_MAP[0], $this->data),
16+
strict: true,
17+
);
18+
if ($decoded === false) {
19+
throw new Exception\CouldNotDecodeData($this, __METHOD__);
20+
}
21+
return static::create($this, $decoded);
22+
} catch (Throwable $reason) {
23+
throw new Exception\CouldNotDecodeData($this, __METHOD__, $reason);
24+
}
25+
}
26+
27+
public function zlib(int $maxLength = self::ZLIB_MAX_LENGTH): static
28+
{
29+
try {
30+
$decoded = zlib_decode($this->data, $maxLength);
31+
if ($decoded === false) {
32+
throw new Exception\CouldNotDecodeData($this, __METHOD__);
33+
}
34+
return static::create($this, $decoded);
35+
} catch (Throwable $reason) {
36+
throw new Exception\CouldNotDecodeData($this, __METHOD__, $reason);
37+
}
38+
}
39+
}

src/DecoderInterface.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
/**
8+
* @extends CoderInterface<Exception\CouldNotDecodeData>
9+
*/
10+
interface DecoderInterface extends CoderInterface
11+
{
12+
public const ZLIB_MAX_LENGTH = 0;
13+
14+
public function zlib(int $maxLength = self::ZLIB_MAX_LENGTH): static;
15+
}

src/Encoder.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
use Throwable;
8+
9+
class Encoder extends Coder implements EncoderInterface
10+
{
11+
public function base64(bool $urlSafe = self::BASE64_URL_SAFE): static
12+
{
13+
try {
14+
$encoded = base64_encode($this->data);
15+
if ($urlSafe) {
16+
$encoded = str_replace(self::BASE64_URL_SAFE_MAP[0], self::BASE64_URL_SAFE_MAP[1], $encoded);
17+
}
18+
return static::create($this, $encoded);
19+
} catch (Throwable $reason) {
20+
throw new Exception\CouldNotEncodeData($this, __METHOD__, $reason);
21+
}
22+
}
23+
24+
public function zlib(int $encoding = self::ZLIB_ENCODING, int $level = self::ZLIB_LEVEL): static
25+
{
26+
try {
27+
$encoded = zlib_encode($this->data, $encoding, $level);
28+
if ($encoded === false) {
29+
throw new Exception\CouldNotEncodeData($this, __METHOD__);
30+
}
31+
return static::create($this, $encoded);
32+
} catch (Throwable $reason) {
33+
throw new Exception\CouldNotEncodeData($this, __METHOD__, $reason);
34+
}
35+
}
36+
}

src/EncoderInterface.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary;
6+
7+
/**
8+
* @extends CoderInterface<Exception\CouldNotEncodeData>
9+
*/
10+
interface EncoderInterface extends CoderInterface
11+
{
12+
public const BASE64_URL_SAFE = false;
13+
public const ZLIB_ENCODING = ZLIB_ENCODING_RAW;
14+
public const ZLIB_LEVEL = -1;
15+
16+
public function base64(bool $urlSafe = self::BASE64_URL_SAFE): static;
17+
18+
public function zlib(int $encoding = self::ZLIB_ENCODING, int $level = self::ZLIB_LEVEL): static;
19+
}

src/Exception/BinaryException.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PetrKnap\Binary\Exception;
6+
7+
use Throwable;
8+
9+
interface BinaryException extends Throwable
10+
{
11+
}

0 commit comments

Comments
 (0)