Commit 8d1d4e3cf8e for php.net
commit 8d1d4e3cf8e1502297695a66b88379fa727a8a72
Author: Weilin Du <weilindu@php.net>
Date: Thu Jul 9 01:59:34 2026 +0800
Zend: Add new zend APIs for `bin2hex` to remove `ext/hash` usage in various extensions (#21724)
There are various extensions in the php code base that includes
ext/hash/php_hash for the php_hash_bin2hex method. While these method is
actually simple, we can make them as APIs in the zend engine to remove the
dependence on ext/hash/
This commit added the needed APIs (zend_bin2hex and zend_bin2hex_str).
A follow-up PR will be made in the future to replace the usage of ext/hash
with the added APIs.
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index adfc91880f2..1c602548b1e 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -68,6 +68,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 52fca0cd434..b1b4a0e17a6 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[]) = "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);
+}
+
+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 e0d1c026a2f..fdfff2bbc89 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -43,6 +43,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,