Created
August 16, 2018 10:08
-
-
Save abler98/5b1d3dea214c465b24d15fb6f7860a79 to your computer and use it in GitHub Desktop.
Simple istr encoder/decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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