From 4aae77900be26fccb23a7508744ef17d6b217e5f Mon Sep 17 00:00:00 2001 From: flashwave Date: Fri, 21 Jul 2023 21:47:41 +0000 Subject: [PATCH] Simplify serialisation. --- VERSION | 2 +- src/Http/Content/BencodedContent.php | 8 +- src/Http/Content/JsonContent.php | 7 +- src/Security/CSRFP.php | 6 +- .../{Base32Serialiser.php => Base32.php} | 12 +- .../{Base62Serialiser.php => Base62.php} | 11 +- .../{Base64Serialiser.php => Base64.php} | 14 +-- .../{BencodeSerialiser.php => Bencode.php} | 42 +++---- .../BencodeSerialiserSettings.php | 48 -------- src/Serialisation/JsonSerialiser.php | 38 ------ src/Serialisation/JsonSerialiserSettings.php | 116 ------------------ src/Serialisation/Serialiser.php | 111 ----------------- ...{UriBase64Serialiser.php => UriBase64.php} | 10 +- tests/Base32Test.php | 8 +- tests/Base62Test.php | 10 +- tests/BencodeTest.php | 48 ++++++++ 16 files changed, 105 insertions(+), 386 deletions(-) rename src/Serialisation/{Base32Serialiser.php => Base32.php} (84%) rename src/Serialisation/{Base62Serialiser.php => Base62.php} (81%) rename src/Serialisation/{Base64Serialiser.php => Base64.php} (63%) rename src/Serialisation/{BencodeSerialiser.php => Bencode.php} (81%) delete mode 100644 src/Serialisation/BencodeSerialiserSettings.php delete mode 100644 src/Serialisation/JsonSerialiser.php delete mode 100644 src/Serialisation/JsonSerialiserSettings.php delete mode 100644 src/Serialisation/Serialiser.php rename src/Serialisation/{UriBase64Serialiser.php => UriBase64.php} (76%) create mode 100644 tests/BencodeTest.php diff --git a/VERSION b/VERSION index 37f3671..e829ad6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2307.212010 +0.2307.212147 diff --git a/src/Http/Content/BencodedContent.php b/src/Http/Content/BencodedContent.php index 52dfa44..368bfb6 100644 --- a/src/Http/Content/BencodedContent.php +++ b/src/Http/Content/BencodedContent.php @@ -1,14 +1,14 @@ serialise($this->content); + return Bencode::encode($this->content); } public function __toString(): string { @@ -35,7 +35,7 @@ class BencodedContent implements Stringable, IHttpContent, IBencodeSerialisable } public static function fromEncoded(Stream|string $encoded): BencodedContent { - return new BencodedContent(Serialiser::bencode()->deserialise($encoded)); + return new BencodedContent(Bencode::decode($encoded)); } public static function fromFile(string $path): BencodedContent { diff --git a/src/Http/Content/JsonContent.php b/src/Http/Content/JsonContent.php index e2658f7..d08bd83 100644 --- a/src/Http/Content/JsonContent.php +++ b/src/Http/Content/JsonContent.php @@ -1,7 +1,7 @@ serialise($this->content); + return json_encode($this->content); } public function __toString(): string { @@ -35,7 +34,7 @@ class JsonContent implements Stringable, IHttpContent, JsonSerializable { } public static function fromEncoded(Stream|string $encoded): JsonContent { - return new JsonContent(Serialiser::json()->deserialise($encoded)); + return new JsonContent(json_decode($encoded)); } public static function fromFile(string $path): JsonContent { diff --git a/src/Security/CSRFP.php b/src/Security/CSRFP.php index 7d11bf0..3e63253 100644 --- a/src/Security/CSRFP.php +++ b/src/Security/CSRFP.php @@ -5,7 +5,7 @@ namespace Index\Security; -use Index\Serialisation\Serialiser; +use Index\Serialisation\UriBase64; /** * Contains a mechanism for validating requests. @@ -60,7 +60,7 @@ class CSRFP { $nonce = random_bytes(self::NONCE_LENGTH); $hash = $this->createHash($time, $nonce); - return Serialiser::uriBase64()->serialise( + return UriBase64::encode( pack('V', $time) . $nonce . $hash ); } @@ -79,7 +79,7 @@ class CSRFP { if($tolerance < 0) $tolerance = $this->tolerance; - $token = Serialiser::uriBase64()->deserialise($token); + $token = UriBase64::decode($token); if(empty($token)) return false; diff --git a/src/Serialisation/Base32Serialiser.php b/src/Serialisation/Base32.php similarity index 84% rename from src/Serialisation/Base32Serialiser.php rename to src/Serialisation/Base32.php index f2bf941..e994d5e 100644 --- a/src/Serialisation/Base32Serialiser.php +++ b/src/Serialisation/Base32.php @@ -1,7 +1,7 @@ = 0; --$i) { @@ -38,7 +37,7 @@ class Base62Serialiser extends Serialiser { * @param Stream|string $input Input Base62 string. * @return int Integer. */ - public function deserialise(Stream|string $input): mixed { + public static function decode(Stream|string $input): int { $input = (string)$input; $output = 0; $length = strlen($input) - 1; diff --git a/src/Serialisation/Base64Serialiser.php b/src/Serialisation/Base64.php similarity index 63% rename from src/Serialisation/Base64Serialiser.php rename to src/Serialisation/Base64.php index 6e8cc39..67965a5 100644 --- a/src/Serialisation/Base64Serialiser.php +++ b/src/Serialisation/Base64.php @@ -1,7 +1,7 @@ settings = $settings ?? new BencodeSerialiserSettings; - } - - public function serialise(mixed $input): string { - return self::encode((string)$input, $this->settings->getMaxDepth()); - } - - public function deserialise(Stream|string $input): mixed { - if(!($input instanceof Stream)) - $input = TempFileStream::fromString($input); - return $this->decode($input, $this->settings->getMaxDepth()); - } - - private static function encode(mixed $input, int $depth): string { + public static function encode(mixed $input, int $depth = self::DEFAULT_DEPTH): string { if($depth < 1) throw new RuntimeException('Maximum depth reached, structure is too dense.'); @@ -79,7 +60,12 @@ class BencodeSerialiser extends Serialiser { } } - private function decode(Stream $input, int $depth): mixed { + public static function decode(Stream|string $input, int $depth = self::DEFAULT_DEPTH, bool $dictAsObject = false): mixed { + if(!($input instanceof Stream)) { + $input = TempFileStream::fromString($input); + $input->seek(0); + } + if($depth < 1) throw new RuntimeException('Maximum depth reached, structure is too dense.'); @@ -120,7 +106,7 @@ class BencodeSerialiser extends Serialiser { if($char === 'e') break; $input->seek(-1, Stream::CURRENT); - $list[] = $this->decode($input, $depth - 1); + $list[] = self::decode($input, $depth - 1, $dictAsObject); } return $list; @@ -137,10 +123,10 @@ class BencodeSerialiser extends Serialiser { if(!ctype_digit($char)) throw new RuntimeException('Unexpected dictionary key type, expected a string.'); $input->seek(-1, Stream::CURRENT); - $dict[$this->decode($input, $depth - 1)] = $this->decode($input, $depth - 1); + $dict[self::decode($input, $depth - 1, $dictAsObject)] = self::decode($input, $depth - 1, $dictAsObject); } - if($this->settings->shouldDecodeDictAsObject()) + if($dictAsObject) $dict = (object)$dict; return $dict; diff --git a/src/Serialisation/BencodeSerialiserSettings.php b/src/Serialisation/BencodeSerialiserSettings.php deleted file mode 100644 index 2051f0d..0000000 --- a/src/Serialisation/BencodeSerialiserSettings.php +++ /dev/null @@ -1,48 +0,0 @@ -maxDepth = $maxDepth; - $this->dictAsObject = $dictAsObject; - } - - /** - * Gets the maximum recursion depth. - * - * @return int Maximum recursion depth. - */ - public function getMaxDepth(): int { - return $this->maxDepth; - } - - /** - * Gets whether dictionaries should be decoded as objects (instances of stdClass). - * - * @return bool True if dictionaries should be objects, false if they should be associative arrays. - */ - public function shouldDecodeDictAsObject(): bool { - return $this->dictAsObject; - } -} diff --git a/src/Serialisation/JsonSerialiser.php b/src/Serialisation/JsonSerialiser.php deleted file mode 100644 index b9b2d90..0000000 --- a/src/Serialisation/JsonSerialiser.php +++ /dev/null @@ -1,38 +0,0 @@ -settings = $settings ?? new JsonSerialiserSettings; - } - - public function serialise(mixed $input): string { - $output = json_encode($input, $this->settings->getFlags(), $this->settings->getMaxDepth()); - if($output === false) - $output = ''; - return $output; - } - - public function deserialise(Stream|string $input): mixed { - //if($input instanceof WString) - // $input = $input->convertEncoding('utf-8'); - return json_decode((string)$input, false, $this->settings->getMaxDepth(), $this->settings->getFlags()); - } -} diff --git a/src/Serialisation/JsonSerialiserSettings.php b/src/Serialisation/JsonSerialiserSettings.php deleted file mode 100644 index 81ef08d..0000000 --- a/src/Serialisation/JsonSerialiserSettings.php +++ /dev/null @@ -1,116 +0,0 @@ - to \u003C and \u003E respectively. - * @param bool $convertAmpersand Converts & to \u0026. - * @param bool $convertApostrophe Converts ' to \u0027. - * @param bool $ignoreInvalidUtf8 Ignores invalid UTF-8 characters. - * @param bool $substituteInvalidUtf8 Converts invalid UTF-8 characters to \0xfffd (Unicode Character 'REPLACEMENT CHARACTER'). - * @param bool $numericCheck Encodes numeric strings as numbers. - * @param bool $partialOutputOnError Substitute some unencodable values instead of failing. - * @param bool $unescapedLineTerminators The line terminators are kept unescaped when $unescapedUnicode is true. - * @param bool $unescapedSlashes Don't escape /. - * @param bool $unescapedUnicode Encode multibyte Unicode characters literally (default is to escape as \uXXXX). - * @param bool $bigIntAsString Decodes large integers as their original string value. - * @param bool $objectAsArray Decodes JSON objects as PHP array. - */ - public function __construct( - int $maxDepth = self::DEFAULT_DEPTH, - bool $throwOnError = true, - bool $preserveZeroFraction = true, - bool $prettyPrint = false, - bool $forceObject = false, - bool $encodeQuotes = false, - bool $convertTags = false, - bool $convertAmpersand = false, - bool $convertApostrophe = false, - bool $ignoreInvalidUtf8 = false, - bool $substituteInvalidUtf8 = false, - bool $numericCheck = false, - bool $partialOutputOnError = false, - bool $unescapedLineTerminators = false, - bool $unescapedSlashes = false, - bool $unescapedUnicode = false, - bool $bigIntAsString = false, - bool $objectAsArray = false - ) { - $this->maxDepth = $maxDepth; - - $flags = 0; - if($throwOnError) - $flags |= JSON_THROW_ON_ERROR; - if($preserveZeroFraction) - $flags |= JSON_PRESERVE_ZERO_FRACTION; - if($prettyPrint) - $flags |= JSON_PRETTY_PRINT; - if($forceObject) - $flags |= JSON_FORCE_OBJECT; - if($encodeQuotes) - $flags |= JSON_HEX_QUOT; - if($convertTags) - $flags |= JSON_HEX_TAG; - if($convertAmpersand) - $flags |= JSON_HEX_AMP; - if($convertApostrophe) - $flags |= JSON_HEX_APOS; - if($ignoreInvalidUtf8) - $flags |= JSON_INVALID_UTF8_IGNORE; - if($substituteInvalidUtf8) - $flags |= JSON_INVALID_UTF8_SUBSTITUTE; - if($numericCheck) - $flags |= JSON_NUMERIC_CHECK; - if($partialOutputOnError) - $flags |= JSON_PARTIAL_OUTPUT_ON_ERROR; - if($unescapedLineTerminators) - $flags |= JSON_UNESCAPED_LINE_TERMINATORS; - if($unescapedSlashes) - $flags |= JSON_UNESCAPED_SLASHES; - if($unescapedUnicode) - $flags |= JSON_UNESCAPED_UNICODE; - if($bigIntAsString) - $flags |= JSON_BIGINT_AS_STRING; - if($objectAsArray) - $flags |= JSON_OBJECT_AS_ARRAY; - $this->flags = $flags; - } - - /** - * Gets the maximum recursion depth. - * - * @return int Maximum recursion depth. - */ - public function getMaxDepth(): int { - return $this->maxDepth; - } - - /** - * Gets the flagset constructed by the constructor arguments. - * - * @return int JSON flagset. - */ - public function getFlags(): int { - return $this->flags; - } -} diff --git a/src/Serialisation/Serialiser.php b/src/Serialisation/Serialiser.php deleted file mode 100644 index 922b9dd..0000000 --- a/src/Serialisation/Serialiser.php +++ /dev/null @@ -1,111 +0,0 @@ -write($this->serialise($input)); - } -} diff --git a/src/Serialisation/UriBase64Serialiser.php b/src/Serialisation/UriBase64.php similarity index 76% rename from src/Serialisation/UriBase64Serialiser.php rename to src/Serialisation/UriBase64.php index 190c465..b02954b 100644 --- a/src/Serialisation/UriBase64Serialiser.php +++ b/src/Serialisation/UriBase64.php @@ -1,7 +1,7 @@ $expected) - $this->assertEquals($expected, (string)Serialiser::base32()->deserialise($value)); + $this->assertEquals($expected, Base32::decode($value)); } public function testEncode(): void { foreach(self::TESTS as $expected => $value) - $this->assertEquals($expected, (string)Serialiser::base32()->serialise($value)); + $this->assertEquals($expected, Base32::encode($value)); } } diff --git a/tests/Base62Test.php b/tests/Base62Test.php index 1916191..93fa6b5 100644 --- a/tests/Base62Test.php +++ b/tests/Base62Test.php @@ -1,15 +1,15 @@ assertEquals($test[1], Serialiser::base62()->deserialise($test[0])); + $this->assertEquals($test[1], Base62::decode($test[0])); } public function testEncode(): void { foreach(self::TESTS as $test) - $this->assertEquals($test[0], (string)Serialiser::base62()->serialise($test[1])); + $this->assertEquals($test[0], Base62::encode($test[1])); } } diff --git a/tests/BencodeTest.php b/tests/BencodeTest.php new file mode 100644 index 0000000..c592219 --- /dev/null +++ b/tests/BencodeTest.php @@ -0,0 +1,48 @@ +assertEquals(5, count($decoded)); + + $this->assertArrayHasKey('announce', $decoded); + $this->assertEquals('https://tracker.flashii.net/announce.php/meow', $decoded['announce']); + + $this->assertArrayHasKey('creation date', $decoded); + $this->assertEquals(1689973664, $decoded['creation date']); + + $this->assertArrayHasKey('info', $decoded); + + $this->assertArrayHasKey('private', $decoded['info']); + $this->assertEquals(1, $decoded['info']['private']); + + $decoded = Bencode::decode(base64_decode(self::TORRENT), dictAsObject: true); + + $this->assertEquals('https://tracker.flashii.net/announce.php/meow', $decoded->announce); + $this->assertEquals(1689973664, $decoded->{'creation date'}); + $this->assertEquals('this is the comments field', $decoded->comment); + $this->assertEquals(1, $decoded->info->private); + } + + public function testEncode(): void { + $original = base64_decode(self::TORRENT); + $decoded = Bencode::decode($original); + $encoded = Bencode::encode($decoded); + + $this->assertEquals($original, $encoded); + } +}