From 01f37ea81d6a85104b457619f837ad8dbe3c1712 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 12:11:48 +0100 Subject: [PATCH 01/12] Adding base32 test files --- .../base32_decode_invalid_parameters_001.phpt | 168 ++++++++++++++++++ .../base32_decode_invalid_parameters_002.phpt | 168 ++++++++++++++++++ .../base32_encode_decode_strict_mode_001.phpt | 25 +++ .../tests/url/base32_encode_hex_001.phpt | 60 +++++++ .../tests/url/base32_encode_hex_002.phpt | 73 ++++++++ .../tests/url/base32_encode_us_ascii_001.phpt | 79 ++++++++ .../tests/url/base32_encode_us_ascii_002.phpt | 73 ++++++++ 7 files changed, 646 insertions(+) create mode 100644 ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt create mode 100644 ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt create mode 100644 ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt create mode 100644 ext/standard/tests/url/base32_encode_hex_001.phpt create mode 100644 ext/standard/tests/url/base32_encode_hex_002.phpt create mode 100644 ext/standard/tests/url/base32_encode_us_ascii_001.phpt create mode 100644 ext/standard/tests/url/base32_encode_us_ascii_002.phpt diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt new file mode 100644 index 0000000000000..149bf939e2659 --- /dev/null +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt @@ -0,0 +1,168 @@ +--TEST-- +Test base32_decode() function : invalid parameters in strict mode +--FILE-- + [ + 'sequence' => 'CPNMUOJ1E8Z======', + 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'alphabet' => PHP_BASE32_HEX, + 'padding' => '=', + ], + 'characters outside of base32 us ascii alphabet' => [ + 'sequence' => '90890808', + 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'characters not upper-cased' => [ + 'sequence' => 'MzxQ====', + 'message' => 'The encoded string contains lower-cased characters which is forbidden on strict mode.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'padding character in the middle of the sequence' => [ + 'sequence' => 'Mzx==Q====', + 'message' => 'A padding character is contained in the middle of the encoded string.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid padding length' => [ + 'sequence' => 'MzxQ=======', + 'message' => 'The encoded string contains an invalid padding length.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid encoded string length' => [ + 'sequence' => 'A', + 'message' => 'The encoded string length is not a multiple of 8.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid alphabet length' => [ + 'sequence' => 'A', + 'message' => 'The alphabet must be a 32 bytes long string.', + 'alphabet' => '1234567890asdfghjklzxcvbnm', + 'padding' => '=', + ], + 'the padding character is contained within the alphabet' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => '*', + ], + 'the padding character is contained within the alphabet is case insensitive' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => 'a', + ]; + 'the padding character is different than one byte' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'yo', + ]; + 'the padding character can not contain "\r"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\r", + ]; + 'the padding character can not contain "\n"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\n", + ]; + 'the padding character can not contain "\t"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\t", + ]; + 'the alphabet can not contain "\r"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_ASCII, 0, -1)."\r", + 'padding' => '=', + ]; + 'the alphabet can not contain "\n"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\n", + 'padding' => '=', + ]; + 'the alphabet can not contain "\t"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\t", + 'padding' => '=', + ]; +]; + +foreach ($testData as $testTitle => $data) { + try { + echo "$testTitle\n"; + var_dump(base32_decode($data['sequence'], $data['alphabet'], $data['padding'], true)); + echo "===\n"; + } catch (ValueError $exception) { + echo "error message: ", $exception->getMessage(), "\n===\n"; + } +} +echo "\nDone\n"; +?> +--EXPECT-- +*** Testing base32_decode() : invalid parameters in strict mode *** + +characters outside of base32 extended hex alphabet +bool(false) +=== +characters outside of base32 us ascii alphabet +bool(false) +=== +characters not upper-cased +bool(false) +=== +padding character in the middle of the sequence +bool(false) +=== +invalid padding length +bool(false) +=== +invalid encoded string length +bool(false) +=== +invalid alphabet length +error message: The alphabet must be a 32 bytes long string. +=== +the padding character is contained within the alphabet +error message: The alphabet can not contain a reserved character. +=== +the padding character is contained within the alphabet is case insensitive +bool(false) +=== +the padding character is different than one byte +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\r" +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\n" +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\t" +error message: The padding character must be a non-reserved single byte character. +=== +the alphabet can not contain "\r" +error message: The alphabet can not contain a reserved character. +=== +the alphabet can not contain "\n" +error message: The alphabet can not contain a reserved character. +=== +the alphabet can not contain "\t" +error message: The alphabet can not contain a reserved character. +=== + +Done diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt new file mode 100644 index 0000000000000..bc09f4b22724b --- /dev/null +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt @@ -0,0 +1,168 @@ +--TEST-- +Test base32_decode() function : invalid parameters in relax mode +--FILE-- + [ + 'sequence' => 'CPNMUOJ1E8Z======', + 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'alphabet' => PHP_BASE32_HEX, + 'padding' => '=', + ], + 'characters outside of base32 us ascii alphabet' => [ + 'sequence' => '90890808', + 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'characters not upper-cased' => [ + 'sequence' => 'MzxQ====', + 'message' => 'The encoded string contains lower-cased characters which is forbidden on strict mode.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'padding character in the middle of the sequence' => [ + 'sequence' => 'Mzx==Q====', + 'message' => 'A padding character is contained in the middle of the encoded string.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid padding length' => [ + 'sequence' => 'MzxQ=======', + 'message' => 'The encoded string contains an invalid padding length.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid encoded string length' => [ + 'sequence' => 'A', + 'message' => 'The encoded string length is not a multiple of 8.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => '=', + ], + 'invalid alphabet length' => [ + 'sequence' => 'A', + 'message' => 'The alphabet must be a 32 bytes long string.', + 'alphabet' => '1234567890asdfghjklzxcvbnm', + 'padding' => '=', + ], + 'the padding character is contained within the alphabet' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => '*', + ], + 'the padding character is contained within the alphabet is case insensitive' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + 'padding' => 'a', + ], + 'the padding character is different than one byte' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => 'yo', + ], + 'the padding character can not contain "\r"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\r", + ], + 'the padding character can not contain "\n"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\n", + ], + 'the padding character can not contain "\t"' => [ + 'sequence' => 'A', + 'message' => 'The padding character must be a non reserved single byte character.', + 'alphabet' => PHP_BASE32_ASCII, + 'padding' => "\t", + ], + 'the alphabet can not contain "\r"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_ASCII, 0, -1)."\r", + 'padding' => '=', + ], + 'the alphabet can not contain "\n"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\n", + 'padding' => '=', + ], + 'the alphabet can not contain "\t"' => [ + 'sequence' => 'A', + 'message' => 'The alphabet can not contain a reserved character.', + 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\t", + 'padding' => '=', + ], +]; + +foreach ($testData as $testTitle => $data) { + try { + echo "$testTitle\n"; + var_dump(base32_decode($data['sequence'], $data['alphabet'], $data['padding'], false)); + echo "===\n"; + } catch (ValueError $exception) { + echo "error message: ", $exception->getMessage(), "\n===\n"; + } +} +echo "\nDone\n"; +?> +--EXPECT-- +*** Testing base32_decode() : invalid parameters in relax mode*** + +characters outside of base32 extended hex alphabet +string(6) "foobar" +=== +characters outside of base32 us ascii alphabet +string(0) "" +=== +characters not upper-cased +string(2) "fo" +=== +padding character in the middle of the sequence +string(2) "fo" +=== +invalid padding length +string(2) "fo" +=== +invalid encoded string length +string(0) "" +=== +invalid alphabet length +error message: The alphabet must be a 32 bytes long string. +=== +the padding character is contained within the alphabet +error message: The alphabet can not contain a reserved character. +=== +the padding character is contained within the alphabet is case insensitive +string(0) "" +=== +the padding character is different than one byte +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\r" +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\n" +error message: The padding character must be a non-reserved single byte character. +=== +the padding character can not contain "\t" +error message: The padding character must be a non-reserved single byte character. +=== +the alphabet can not contain "\r" +error message: The alphabet can not contain a reserved character. +=== +the alphabet can not contain "\n" +error message: The alphabet can not contain a reserved character. +=== +the alphabet can not contain "\t" +error message: The alphabet can not contain a reserved character. +=== + +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..89360fde22eed --- /dev/null +++ b/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt @@ -0,0 +1,25 @@ +--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 From e340992d1326f7f5dee321c1e0a159158e14f10c Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 12:12:13 +0100 Subject: [PATCH 02/12] Adding base32 stub info --- ext/standard/base32.c | 0 ext/standard/base32.h | 0 ext/standard/basic_functions.stub.php | 14 ++++++++++++++ 3 files changed, 14 insertions(+) create mode 100644 ext/standard/base32.c create mode 100644 ext/standard/base32.h diff --git a/ext/standard/base32.c b/ext/standard/base32.c new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/ext/standard/base32.h b/ext/standard/base32.h new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 891edd9b092b0..5c834e4fcc296 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1924,6 +1924,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 */ /** From 7b5c4a77a4c99c689d656eb63451b1435dba89dc Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 16:06:20 +0100 Subject: [PATCH 03/12] Adding arginfo entry and base32 headers --- ext/standard/base32.h | 10 ++++++++++ ext/standard/basic_functions_arginfo.h | 15 +++++++++++++++ ...se32_decode_invalid_parameters_relax_001.phpt} | 0 ...e32_decode_invalid_parameters_strict_001.phpt} | 0 4 files changed, 25 insertions(+) rename ext/standard/tests/url/{base32_decode_invalid_parameters_002.phpt => base32_decode_invalid_parameters_relax_001.phpt} (100%) rename ext/standard/tests/url/{base32_decode_invalid_parameters_001.phpt => base32_decode_invalid_parameters_strict_001.phpt} (100%) diff --git a/ext/standard/base32.h b/ext/standard/base32.h index e69de29bb2d1d..665bef6bb72a5 100644 --- a/ext/standard/base32.h +++ b/ext/standard/base32.h @@ -0,0 +1,10 @@ + +#ifndef BASE32_H +#define BASE32_H + +extern const char *PHP_BASE32_ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; +extern const char *PHP_BASE32_HEX = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; +PHP_FUNCTION(base32_decode); +PHP_FUNCTION(base32_encode); + +#endif diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e1004480ece6a..01e4dd822cc9d 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -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() @@ -3583,6 +3596,8 @@ static const zend_function_entry class_AssertionError_methods[] = { static void register_basic_functions_symbols(int module_number) { + REGISTER_STRING_CONSTANT("PHP_BASE32_ASCII", PHP_BASE32_ASCII, CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("PHP_BASE32_HEX", PHP_BASE32_HEX, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", PHP_EXTR_OVERWRITE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_SKIP", PHP_EXTR_SKIP, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", PHP_EXTR_PREFIX_SAME, CONST_PERSISTENT); diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt similarity index 100% rename from ext/standard/tests/url/base32_decode_invalid_parameters_002.phpt rename to ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt diff --git a/ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt b/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt similarity index 100% rename from ext/standard/tests/url/base32_decode_invalid_parameters_001.phpt rename to ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt From ec7211a6b13d71b53b8f7a8c3c486e332723d006 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 16:14:39 +0100 Subject: [PATCH 04/12] Adding arginfo entry and base32 headers --- ext/standard/basic_functions_arginfo.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 01e4dd822cc9d..37301dae772db 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -3040,6 +3040,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) From cdb04bfa4a91beb222cd8d46bb7e3b3129d230e4 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 16:57:56 +0100 Subject: [PATCH 05/12] Improve test suite --- ...2_decode_invalid_parameters_relax_001.phpt | 156 +++++----- ..._decode_invalid_parameters_strict_001.phpt | 282 +++++++++--------- .../base32_encode_decode_strict_mode_001.phpt | 19 +- 3 files changed, 213 insertions(+), 244 deletions(-) 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 index bc09f4b22724b..6cc311bc8f19c 100644 --- a/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_relax_001.phpt @@ -5,110 +5,126 @@ Test base32_decode() function : invalid parameters in relax mode echo "*** Testing base32_decode() : invalid parameters in relax mode***\n\n"; $testData = [ 'characters outside of base32 extended hex alphabet' => [ - 'sequence' => 'CPNMUOJ1E8Z======', - 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'encoded' => 'CPNMUOJ1E8Z======', 'alphabet' => PHP_BASE32_HEX, 'padding' => '=', + 'expected' => 'foobar', ], 'characters outside of base32 us ascii alphabet' => [ - 'sequence' => '90890808', - 'message' => 'The encoded string contains characters outside of the base32 alphabet.', + 'encoded' => '90890808', 'alphabet' => PHP_BASE32_ASCII, 'padding' => '=', + 'expected' => '', ], 'characters not upper-cased' => [ - 'sequence' => 'MzxQ====', - 'message' => 'The encoded string contains lower-cased characters which is forbidden on strict mode.', + 'encoded' => 'MzxQ====', 'alphabet' => PHP_BASE32_ASCII, 'padding' => '=', + 'expected' => 'fo', ], 'padding character in the middle of the sequence' => [ - 'sequence' => 'Mzx==Q====', - 'message' => 'A padding character is contained in the middle of the encoded string.', + 'encoded' => 'Mzx==Q====', 'alphabet' => PHP_BASE32_ASCII, 'padding' => '=', + 'expected' => 'fo', ], 'invalid padding length' => [ - 'sequence' => 'MzxQ=======', - 'message' => 'The encoded string contains an invalid padding length.', + 'encoded' => 'MzxQ=======', 'alphabet' => PHP_BASE32_ASCII, 'padding' => '=', + 'expected' => 'fo', ], 'invalid encoded string length' => [ - 'sequence' => 'A', - 'message' => 'The encoded string length is not a multiple of 8.', + 'encoded' => 'MzxQ', 'alphabet' => PHP_BASE32_ASCII, 'padding' => '=', + 'expected' => 'fo', ], 'invalid alphabet length' => [ - 'sequence' => 'A', - 'message' => 'The alphabet must be a 32 bytes long string.', - 'alphabet' => '1234567890asdfghjklzxcvbnm', + 'encoded' => 'MZXQ=====', + 'alphabet' => '1234560asdfghjklzxcvbnm', 'padding' => '=', + 'error' => 'The alphabet must be a 32 bytes long string.', ], 'the padding character is contained within the alphabet' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', + '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' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), + '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' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', + '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"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', + '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\n"; - var_dump(base32_decode($data['sequence'], $data['alphabet'], $data['padding'], false)); - echo "===\n"; + 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) { - echo "error message: ", $exception->getMessage(), "\n===\n"; + 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"; @@ -116,53 +132,21 @@ echo "\nDone\n"; --EXPECT-- *** Testing base32_decode() : invalid parameters in relax mode*** -characters outside of base32 extended hex alphabet -string(6) "foobar" -=== -characters outside of base32 us ascii alphabet -string(0) "" -=== -characters not upper-cased -string(2) "fo" -=== -padding character in the middle of the sequence -string(2) "fo" -=== -invalid padding length -string(2) "fo" -=== -invalid encoded string length -string(0) "" -=== -invalid alphabet length -error message: The alphabet must be a 32 bytes long string. -=== -the padding character is contained within the alphabet -error message: The alphabet can not contain a reserved character. -=== -the padding character is contained within the alphabet is case insensitive -string(0) "" -=== -the padding character is different than one byte -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\r" -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\n" -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\t" -error message: The padding character must be a non-reserved single byte character. -=== -the alphabet can not contain "\r" -error message: The alphabet can not contain a reserved character. -=== -the alphabet can not contain "\n" -error message: The alphabet can not contain a reserved character. -=== -the alphabet can not contain "\t" -error message: The alphabet can not contain a reserved character. -=== +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 index 149bf939e2659..ea1928591b046 100644 --- a/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt +++ b/ext/standard/tests/url/base32_decode_invalid_parameters_strict_001.phpt @@ -4,165 +4,149 @@ Test base32_decode() function : invalid parameters in strict mode [ - 'sequence' => 'CPNMUOJ1E8Z======', - 'message' => 'The encoded string contains characters outside of the base32 alphabet.', - 'alphabet' => PHP_BASE32_HEX, - 'padding' => '=', - ], - 'characters outside of base32 us ascii alphabet' => [ - 'sequence' => '90890808', - 'message' => 'The encoded string contains characters outside of the base32 alphabet.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => '=', - ], - 'characters not upper-cased' => [ - 'sequence' => 'MzxQ====', - 'message' => 'The encoded string contains lower-cased characters which is forbidden on strict mode.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => '=', - ], - 'padding character in the middle of the sequence' => [ - 'sequence' => 'Mzx==Q====', - 'message' => 'A padding character is contained in the middle of the encoded string.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => '=', - ], - 'invalid padding length' => [ - 'sequence' => 'MzxQ=======', - 'message' => 'The encoded string contains an invalid padding length.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => '=', - ], - 'invalid encoded string length' => [ - 'sequence' => 'A', - 'message' => 'The encoded string length is not a multiple of 8.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => '=', - ], - 'invalid alphabet length' => [ - 'sequence' => 'A', - 'message' => 'The alphabet must be a 32 bytes long string.', - 'alphabet' => '1234567890asdfghjklzxcvbnm', - 'padding' => '=', - ], - 'the padding character is contained within the alphabet' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), - 'padding' => '*', - ], - 'the padding character is contained within the alphabet is case insensitive' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => str_replace('A', '*', PHP_BASE32_ASCII), - 'padding' => 'a', - ]; - 'the padding character is different than one byte' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => 'yo', - ]; - 'the padding character can not contain "\r"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => "\r", - ]; - 'the padding character can not contain "\n"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => "\n", - ]; - 'the padding character can not contain "\t"' => [ - 'sequence' => 'A', - 'message' => 'The padding character must be a non reserved single byte character.', - 'alphabet' => PHP_BASE32_ASCII, - 'padding' => "\t", - ]; - 'the alphabet can not contain "\r"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => substr(PHP_BASE32_ASCII, 0, -1)."\r", - 'padding' => '=', - ]; - 'the alphabet can not contain "\n"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\n", - 'padding' => '=', - ]; - 'the alphabet can not contain "\t"' => [ - 'sequence' => 'A', - 'message' => 'The alphabet can not contain a reserved character.', - 'alphabet' => substr(PHP_BASE32_HEX, 0, -1)."\t", - 'padding' => '=', - ]; + 'characters outside of base32 extended hex alphabet' => [ + '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\n"; - var_dump(base32_decode($data['sequence'], $data['alphabet'], $data['padding'], true)); - echo "===\n"; + 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) { - echo "error message: ", $exception->getMessage(), "\n===\n"; + 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 *** +*** Testing base32_decode() : invalid parameters in strict mode*** -characters outside of base32 extended hex alphabet -bool(false) -=== -characters outside of base32 us ascii alphabet -bool(false) -=== -characters not upper-cased -bool(false) -=== -padding character in the middle of the sequence -bool(false) -=== -invalid padding length -bool(false) -=== -invalid encoded string length -bool(false) -=== -invalid alphabet length -error message: The alphabet must be a 32 bytes long string. -=== -the padding character is contained within the alphabet -error message: The alphabet can not contain a reserved character. -=== -the padding character is contained within the alphabet is case insensitive -bool(false) -=== -the padding character is different than one byte -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\r" -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\n" -error message: The padding character must be a non-reserved single byte character. -=== -the padding character can not contain "\t" -error message: The padding character must be a non-reserved single byte character. -=== -the alphabet can not contain "\r" -error message: The alphabet can not contain a reserved character. -=== -the alphabet can not contain "\n" -error message: The alphabet can not contain a reserved character. -=== -the alphabet can not contain "\t" -error message: The alphabet can not contain a reserved character. -=== +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 index 89360fde22eed..e11d3266eed96 100644 --- a/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt +++ b/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt @@ -2,24 +2,25 @@ Test base32_decode() function strict mode vs relax mode --FILE-- Date: Fri, 29 Mar 2024 22:15:38 +0100 Subject: [PATCH 06/12] Update base32 files and declaration --- ext/standard/base32.c | 23 +++++++++++++++++++++++ ext/standard/base32.h | 17 +++++++++++++++-- ext/standard/basic_functions.stub.php | 13 +++++++++++++ ext/standard/basic_functions_arginfo.h | 2 -- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/ext/standard/base32.c b/ext/standard/base32.c index e69de29bb2d1d..ee98eadc56a19 100644 --- a/ext/standard/base32.c +++ b/ext/standard/base32.c @@ -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 | + +----------------------------------------------------------------------+ + */ + +#include + +#include "php.h" +#include "base32.h" + +#define PHP_BASE32_ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" +#define PHP_BASE32_HEX "0123456789ABCDEFGHIJKLMNOPQRSTUV" diff --git a/ext/standard/base32.h b/ext/standard/base32.h index 665bef6bb72a5..fd788f5261011 100644 --- a/ext/standard/base32.h +++ b/ext/standard/base32.h @@ -1,9 +1,22 @@ +/* + +----------------------------------------------------------------------+ + | 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 -extern const char *PHP_BASE32_ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -extern const char *PHP_BASE32_HEX = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; PHP_FUNCTION(base32_decode); PHP_FUNCTION(base32_encode); diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 5c834e4fcc296..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 diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 37301dae772db..4badbc12a4eb6 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -3598,8 +3598,6 @@ static const zend_function_entry class_AssertionError_methods[] = { static void register_basic_functions_symbols(int module_number) { - REGISTER_STRING_CONSTANT("PHP_BASE32_ASCII", PHP_BASE32_ASCII, CONST_PERSISTENT); - REGISTER_STRING_CONSTANT("PHP_BASE32_HEX", PHP_BASE32_HEX, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", PHP_EXTR_OVERWRITE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_SKIP", PHP_EXTR_SKIP, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", PHP_EXTR_PREFIX_SAME, CONST_PERSISTENT); From 3adc8b01c1a6a9baeb81f9a17b1cb3a070885202 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 29 Mar 2024 22:31:47 +0100 Subject: [PATCH 07/12] Update base32 files and declaration --- ext/standard/basic_functions_arginfo.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 4badbc12a4eb6..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) @@ -367,13 +367,13 @@ 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_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, padding, IS_STRING, 0, "\'=\'") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, strict, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() @@ -2417,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); @@ -3645,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); From 5ca79d979feb66b4ef2a85c779af15334e02230c Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Wed, 3 Apr 2024 09:31:41 +0200 Subject: [PATCH 08/12] Update base32 test suite --- .../tests/url/base32_encode_decode_strict_mode_001.phpt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 index e11d3266eed96..a52e00e18ecfa 100644 --- a/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt +++ b/ext/standard/tests/url/base32_encode_decode_strict_mode_001.phpt @@ -3,7 +3,7 @@ Test base32_decode() function strict mode vs relax mode --FILE-- Date: Sat, 20 Apr 2024 07:15:33 +0200 Subject: [PATCH 09/12] Adding base32_encode function to php-src --- ext/standard/base32.c | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/ext/standard/base32.c b/ext/standard/base32.c index ee98eadc56a19..f5d0a33f09d1e 100644 --- a/ext/standard/base32.c +++ b/ext/standard/base32.c @@ -21,3 +21,87 @@ #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); + } + + 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); +} +/* }}} */ From 4d249d65fed4d378355fca71dbc7eb2df7ac380b Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Sat, 20 Apr 2024 07:22:27 +0200 Subject: [PATCH 10/12] Adding missing smart_str_free call --- ext/standard/base32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/standard/base32.c b/ext/standard/base32.c index f5d0a33f09d1e..62f6cb3a65ea4 100644 --- a/ext/standard/base32.c +++ b/ext/standard/base32.c @@ -73,6 +73,7 @@ PHP_FUNCTION(base32_encode) smart_str_appends(&unique_chars, c); } + smart_str_free(&unique_chars); len = ZSTR_LEN(decoded); if (len == 0) { From 14ba3510108c5de2fcbc0487491d3fabd512ab66 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Sat, 20 Apr 2024 07:28:20 +0200 Subject: [PATCH 11/12] Adding base32_decode function skeleton --- ext/standard/base32.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/ext/standard/base32.c b/ext/standard/base32.c index 62f6cb3a65ea4..d75fbe67efd4c 100644 --- a/ext/standard/base32.c +++ b/ext/standard/base32.c @@ -106,3 +106,66 @@ PHP_FUNCTION(base32_encode) 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, 3) + 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); +} +/* }}} */ From 1c447edae70d1bd0ebc037f33807a2d13109ea40 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Sat, 20 Apr 2024 08:06:20 +0200 Subject: [PATCH 12/12] Fix base32_decode parameters count --- ext/standard/base32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/base32.c b/ext/standard/base32.c index d75fbe67efd4c..c3aecb0fe25d1 100644 --- a/ext/standard/base32.c +++ b/ext/standard/base32.c @@ -114,7 +114,7 @@ PHP_FUNCTION(base32_decode) int offset = 0, bitLen = 0, val = 0, len, shift; bool strict; - ZEND_PARSE_PARAMETERS_START(1, 3) + ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_STR(encoded) Z_PARAM_OPTIONAL Z_PARAM_STR(alphabet)