Commit 1fd15d42541 for php.net

commit 1fd15d425417e091f2ef1a479d7376a11c7126ff
Author: Weilin Du <weilindu@php.net>
Date:   Sun Jul 12 06:45:34 2026 +0800

    ext/soap: Fix SOAP xsd:hexBinary odd-length decoding (#22698)

    xsd:hexBinary values must contain an even number of hexadecimal digits.

    However, previously we allocated strlen(content) / 2 bytes and decoded only
    complete byte pairs. As a result, an odd-length value such as ABC was
    accepted as ab (what...?), silently ignoring the trailing nibble.

    Lets reject odd-length xsd:hexBinary values instead and throw an Error here
    which makes better sense. The error message is copied from other decoding
    errors. (I think in the future, we can make the decoding error message more
    useful, in bulk.)

    This is in master as a stricter parsing PR

diff --git a/NEWS b/NEWS
index f40c6dfd8da..190c6c16a93 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,8 @@ PHP                                                                        NEWS
 - SOAP:
   . Fixed bug GH-22585 (OOM on bailout with uninitialized
     do_request() parameters). (David Carlier)
+  . Fixed xsd:hexBinary decoding to reject odd-length values instead of
+    silently truncating the last nibble. (Weilin Du)

 - Standard:
   . Fixed sleep() and usleep() to reject values that overflow the underlying
diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index e474798df6d..301cdd8588b 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -766,6 +766,7 @@ static zval *to_zval_base64(zval *ret, encodeTypePtr type, xmlNodePtr data)
 static zval *to_zval_hexbin(zval *ret, encodeTypePtr type, xmlNodePtr data)
 {
 	zend_string *str;
+	size_t content_len;
 	size_t i, j;
 	unsigned char c;

@@ -778,7 +779,12 @@ static zval *to_zval_hexbin(zval *ret, encodeTypePtr type, xmlNodePtr data)
 			soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
 			return ret;
 		}
-		str = zend_string_alloc(strlen((char*)data->children->content) / 2, 0);
+		content_len = strlen((char*) data->children->content);
+		if (content_len % 2 != 0) {
+			soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
+			return ret;
+		}
+		str = zend_string_alloc(content_len / 2, 0);
 		for (i = j = 0; i < ZSTR_LEN(str); i++) {
 			c = data->children->content[j++];
 			if (c >= '0' && c <= '9') {
diff --git a/ext/soap/tests/hexbin_odd_length.phpt b/ext/soap/tests/hexbin_odd_length.phpt
new file mode 100644
index 00000000000..bfe84ab643d
--- /dev/null
+++ b/ext/soap/tests/hexbin_odd_length.phpt
@@ -0,0 +1,37 @@
+--TEST--
+SOAP rejects odd-length xsd:hexBinary values
+--EXTENSIONS--
+soap
+--FILE--
+<?php
+class TestSoapClient extends SoapClient {
+    public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <SOAP-ENV:Body>
+    <ns1:testResponse xmlns:ns1="urn:test">
+      <return xsi:type="xsd:hexBinary">ABC</return>
+    </ns1:testResponse>
+  </SOAP-ENV:Body>
+</SOAP-ENV:Envelope>
+XML;
+    }
+}
+
+$client = new TestSoapClient(null, [
+    'location' => 'test://',
+    'uri' => 'urn:test',
+    'exceptions' => true,
+]);
+
+try {
+    var_dump(bin2hex($client->test()));
+} catch (SoapFault $e) {
+    echo $e->faultstring, "\n";
+}
+?>
+--EXPECT--
+SOAP-ERROR: Encoding: Violation of encoding rules