From d6409b2a1db3ed2b6e1abafd9f33fbb1d0862084 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Wed, 24 Jun 2026 18:59:02 +0800 Subject: [PATCH] Zend: Add bin2hex helpers --- UPGRADING.INTERNALS | 2 ++ Zend/zend_string.c | 26 ++++++++++++++++++++++++++ Zend/zend_string.h | 2 ++ 3 files changed, 30 insertions(+) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 2f0d016a99cd..45163f6a0aaf 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -66,6 +66,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Added Z_PARAM_ENUM(). . Added zend_enum_fetch_case_id(). . Added zend_enum_get_case_by_id(). + . Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove + dependencies on /ext/hash in various extensions. . ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This more correctly represents the generic nature of the returned pointer and allows to remove explicit casts, but possibly breaks pointer arithmetic diff --git a/Zend/zend_string.c b/Zend/zend_string.c index 52fca0cd4346..1dafcd814b26 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -52,6 +52,17 @@ ZEND_API zend_string *zend_empty_string = NULL; ZEND_API zend_string *zend_one_char_string[256]; ZEND_API zend_string **zend_known_strings = NULL; +/* this is read-only, so it's ok */ +ZEND_SET_ALIGNED(16, static const char zend_hexconvtab_lower[]) = "0123456789abcdef"; + +static zend_always_inline void zend_bin2hex_impl(char *out, const unsigned char *in, size_t in_len, const char *hexconvtab) +{ + for (size_t i = 0; i < in_len; i++) { + out[i * 2] = hexconvtab[in[i] >> 4]; + out[i * 2 + 1] = hexconvtab[in[i] & 0x0f]; + } +} + ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str) { return ZSTR_H(str) = zend_hash_func(ZSTR_VAL(str), ZSTR_LEN(str)); @@ -62,6 +73,21 @@ ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len) return zend_inline_hash_func(str, len); } +ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len) +{ + zend_bin2hex_impl(out, in, in_len, zend_hexconvtab_lower); +} + +ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len) +{ + zend_string *result = zend_string_safe_alloc(in_len, 2 * sizeof(char), 0, 0); + + zend_bin2hex(ZSTR_VAL(result), in, in_len); + ZSTR_VAL(result)[in_len * 2] = '\0'; + + return result; +} + static void _str_dtor(zval *zv) { zend_string *str = Z_STR_P(zv); diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 930d733307f4..0ec27917396d 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -37,6 +37,8 @@ ZEND_API extern zend_string_init_existing_interned_func_t zend_string_init_exist ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str); ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len); ZEND_API zend_string* ZEND_FASTCALL zend_interned_string_find_permanent(zend_string *str); +ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len); +ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len); ZEND_API zend_string *zend_string_concat2( const char *str1, size_t str1_len,