Skip to content

Commit 832a929

Browse files
committed
feat: Adds encoder implementation.
0 parents  commit 832a929

File tree

11 files changed

+417
-0
lines changed

11 files changed

+417
-0
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
auto-review:
12+
name: Auto review
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v3
18+
19+
- name: Install dependencies
20+
run: composer update --no-progress --optimize-autoloader
21+
22+
- name: Run phpcs
23+
run: composer phpcs
24+
25+
- name: Run phpmd
26+
run: composer phpmd
27+
28+
tests:
29+
name: Tests
30+
runs-on: ubuntu-latest
31+
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v3
35+
36+
- name: Install dependencies
37+
run: composer update --no-progress --optimize-autoloader
38+
39+
- name: Run unit tests
40+
env:
41+
XDEBUG_MODE: coverage
42+
run: composer test
43+
44+
- name: Run mutation tests
45+
run: composer test-mutation

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
vendor
3+
report
4+
composer.lock
5+
.phpunit.result.cache

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022-2023 Tiny Blocks
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
DOCKER_RUN = docker run --rm -it --net=host -v ${PWD}:/app -w /app gustavofreze/php:8.2.6
2+
3+
.PHONY: configure test test-no-coverage review show-reports clean
4+
5+
configure:
6+
@${DOCKER_RUN} composer update --optimize-autoloader
7+
8+
test: review
9+
@${DOCKER_RUN} composer tests
10+
11+
test-no-coverage: review
12+
@${DOCKER_RUN} composer tests-no-coverage
13+
14+
review:
15+
@${DOCKER_RUN} composer review
16+
17+
show-reports:
18+
@sensible-browser report/coverage/coverage-html/index.html report/coverage/mutation-report.html
19+
20+
clean:
21+
@sudo chown -R ${USER}:${USER} ${PWD}
22+
@rm -rf report vendor

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Encoder
2+
3+
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
4+
5+
* [Overview](#overview)
6+
* [Installation](#installation)
7+
* [How to use](#how-to-use)
8+
* [License](#license)
9+
* [Contributing](#contributing)
10+
11+
<div id='overview'></div>
12+
13+
## Overview
14+
15+
Encoder and decoder for arbitrary data.
16+
17+
<div id='installation'></div>
18+
19+
## Installation
20+
21+
```bash
22+
composer require tiny-blocks/encoder
23+
```
24+
25+
<div id='how-to-use'></div>
26+
27+
## How to use
28+
29+
The library exposes concrete implementations for encoding and decoding data.
30+
31+
### Using Base62
32+
33+
```php
34+
$encoded = Base62::encode(value: 'Hello world!')
35+
36+
echo $encoded; # T8dgcjRGuYUueWht
37+
38+
$decoded = Base62::decode(value: $encoded)
39+
40+
echo $encoded; # Hello world!
41+
```
42+
43+
## License
44+
45+
Math is licensed under [MIT](/LICENSE).
46+
47+
<div id='contributing'></div>
48+
49+
## Contributing
50+
51+
Please follow the [contributing guidelines](https://github.com/tiny-blocks/tiny-blocks/blob/main/CONTRIBUTING.md) to
52+
contribute to the project.

composer.json

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"name": "tiny-blocks/encoder",
3+
"type": "library",
4+
"license": "MIT",
5+
"homepage": "https://github.com/tiny-blocks/encoder",
6+
"description": "Encoder and decoder for arbitrary data.",
7+
"prefer-stable": true,
8+
"minimum-stability": "stable",
9+
"keywords": [
10+
"psr",
11+
"psr-4",
12+
"psr-12",
13+
"base62",
14+
"decoder",
15+
"encoder",
16+
"tiny-blocks"
17+
],
18+
"authors": [
19+
{
20+
"name": "Gustavo Freze de Araujo Santos",
21+
"homepage": "https://github.com/gustavofreze"
22+
}
23+
],
24+
"config": {
25+
"sort-packages": true,
26+
"allow-plugins": {
27+
"infection/extension-installer": true
28+
}
29+
},
30+
"autoload": {
31+
"psr-4": {
32+
"TinyBlocks\\Encoder\\": "src/"
33+
}
34+
},
35+
"autoload-dev": {
36+
"psr-4": {
37+
"TinyBlocks\\Encoder\\": "tests/"
38+
}
39+
},
40+
"require": {
41+
"php": "^8.2",
42+
"ext-gmp": "*"
43+
},
44+
"require-dev": {
45+
"infection/infection": "^0.26",
46+
"phpmd/phpmd": "^2.12",
47+
"phpunit/phpunit": "^9.5",
48+
"squizlabs/php_codesniffer": "^3.7"
49+
},
50+
"scripts": {
51+
"phpcs": "phpcs --standard=PSR12 --extensions=php ./src",
52+
"phpmd": "phpmd ./src text phpmd.xml --suffixes php --ignore-violations-on-exit",
53+
"test": "phpunit --log-junit=report/coverage/junit.xml --coverage-xml=report/coverage/coverage-xml --coverage-html=report/coverage/coverage-html tests",
54+
"test-mutation": "infection --only-covered --logger-html=report/coverage/mutation-report.html --coverage=report/coverage --min-msi=100 --min-covered-msi=100 --threads=4",
55+
"test-no-coverage": "phpunit --no-coverage",
56+
"test-mutation-no-coverage": "infection --only-covered --min-msi=100 --threads=4",
57+
"review": [
58+
"@phpcs",
59+
"@phpmd"
60+
],
61+
"tests": [
62+
"@test",
63+
"@test-mutation"
64+
],
65+
"tests-no-coverage": [
66+
"@test-no-coverage",
67+
"@test-mutation-no-coverage"
68+
]
69+
}
70+
}

infection.json.dist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"timeout": 10,
3+
"testFramework": "phpunit",
4+
"tmpDir": "report/",
5+
"source": {
6+
"directories": [
7+
"src"
8+
]
9+
},
10+
"logs": {
11+
"text": "report/logs/infection-text.log",
12+
"summary": "report/logs/infection-summary.log"
13+
},
14+
"mutators": {
15+
"@default": true,
16+
"FalseValue": false
17+
},
18+
"phpUnit": {
19+
"configDir": "",
20+
"customPath": "./vendor/bin/phpunit"
21+
}
22+
}

phpmd.xml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="PHPMD Custom rules"
3+
xmlns="http://pmd.sf.net/ruleset/1.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
6+
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
7+
<description>PHPMD Custom rules</description>
8+
9+
<rule ref="rulesets/cleancode.xml/ElseExpression"/>
10+
<rule ref="rulesets/cleancode.xml/BooleanArgumentFlag"/>
11+
12+
<rule ref="rulesets/codesize.xml/TooManyFields"/>
13+
<rule ref="rulesets/codesize.xml/TooManyMethods"/>
14+
<rule ref="rulesets/codesize.xml/NPathComplexity"/>
15+
<rule ref="rulesets/codesize.xml/CyclomaticComplexity"/>
16+
<rule ref="rulesets/codesize.xml/ExcessivePublicCount"/>
17+
<rule ref="rulesets/codesize.xml/ExcessiveClassLength"/>
18+
<rule ref="rulesets/codesize.xml/TooManyPublicMethods"/>
19+
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>
20+
<rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>
21+
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity"/>
22+
23+
<rule ref="rulesets/controversial.xml/Superglobals"/>
24+
<rule ref="rulesets/controversial.xml/CamelCaseClassName"/>
25+
<rule ref="rulesets/controversial.xml/CamelCaseMethodName"/>
26+
<rule ref="rulesets/controversial.xml/CamelCasePropertyName"/>
27+
<rule ref="rulesets/controversial.xml/CamelCaseVariableName"/>
28+
<rule ref="rulesets/controversial.xml/CamelCaseParameterName"/>
29+
30+
<rule ref="rulesets/design.xml/GotoStatement"/>
31+
<rule ref="rulesets/design.xml/ExitExpression"/>
32+
<rule ref="rulesets/design.xml/EvalExpression"/>
33+
<rule ref="rulesets/design.xml/NumberOfChildren"/>
34+
<rule ref="rulesets/design.xml/DepthOfInheritance"/>
35+
<rule ref="rulesets/design.xml/CouplingBetweenObjects"/>
36+
<rule ref="rulesets/design.xml/DevelopmentCodeFragment"/>
37+
38+
<rule ref="rulesets/naming.xml/LongVariable"/>
39+
<rule ref="rulesets/naming.xml/ShortVariable">
40+
<properties>
41+
<property name="minimum" value="2"/>
42+
</properties>
43+
</rule>
44+
<rule ref="rulesets/naming.xml/ShortMethodName">
45+
<properties>
46+
<property name="minimum" value="2"/>
47+
</properties>
48+
</rule>
49+
<rule ref="rulesets/naming.xml/BooleanGetMethodName"/>
50+
<rule ref="rulesets/naming.xml/ConstantNamingConventions"/>
51+
<rule ref="rulesets/naming.xml/ConstructorWithNameAsEnclosingClass"/>
52+
53+
<rule ref="rulesets/unusedcode.xml/UnusedPrivateField"/>
54+
<rule ref="rulesets/unusedcode.xml/UnusedLocalVariable"/>
55+
<rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod"/>
56+
<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter"/>
57+
</ruleset>

phpunit.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
bootstrap="vendor/autoload.php"
4+
cacheResultFile="report/.phpunit.result.cache"
5+
backupGlobals="false"
6+
backupStaticAttributes="false"
7+
colors="true"
8+
convertErrorsToExceptions="true"
9+
convertNoticesToExceptions="true"
10+
convertWarningsToExceptions="true"
11+
processIsolation="false"
12+
stopOnFailure="false"
13+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
14+
<testsuites>
15+
<testsuite name="default">
16+
<directory suffix="Test.php">tests</directory>
17+
</testsuite>
18+
</testsuites>
19+
20+
<coverage>
21+
<include>
22+
<directory suffix=".php">src</directory>
23+
</include>
24+
</coverage>
25+
</phpunit>

src/Base62.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace TinyBlocks\Encoder;
4+
5+
final class Base62
6+
{
7+
private const BASE62_RADIX = 62;
8+
private const BASE62_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
9+
private const HEXADECIMAL_RADIX = 16;
10+
11+
public static function encode(string $value): string
12+
{
13+
if (empty($value)) {
14+
return $value;
15+
}
16+
17+
$hexadecimal = bin2hex($value);
18+
$decimal = gmp_init($hexadecimal, self::HEXADECIMAL_RADIX);
19+
$encoded = '';
20+
21+
while (gmp_cmp($decimal, '0') > 0) {
22+
$remainder = gmp_intval(gmp_mod($decimal, self::BASE62_RADIX));
23+
$decimal = gmp_div_q($decimal, self::BASE62_RADIX);
24+
$encoded = self::BASE62_ALPHABET[$remainder] . $encoded;
25+
}
26+
27+
return $encoded;
28+
}
29+
30+
public static function decode(string $value): string
31+
{
32+
if (empty($value)) {
33+
return $value;
34+
}
35+
36+
$decimal = gmp_init('0');
37+
38+
for ($i = 0, $length = strlen($value); $i < $length; $i++) {
39+
$character = $value[$i];
40+
$position = strpos(self::BASE62_ALPHABET, $character);
41+
$decimal = gmp_mul($decimal, self::BASE62_RADIX);
42+
$decimal = gmp_add($decimal, $position);
43+
}
44+
45+
$hexadecimal = gmp_strval($decimal, self::HEXADECIMAL_RADIX);
46+
$decoded = hex2bin($hexadecimal);
47+
48+
return $decoded !== false ? $decoded : '';
49+
}
50+
}

0 commit comments

Comments
 (0)