Commit 3c6b25cca51 for php.net

commit 3c6b25cca5142b12a2ce440a9e965ac795a24ee6
Author: Tim Düsterhus <tim@bastelstu.be>
Date:   Sun Jun 14 12:48:06 2026 +0200

    zend_string: Add `zend_string_equals_cstr_ci()` (#22296)

    This function was missing for consistency with the other functions which all
    have a `cstr` variant. Adding this function also made it easy to convert some
    more copy-and-pasted logic.

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index f89123116c7..bb2f6227475 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -17,6 +17,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
   . ZSTR_INIT_LITERAL(), zend_string_starts_with_literal(), and
     zend_string_starts_with_literal_ci() now support strings containing NUL
     bytes. Passing non-literal char* is no longer supported.
+  . Added zend_string_equals_cstr_ci().
   . The misnamed ZVAL_IS_NULL() has been removed. Use Z_ISNULL() instead.
   . New zend_class_entry.ce_flags2 and zend_function.fn_flags2 fields were
     added, given the primary flags were running out of bits.
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index b6e1923b3bf..27aa4fdb048 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -46,7 +46,6 @@
 #include "zend_portability.h"
 #include "zend_strtod.h"
 #include "zend_multiply.h"
-#include "zend_object_handlers.h"

 #define LONG_SIGN_MASK ZEND_LONG_MIN

diff --git a/Zend/zend_string.h b/Zend/zend_string.h
index 3f0c9abd259..930d733307f 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -397,11 +397,22 @@ static zend_always_inline bool zend_string_equals(const zend_string *s1, const z
 	return s1 == s2 || zend_string_equal_content(s1, s2);
 }

-#define zend_string_equals_ci(s1, s2) \
-	(ZSTR_LEN(s1) == ZSTR_LEN(s2) && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2)))
+BEGIN_EXTERN_C()
+ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2);
+END_EXTERN_C()
+
+static zend_always_inline bool zend_string_equals_cstr_ci(const zend_string *s1, const char *s2, size_t s2_length)
+{
+	return ZSTR_LEN(s1) == s2_length && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), s2, s2_length);
+}
+
+#define zend_string_equals_literal_ci(str, literal) \
+	zend_string_equals_cstr_ci(str, "" literal, sizeof(literal) - 1)

-#define zend_string_equals_literal_ci(str, c) \
-	(ZSTR_LEN(str) == sizeof("" c) - 1 && !zend_binary_strcasecmp(ZSTR_VAL(str), ZSTR_LEN(str), (c), sizeof(c) - 1))
+static zend_always_inline bool zend_string_equals_ci(const zend_string *s1, const zend_string *s2)
+{
+	return zend_string_equals_cstr_ci(s1, ZSTR_VAL(s2), ZSTR_LEN(s2));
+}

 #define zend_string_equals_literal(str, literal) \
 	zend_string_equals_cstr(str, "" literal, sizeof(literal) - 1)