Skip to content

Instantly share code, notes, and snippets.

@abler98
Created August 16, 2018 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abler98/5b1d3dea214c465b24d15fb6f7860a79 to your computer and use it in GitHub Desktop.
Save abler98/5b1d3dea214c465b24d15fb6f7860a79 to your computer and use it in GitHub Desktop.
Simple istr encoder/decoder
<?php
class IntString
{
/**
* Набор символов для кодирования
*/
const CHARSET = '0-9a-zA-Z_-';
/**
* @param string $input
* @param string $charset
* @param bool $charsetFormat
* @return string
*/
public static function encode(string $input, string $charset = self::CHARSET, bool $charsetFormat = true): string
{
$charset = static::charset($charset, $charsetFormat);
$base = strlen($charset) - 1;
$inputLength = strlen($input);
$chr = function (int $ord) use ($charset) {
return substr($charset, $ord, 1);
};
$encoded = '';
$value = intval($input);
$i = 0;
if ($inputLength > 1) {
$encoded .= $chr($inputLength);
$i++;
}
while ($value > $base) {
$ord = $value & $base;
$encoded .= $chr($ord);
$value >>= strlen(decbin($base));
$i++;
}
$encoded .= $chr($value);
return $encoded;
}
/**
* @param string $input
* @param string $charset
* @param bool $charsetFormat
* @return string
*/
public static function decode(string $input, string $charset = self::CHARSET, bool $charsetFormat = true): string
{
$charset = static::charset($charset, $charsetFormat);
$base = strlen($charset) - 1;
$inputLength = strlen($input);
$ord = function (string $chr) use ($charset) {
return strpos($charset, $chr);
};
$result = $shift = $i = 0;
if ($inputLength > 1) {
$size = $ord(substr($input, $i++, 1));
} else {
$size = 1;
}
for (; $i < $inputLength; $i++) {
$b = $ord(substr($input, $i, 1));
$result |= ($b & $base) << $shift;
$shift += strlen(decbin($base));
}
return str_pad($result, $size, 0, STR_PAD_LEFT);
}
/**
* @param array $input
* @param string $divider
* @param string $charset
* @param bool $charsetFormat
* @return string
*/
public static function encodeArray(array $input, string $divider = '.', string $charset = self::CHARSET, bool $charsetFormat = true): string
{
$charset = static::charset($charset, $charsetFormat);
$encoded = [];
$input = array_values($input);
$inputLength = count($input);
for ($i = 0; $i < $inputLength; $i++) {
$encoded[] = static::encode($input[$i], $charset, false);
}
return implode($divider, $encoded);
}
/**
* @param string $input
* @param string $divider
* @param string $charset
* @param bool $charsetFormat
* @return array
*/
public static function decodeArray(string $input, string $divider = '.', string $charset = self::CHARSET, bool $charsetFormat = true): array
{
$charset = static::charset($charset, $charsetFormat);
$decoded = [];
$encoded = explode($divider, $input);
$encodedLength = count($encoded);
for ($i = 0; $i < $encodedLength; $i++) {
$decoded[] = static::decode($encoded[$i], $charset, false);
}
return $decoded;
}
/**
* @param string $charset
* @param bool $charsetFormat
* @return string
*/
private static function charset(string $charset, bool $charsetFormat): string
{
if ($charsetFormat) {
$charset = static::charsetFormat($charset);
}
if (! static::charsetValidate($charset)) {
throw new InvalidArgumentException('Invalid charset size');
}
return $charset;
}
/**
* @param string $template
* @return string
*/
public static function charsetFormat(string $template): string
{
return preg_replace_callback('/(\w)-(\w)/', function ($matches) {
return implode('', range($matches[1], $matches[2]));
}, $template);
}
/**
* @param string $charset
* @return bool
*/
public static function charsetValidate(string $charset): bool
{
$base = strlen($charset) - 1;
$valid = pow(2, strlen(decbin($base))) - 1;
return $base === $valid;
}
}
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class IntStringTest extends TestCase
{
/**
* @return void
*/
public function testEncode()
{
$input = '1234';
$charset = '0-9a-zA-Z_-';
$encoded = IntString::encode($input, $charset);
$this->assertEquals($encoded, '4ij');
}
/**
* @return void
*/
public function testDecode()
{
$input = '4ij';
$charset = '0-9a-zA-Z_-';
$decoded = IntString::decode($input, $charset);
$this->assertEquals($decoded, '1234');
}
/**
* @return void
*/
public function testEncodeDecode()
{
$input = '0001';
$encoded = IntString::encode($input);
$decoded = IntString::decode($encoded);
$this->assertEquals($input, $decoded);
$input = '0123456789';
$encoded = IntString::encode($input);
$decoded = IntString::decode($encoded);
$this->assertEquals($input, $decoded);
$input = PHP_INT_MAX;
$encoded = IntString::encode($input);
$decoded = IntString::decode($encoded);
$this->assertEquals($input, $decoded);
$input = str_repeat(PHP_INT_MAX, 2);
$encoded = IntString::encode($input);
$decoded = IntString::decode($encoded);
$this->assertNotEquals($input, $decoded);
}
/**
* @return void
*/
public function testCharsetFormat()
{
$charset = IntString::charsetFormat('0-9a-z_-');
$this->assertEquals('0123456789abcdefghijklmnopqrstuvwxyz_-', $charset);
}
/**
* @return void
*/
public function testCharsetValidate()
{
$charset = IntString::charsetFormat('0-9a-zA-Z_-');
$valid = IntString::charsetValidate($charset);
$this->assertTrue($valid);
$charset = IntString::charsetFormat('0-9a-zA-Z');
$valid = IntString::charsetValidate($charset);
$this->assertNotTrue($valid);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment