Skip to content

add padding option to base64_encode #13698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 36 additions & 29 deletions ext/standard/base64.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ static zend_always_inline unsigned char *neon_base64_encode(const unsigned char
}
#endif /* defined(__aarch64__) || defined(_M_ARM64) */

static zend_always_inline unsigned char *php_base64_encode_impl(const unsigned char *in, size_t inl, unsigned char *out) /* {{{ */
static zend_always_inline unsigned char *php_base64_encode_impl(const unsigned char *in, size_t inl, unsigned char *out, zend_long flags) /* {{{ */
{
#if defined(__aarch64__) || defined(_M_ARM64)
if (inl >= 16 * 3) {
Expand All @@ -147,11 +147,15 @@ static zend_always_inline unsigned char *php_base64_encode_impl(const unsigned c
if (inl > 1) {
*out++ = base64_table[((in[0] & 0x03) << 4) + (in[1] >> 4)];
*out++ = base64_table[(in[1] & 0x0f) << 2];
*out++ = base64_pad;
if ((flags & PHP_BASE64_NO_PADDING) == 0) {
*out++ = base64_pad;
}
} else {
*out++ = base64_table[(in[0] & 0x03) << 4];
*out++ = base64_pad;
*out++ = base64_pad;
if ((flags & PHP_BASE64_NO_PADDING) == 0) {
*out++ = base64_pad;
*out++ = base64_pad;
}
}
}

Expand Down Expand Up @@ -381,32 +385,32 @@ static zend_always_inline int php_base64_decode_impl(const unsigned char *in, si
# include "Zend/zend_cpuinfo.h"

# if BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PTR
ZEND_INTRIN_AVX512_FUNC_DECL(zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length));
ZEND_INTRIN_AVX512_FUNC_DECL(zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length, zend_long flags));
ZEND_INTRIN_AVX512_FUNC_DECL(zend_string *php_base64_decode_ex_avx512(const unsigned char *str, size_t length, bool strict));
# endif
# if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PTR
ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length));
ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length, zend_long flags));
ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(zend_string *php_base64_decode_ex_avx512_vbmi(const unsigned char *str, size_t length, bool strict));
# endif

# if ZEND_INTRIN_AVX2_RESOLVER
ZEND_INTRIN_AVX2_FUNC_DECL(zend_string *php_base64_encode_avx2(const unsigned char *str, size_t length));
ZEND_INTRIN_AVX2_FUNC_DECL(zend_string *php_base64_encode_avx2(const unsigned char *str, size_t length, zend_long flags));
ZEND_INTRIN_AVX2_FUNC_DECL(zend_string *php_base64_decode_ex_avx2(const unsigned char *str, size_t length, bool strict));
# endif

# if ZEND_INTRIN_SSSE3_RESOLVER
ZEND_INTRIN_SSSE3_FUNC_DECL(zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length));
ZEND_INTRIN_SSSE3_FUNC_DECL(zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length, zend_long flags));
ZEND_INTRIN_SSSE3_FUNC_DECL(zend_string *php_base64_decode_ex_ssse3(const unsigned char *str, size_t length, bool strict));
# endif

zend_string *php_base64_encode_default(const unsigned char *str, size_t length);
zend_string *php_base64_encode_default(const unsigned char *str, size_t length, zend_long flags);
zend_string *php_base64_decode_ex_default(const unsigned char *str, size_t length, bool strict);

# if (ZEND_INTRIN_AVX2_FUNC_PROTO || ZEND_INTRIN_SSSE3_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO)
PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length) __attribute__((ifunc("resolve_base64_encode")));
PHPAPI zend_string *php_base64_encode_ex(const unsigned char *str, size_t length, zend_long flags) __attribute__((ifunc("resolve_base64_encode")));
PHPAPI zend_string *php_base64_decode_ex(const unsigned char *str, size_t length, bool strict) __attribute__((ifunc("resolve_base64_decode")));

typedef zend_string *(*base64_encode_func_t)(const unsigned char *, size_t);
typedef zend_string *(*base64_encode_func_t)(const unsigned char *, size_t, zend_long flags);
typedef zend_string *(*base64_decode_func_t)(const unsigned char *, size_t, bool);

ZEND_NO_SANITIZE_ADDRESS
Expand Down Expand Up @@ -462,11 +466,11 @@ static base64_decode_func_t resolve_base64_decode(void) {
}
# else /* (ZEND_INTRIN_AVX2_FUNC_PROTO || ZEND_INTRIN_SSSE3_FUNC_PROTO) */

PHPAPI zend_string *(*php_base64_encode_ptr)(const unsigned char *str, size_t length) = NULL;
PHPAPI zend_string *(*php_base64_encode_ptr)(const unsigned char *str, size_t length, zend_long flags) = NULL;
PHPAPI zend_string *(*php_base64_decode_ex_ptr)(const unsigned char *str, size_t length, bool strict) = NULL;

PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length) {
return php_base64_encode_ptr(str, length);
PHPAPI zend_string *php_base64_encode_ex(const unsigned char *str, size_t length, zend_long flags) {
return php_base64_encode_ptr(str, length, flags);
}
PHPAPI zend_string *php_base64_decode_ex(const unsigned char *str, size_t length, bool strict) {
return php_base64_decode_ex_ptr(str, length, strict);
Expand Down Expand Up @@ -508,7 +512,7 @@ PHP_MINIT_FUNCTION(base64_intrin)
#endif /* ZEND_INTRIN_AVX2_NATIVE */

#if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PTR
zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length)
zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length, zend_long flags)
{
const unsigned char *c = str;
unsigned char *o;
Expand Down Expand Up @@ -545,7 +549,7 @@ zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t leng
length -= 48;
}

o = php_base64_encode_impl(c, length, o);
o = php_base64_encode_impl(c, length, o, flags);

ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result));

Expand Down Expand Up @@ -618,7 +622,7 @@ zend_string *php_base64_decode_ex_avx512_vbmi(const unsigned char *str, size_t l
#endif

#if BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PTR
zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length)
zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length, zend_long flags)
{
const unsigned char *c = str;
unsigned char *o;
Expand Down Expand Up @@ -665,7 +669,7 @@ zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length)
length -= 48;
}

o = php_base64_encode_impl(c, length, o);
o = php_base64_encode_impl(c, length, o, flags);

ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result));

Expand Down Expand Up @@ -900,11 +904,11 @@ static __m128i php_base64_encode_ssse3_translate(__m128i in)

#if ZEND_INTRIN_AVX2_NATIVE || ZEND_INTRIN_AVX2_RESOLVER || ZEND_INTRIN_SSSE3_NATIVE || ZEND_INTRIN_SSSE3_RESOLVER
# if ZEND_INTRIN_AVX2_NATIVE || ZEND_INTRIN_SSSE3_NATIVE
PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length)
PHPAPI zend_string *php_base64_encode_ex(const unsigned char *str, size_t length, zend_long flags)
# elif ZEND_INTRIN_AVX2_RESOLVER
zend_string *php_base64_encode_avx2(const unsigned char *str, size_t length)
zend_string *php_base64_encode_avx2(const unsigned char *str, size_t length, zend_long flags)
# else /* ZEND_INTRIN_SSSE3_RESOLVER */
zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length)
zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length, zend_long flags)
# endif
{
const unsigned char *c = str;
Expand Down Expand Up @@ -938,15 +942,15 @@ zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length)
PHP_BASE64_ENCODE_SSSE3_LOOP;
# endif

o = php_base64_encode_impl(c, length, o);
o = php_base64_encode_impl(c, length, o, flags);

ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result));

return result;
}

# if ZEND_INTRIN_SSSE3_RESOLVER && ZEND_INTRIN_AVX2_RESOLVER
zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length)
zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length, zend_long flags)
{
const unsigned char *c = str;
unsigned char *o;
Expand All @@ -957,7 +961,7 @@ zend_string *php_base64_encode_ssse3(const unsigned char *str, size_t length)

PHP_BASE64_ENCODE_SSSE3_LOOP;

o = php_base64_encode_impl(c, length, o);
o = php_base64_encode_impl(c, length, o, flags);

ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result));

Expand Down Expand Up @@ -1180,9 +1184,9 @@ zend_string *php_base64_decode_ex_ssse3(const unsigned char *str, size_t length,

#if !ZEND_INTRIN_AVX2_NATIVE && !ZEND_INTRIN_SSSE3_NATIVE
#if ZEND_INTRIN_AVX2_RESOLVER || ZEND_INTRIN_SSSE3_RESOLVER
zend_string *php_base64_encode_default(const unsigned char *str, size_t length)
zend_string *php_base64_encode_default(const unsigned char *str, size_t length, zend_long flags)
#else
PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length)
PHPAPI zend_string *php_base64_encode_ex(const unsigned char *str, size_t length, zend_long flags)
#endif
{
unsigned char *p;
Expand All @@ -1191,7 +1195,7 @@ PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length)
result = zend_string_safe_alloc(((length + 2) / 3), 4 * sizeof(char), 0, 0);
p = (unsigned char *)ZSTR_VAL(result);

p = php_base64_encode_impl(str, length, p);
p = php_base64_encode_impl(str, length, p, flags);

ZSTR_LEN(result) = (p - (unsigned char *)ZSTR_VAL(result));

Expand Down Expand Up @@ -1229,12 +1233,15 @@ PHP_FUNCTION(base64_encode)
char *str;
size_t str_len;
zend_string *result;
bool padding = true;

ZEND_PARSE_PARAMETERS_START(1, 1)
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STRING(str, str_len)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(padding)
ZEND_PARSE_PARAMETERS_END();

result = php_base64_encode((unsigned char*)str, str_len);
result = php_base64_encode_ex((unsigned char*)str, str_len, (padding ? 0 : PHP_BASE64_NO_PADDING));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you used a flag for future proofing in case a new option would be needed in the future, right? Personally, I'd be fine with a bool value, but I can also understand your POV :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes (see discussion about URL SAFE mode) and to avoid changing function prototype again in so much places ;)

RETURN_STR(result);
}
/* }}} */
Expand Down
8 changes: 7 additions & 1 deletion ext/standard/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,15 @@
PHP_MINIT_FUNCTION(base64_intrin);
#endif

PHPAPI extern zend_string *php_base64_encode(const unsigned char *, size_t);
/* php_base64_encode_ex flags */
#define PHP_BASE64_NO_PADDING 1

PHPAPI extern zend_string *php_base64_encode_ex(const unsigned char *, size_t, zend_long flags);
PHPAPI extern zend_string *php_base64_decode_ex(const unsigned char *, size_t, bool);

static inline zend_string *php_base64_encode(const unsigned char *str, size_t len) {
return php_base64_encode_ex(str, len, 0);
}
static inline zend_string *php_base64_encode_str(const zend_string *str) {
return php_base64_encode((const unsigned char*)(ZSTR_VAL(str)), ZSTR_LEN(str));
}
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -1930,7 +1930,7 @@ function array_is_list(array $array): bool {}
* @compile-time-eval
* @refcount 1
*/
function base64_encode(string $string): string {}
function base64_encode(string $string, bool $padding = true): string {}

/**
* @compile-time-eval
Expand Down
53 changes: 28 additions & 25 deletions ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading