diff --git a/ext/standard/base32.c b/ext/standard/base32.c new file mode 100644 index 0000000000000..c3aecb0fe25d1 --- /dev/null +++ b/ext/standard/base32.c @@ -0,0 +1,171 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Ignace Nyamagana Butera | + +----------------------------------------------------------------------+ + */ + +#include + +#include "php.h" +#include "base32.h" + +#define PHP_BASE32_ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" +#define PHP_BASE32_HEX "0123456789ABCDEFGHIJKLMNOPQRSTUV" + +/* reserved invalid characters for padding or alphabet. */ +static const char reserved[4] = "\r\n\t "; +static const char base32_pad = '='; + +/* {{{ functions to allow encoding a string using RFC4648 base32 algorithm. */ +PHP_FUNCTION(base32_encode) +{ + zend_string *decoded, *padding = base32_pad, *alphabet = PHP_BASE32_ASCII; + int offset = 0, bitLen = 0, val = 0, len, shift; + + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_STR(decoded) + Z_PARAM_OPTIONAL + Z_PARAM_STR(alphabet) + Z_PARAM_STR(padding) + ZEND_PARSE_PARAMETERS_END(); + + if (ZSTR_LEN(padding) != 1) { + zend_argument_value_error(3, "The padding character must be a single byte character."); + RETURN_THROWS(); + } + + if (strcspn(reserved, ZSTR_VAL(padding)) != 4) { + zend_argument_value_error(1, "The padding character can not be a reserved character."); + RETURN_THROWS(); + } + + if (ZSTR_LEN(alphabet) != 32) { + zend_argument_value_error(1, "The alphabet must be a 32 bytes long string."); + RETURN_THROWS(); + } + + zend_string *upper_alpha = zend_string_toupper(alphabet); + zend_string *upper_padding = zend_string_toupper(padding); + zend_string *reserved_chars = zend_string_concat2(reserved, 4, ZSTR_VAL(upper_padding), 1); + + if (strcspn(ZSTR_VAL(upper_alpha), reserved_chars) != 32) { + zend_argument_value_error(1, "The alphabet can not contain a reserved character or the padding character."); + RETURN_THROWS(); + } + + smart_str unique_chars = {0}; + for (int i = 0; i < 32; i++) { + char c = upper_alpha[i]; + if (strstr(unique_chars, c)) { + zend_argument_value_error(1, 'The alphabet must only contain unique characters.'); + RETURN_THROWS(); + } + + smart_str_appends(&unique_chars, c); + } + smart_str_free(&unique_chars); + + len = ZSTR_LEN(decoded); + if (len == 0) { + RETURN_EMPTY_STRING(); + } + + char chars[] = ZSTR_VAL(decoded); + + smart_str encoded = {0}; + while (offset < len || bitLen != 0) { + if (bitLen < 5) { + bitLen += 8; + offset++; + val = (val << 8) + chars[offset]; + } + + shift = bitLen - 5; + if (offset - (bitLen > 8 ? 1 : 0) > len && 0 === val) { + smart_str_appends(&encoded, padding); + } else { + smart_str_appends(&encoded, alphabet[val >> shift]); + } + + val &= ((1 << shift) - 1); + bitLen -= 5; + } + + zend_string *ret_val = smart_str_extract(encoded); + + RETURN_STR(ret_val); +} +/* }}} */ + +/* {{{ functions to allow decoding a base32 encoded string using RFC4648 base32 algorithm. */ +PHP_FUNCTION(base32_decode) +{ + zend_string *encoded, *padding = base32_pad, *alphabet = PHP_BASE32_ASCII; + int offset = 0, bitLen = 0, val = 0, len, shift; + bool strict; + + ZEND_PARSE_PARAMETERS_START(1, 4) + Z_PARAM_STR(encoded) + Z_PARAM_OPTIONAL + Z_PARAM_STR(alphabet) + Z_PARAM_STR(padding) + Z_PARAM_BOOL(strict) + ZEND_PARSE_PARAMETERS_END(); + + if (ZSTR_LEN(padding) != 1) { + zend_argument_value_error(3, "The padding character must be a single byte character."); + RETURN_THROWS(); + } + + if (strcspn(reserved, ZSTR_VAL(padding)) != 4) { + zend_argument_value_error(1, "The padding character can not be a reserved character."); + RETURN_THROWS(); + } + + if (ZSTR_LEN(alphabet) != 32) { + zend_argument_value_error(1, "The alphabet must be a 32 bytes long string."); + RETURN_THROWS(); + } + + zend_string *upper_alpha = zend_string_toupper(alphabet); + zend_string *upper_padding = zend_string_toupper(padding); + zend_string *reserved_chars = zend_string_concat2(reserved, 4, ZSTR_VAL(upper_padding), 1); + + if (strcspn(ZSTR_VAL(upper_alpha), reserved_chars) != 32) { + zend_argument_value_error(1, "The alphabet can not contain a reserved character or the padding character."); + RETURN_THROWS(); + } + + smart_str unique_chars = {0}; + for (int i = 0; i < 32; i++) { + char c = upper_alpha[i]; + if (strstr(unique_chars, c)) { + zend_argument_value_error(1, 'The alphabet must only contain unique characters.'); + RETURN_THROWS(); + } + + smart_str_appends(&unique_chars, c); + } + smart_str_free(&unique_chars); + + len = ZSTR_LEN(encoded); + if (len == 0) { + RETURN_EMPTY_STRING(); + } + + //@todo adding encoded validation + //@todo adding RFC4648 decoding algorithm + + RETURN_STR(encoded); +} +/* }}} */ diff --git a/ext/standard/base32.h b/ext/standard/base32.h new file mode 100644 index 0000000000000..fd788f5261011 --- /dev/null +++ b/ext/standard/base32.h @@ -0,0 +1,23 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Ignace Nyamagana Butera | + +----------------------------------------------------------------------+ + */ + +#ifndef BASE32_H +#define BASE32_H + +PHP_FUNCTION(base32_decode); +PHP_FUNCTION(base32_encode); + +#endif diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 891edd9b092b0..ce75bcd6a3e25 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -259,6 +259,19 @@ */ const PHP_QUERY_RFC3986 = UNKNOWN; +/** + * @var string + * @cvalue PHP_BASE32_ASCII + */ +const PHP_BASE32_ASCII = UNKNOWN; + +/** + * @var string + * @cvalue PHP_BASE32_HEX + */ +const PHP_BASE32_HEX = UNKNOWN; + + /** * @var float * @cvalue M_E @@ -1924,6 +1937,20 @@ function array_combine(array $keys, array $values): array {} /** @compile-time-eval */ function array_is_list(array $array): bool {} +/* base32.c */ + +/** + * @compile-time-eval + * @refcount 1 + */ +function base32_encode(string $decoded, string $alphabet = PHP_BASE32_ASCII, string $padding = '='): string {} + +/** + * @compile-time-eval + * @refcount 1 + */ +function base32_decode(string $encoded, string $alphabet = PHP_BASE32_ASCII, string $padding = '=', bool $strict = false): string|false {} + /* base64.c */ /** diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e1004480ece6a..6226403b04e08 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: b8ea4527467c70a6f665129cd5d5f34ea2386a70 */ + * Stub hash: 929b27449ba8839b14a248c62ef2d4ff14a0daad */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -364,6 +364,19 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_is_list, 0, 1, _IS_BOOL, 0 ZEND_ARG_TYPE_INFO(0, array, IS_ARRAY, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_base32_encode, 0, 1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, decoded, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, alphabet, IS_STRING, 0, "PHP_BASE32_ASCII") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, padding, IS_STRING, 0, "\'=\'") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_base32_decode, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, encoded, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, alphabet, IS_STRING, 0, "PHP_BASE32_ASCII") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, padding, IS_STRING, 0, "\'=\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, strict, _IS_BOOL, 0, "false") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_base64_encode, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -2404,6 +2417,8 @@ ZEND_FUNCTION(array_key_exists); ZEND_FUNCTION(array_chunk); ZEND_FUNCTION(array_combine); ZEND_FUNCTION(array_is_list); +ZEND_FUNCTION(base32_encode); +ZEND_FUNCTION(base32_decode); ZEND_FUNCTION(base64_encode); ZEND_FUNCTION(base64_decode); ZEND_FUNCTION(constant); @@ -3027,6 +3042,8 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY("array_chunk", zif_array_chunk, arginfo_array_chunk, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_RAW_FENTRY("array_combine", zif_array_combine, arginfo_array_combine, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_RAW_FENTRY("array_is_list", zif_array_is_list, arginfo_array_is_list, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) + ZEND_RAW_FENTRY("base32_encode", zif_base32_encode, arginfo_base32_encode, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) + ZEND_RAW_FENTRY("base32_decode", zif_base32_decode, arginfo_base32_decode, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_RAW_FENTRY("base64_encode", zif_base64_encode, arginfo_base64_encode, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_RAW_FENTRY("base64_decode", zif_base64_decode, arginfo_base64_decode, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_FE(constant, arginfo_constant) @@ -3630,6 +3647,8 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_URL_FRAGMENT", PHP_URL_FRAGMENT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_QUERY_RFC1738", PHP_QUERY_RFC1738, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_QUERY_RFC3986", PHP_QUERY_RFC3986, CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("PHP_BASE32_ASCII", PHP_BASE32_ASCII, CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("PHP_BASE32_HEX", PHP_BASE32_HEX, CONST_PERSISTENT); REGISTER_DOUBLE_CONSTANT("M_E", M_E, CONST_PERSISTENT); ZEND_ASSERT(M_E == 2.718281828459045); REGISTER_DOUBLE_CONSTANT("M_LOG2E", M_LOG2E, CONST_PERSISTENT); diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt new file mode 100644 index 0000000000000..6cc311bc8f19c --- /dev/null +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt @@ -0,0 +1,152 @@ +--TEST-- +Test base32_decode() function : invalid parameters in relax mode +--FILE-- + [ + 'encoded' => 'CPNMUOJ1E8Z======', + 'alphabet' => PHP_BASE32_HEX, + 'padding' => '=', + 'expected' => 'foobar', + ], + 'characters outside of base32 us ascii alphabet' => [ + 'encoded' => '90890808', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => '', + ], + 'characters not upper-cased' => [ + 'encoded' => 'MzxQ====', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => 'fo', + ], + 'padding character in the middle of the sequence' => [ + 'encoded' => 'Mzx==Q====', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => 'fo', + ], + 'invalid padding length' => [ + 'encoded' => 'MzxQ=======', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => 'fo', + ], + 'invalid encoded string length' => [ + 'encoded' => 'MzxQ', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => 'fo', + ], + 'invalid alphabet length' => [ + 'encoded' => 'MZXQ=====', + 'alphabet' => '1234560asdfghjklzxcvbnm', + 'padding' => '=', + 'error' => 'The alphabet must be a 32 bytes long string.', + ], + 'the padding character is contained within the alphabet' => [ + 'encoded' => 'MZXQ=======', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => '*', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the padding character is contained within the alphabet is case insensitive' => [ + 'encoded' => 'MZXQ=======', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'a', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the padding character is different than one byte' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'yo', + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\r"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\r", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\n"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\n", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\t"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\t", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the alphabet can not contain "\r"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_ASCII, 0, -1)."\r", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the alphabet can not contain "\n"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\n", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the alphabet can not contain "\t"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\t", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], +]; + +foreach ($testData as $testTitle => $data) { + try { + echo "$testTitle: "; + $res = base32_decode($data['encoded'], $data['alphabet'], $data['padding']); + if (isset($data['expected'])) { + if ($res === $data['expected']) { + echo "TEST PASSED\n"; + } else { + echo "TEST FAILED\n"; + } + } else { + echo "TEST FAILED\n"; + } + } catch (ValueError $exception) { + if (isset($data['error'])) { + if ($exception->getMessage() === $data['error']) { + echo "TEST PASSED\n"; + } else { + echo "TEST FAILED\n"; + } + } else { + echo "TEST FAILED\n"; + } + } +} +echo "\nDone\n"; +?> +--EXPECT-- +*** Testing base32_decode() : invalid parameters in relax mode*** + +characters outside of base32 extended hex alphabet: TEST PASSED +characters outside of base32 us ascii alphabet: TEST PASSED +characters not upper-cased: TEST PASSED +padding character in the middle of the sequence: TEST PASSED +invalid padding length: TEST PASSED +invalid encoded string length: TEST PASSED +invalid alphabet length: TEST PASSED +the padding character is contained within the alphabet: TEST PASSED +the padding character is contained within the alphabet is case insensitive: TEST PASSED +the padding character is different than one byte: TEST PASSED +the padding character can not contain "\r": TEST PASSED +the padding character can not contain "\n": TEST PASSED +the padding character can not contain "\t": TEST PASSED +the alphabet can not contain "\r": TEST PASSED +the alphabet can not contain "\n": TEST PASSED +the alphabet can not contain "\t": TEST PASSED + +Done diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt new file mode 100644 index 0000000000000..ea1928591b046 --- /dev/null +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt @@ -0,0 +1,152 @@ +--TEST-- +Test base32_decode() function : invalid parameters in strict mode +--FILE-- + [ + 'encoded' => 'CPNMUOJ1E8Z======', + 'alphabet' => PHP_BASE32_HEX, + 'padding' => '=', + 'expected' => false, + ], + 'characters outside of base32 us ascii alphabet' => [ + 'encoded' => '90890808', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => false, + ], + 'characters not upper-cased' => [ + 'encoded' => 'MzxQ====', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => false, + ], + 'padding character in the middle of the sequence' => [ + 'encoded' => 'Mzx==Q====', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => false, + ], + 'invalid padding length' => [ + 'encoded' => 'MzxQ=======', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => false, + ], + 'invalid encoded string length' => [ + 'encoded' => 'MzxQ', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + 'expected' => false, + ], + 'invalid alphabet length' => [ + 'encoded' => 'MZXQ=====', + 'alphabet' => '1234560asdfghjklzxcvbnm', + 'padding' => '=', + 'error' => 'The alphabet must be a 32 bytes long string.', + ], + 'the padding character is contained within the alphabet' => [ + 'encoded' => 'MZXQ=======', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => '*', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the padding character is contained within the alphabet is case insensitive' => [ + 'encoded' => 'MZXQ=======', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'a', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the padding character is different than one byte' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'yo', + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\r"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\r", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\n"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\n", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the padding character can not contain "\t"' => [ + 'encoded' => 'A', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\t", + 'error' => 'The padding character must be a non-reserved single byte character.', + ], + 'the alphabet can not contain "\r"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_ASCII, 0, -1)."\r", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the alphabet can not contain "\n"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\n", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], + 'the alphabet can not contain "\t"' => [ + 'encoded' => 'A', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\t", + 'padding' => '=', + 'error' => 'The alphabet can not contain a reserved character.', + ], +]; + +foreach ($testData as $testTitle => $data) { + try { + echo "$testTitle: "; + $res = base32_decode($data['encoded'], $data['alphabet'], $data['padding'], true); + if (isset($data['expected'])) { + if ($res === $data['expected']) { + echo "TEST PASSED\n"; + } else { + echo "TEST FAILED\n"; + } + } else { + echo "TEST FAILED\n"; + } + } catch (ValueError $exception) { + if (isset($data['error'])) { + if ($exception->getMessage() === $data['error']) { + echo "TEST PASSED\n"; + } else { + echo "TEST FAILED\n"; + } + } else { + echo "TEST FAILED\n"; + } + } +} +echo "\nDone\n"; +?> +--EXPECT-- +*** Testing base32_decode() : invalid parameters in strict mode*** + +characters outside of base32 extended hex alphabet: TEST PASSED +characters outside of base32 us ascii alphabet: TEST PASSED +characters not upper-cased: TEST PASSED +padding character in the middle of the sequence: TEST PASSED +invalid padding length: TEST PASSED +invalid encoded string length: TEST PASSED +invalid alphabet length: TEST PASSED +the padding character is contained within the alphabet: TEST PASSED +the padding character is contained within the alphabet is case insensitive: TEST PASSED +the padding character is different than one byte: TEST PASSED +the padding character can not contain "\r": TEST PASSED +the padding character can not contain "\n": TEST PASSED +the padding character can not contain "\t": TEST PASSED +the alphabet can not contain "\r": TEST PASSED +the alphabet can not contain "\n": TEST PASSED +the alphabet can not contain "\t": TEST PASSED + +Done diff --git a/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt b/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt new file mode 100644 index 0000000000000..a52e00e18ecfa --- /dev/null +++ b/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test base32_decode() function strict mode vs relax mode +--FILE-- + ['f', 'CO======'], + 'RFC Vector 2' => ['fo', 'CPNG===='], + 'RFC Vector 3' => ['foo', 'CPNMU==='], + 'RFC Vector 4' => ['foob', 'CPNMUOG='], + 'RFC Vector 5' => ['fooba', 'CPNMUOJ1'], + 'RFC Vector 6' => ['foobar', 'CPNMUOJ1E8======'], + 'Old Vector 1' => [' ', '40======'], + 'Old Vector 2' => [' ', '40G0===='], + 'Old Vector 3' => [' ', '40G20==='], + 'Old Vector 4' => [' ', '40G2080='], + 'Old Vector 5' => [' ', '40G20810'], + 'Old Vector 6' => [' ', '40G2081040======'], + 'Empty String' => ['', ''], + 'Random Integers' => [base64_decode('HgxBl1kJ4souh+ELRIHm/x8yTc/cgjDmiCNyJR/NJfs=', true), '3O6435QP17HCKBK7S45K90F6VSFJ4JEFRI131PK84DP2A7UD4NTG===='], +]; + +foreach ($values as $name => [$decoded, $encoded]) { + echo $name, PHP_EOL; + var_dump(base32_encode(decoded: $decoded, alphaber:PHP_BASE32_HEX, padding: '=')); +} +echo "Done"; +?> +--EXPECT-- +*** Testing base32_encode() : basic functionality with hex alphabet *** +RFC Vector 1 +string(8) "CO======" +RFC Vector 2 +string(8) "CPNG====" +RFC Vector 3 +string(8) "CPNMU===" +RFC Vector 4 +string(8) "CPNMUOG=" +RFC Vector 5 +string(8) "CPNMUOJ1" +RFC Vector 6 +string(16) "CPNMUOJ1E8======" +Old Vector 1 +string(8) "40======" +Old Vector 2 +string(8) "40G0====" +Old Vector 3 +string(8) "40G20===" +Old Vector 4 +string(8) "40G2080=" +Old Vector 5 +string(8) "40G20810" +Old Vector 6 +string(16) "40G2081040======" +Empty String +string(0) "" +Random Integers +string(56) "3O6435QP17HCKBK7S45K90F6VSFJ4JEFRI131PK84DP2A7UD4NTG====" +Done diff --git a/ext/standard/tests/url/base32_encode_hex_002.phpt b/ext/standard/tests/url/base32_encode_hex_002.phpt new file mode 100644 index 0000000000000..276a1ee629c2d --- /dev/null +++ b/ext/standard/tests/url/base32_encode_hex_002.phpt @@ -0,0 +1,73 @@ +--TEST-- +Test base32_encode() function : basic functionality - check algorithm round trips with hex alphabet +--FILE-- + +--EXPECT-- +*** Testing base32_encode() : basic functionality *** + +--- Testing base32_encode() with binary string input --- +-- Iteration 1 -- +TEST PASSED +-- Iteration 2 -- +TEST PASSED +-- Iteration 3 -- +TEST PASSED +-- Iteration 4 -- +TEST PASSED +-- Iteration 5 -- +TEST PASSED +-- Iteration 6 -- +TEST PASSED +-- Iteration 7 -- +TEST PASSED +-- Iteration 8 -- +TEST PASSED +-- Iteration 9 -- +TEST PASSED diff --git a/ext/standard/tests/url/base32_encode_us_ascii_001.phpt b/ext/standard/tests/url/base32_encode_us_ascii_001.phpt new file mode 100644 index 0000000000000..bd8a5e20e43c1 --- /dev/null +++ b/ext/standard/tests/url/base32_encode_us_ascii_001.phpt @@ -0,0 +1,79 @@ +--TEST-- +Test base32_encode() function : basic functionality with us-ascii alphabet +--FILE-- + ['f', 'MY======'], + 'RFC Vector 2' => ['fo', 'MZXQ===='], + 'RFC Vector 3' => ['foo', 'MZXW6==='], + 'RFC Vector 4' => ['foob', 'MZXW6YQ='], + 'RFC Vector 5' => ['fooba', 'MZXW6YTB'], + 'RFC Vector 6' => ['foobar', 'MZXW6YTBOI======'], + 'Old Vector 1' => [' ', 'EA======'], + 'Old Vector 2' => [' ', 'EAQA===='], + 'Old Vector 3' => [' ', 'EAQCA==='], + 'Old Vector 4' => [' ', 'EAQCAIA='], + 'Old Vector 5' => [' ', 'EAQCAIBA'], + 'Old Vector 6' => [' ', 'EAQCAIBAEA======'], + 'Empty String' => ['', ''], + 'Random Integers' => [base64_decode('HgxBl1kJ4souh+ELRIHm/x8yTc/cgjDmiCNyJR/NJfs=', true), 'DYGEDF2ZBHRMULUH4EFUJAPG74PTETOP3SBDBZUIENZCKH6NEX5Q===='], + 'Partial zero edge case' => ['8', 'HA======'], +]; + +foreach ($values as $name => [$decoded, $encoded]) { + echo $name, PHP_EOL; + var_dump(base32_encode($decoded)); + var_dump(base32_encode(decoded: $decoded, alphaber:PHP_BASE32_ASCII, padding: '=')); +} +echo "Done"; +?> +--EXPECT-- +*** Testing base32_encode() : basic functionality *** +RFC Vector 1 +string(8) "MY======" +string(8) "MY======" +RFC Vector 2 +string(8) "MZXQ====" +string(8) "MZXQ====" +RFC Vector 3 +string(8) "MZXW6===" +string(8) "MZXW6===" +RFC Vector 4 +string(8) "MZXW6YQ=" +string(8) "MZXW6YQ=" +RFC Vector 5 +string(8) "MZXW6YTB" +string(8) "MZXW6YTB" +RFC Vector 6 +string(16) "MZXW6YTBOI======" +string(16) "MZXW6YTBOI======" +Old Vector 1 +string(8) "EA======" +string(8) "EA======" +Old Vector 2 +string(8) "EAQA====" +string(8) "EAQA====" +Old Vector 3 +string(8) "EAQCA===" +string(8) "EAQCA===" +Old Vector 4 +string(8) "EAQCAIA=" +string(8) "EAQCAIA=" +Old Vector 5 +string(8) "EAQCAIBA" +string(8) "EAQCAIBA" +Old Vector 6 +string(16) "EAQCAIBAEA======" +string(16) "EAQCAIBAEA======" +Empty String +string(0) "" +string(0) "" +Random Integers +string(56) "DYGEDF2ZBHRMULUH4EFUJAPG74PTETOP3SBDBZUIENZCKH6NEX5Q====" +string(56) "DYGEDF2ZBHRMULUH4EFUJAPG74PTETOP3SBDBZUIENZCKH6NEX5Q====" +Partial zero edge case +string(8) "HA======" +string(8) "HA======" +Done diff --git a/ext/standard/tests/url/base32_encode_us_ascii_002.phpt b/ext/standard/tests/url/base32_encode_us_ascii_002.phpt new file mode 100644 index 0000000000000..1335b66efa562 --- /dev/null +++ b/ext/standard/tests/url/base32_encode_us_ascii_002.phpt @@ -0,0 +1,73 @@ +--TEST-- +Test base32_encode() function : basic functionality - check algorithm round trips with us-ascii alphabet +--FILE-- + +--EXPECT-- +*** Testing base32_encode() : basic functionality *** + +--- Testing base32_encode() with binary string input --- +-- Iteration 1 -- +TEST PASSED +-- Iteration 2 -- +TEST PASSED +-- Iteration 3 -- +TEST PASSED +-- Iteration 4 -- +TEST PASSED +-- Iteration 5 -- +TEST PASSED +-- Iteration 6 -- +TEST PASSED +-- Iteration 7 -- +TEST PASSED +-- Iteration 8 -- +TEST PASSED +-- Iteration 9 -- +TEST PASSED