[php-src] master: Zend: Add new zend APIs for `bin2hex` to remove `ext/hash` usage in various extensions (#21724)

Weilin Du via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Weilin Du (LamentXU123)
Committer: GitHub (web-flow)
Pusher: LamentXU123
Date: 2026-07-09T01:59:34+08:00

Commit: https://github.com/php/php-src/commit/8d1d4e3cf8e1502297695a66b88379fa727a8a72
Raw diff: https://github.com/php/php-src/commit/8d1d4e3cf8e1502297695a66b88379fa727a8a72.diff

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.

Changed paths:
  M  UPGRADING.INTERNALS
  M  Zend/zend_string.c
  M  Zend/zend_string.h


Diff:

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index adfc91880f29..1c602548b1ed 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 52fca0cd4346..b1b4a0e17a69 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 e0d1c026a2f2..fdfff2bbc894 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,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.