summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--failed.txt29
-rw-r--r--php-cve-2026-14179.patch274
-rw-r--r--php-cve-2026-6722.patch107
-rw-r--r--php-cve-2026-6735.patch144
-rw-r--r--php-cve-2026-7258.patch1719
-rw-r--r--php-cve-2026-7259.patch66
-rw-r--r--php-cve-2026-7261.patch111
-rw-r--r--php-cve-2026-7262.patch77
-rw-r--r--php-cve-2026-7568.patch101
-rw-r--r--php81.spec51
10 files changed, 2664 insertions, 15 deletions
diff --git a/failed.txt b/failed.txt
index 51bc18f..b6e729d 100644
--- a/failed.txt
+++ b/failed.txt
@@ -1,25 +1,28 @@
-===== 8.1.34 (2025-12-18)
+===== 8.1.34-2 (2026-05-07)
$ grep -ar 'Tests failed' /var/lib/mock/*/build.log
-/var/lib/mock/el8a81/build.log:Tests failed : 0
-/var/lib/mock/el8x81/build.log:Tests failed : 0
-/var/lib/mock/el9a81/build.log:Tests failed : 2
-/var/lib/mock/el9x81/build.log:Tests failed : 2
-/var/lib/mock/el10a81/build.log:Tests failed : 2
-/var/lib/mock/el10x81/build.log:Tests failed : 2
-/var/lib/mock/fc41a81/build.log:Tests failed : 1
-/var/lib/mock/fc41x81/build.log:Tests failed : 1
-/var/lib/mock/fc42a81/build.log:Tests failed : 1
-/var/lib/mock/fc42x81/build.log:Tests failed : 1
-/var/lib/mock/fc43a81/build.log:Tests failed : 2
-/var/lib/mock/fc43x81/build.log:Tests failed : 2
+/var/lib/mock/el8a81/build.log:Tests failed : 2
+/var/lib/mock/el8x81/build.log:Tests failed : 2
+/var/lib/mock/el9a81/build.log:Tests failed : 4
+/var/lib/mock/el9x81/build.log:Tests failed : 4
+/var/lib/mock/el10a81/build.log:Tests failed : 4
+/var/lib/mock/el10x81/build.log:Tests failed : 4
+/var/lib/mock/fc42a81/build.log:Tests failed : 3
+/var/lib/mock/fc42x81/build.log:Tests failed : 3
+/var/lib/mock/fc43a81/build.log:Tests failed : 4
+/var/lib/mock/fc43x81/build.log:Tests failed : 4
+/var/lib/mock/fc44a81/build.log:Tests failed : 4
+/var/lib/mock/fc44x81/build.log:Tests failed : 4
fc*, el10:
3 openssl_x509_parse() tests [ext/openssl/tests/openssl_x509_parse_basic.phpt]
fc43, el9, el10:
3 Bug #74341 (openssl_x509_parse fails to parse ASN.1 UTCTime without seconds) [ext/openssl/tests/bug74341.phpt]
+all
+ 3 sni_server [ext/openssl/tests/sni_server.phpt]
+ 3 sni_server with separate pk and cert [ext/openssl/tests/sni_server_key_cert.phpt]
1 proc_open give erratic test results :(
diff --git a/php-cve-2026-14179.patch b/php-cve-2026-14179.patch
new file mode 100644
index 0000000..71e15cd
--- /dev/null
+++ b/php-cve-2026-14179.patch
@@ -0,0 +1,274 @@
+From 4b0dd469bbba7bf5f25f1a4f694aeb15c3515be4 Mon Sep 17 00:00:00 2001
+From: Saki Takamachi <saki@sakiot.com>
+Date: Sun, 3 May 2026 19:56:30 +0200
+Subject: [PATCH 07/10] GHSA-w476-322c-wpvm: [pdo_firebird] Fix SQL injection
+ via NUL bytes in quoted strings
+
+Fixes GHSA-w476-322c-wpvm
+Fixes CVE-2025-14179
+
+(cherry picked from commit 3f40b65323dd1b85e9bab6878237d3867e449d5c)
+---
+ ext/pdo_firebird/firebird_driver.c | 69 ++++++++++++-------
+ .../tests/ghsa-w476-322c-wpvm.phpt | 44 ++++++++++++
+ 2 files changed, 88 insertions(+), 25 deletions(-)
+ create mode 100644 ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt
+
+diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
+index a446622c90e..25882919f86 100644
+--- a/ext/pdo_firebird/firebird_driver.c
++++ b/ext/pdo_firebird/firebird_driver.c
+@@ -291,7 +291,7 @@ static FbTokenType getToken(const char** begin, const char* end)
+ return ret;
+ }
+
+-int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
++int preprocess(const zend_string* sql, char* sql_out, size_t* sql_out_len, HashTable* named_params)
+ {
+ bool passAsIs = 1, execBlock = 0;
+ zend_long pindex = -1;
+@@ -322,7 +322,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ if (l > 252) {
+ return 0;
+ }
+- strncpy(ident, i, l);
++ memcpy(ident, i, l);
+ ident[l] = '\0';
+ if (!strcasecmp(ident, "EXECUTE"))
+ {
+@@ -347,7 +347,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ if (l > 252) {
+ return 0;
+ }
+- strncpy(ident2, i2, l);
++ memcpy(ident2, i2, l);
+ ident2[l] = '\0';
+ execBlock = !strcasecmp(ident2, "BLOCK");
+ passAsIs = 0;
+@@ -363,11 +363,15 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+
+ if (passAsIs)
+ {
+- strcpy(sql_out, ZSTR_VAL(sql));
++ memcpy(sql_out, ZSTR_VAL(sql), ZSTR_LEN(sql));
++ sql_out[ZSTR_LEN(sql)] = '\0';
++ *sql_out_len = ZSTR_LEN(sql);
+ return 1;
+ }
+
+- strncat(sql_out, start, p - start);
++ char *sql_out_p = sql_out;
++ memcpy(sql_out_p, start, p - start);
++ sql_out_p += p - start;
+
+ while (p < end)
+ {
+@@ -375,10 +379,12 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ tok = getToken(&p, end);
+ switch (tok)
+ {
+- case ttParamMark:
+- tok = getToken(&p, end);
++ case ttParamMark: {
++ const char* p_peek = p;
++ tok = getToken(&p_peek, end);
+ if (tok == ttIdent /*|| tok == ttString*/)
+ {
++ p = p_peek;
+ ++pindex;
+ l = p - start;
+ /* check the length of the identifier */
+@@ -387,7 +393,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ if (l > 253) {
+ return 0;
+ }
+- strncpy(pname, start, l);
++ memcpy(pname, start, l);
+ pname[l] = '\0';
+
+ if (named_params) {
+@@ -396,7 +402,7 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ zend_hash_str_update(named_params, pname, l, &tmp);
+ }
+
+- strcat(sql_out, "?");
++ *sql_out_p++ = '?';
+ }
+ else
+ {
+@@ -406,10 +412,11 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ return 0;
+ }
+ ++pindex;
+- strncat(sql_out, start, p - start);
++ memcpy(sql_out_p, start, p - start);
++ sql_out_p += p - start;
+ }
+ break;
+-
++ }
+ case ttIdent:
+ if (execBlock)
+ {
+@@ -421,11 +428,14 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ if (l > 252) {
+ return 0;
+ }
+- strncpy(ident, start, l);
++ memcpy(ident, start, l);
+ ident[l] = '\0';
+ if (!strcasecmp(ident, "AS"))
+ {
+- strncat(sql_out, start, end - start);
++ memcpy(sql_out_p, start, end - start);
++ sql_out_p += end - start;
++ *sql_out_p = '\0';
++ *sql_out_len = sql_out_p - sql_out;
+ return 1;
+ }
+ }
+@@ -436,7 +446,8 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ case ttComment:
+ case ttString:
+ case ttOther:
+- strncat(sql_out, start, p - start);
++ memcpy(sql_out_p, start, p - start);
++ sql_out_p += p - start;
+ break;
+
+ case ttBrokenComment:
+@@ -454,6 +465,8 @@ int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params)
+ break;
+ }
+ }
++ *sql_out_p = '\0';
++ *sql_out_len = sql_out_p - sql_out;
+ return 1;
+ }
+
+@@ -663,7 +676,7 @@ free_statement:
+ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype)
+ {
+ size_t qcount = 0;
+- char const *co, *l, *r;
++ char const *co, *l;
+ char *c;
+ size_t quotedlen;
+ zend_string *quoted_str;
+@@ -672,9 +685,15 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
+ return zend_string_init("''", 2, 0);
+ }
+
++ const char * const end = ZSTR_VAL(unquoted) + ZSTR_LEN(unquoted);
++
+ /* Firebird only requires single quotes to be doubled if string lengths are used */
+ /* count the number of ' characters */
+- for (co = ZSTR_VAL(unquoted); (co = strchr(co,'\'')); qcount++, co++);
++ for (co = ZSTR_VAL(unquoted); co < end; co++) {
++ if (*co == '\'') {
++ qcount++;
++ }
++ }
+
+ if (UNEXPECTED(ZSTR_LEN(unquoted) + 2 > ZSTR_MAX_LEN - qcount)) {
+ return NULL;
+@@ -686,15 +705,14 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un
+ *c++ = '\'';
+
+ /* foreach (chunk that ends in a quote) */
+- for (l = ZSTR_VAL(unquoted); (r = strchr(l,'\'')); l = r+1) {
+- strncpy(c, l, r-l+1);
+- c += (r-l+1);
+- /* add the second quote */
+- *c++ = '\'';
++ for (l = ZSTR_VAL(unquoted); l < end; l++) {
++ *c++ = *l;
++ if (*l == '\'') {
++ /* add the second quote */
++ *c++ = '\'';
++ }
+ }
+
+- /* copy the remainder */
+- strncpy(c, l, quotedlen-(c-ZSTR_VAL(quoted_str))-1);
+ ZSTR_VAL(quoted_str)[quotedlen-1] = '\'';
+ ZSTR_VAL(quoted_str)[quotedlen] = '\0';
+
+@@ -787,6 +805,7 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql,
+ {
+ pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
+ char *new_sql;
++ size_t new_sql_len;
+
+ /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */
+ if (ZSTR_LEN(sql) > 65536) {
+@@ -814,14 +833,14 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql,
+ we need to replace :foo by ?, and store the name we just replaced */
+ new_sql = emalloc(ZSTR_LEN(sql)+1);
+ new_sql[0] = '\0';
+- if (!preprocess(sql, new_sql, named_params)) {
++ if (!preprocess(sql, new_sql, &new_sql_len, named_params)) {
+ strcpy(dbh->error_code, "07000");
+ efree(new_sql);
+ return 0;
+ }
+
+ /* prepare the statement */
+- if (isc_dsql_prepare(H->isc_status, &H->tr, s, 0, new_sql, H->sql_dialect, out_sqlda)) {
++ if (isc_dsql_prepare(H->isc_status, &H->tr, s, new_sql_len, new_sql, H->sql_dialect, out_sqlda)) {
+ RECORD_ERROR(dbh);
+ efree(new_sql);
+ return 0;
+diff --git a/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt b/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt
+new file mode 100644
+index 00000000000..41c1125e9b9
+--- /dev/null
++++ b/ext/pdo_firebird/tests/ghsa-w476-322c-wpvm.phpt
+@@ -0,0 +1,44 @@
++--TEST--
++GHSA-w476-322c-wpvm: SQL injection in pdo_firebird via NUL bytes in quoted strings
++--EXTENSIONS--
++pdo_firebird
++--SKIPIF--
++<?php require('skipif.inc'); ?>
++--XLEAK--
++A bug in firebird causes a memory leak when calling `isc_attach_database()`.
++See https://github.com/FirebirdSQL/firebird/issues/7849
++--FILE--
++<?php
++
++require("testdb.inc");
++
++$dbh->exec('CREATE TABLE ghsa_w476_322c_wpvm (name VARCHAR(255))');
++
++$param = $dbh->quote("\0");
++$param2 = $dbh->quote('or 1=1--');
++var_export($param);
++echo("\n");
++
++echo "prepare: ";
++$stmt = $dbh->prepare("SELECT * FROM ghsa_w476_322c_wpvm WHERE name = {$param} AND name = {$param2}");
++$stmt->execute();
++echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)) . "\n";
++
++echo "query: ";
++$stmt = $dbh->query("SELECT * FROM ghsa_w476_322c_wpvm WHERE name = {$param} AND name = {$param2}");
++echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)) . "\n";
++
++echo "exec: ";
++$affectedRows = $dbh->exec("UPDATE ghsa_w476_322c_wpvm SET name = 'updated' WHERE name = {$param} AND name = {$param2}");
++echo $affectedRows . "\n";
++?>
++--CLEAN--
++<?php
++require 'testdb.inc';
++$dbh->exec("DROP TABLE ghsa_w476_322c_wpvm");
++?>
++--EXPECT--
++'\'' . "\0" . '\''
++prepare: []
++query: []
++exec: 0
+--
+2.54.0
+
diff --git a/php-cve-2026-6722.patch b/php-cve-2026-6722.patch
new file mode 100644
index 0000000..3365479
--- /dev/null
+++ b/php-cve-2026-6722.patch
@@ -0,0 +1,107 @@
+From 15064460d6682766f91c1a841d27cdfbc38907e8 Mon Sep 17 00:00:00 2001
+From: Ilija Tovilo <ilija.tovilo@me.com>
+Date: Sun, 3 May 2026 19:56:53 +0200
+Subject: [PATCH 01/10] GHSA-85c2-q967-79q5: [soap] Fix stale
+ SOAP_GLOBAL(ref_map) pointer with Apache Map
+
+Fixes GHSA-85c2-q967-79q5
+Fixes CVE-2026-6722
+
+(cherry picked from commit aee3b3ac9b816b0def1c462695b483b49a83148e)
+---
+ ext/soap/php_encoding.c | 3 +-
+ ext/soap/tests/GHSA-85c2-q967-79q5.phpt | 61 +++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+), 1 deletion(-)
+ create mode 100644 ext/soap/tests/GHSA-85c2-q967-79q5.phpt
+
+diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
+index 4d389a8c585..bf394f7ea92 100644
+--- a/ext/soap/php_encoding.c
++++ b/ext/soap/php_encoding.c
+@@ -365,6 +365,7 @@ static bool soap_check_xml_ref(zval *data, xmlNodePtr node)
+ static void soap_add_xml_ref(zval *data, xmlNodePtr node)
+ {
+ if (SOAP_GLOBAL(ref_map)) {
++ Z_TRY_ADDREF_P(data);
+ zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
+ }
+ }
+@@ -3437,7 +3438,7 @@ void encode_reset_ns()
+ } else {
+ SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable));
+ }
+- zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0);
++ zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0);
+ }
+
+ void encode_finish()
+diff --git a/ext/soap/tests/GHSA-85c2-q967-79q5.phpt b/ext/soap/tests/GHSA-85c2-q967-79q5.phpt
+new file mode 100644
+index 00000000000..8bcac26ad18
+--- /dev/null
++++ b/ext/soap/tests/GHSA-85c2-q967-79q5.phpt
+@@ -0,0 +1,61 @@
++--TEST--
++GHSA-85c2-q967-79q5: Stale SOAP_GLOBAL(ref_map) pointer with Apache Map
++--CREDITS--
++brettgervasoni
++--EXTENSIONS--
++soap
++--FILE--
++<?php
++
++class Handler {
++ public function test(...$args) {
++ $GLOBALS['result'] = $args;
++ }
++}
++
++$envelope = <<<'XML'
++<?xml version="1.0" encoding="UTF-8"?>
++<soapenv:Envelope
++ xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
++ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
++ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
++
++ <soapenv:Body>
++ <test>
++ <map xsi:type="apache:Map" xmlns:apache="http://xml.apache.org/xml-soap">
++ <item>
++ <key>foo</key>
++ <value id="stale"><object>bar</object></value>
++ </item>
++ <item>
++ <key>foo</key>
++ <value>baz</value>
++ </item>
++ </map>
++ <stale href="#stale"/>
++ </test>
++ </soapenv:Body>
++</soapenv:Envelope>
++XML;
++
++$s = new SoapServer(null, ['uri' => 'urn:a']);
++$s->setClass(Handler::class);
++$s->handle($envelope);
++var_dump($result);
++
++?>
++--EXPECTF--
++<?xml version="1.0" encoding="UTF-8"?>
++<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:testResponse><return xsi:nil="true"/></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
++array(2) {
++ [0]=>
++ array(1) {
++ ["foo"]=>
++ string(3) "baz"
++ }
++ [1]=>
++ object(stdClass)#%d (1) {
++ ["object"]=>
++ string(3) "bar"
++ }
++}
+--
+2.54.0
+
diff --git a/php-cve-2026-6735.patch b/php-cve-2026-6735.patch
new file mode 100644
index 0000000..9f287dd
--- /dev/null
+++ b/php-cve-2026-6735.patch
@@ -0,0 +1,144 @@
+From cc2960e782eb5cc262d7bd572a7d18979a811954 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 3 May 2026 20:01:41 +0200
+Subject: [PATCH 04/10] GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint
+
+Fixes GHSA-7qg2-v9fj-4mwv
+Fixes CVE-2026-6735
+
+(cherry picked from commit 99a5ad7441de9914246c7863adb6997396008b9d)
+---
+ sapi/fpm/fpm/fpm_status.c | 34 +++++++++++--
+ .../tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt | 48 +++++++++++++++++++
+ 2 files changed, 78 insertions(+), 4 deletions(-)
+ create mode 100644 sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
+
+diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c
+index f698753cf4c..81292aa3bf8 100644
+--- a/sapi/fpm/fpm/fpm_status.c
++++ b/sapi/fpm/fpm/fpm_status.c
+@@ -525,8 +525,8 @@ int fpm_status_handle_request(void) /* {{{ */
+ if (full_syntax) {
+ unsigned int i;
+ int first;
+- zend_string *tmp_query_string;
+- char *query_string;
++ zend_string *tmp_query_string, *tmp_request_uri_string;
++ char *query_string, *request_uri_string;
+ struct timeval duration, now;
+ float cpu;
+
+@@ -551,13 +551,36 @@ int fpm_status_handle_request(void) /* {{{ */
+ }
+ }
+
++ request_uri_string = NULL;
++ tmp_request_uri_string = NULL;
++ if (proc->request_uri[0] != '\0') {
++ if (encode_html) {
++ tmp_request_uri_string = php_escape_html_entities_ex(
++ (const unsigned char *) proc->request_uri,
++ strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
++ NULL, /* double_encode */ 1, /* quiet */ 0);
++ request_uri_string = ZSTR_VAL(tmp_request_uri_string);
++ } else if (encode_json) {
++ tmp_request_uri_string = php_json_encode_string(proc->request_uri,
++ strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
++ request_uri_string = ZSTR_VAL(tmp_request_uri_string);
++ /* remove quotes around the string */
++ if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
++ request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
++ ++request_uri_string;
++ }
++ } else {
++ request_uri_string = proc->request_uri;
++ }
++ }
++
+ query_string = NULL;
+ tmp_query_string = NULL;
+ if (proc->query_string[0] != '\0') {
+ if (encode_html) {
+ tmp_query_string = php_escape_html_entities_ex(
+ (const unsigned char *) proc->query_string,
+- strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
++ strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
+ NULL, /* double_encode */ 1, /* quiet */ 0);
+ } else if (encode_json) {
+ tmp_query_string = php_json_encode_string(proc->query_string,
+@@ -596,7 +619,7 @@ int fpm_status_handle_request(void) /* {{{ */
+ proc->requests,
+ duration.tv_sec * 1000000UL + duration.tv_usec,
+ proc->request_method[0] != '\0' ? proc->request_method : "-",
+- proc->request_uri[0] != '\0' ? proc->request_uri : "-",
++ request_uri_string ? request_uri_string : "-",
+ query_string ? "?" : "",
+ query_string ? query_string : "",
+ proc->content_length,
+@@ -607,6 +630,9 @@ int fpm_status_handle_request(void) /* {{{ */
+ PUTS(buffer);
+ efree(buffer);
+
++ if (tmp_request_uri_string) {
++ zend_string_free(tmp_request_uri_string);
++ }
+ if (tmp_query_string) {
+ zend_string_free(tmp_query_string);
+ }
+diff --git a/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
+new file mode 100644
+index 00000000000..475bc130a42
+--- /dev/null
++++ b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++FPM: GHSA-7qg2-v9fj-4mwv - status xss
++--SKIPIF--
++<?php include "skipif.inc"; ?>
++--FILE--
++<?php
++
++require_once "tester.inc";
++
++$cfg = <<<EOT
++[global]
++error_log = {{FILE:LOG}}
++[unconfined]
++listen = {{ADDR}}
++pm = static
++pm.max_children = 2
++pm.status_path = /status
++catch_workers_output = yes
++EOT;
++
++$code = <<<EOT
++<?php
++usleep(200000);
++EOT;
++
++$tester = new FPM\Tester($cfg, $code);
++$tester->start();
++$tester->expectLogStartNotices();
++$responses = $tester
++ ->multiRequest([
++ ['uri' => '/<script>alert(1)</script>', 'query' => '<script>alert(2)</script>'],
++ ['uri' => '/status', 'query' => 'full&html', 'delay' => 100000],
++ ]);
++var_dump(strpos($responses[1]->getBody(), '<script>'));
++$tester->terminate();
++$tester->expectLogTerminatingNotices();
++$tester->close();
++
++?>
++Done
++--EXPECT--
++bool(false)
++Done
++--CLEAN--
++<?php
++require_once "tester.inc";
++FPM\Tester::clean();
++?>
+--
+2.54.0
+
diff --git a/php-cve-2026-7258.patch b/php-cve-2026-7258.patch
new file mode 100644
index 0000000..b9c8180
--- /dev/null
+++ b/php-cve-2026-7258.patch
@@ -0,0 +1,1719 @@
+From 07e5a9263314fd9a2a4479661353704e00dd8d0c Mon Sep 17 00:00:00 2001
+From: Ilija Tovilo <ilija.tovilo@me.com>
+Date: Sun, 3 May 2026 20:03:18 +0200
+Subject: [PATCH 08/10] GHSA-m8rr-4c36-8gq4: Consistently pass unsigned char to
+ ctype.h functions
+
+Fixes GHSA-m8rr-4c36-8gq4
+Fixes CVE-2026-7258
+
+(cherry picked from commit a38418777f65780d9d622197677e90567690fc07)
+---
+ Zend/zend_compile.c | 2 +-
+ Zend/zend_operators.c | 8 ++++----
+ Zend/zend_virtual_cwd.c | 10 +++++-----
+ Zend/zend_virtual_cwd.h | 2 +-
+ ext/com_dotnet/com_extension.c | 4 ++--
+ ext/date/lib/parse_date.c | 10 +++++-----
+ ext/date/lib/parse_date.re | 10 +++++-----
+ ext/date/lib/parse_iso_intervals.c | 4 ++--
+ ext/date/lib/parse_iso_intervals.re | 4 ++--
+ ext/date/lib/timelib.c | 2 +-
+ ext/filter/logical_filters.c | 10 +++++-----
+ ext/ftp/ftp.c | 10 +++++-----
+ ext/gd/libgd/gd_xbm.c | 2 +-
+ ext/imap/php_imap.c | 2 +-
+ ext/intl/locale/locale_methods.c | 2 +-
+ ext/mbstring/mbstring.c | 4 ++--
+ ext/mbstring/php_mbregex.c | 2 +-
+ ext/pcre/php_pcre.c | 4 ++--
+ ext/pdo/pdo.c | 2 +-
+ ext/pdo/pdo_sql_parser.re | 2 +-
+ ext/pdo/pdo_stmt.c | 2 +-
+ ext/standard/dl.c | 2 +-
+ ext/standard/exec.c | 2 +-
+ ext/standard/file.c | 2 +-
+ ext/standard/filters.c | 2 +-
+ ext/standard/formatted_print.c | 8 ++++----
+ ext/standard/ftp_fopen_wrapper.c | 12 ++++++------
+ ext/standard/html.c | 4 ++--
+ ext/standard/math.c | 6 +++---
+ ext/standard/metaphone.c | 18 ++++++++---------
+ ext/standard/quot_print.c | 8 ++++----
+ ext/standard/scanf.c | 10 +++++-----
+ ext/standard/soundex.c | 2 +-
+ ext/standard/string.c | 14 +++++++-------
+ ext/standard/strnatcmp.c | 30 ++++++++++++++---------------
+ ext/standard/type.c | 2 +-
+ ext/standard/url.c | 20 +++++++++----------
+ ext/standard/url_scanner_ex.re | 6 +++---
+ ext/standard/versioning.c | 16 +++++++--------
+ main/SAPI.c | 6 +++---
+ main/fopen_wrappers.c | 6 +++---
+ main/php_ini.c | 2 +-
+ main/php_variables.c | 4 ++--
+ main/rfc1867.c | 12 ++++++------
+ main/snprintf.c | 14 +++++++-------
+ main/spprintf.c | 14 +++++++-------
+ main/streams/streams.c | 4 ++--
+ main/streams/transports.c | 2 +-
+ sapi/cli/php_cli_server.c | 2 +-
+ sapi/fpm/fpm/fpm_conf.c | 4 ++--
+ sapi/litespeed/lsapi_main.c | 4 ++--
+ sapi/litespeed/lsapilib.c | 6 +++---
+ sapi/phpdbg/phpdbg_cmd.c | 4 ++--
+ sapi/phpdbg/phpdbg_prompt.c | 2 +-
+ sapi/phpdbg/phpdbg_utils.c | 10 +++++-----
+ win32/sendmail.c | 6 +++---
+ 56 files changed, 182 insertions(+), 182 deletions(-)
+
+diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
+index c0cd3c97341..856e81ace7f 100644
+--- a/Zend/zend_compile.c
++++ b/Zend/zend_compile.c
+@@ -2006,7 +2006,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
+ /* Note that on Win32 CWD is per drive (heritage from CP/M).
+ * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
+ */
+- if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
++ if ((2 <= len) && isalpha((unsigned char)path[0]) && (':' == path[1])) {
+ /* Skip over the drive spec (if any) so as not to change */
+ path += 2;
+ len_adjust += 2;
+diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
+index ef5c50c4336..1c4abc9ede5 100644
+--- a/Zend/zend_operators.c
++++ b/Zend/zend_operators.c
+@@ -2883,8 +2883,8 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1,
+
+ len = MIN(len1, len2);
+ while (len--) {
+- c1 = zend_tolower((int)*(unsigned char *)s1++);
+- c2 = zend_tolower((int)*(unsigned char *)s2++);
++ c1 = zend_tolower((unsigned char)*(s1++));
++ c2 = zend_tolower((unsigned char)*(s2++));
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+@@ -2904,8 +2904,8 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1
+ }
+ len = MIN(length, MIN(len1, len2));
+ while (len--) {
+- c1 = zend_tolower((int)*(unsigned char *)s1++);
+- c2 = zend_tolower((int)*(unsigned char *)s2++);
++ c1 = zend_tolower((unsigned char)*(s1++));
++ c2 = zend_tolower((unsigned char)*(s2++));
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c
+index d8a9046d04d..ca5f79d9933 100644
+--- a/Zend/zend_virtual_cwd.c
++++ b/Zend/zend_virtual_cwd.c
+@@ -195,7 +195,7 @@ void virtual_cwd_main_cwd_init(uint8_t reinit) /* {{{ */
+ main_cwd_state.cwd_length = strlen(cwd);
+ #ifdef ZEND_WIN32
+ if (main_cwd_state.cwd_length >= 2 && cwd[1] == ':') {
+- cwd[0] = toupper(cwd[0]);
++ cwd[0] = toupper((unsigned char)cwd[0]);
+ }
+ #endif
+ main_cwd_state.cwd = strdup(cwd);
+@@ -273,7 +273,7 @@ CWD_API char *virtual_getcwd_ex(size_t *length) /* {{{ */
+ *length = state->cwd_length+1;
+ retval = (char *) emalloc(*length+1);
+ memcpy(retval, state->cwd, *length);
+- retval[0] = toupper(retval[0]);
++ retval[0] = toupper((unsigned char)retval[0]);
+ retval[*length-1] = DEFAULT_SLASH;
+ retval[*length] = '\0';
+ return retval;
+@@ -1114,7 +1114,7 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
+ if (resolved_path[start] == 0) {
+ goto verify;
+ }
+- resolved_path[start] = toupper(resolved_path[start]);
++ resolved_path[start] = toupper((unsigned char)resolved_path[start]);
+ start++;
+ }
+ resolved_path[start++] = DEFAULT_SLASH;
+@@ -1122,13 +1122,13 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
+ if (resolved_path[start] == 0) {
+ goto verify;
+ }
+- resolved_path[start] = toupper(resolved_path[start]);
++ resolved_path[start] = toupper((unsigned char)resolved_path[start]);
+ start++;
+ }
+ resolved_path[start++] = DEFAULT_SLASH;
+ } else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
+ /* skip DRIVE name */
+- resolved_path[0] = toupper(resolved_path[0]);
++ resolved_path[0] = toupper((unsigned char)resolved_path[0]);
+ resolved_path[2] = DEFAULT_SLASH;
+ start = 3;
+ }
+diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h
+index 728e3ba69d8..d15c8e28d5d 100644
+--- a/Zend/zend_virtual_cwd.h
++++ b/Zend/zend_virtual_cwd.h
+@@ -82,7 +82,7 @@ typedef unsigned short mode_t;
+ #define IS_UNC_PATH(path, len) \
+ (len >= 2 && IS_SLASH(path[0]) && IS_SLASH(path[1]))
+ #define IS_ABSOLUTE_PATH(path, len) \
+- (len >= 2 && (/* is local */isalpha(path[0]) && path[1] == ':' || /* is UNC */IS_SLASH(path[0]) && IS_SLASH(path[1])))
++ (len >= 2 && (/* is local */isalpha((unsigned char)(path)[0]) && path[1] == ':' || /* is UNC */IS_SLASH(path[0]) && IS_SLASH(path[1])))
+
+ #else
+ #ifdef HAVE_DIRENT_H
+diff --git a/ext/com_dotnet/com_extension.c b/ext/com_dotnet/com_extension.c
+index 55b3c282aee..380ca0791e8 100644
+--- a/ext/com_dotnet/com_extension.c
++++ b/ext/com_dotnet/com_extension.c
+@@ -104,11 +104,11 @@ static PHP_INI_MH(OnTypeLibFileUpdate)
+ }
+
+ /* Remove leading/training white spaces on search_string */
+- while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */
++ while (isspace((unsigned char)*typelib_name)) {/* Ends on '\0' in worst case */
+ typelib_name ++;
+ }
+ ptr = typelib_name + strlen(typelib_name) - 1;
+- while ((ptr != typelib_name) && isspace(*ptr)) {
++ while ((ptr != typelib_name) && isspace((unsigned char)*ptr)) {
+ *ptr = '\0';
+ ptr--;
+ }
+diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c
+index 78feb742081..9c5c9d602a1 100644
+--- a/ext/date/lib/parse_date.c
++++ b/ext/date/lib/parse_date.c
+@@ -509,7 +509,7 @@ static timelib_sll timelib_get_nr(const char **ptr, int max_length)
+
+ static void timelib_skip_day_suffix(const char **ptr)
+ {
+- if (isspace(**ptr)) {
++ if (isspace((unsigned char)**ptr)) {
+ return;
+ }
+ if (!timelib_strncasecmp(*ptr, "nd", 2) || !timelib_strncasecmp(*ptr, "rd", 2) ||!timelib_strncasecmp(*ptr, "st", 2) || !timelib_strncasecmp(*ptr, "th", 2)) {
+@@ -792,7 +792,7 @@ static timelib_long timelib_parse_tz_cor(const char **ptr, int *tz_not_found)
+
+ *tz_not_found = 1;
+
+- while (isdigit(**ptr) || **ptr == ':') {
++ while (isdigit((unsigned char)**ptr) || **ptr == ':') {
+ ++*ptr;
+ }
+ end = *ptr;
+@@ -857,7 +857,7 @@ static timelib_long timelib_parse_tz_minutes(const char **ptr, timelib_time *t)
+ }
+
+ ++*ptr;
+- while (isdigit(**ptr)) {
++ while (isdigit((unsigned char)**ptr)) {
+ ++*ptr;
+ }
+
+@@ -25936,10 +25936,10 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain
+ in.errors->error_messages = NULL;
+
+ if (len > 0) {
+- while (isspace(*s) && s < e) {
++ while (isspace((unsigned char)*s) && s < e) {
+ s++;
+ }
+- while (isspace(*e) && e > s) {
++ while (isspace((unsigned char)*e) && e > s) {
+ e--;
+ }
+ }
+diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re
+index f0db34d302b..a2d12361df9 100644
+--- a/ext/date/lib/parse_date.re
++++ b/ext/date/lib/parse_date.re
+@@ -507,7 +507,7 @@ static timelib_sll timelib_get_nr(const char **ptr, int max_length)
+
+ static void timelib_skip_day_suffix(const char **ptr)
+ {
+- if (isspace(**ptr)) {
++ if (isspace((unsigned char)**ptr)) {
+ return;
+ }
+ if (!timelib_strncasecmp(*ptr, "nd", 2) || !timelib_strncasecmp(*ptr, "rd", 2) ||!timelib_strncasecmp(*ptr, "st", 2) || !timelib_strncasecmp(*ptr, "th", 2)) {
+@@ -790,7 +790,7 @@ static timelib_long timelib_parse_tz_cor(const char **ptr, int *tz_not_found)
+
+ *tz_not_found = 1;
+
+- while (isdigit(**ptr) || **ptr == ':') {
++ while (isdigit((unsigned char)**ptr) || **ptr == ':') {
+ ++*ptr;
+ }
+ end = *ptr;
+@@ -855,7 +855,7 @@ static timelib_long timelib_parse_tz_minutes(const char **ptr, timelib_time *t)
+ }
+
+ ++*ptr;
+- while (isdigit(**ptr)) {
++ while (isdigit((unsigned char)**ptr)) {
+ ++*ptr;
+ }
+
+@@ -1938,10 +1938,10 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain
+ in.errors->error_messages = NULL;
+
+ if (len > 0) {
+- while (isspace(*s) && s < e) {
++ while (isspace((unsigned char)*s) && s < e) {
+ s++;
+ }
+- while (isspace(*e) && e > s) {
++ while (isspace((unsigned char)*e) && e > s) {
+ e--;
+ }
+ }
+diff --git a/ext/date/lib/parse_iso_intervals.c b/ext/date/lib/parse_iso_intervals.c
+index a467da3471f..113343f5615 100644
+--- a/ext/date/lib/parse_iso_intervals.c
++++ b/ext/date/lib/parse_iso_intervals.c
+@@ -948,10 +948,10 @@ void timelib_strtointerval(const char *s, size_t len,
+ in.errors->error_messages = NULL;
+
+ if (len > 0) {
+- while (isspace(*s) && s < e) {
++ while (isspace((unsigned char)*s) && s < e) {
+ s++;
+ }
+- while (isspace(*e) && e > s) {
++ while (isspace((unsigned char)*e) && e > s) {
+ e--;
+ }
+ }
+diff --git a/ext/date/lib/parse_iso_intervals.re b/ext/date/lib/parse_iso_intervals.re
+index 2a394156f98..00942007751 100644
+--- a/ext/date/lib/parse_iso_intervals.re
++++ b/ext/date/lib/parse_iso_intervals.re
+@@ -343,10 +343,10 @@ void timelib_strtointerval(const char *s, size_t len,
+ in.errors->error_messages = NULL;
+
+ if (len > 0) {
+- while (isspace(*s) && s < e) {
++ while (isspace((unsigned char)*s) && s < e) {
+ s++;
+ }
+- while (isspace(*e) && e > s) {
++ while (isspace((unsigned char)*e) && e > s) {
+ e--;
+ }
+ }
+diff --git a/ext/date/lib/timelib.c b/ext/date/lib/timelib.c
+index d42c69bbd6f..9949225df7e 100644
+--- a/ext/date/lib/timelib.c
++++ b/ext/date/lib/timelib.c
+@@ -126,7 +126,7 @@ void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
+ TIMELIB_TIME_FREE(tm->tz_abbr);
+ tm->tz_abbr = timelib_strdup(tz_abbr);
+ for (i = 0; i < tz_abbr_len; i++) {
+- tm->tz_abbr[i] = toupper(tz_abbr[i]);
++ tm->tz_abbr[i] = toupper((unsigned char)tz_abbr[i]);
+ }
+ }
+
+diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c
+index 3db0ef40905..472e2768651 100644
+--- a/ext/filter/logical_filters.c
++++ b/ext/filter/logical_filters.c
+@@ -528,21 +528,21 @@ static int _php_filter_validate_domain(char * domain, size_t len, zend_long flag
+ }
+
+ /* First char must be alphanumeric */
+- if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) {
++ if(*s == '.' || (hostname && !isalnum((unsigned char)*s))) {
+ return 0;
+ }
+
+ while (s < e) {
+ if (*s == '.') {
+ /* The first and the last character of a label must be alphanumeric */
+- if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) {
++ if (*(s + 1) == '.' || (hostname && (!isalnum((unsigned char)s[-1]) || !isalnum((unsigned char)s[1])))) {
+ return 0;
+ }
+
+ /* Reset label length counter */
+ i = 1;
+ } else {
+- if (i > 63 || (hostname && *s != '-' && !isalnum((int)*(unsigned char *)s))) {
++ if (i > 63 || (hostname && *s != '-' && !isalnum((unsigned char)*s))) {
+ return 0;
+ }
+
+@@ -569,9 +569,9 @@ static int is_userinfo_valid(zend_string *str)
+ const char *valid = "-._~!$&'()*+,;=:";
+ const char *p = ZSTR_VAL(str);
+ while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
+- if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
++ if (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || strchr(valid, *p)) {
+ p++;
+- } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
++ } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit((unsigned char)p[1]) && isxdigit((unsigned char)p[2])) {
+ p += 3;
+ } else {
+ return 0;
+diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c
+index 9253edc5589..9da59eabfb2 100644
+--- a/ext/ftp/ftp.c
++++ b/ext/ftp/ftp.c
+@@ -499,7 +499,7 @@ ftp_raw(ftpbuf_t *ftp, const char *cmd, const size_t cmd_len, zval *return_value
+ array_init(return_value);
+ while (ftp_readline(ftp)) {
+ add_next_index_string(return_value, ftp->inbuf);
+- if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
++ if (isdigit((unsigned char)ftp->inbuf[0]) && isdigit((unsigned char)ftp->inbuf[1]) && isdigit((unsigned char)ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
+ return;
+ }
+ }
+@@ -841,7 +841,7 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
+ return 0;
+ }
+ /* parse out the IP and port */
+- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
++ for (ptr = ftp->inbuf; *ptr && !isdigit((unsigned char)*ptr); ptr++);
+ n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
+ if (n != 6) {
+ return 0;
+@@ -1144,7 +1144,7 @@ ftp_mdtm(ftpbuf_t *ftp, const char *path, const size_t path_len)
+ return -1;
+ }
+ /* parse out the timestamp */
+- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
++ for (ptr = ftp->inbuf; *ptr && !isdigit((unsigned char)*ptr); ptr++);
+ n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ if (n != 6) {
+ return -1;
+@@ -1342,13 +1342,13 @@ ftp_getresp(ftpbuf_t *ftp)
+ }
+
+ /* Break out when the end-tag is found */
+- if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
++ if (isdigit((unsigned char)ftp->inbuf[0]) && isdigit((unsigned char)ftp->inbuf[1]) && isdigit((unsigned char)ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
+ break;
+ }
+ }
+
+ /* translate the tag */
+- if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
++ if (!isdigit((unsigned char)ftp->inbuf[0]) || !isdigit((unsigned char)ftp->inbuf[1]) || !isdigit((unsigned char)ftp->inbuf[2])) {
+ return 0;
+ }
+
+diff --git a/ext/gd/libgd/gd_xbm.c b/ext/gd/libgd/gd_xbm.c
+index 3c655a2998c..8efb34fbb0d 100644
+--- a/ext/gd/libgd/gd_xbm.c
++++ b/ext/gd/libgd/gd_xbm.c
+@@ -191,7 +191,7 @@ void gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out)
+ } else {
+ for (i=0; i<l; i++) {
+ /* only in C-locale isalnum() would work */
+- if (!isupper(name[i]) && !islower(name[i]) && !isdigit(name[i])) {
++ if (!isupper((unsigned char)name[i]) && !islower((unsigned char)name[i]) && !isdigit((unsigned char)name[i])) {
+ name[i] = '_';
+ }
+ }
+diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c
+index 5c45e213aa5..74fa59d1c5d 100644
+--- a/ext/imap/php_imap.c
++++ b/ext/imap/php_imap.c
+@@ -2316,7 +2316,7 @@ PHP_FUNCTION(imap_utf8)
+ #define SPECIAL(c) ((c) <= 0x1f || (c) >= 0x7f)
+
+ /* validate a modified-base64 character */
+-#define B64CHAR(c) (isalnum(c) || (c) == '+' || (c) == ',')
++#define B64CHAR(c) (isalnum((unsigned char)(c)) || (c) == '+' || (c) == ',')
+
+ /* map the low 64 bits of `n' to the modified-base64 characters */
+ #define B64(n) ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c
+index 159b3ea0a19..adca3ed3e32 100644
+--- a/ext/intl/locale/locale_methods.c
++++ b/ext/intl/locale/locale_methods.c
+@@ -1135,7 +1135,7 @@ static int strToMatch(const char* str ,char *retstr)
+ if( *str == '-' ){
+ *retstr = '_';
+ } else {
+- *retstr = tolower(*str);
++ *retstr = tolower((unsigned char)*str);
+ }
+ str++;
+ retstr++;
+diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
+index 238d74e4838..265356a21ce 100644
+--- a/ext/mbstring/mbstring.c
++++ b/ext/mbstring/mbstring.c
+@@ -626,7 +626,7 @@ static char *php_mb_rfc1867_getword(const zend_encoding *encoding, char **line,
+
+ static char *php_mb_rfc1867_getword_conf(const zend_encoding *encoding, char *str) /* {{{ */
+ {
+- while (*str && isspace(*(unsigned char *)str)) {
++ while (*str && isspace((unsigned char)*str)) {
+ ++str;
+ }
+
+@@ -642,7 +642,7 @@ static char *php_mb_rfc1867_getword_conf(const zend_encoding *encoding, char *st
+ } else {
+ char *strend = str;
+
+- while (*strend && !isspace(*(unsigned char *)strend)) {
++ while (*strend && !isspace((unsigned char)*strend)) {
+ ++strend;
+ }
+ return php_mb_rfc1867_substring_conf(encoding, str, strend - str, 0);
+diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c
+index 0734011f9fb..5342de2b4ca 100644
+--- a/ext/mbstring/php_mbregex.c
++++ b/ext/mbstring/php_mbregex.c
+@@ -784,7 +784,7 @@ static inline void mb_regex_substitute(
+ continue;
+ }
+ if (name_end[0] == delim) break;
+- if (maybe_num && !isdigit(name_end[0])) maybe_num = 0;
++ if (maybe_num && !isdigit((unsigned char)name_end[0])) maybe_num = 0;
+ name_end++;
+ }
+ p = name_end + 1;
+diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
+index 6249a807970..65891091256 100644
+--- a/ext/pcre/php_pcre.c
++++ b/ext/pcre/php_pcre.c
+@@ -648,7 +648,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
+
+ /* Parse through the leading whitespace, and display a warning if we
+ get to the end without encountering a delimiter. */
+- while (isspace((int)*(unsigned char *)p)) p++;
++ while (isspace((unsigned char)*p)) p++;
+ if (*p == 0) {
+ if (key != regex) {
+ zend_string_release_ex(key, 0);
+@@ -662,7 +662,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
+ /* Get the delimiter and display a warning if it is alphanumeric
+ or a backslash. */
+ delimiter = *p++;
+- if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\\') {
++ if (isalnum((unsigned char)delimiter) || delimiter == '\\') {
+ if (key != regex) {
+ zend_string_release_ex(key, 0);
+ }
+diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c
+index b18efe46284..03925abbc3b 100644
+--- a/ext/pdo/pdo.c
++++ b/ext/pdo/pdo.c
+@@ -229,7 +229,7 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, zend_ulong data_s
+ }
+ }
+
+- while (i < data_source_len && isspace(data_source[i])) {
++ while (i < data_source_len && isspace((unsigned char)data_source[i])) {
+ i++;
+ }
+
+diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re
+index 7f4721d12a6..7d282352396 100644
+--- a/ext/pdo/pdo_sql_parser.re
++++ b/ext/pdo/pdo_sql_parser.re
+@@ -105,7 +105,7 @@ PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string
+
+ if (t == PDO_PARSER_BIND) {
+ ptrdiff_t len = s.cur - s.tok;
+- if ((ZSTR_VAL(inquery) < (s.cur - len)) && isalnum(*(s.cur - len - 1))) {
++ if ((ZSTR_VAL(inquery) < (s.cur - len)) && isalnum((unsigned char)s.cur[-len - 1])) {
+ continue;
+ }
+ query_type |= PDO_PLACEHOLDER_NAMED;
+diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
+index c3c466fbdd2..ea2046a134b 100644
+--- a/ext/pdo/pdo_stmt.c
++++ b/ext/pdo/pdo_stmt.c
+@@ -148,7 +148,7 @@ bool pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
+ stmt->columns[col].name = zend_string_separate(orig_name, 0);
+ char *s = ZSTR_VAL(stmt->columns[col].name);
+ while (*s != '\0') {
+- *s = toupper(*s);
++ *s = toupper((unsigned char)*s);
+ s++;
+ }
+ break;
+diff --git a/ext/standard/dl.c b/ext/standard/dl.c
+index 0df3848852f..babab64864c 100644
+--- a/ext/standard/dl.c
++++ b/ext/standard/dl.c
+@@ -93,7 +93,7 @@ PHPAPI void *php_load_shlib(const char *path, char **errp)
+ size_t i = strlen(err);
+ (*errp)=estrdup(err);
+ php_win32_error_msg_free(err);
+- while (i > 0 && isspace((*errp)[i-1])) { (*errp)[i-1] = '\0'; i--; }
++ while (i > 0 && isspace((unsigned char)(*errp)[i-1])) { (*errp)[i-1] = '\0'; i--; }
+ } else {
+ (*errp) = estrdup("<No message>");
+ }
+diff --git a/ext/standard/exec.c b/ext/standard/exec.c
+index 1831b8eaa54..156eaa2cd3d 100644
+--- a/ext/standard/exec.c
++++ b/ext/standard/exec.c
+@@ -83,7 +83,7 @@ PHP_MINIT_FUNCTION(exec)
+
+ static size_t strip_trailing_whitespace(char *buf, size_t bufl) {
+ size_t l = bufl;
+- while (l-- > 0 && isspace(((unsigned char *)buf)[l]));
++ while (l-- > 0 && isspace((unsigned char)buf[l]));
+ if (l != (bufl - 1)) {
+ bufl = l + 1;
+ buf[bufl] = '\0';
+diff --git a/ext/standard/file.c b/ext/standard/file.c
+index 8bab36096b1..bf20702e976 100644
+--- a/ext/standard/file.c
++++ b/ext/standard/file.c
+@@ -2086,7 +2086,7 @@ PHPAPI void php_fgetcsv(php_stream *stream, char delimiter, char enclosure, int
+ inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0);
+ if (inc_len == 1) {
+ char *tmp = bptr;
+- while ((*tmp != delimiter) && isspace((int)*(unsigned char *)tmp)) {
++ while ((*tmp != delimiter) && isspace((unsigned char)*tmp)) {
+ tmp++;
+ }
+ if (*tmp == enclosure && tmp < limit) {
+diff --git a/ext/standard/filters.c b/ext/standard/filters.c
+index 9b54b3deab1..08678f8d5d8 100644
+--- a/ext/standard/filters.c
++++ b/ext/standard/filters.c
+@@ -958,7 +958,7 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins
+ goto out;
+ }
+
+- if (!isxdigit((int) *ps)) {
++ if (!isxdigit(*ps)) {
+ err = PHP_CONV_ERR_INVALID_SEQ;
+ goto out;
+ }
+diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c
+index b988422df21..a1927b5fe88 100644
+--- a/ext/standard/formatted_print.c
++++ b/ext/standard/formatted_print.c
+@@ -378,7 +378,7 @@ php_sprintf_getnumber(char **buffer, size_t *len)
+
+ int php_sprintf_get_argnum(char **format, size_t *format_len) {
+ char *temppos = *format;
+- while (isdigit((int) *temppos)) temppos++;
++ while (isdigit((unsigned char)*temppos)) temppos++;
+ if (*temppos != '$') {
+ return ARG_NUM_NEXT;
+ }
+@@ -466,7 +466,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
+
+ PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
+ *format, format - Z_STRVAL_P(z_format)));
+- if (isalpha((int)*format)) {
++ if (isalpha((unsigned char)*format)) {
+ width = precision = 0;
+ argnum = ARG_NUM_NEXT;
+ } else {
+@@ -535,7 +535,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
+ }
+ width = Z_LVAL_P(tmp);
+ adjusting |= ADJ_WIDTH;
+- } else if (isdigit((int)*format)) {
++ } else if (isdigit((unsigned char)*format)) {
+ PRINTF_DEBUG(("sprintf: getting width\n"));
+ if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) {
+ zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
+@@ -580,7 +580,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
+ precision = Z_LVAL_P(tmp);
+ adjusting |= ADJ_PRECISION;
+ expprec = 1;
+- } else if (isdigit((int)*format)) {
++ } else if (isdigit((unsigned char)*format)) {
+ if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) {
+ zend_value_error("Precision must be greater than zero and less than %d", INT_MAX);
+ goto fail;
+diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c
+index d19113f7c77..c7491179fa9 100644
+--- a/ext/standard/ftp_fopen_wrapper.c
++++ b/ext/standard/ftp_fopen_wrapper.c
+@@ -78,8 +78,8 @@ static inline int get_ftp_result(php_stream *stream, char *buffer, size_t buffer
+ {
+ buffer[0] = '\0'; /* in case read fails to read anything */
+ while (php_stream_gets(stream, buffer, buffer_size-1) &&
+- !(isdigit((int) buffer[0]) && isdigit((int) buffer[1]) &&
+- isdigit((int) buffer[2]) && buffer[3] == ' '));
++ !(isdigit((unsigned char)buffer[0]) && isdigit((unsigned char)buffer[1]) &&
++ isdigit((unsigned char)buffer[2]) && buffer[3] == ' '));
+ return strtol(buffer, NULL, 10);
+ }
+ /* }}} */
+@@ -228,7 +228,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char
+ #define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) { \
+ unsigned char *s = (unsigned char *) val, *e = (unsigned char *) s + val_len; \
+ while (s < e) { \
+- if (iscntrl(*s)) { \
++ if (iscntrl((unsigned char)*s)) { \
+ php_stream_wrapper_log_error(wrapper, options, err_msg, val); \
+ goto connect_errexit; \
+ } \
+@@ -339,14 +339,14 @@ static unsigned short php_fopen_do_pasv(php_stream *stream, char *ip, size_t ip_
+ /* parse pasv command (129, 80, 95, 25, 13, 221) */
+ tpath = tmp_line;
+ /* skip over the "227 Some message " part */
+- for (tpath += 4; *tpath && !isdigit((int) *tpath); tpath++);
++ for (tpath += 4; *tpath && !isdigit((unsigned char)*tpath); tpath++);
+ if (!*tpath) {
+ return 0;
+ }
+ /* skip over the host ip, to get the port */
+ hoststart = tpath;
+ for (i = 0; i < 4; i++) {
+- for (; isdigit((int) *tpath); tpath++);
++ for (; isdigit((unsigned char)*tpath); tpath++);
+ if (*tpath != ',') {
+ return 0;
+ }
+@@ -826,7 +826,7 @@ static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url,
+ struct tm tm, tmbuf, *gmt;
+ time_t stamp;
+
+- while ((size_t)(p - tmp_line) < sizeof(tmp_line) && !isdigit(*p)) {
++ while ((size_t)(p - tmp_line) < sizeof(tmp_line) && !isdigit((unsigned char)*p)) {
+ p++;
+ }
+
+diff --git a/ext/standard/html.c b/ext/standard/html.c
+index 14ccd71a236..8d39490b888 100644
+--- a/ext/standard/html.c
++++ b/ext/standard/html.c
+@@ -682,8 +682,8 @@ static inline int process_numeric_entity(const char **buf, unsigned *code_point)
+
+ /* strtol allows whitespace and other stuff in the beginning
+ * we're not interested */
+- if ((hexadecimal && !isxdigit(**buf)) ||
+- (!hexadecimal && !isdigit(**buf))) {
++ if ((hexadecimal && !isxdigit((unsigned char)**buf)) ||
++ (!hexadecimal && !isdigit((unsigned char)**buf))) {
+ return FAILURE;
+ }
+
+diff --git a/ext/standard/math.c b/ext/standard/math.c
+index 8643676b03e..af5869c88bc 100644
+--- a/ext/standard/math.c
++++ b/ext/standard/math.c
+@@ -727,9 +727,9 @@ PHPAPI void _php_math_basetozval(zend_string *str, int base, zval *ret)
+ e = s + ZSTR_LEN(str);
+
+ /* Skip leading whitespace */
+- while (s < e && isspace(*s)) s++;
++ while (s < e && isspace((unsigned char)*s)) s++;
+ /* Skip trailing whitespace */
+- while (s < e && isspace(*(e-1))) e--;
++ while (s < e && isspace((unsigned char)e[-1])) e--;
+
+ if (e - s >= 2) {
+ if (base == 16 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2;
+@@ -1031,7 +1031,7 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, const char *de
+ tmpbuf = strpprintf(0, "%.*F", dec, d);
+ if (tmpbuf == NULL) {
+ return NULL;
+- } else if (!isdigit((int)ZSTR_VAL(tmpbuf)[0])) {
++ } else if (!isdigit((unsigned char)ZSTR_VAL(tmpbuf)[0])) {
+ return tmpbuf;
+ }
+
+diff --git a/ext/standard/metaphone.c b/ext/standard/metaphone.c
+index 7affde44de1..01ae1f965c1 100644
+--- a/ext/standard/metaphone.c
++++ b/ext/standard/metaphone.c
+@@ -78,7 +78,7 @@ static const char _codes[26] =
+ };
+
+
+-#define ENCODE(c) (isalpha(c) ? _codes[((toupper(c)) - 'A')] : 0)
++#define ENCODE(c) (isalpha((unsigned char)(c)) ? _codes[((toupper((unsigned char)(c))) - 'A')] : 0)
+
+ #define isvowel(c) (ENCODE(c) & 1) /* AEIOU */
+
+@@ -102,17 +102,17 @@ static const char _codes[26] =
+ * accesssing the array directly... */
+
+ /* Look at the next letter in the word */
+-#define Next_Letter (toupper(word[w_idx+1]))
++#define Next_Letter (toupper((unsigned char)word[w_idx+1]))
+ /* Look at the current letter in the word */
+-#define Curr_Letter (toupper(word[w_idx]))
++#define Curr_Letter (toupper((unsigned char)word[w_idx]))
+ /* Go N letters back. */
+-#define Look_Back_Letter(n) (w_idx >= n ? toupper(word[w_idx-n]) : '\0')
++#define Look_Back_Letter(n) (w_idx >= n ? toupper((unsigned char)word[w_idx-n]) : '\0')
+ /* Previous letter. I dunno, should this return null on failure? */
+ #define Prev_Letter (Look_Back_Letter(1))
+ /* Look two letters down. It makes sure you don't walk off the string. */
+-#define After_Next_Letter (Next_Letter != '\0' ? toupper(word[w_idx+2]) \
++#define After_Next_Letter (Next_Letter != '\0' ? toupper((unsigned char)word[w_idx+2]) \
+ : '\0')
+-#define Look_Ahead_Letter(n) (toupper(Lookahead((char *) word+w_idx, n)))
++#define Look_Ahead_Letter(n) (toupper((unsigned char)Lookahead((char *) word+w_idx, n)))
+
+
+ /* Allows us to safely look ahead an arbitrary # of letters */
+@@ -156,7 +156,7 @@ static char Lookahead(char *word, size_t how_far)
+ #define Phone_Len (p_idx)
+
+ /* Note is a letter is a 'break' in the word */
+-#define Isbreak(c) (!isalpha(c))
++#define Isbreak(c) (!isalpha((unsigned char)(c)))
+
+ /* {{{ metaphone */
+ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonemes, zend_string **phoned_word, int traditional)
+@@ -179,7 +179,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem
+
+ /*-- The first phoneme has to be processed specially. --*/
+ /* Find our first letter */
+- for (; !isalpha(Curr_Letter); w_idx++) {
++ for (; !isalpha((unsigned char)Curr_Letter); w_idx++) {
+ /* On the off chance we were given nothing but crap... */
+ if (Curr_Letter == '\0') {
+ End_Phoned_Word();
+@@ -263,7 +263,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem
+ */
+
+ /* Ignore non-alphas */
+- if (!isalpha(Curr_Letter))
++ if (!isalpha((unsigned char)Curr_Letter))
+ continue;
+
+ /* Drop duplicates, except CC */
+diff --git a/ext/standard/quot_print.c b/ext/standard/quot_print.c
+index e6aa2e43f4c..fba61f9f484 100644
+--- a/ext/standard/quot_print.c
++++ b/ext/standard/quot_print.c
+@@ -216,11 +216,11 @@ PHP_FUNCTION(quoted_printable_decode)
+ switch (str_in[i]) {
+ case '=':
+ if (str_in[i + 1] && str_in[i + 2] &&
+- isxdigit((int) str_in[i + 1]) &&
+- isxdigit((int) str_in[i + 2]))
++ isxdigit((unsigned char)str_in[i + 1]) &&
++ isxdigit((unsigned char)str_in[i + 2]))
+ {
+- ZSTR_VAL(str_out)[j++] = (php_hex2int((int) str_in[i + 1]) << 4)
+- + php_hex2int((int) str_in[i + 2]);
++ ZSTR_VAL(str_out)[j++] = (php_hex2int((unsigned char)str_in[i + 1]) << 4)
++ + php_hex2int((unsigned char)str_in[i + 2]);
+ i += 3;
+ } else /* check for soft line break according to RFC 2045*/ {
+ k = 1;
+diff --git a/ext/standard/scanf.c b/ext/standard/scanf.c
+index 78ecc1642cf..61154eca3a3 100644
+--- a/ext/standard/scanf.c
++++ b/ext/standard/scanf.c
+@@ -345,7 +345,7 @@ PHPAPI int ValidateFormat(char *format, int numVars, int *totalSubs)
+ goto xpgCheckDone;
+ }
+
+- if ( isdigit( (int)*ch ) ) {
++ if ( isdigit( (unsigned char)*ch ) ) {
+ /*
+ * Check for an XPG3-style %n$ specification. Note: there
+ * must not be a mixture of XPG3 specs and non-XPG3 specs
+@@ -656,9 +656,9 @@ PHPAPI int php_sscanf_internal( char *string, char *format,
+ /*
+ * If we see whitespace in the format, skip whitespace in the string.
+ */
+- if ( isspace( (int)*ch ) ) {
++ if ( isspace( (unsigned char)*ch ) ) {
+ sch = *string;
+- while ( isspace( (int)sch ) ) {
++ while ( isspace( (unsigned char)sch ) ) {
+ if (*string == '\0') {
+ goto done;
+ }
+@@ -809,7 +809,7 @@ literal:
+ if (!(flags & SCAN_NOSKIP)) {
+ while (*string != '\0') {
+ sch = *string;
+- if (! isspace((int)sch) ) {
++ if (! isspace((unsigned char)sch) ) {
+ break;
+ }
+ string++;
+@@ -835,7 +835,7 @@ literal:
+ end = string;
+ while (*end != '\0') {
+ sch = *end;
+- if ( isspace( (int)sch ) ) {
++ if ( isspace( (unsigned char)sch ) ) {
+ break;
+ }
+ end++;
+diff --git a/ext/standard/soundex.c b/ext/standard/soundex.c
+index 7d50be97e75..4dded617a65 100644
+--- a/ext/standard/soundex.c
++++ b/ext/standard/soundex.c
+@@ -67,7 +67,7 @@ PHP_FUNCTION(soundex)
+ /* BUG: should also map here accented letters used in non */
+ /* English words or names (also found in English text!): */
+ /* esstsett, thorn, n-tilde, c-cedilla, s-caron, ... */
+- code = toupper((int)(unsigned char)str[i]);
++ code = toupper((unsigned char)str[i]);
+ if (code >= 'A' && code <= 'Z') {
+ if (_small == 0) {
+ /* remember first valid char */
+diff --git a/ext/standard/string.c b/ext/standard/string.c
+index da1a97f49da..8ca36ed7186 100644
+--- a/ext/standard/string.c
++++ b/ext/standard/string.c
+@@ -3534,9 +3534,9 @@ PHPAPI void php_stripcslashes(zend_string *str)
+ case 'f': *target++='\f'; nlen--; break;
+ case '\\': *target++='\\'; nlen--; break;
+ case 'x':
+- if (source+1 < end && isxdigit((int)(*(source+1)))) {
++ if (source+1 < end && isxdigit((unsigned char)source[1])) {
+ numtmp[0] = *++source;
+- if (source+1 < end && isxdigit((int)(*(source+1)))) {
++ if (source+1 < end && isxdigit((unsigned char)source[1])) {
+ numtmp[1] = *++source;
+ numtmp[2] = '\0';
+ nlen-=3;
+@@ -4386,7 +4386,7 @@ PHP_FUNCTION(hebrev)
+
+ do {
+ if (block_type == _HEB_BLOCK_TYPE_HEB) {
+- while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
++ while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((unsigned char)tmp[1]) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
+ tmp++;
+ block_end++;
+ block_length++;
+@@ -4436,7 +4436,7 @@ PHP_FUNCTION(hebrev)
+ block_end++;
+ block_length++;
+ }
+- while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
++ while ((_isblank((int)*tmp) || ispunct((unsigned char)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
+ tmp--;
+ block_end--;
+ }
+@@ -4818,7 +4818,7 @@ int php_tag_find(char *tag, size_t len, const char *set) {
+ done =1;
+ break;
+ default:
+- if (!isspace((int)c)) {
++ if (!isspace((unsigned char)c)) {
+ if (state == 0) {
+ state=1;
+ }
+@@ -4908,7 +4908,7 @@ state_0:
+ if (in_q) {
+ break;
+ }
+- if (isspace(*(p + 1)) && !allow_tag_spaces) {
++ if (isspace((unsigned char)p[1]) && !allow_tag_spaces) {
+ *(rp++) = c;
+ break;
+ }
+@@ -4955,7 +4955,7 @@ state_1:
+ if (in_q) {
+ break;
+ }
+- if (isspace(*(p + 1)) && !allow_tag_spaces) {
++ if (isspace((unsigned char)p[1]) && !allow_tag_spaces) {
+ goto reg_char_1;
+ }
+ depth++;
+diff --git a/ext/standard/strnatcmp.c b/ext/standard/strnatcmp.c
+index 8cbc0db1c3f..6d45785bcdd 100644
+--- a/ext/standard/strnatcmp.c
++++ b/ext/standard/strnatcmp.c
+@@ -40,12 +40,12 @@ compare_right(char const **a, char const *aend, char const **b, char const *bend
+ both numbers to know that they have the same magnitude, so we
+ remember it in BIAS. */
+ for(;; (*a)++, (*b)++) {
+- if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
+- (*b == bend || !isdigit((int)(unsigned char)**b)))
++ if ((*a == aend || !isdigit((unsigned char)**a)) &&
++ (*b == bend || !isdigit((unsigned char)**b)))
+ return bias;
+- else if (*a == aend || !isdigit((int)(unsigned char)**a))
++ else if (*a == aend || !isdigit((unsigned char)**a))
+ return -1;
+- else if (*b == bend || !isdigit((int)(unsigned char)**b))
++ else if (*b == bend || !isdigit((unsigned char)**b))
+ return +1;
+ else if (**a < **b) {
+ if (!bias)
+@@ -67,12 +67,12 @@ compare_left(char const **a, char const *aend, char const **b, char const *bend)
+ /* Compare two left-aligned numbers: the first to have a
+ different value wins. */
+ for(;; (*a)++, (*b)++) {
+- if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
+- (*b == bend || !isdigit((int)(unsigned char)**b)))
++ if ((*a == aend || !isdigit((unsigned char)**a)) &&
++ (*b == bend || !isdigit((unsigned char)**b)))
+ return 0;
+- else if (*a == aend || !isdigit((int)(unsigned char)**a))
++ else if (*a == aend || !isdigit((unsigned char)**a))
+ return -1;
+- else if (*b == bend || !isdigit((int)(unsigned char)**b))
++ else if (*b == bend || !isdigit((unsigned char)**b))
+ return +1;
+ else if (**a < **b)
+ return -1;
+@@ -103,27 +103,27 @@ PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len
+ ca = *ap; cb = *bp;
+
+ /* skip over leading zeros */
+- while (ca == '0' && (ap+1 < aend) && isdigit((int)(unsigned char)*(ap+1))) {
++ while (ca == '0' && (ap+1 < aend) && isdigit((unsigned char)ap[1])) {
+ ca = *++ap;
+ }
+
+- while (cb == '0' && (bp+1 < bend) && isdigit((int)(unsigned char)*(bp+1))) {
++ while (cb == '0' && (bp+1 < bend) && isdigit((unsigned char)bp[1])) {
+ cb = *++bp;
+ }
+
+ while (1) {
+
+ /* Skip consecutive whitespace */
+- while (isspace((int)(unsigned char)ca)) {
++ while (isspace(ca)) {
+ ca = *++ap;
+ }
+
+- while (isspace((int)(unsigned char)cb)) {
++ while (isspace(cb)) {
+ cb = *++bp;
+ }
+
+ /* process run of digits */
+- if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) {
++ if (isdigit(ca) && isdigit(cb)) {
+ fractional = (ca == '0' || cb == '0');
+
+ if (fractional)
+@@ -147,8 +147,8 @@ PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len
+ }
+
+ if (fold_case) {
+- ca = toupper((int)(unsigned char)ca);
+- cb = toupper((int)(unsigned char)cb);
++ ca = toupper(ca);
++ cb = toupper(cb);
+ }
+
+ if (ca < cb)
+diff --git a/ext/standard/type.c b/ext/standard/type.c
+index 93df434fe31..bf56c70d73d 100644
+--- a/ext/standard/type.c
++++ b/ext/standard/type.c
+@@ -161,7 +161,7 @@ PHP_FUNCTION(intval)
+ char *strval = Z_STRVAL_P(num);
+ size_t strlen = Z_STRLEN_P(num);
+
+- while (isspace(*strval) && strlen) {
++ while (isspace((unsigned char)*strval) && strlen) {
+ strval++;
+ strlen--;
+ }
+diff --git a/ext/standard/url.c b/ext/standard/url.c
+index e3d95768fb0..def29df906a 100644
+--- a/ext/standard/url.c
++++ b/ext/standard/url.c
+@@ -117,7 +117,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port
+ p = s;
+ while (p < e) {
+ /* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
+- if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
++ if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p) && *p != '+' && *p != '.' && *p != '-') {
+ if (e + 1 < ue && e < binary_strcspn(s, ue, "?#")) {
+ goto parse_port;
+ } else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
+@@ -146,7 +146,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port
+ * correctly parse things like a.com:80
+ */
+ p = e + 1;
+- while (p < ue && isdigit(*p)) {
++ while (p < ue && isdigit((unsigned char)*p)) {
+ p++;
+ }
+
+@@ -186,7 +186,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port
+ p = e + 1;
+ pp = p;
+
+- while (pp < ue && pp - p < 6 && isdigit(*pp)) {
++ while (pp < ue && pp - p < 6 && isdigit((unsigned char)*pp)) {
+ pp++;
+ }
+
+@@ -429,12 +429,12 @@ static int php_htoi(char *s)
+ int value;
+ int c;
+
+- c = ((unsigned char *)s)[0];
++ c = (unsigned char)s[0];
+ if (isupper(c))
+ c = tolower(c);
+ value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
+
+- c = ((unsigned char *)s)[1];
++ c = (unsigned char)s[1];
+ if (isupper(c))
+ c = tolower(c);
+ value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
+@@ -601,8 +601,8 @@ PHPAPI size_t php_url_decode(char *str, size_t len)
+ if (*data == '+') {
+ *dest = ' ';
+ }
+- else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1))
+- && isxdigit((int) *(data + 2))) {
++ else if (*data == '%' && len >= 2 && isxdigit((unsigned char)data[1])
++ && isxdigit((unsigned char)data[2])) {
+ *dest = (char) php_htoi(data + 1);
+ data += 2;
+ len -= 2;
+@@ -660,8 +660,8 @@ PHPAPI size_t php_raw_url_decode(char *str, size_t len)
+ char *data = str;
+
+ while (len--) {
+- if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1))
+- && isxdigit((int) *(data + 2))) {
++ if (*data == '%' && len >= 2 && isxdigit((unsigned char)data[1])
++ && isxdigit((unsigned char)data[2])) {
+ *dest = (char) php_htoi(data + 1);
+ data += 2;
+ len -= 2;
+@@ -722,7 +722,7 @@ no_name_header:
+ c = *p;
+ *p = '\0';
+ s = p + 1;
+- while (isspace((int)*(unsigned char *)s)) {
++ while (isspace((unsigned char)*s)) {
+ s++;
+ }
+
+diff --git a/ext/standard/url_scanner_ex.re b/ext/standard/url_scanner_ex.re
+index bac49206e63..30b395b3957 100644
+--- a/ext/standard/url_scanner_ex.re
++++ b/ext/standard/url_scanner_ex.re
+@@ -85,7 +85,7 @@ static int php_ini_on_update_tags(zend_ini_entry *entry, zend_string *new_value,
+
+ *val++ = '\0';
+ for (q = key; *q; q++) {
+- *q = tolower(*q);
++ *q = tolower((unsigned char)*q);
+ }
+ keylen = q - key;
+ str = zend_string_init(key, keylen, 1);
+@@ -134,7 +134,7 @@ static int php_ini_on_update_hosts(zend_ini_entry *entry, zend_string *new_value
+ char *q;
+
+ for (q = key; *q; q++) {
+- *q = tolower(*q);
++ *q = tolower((unsigned char)*q);
+ }
+ keylen = q - key;
+ if (keylen > 0) {
+@@ -454,7 +454,7 @@ static inline void handle_tag(STD_PARA)
+ }
+ smart_str_appendl(&ctx->tag, start, YYCURSOR - start);
+ for (i = 0; i < ZSTR_LEN(ctx->tag.s); i++)
+- ZSTR_VAL(ctx->tag.s)[i] = tolower((int)(unsigned char)ZSTR_VAL(ctx->tag.s)[i]);
++ ZSTR_VAL(ctx->tag.s)[i] = tolower((unsigned char)ZSTR_VAL(ctx->tag.s)[i]);
+ /* intentionally using str_find here, in case the hash value is set, but the string val is changed later */
+ if ((ctx->lookup_data = zend_hash_str_find_ptr(ctx->tags, ZSTR_VAL(ctx->tag.s), ZSTR_LEN(ctx->tag.s))) != NULL) {
+ ok = 1;
+diff --git a/ext/standard/versioning.c b/ext/standard/versioning.c
+index aa60d974672..178539709c7 100644
+--- a/ext/standard/versioning.c
++++ b/ext/standard/versioning.c
+@@ -45,8 +45,8 @@ php_canonicalize_version(const char *version)
+ * s/([^\d\.])([^\D\.])/$1.$2/g;
+ * s/([^\D\.])([^\d\.])/$1.$2/g;
+ */
+-#define isdig(x) (isdigit(x)&&(x)!='.')
+-#define isndig(x) (!isdigit(x)&&(x)!='.')
++#define isdig(x) (isdigit((unsigned char)(x))&&(x)!='.')
++#define isndig(x) (!isdigit((unsigned char)(x))&&(x)!='.')
+ #define isspecialver(x) ((x)=='-'||(x)=='_'||(x)=='+')
+
+ lq = *(q - 1);
+@@ -59,7 +59,7 @@ php_canonicalize_version(const char *version)
+ *q++ = '.';
+ }
+ *q++ = *p;
+- } else if (!isalnum(*p)) {
++ } else if (!isalnum((unsigned char)*p)) {
+ if (lq != '.') {
+ *q++ = '.';
+ }
+@@ -152,17 +152,17 @@ php_version_compare(const char *orig_ver1, const char *orig_ver2)
+ if ((n2 = strchr(p2, '.')) != NULL) {
+ *n2 = '\0';
+ }
+- if (isdigit(*p1) && isdigit(*p2)) {
++ if (isdigit((unsigned char)*p1) && isdigit((unsigned char)*p2)) {
+ /* compare element numerically */
+ l1 = strtol(p1, NULL, 10);
+ l2 = strtol(p2, NULL, 10);
+ compare = ZEND_NORMALIZE_BOOL(l1 - l2);
+- } else if (!isdigit(*p1) && !isdigit(*p2)) {
++ } else if (!isdigit((unsigned char)*p1) && !isdigit((unsigned char)*p2)) {
+ /* compare element names */
+ compare = compare_special_version_forms(p1, p2);
+ } else {
+ /* mix of names and numbers */
+- if (isdigit(*p1)) {
++ if (isdigit((unsigned char)*p1)) {
+ compare = compare_special_version_forms("#N#", p2);
+ } else {
+ compare = compare_special_version_forms(p1, "#N#");
+@@ -180,13 +180,13 @@ php_version_compare(const char *orig_ver1, const char *orig_ver2)
+ }
+ if (compare == 0) {
+ if (n1 != NULL) {
+- if (isdigit(*p1)) {
++ if (isdigit((unsigned char)*p1)) {
+ compare = 1;
+ } else {
+ compare = php_version_compare(p1, "#N#");
+ }
+ } else if (n2 != NULL) {
+- if (isdigit(*p2)) {
++ if (isdigit((unsigned char)*p2)) {
+ compare = -1;
+ } else {
+ compare = php_version_compare("#N#", p2);
+diff --git a/main/SAPI.c b/main/SAPI.c
+index 561cf6d598c..8b47a6c828c 100644
+--- a/main/SAPI.c
++++ b/main/SAPI.c
+@@ -193,7 +193,7 @@ static void sapi_read_post_data(void)
+ *p = 0;
+ break;
+ default:
+- *p = tolower(*p);
++ *p = tolower((unsigned char)*p);
+ break;
+ }
+ }
+@@ -710,10 +710,10 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg)
+ }
+
+ /* cut off trailing spaces, linefeeds and carriage-returns */
+- if (header_line_len && isspace(header_line[header_line_len-1])) {
++ if (header_line_len && isspace((unsigned char)header_line[header_line_len - 1])) {
+ do {
+ header_line_len--;
+- } while(header_line_len && isspace(header_line[header_line_len-1]));
++ } while(header_line_len && isspace((unsigned char)header_line[header_line_len - 1]));
+ header_line[header_line_len]='\0';
+ }
+
+diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
+index efb110171b1..2ba2615ee6f 100644
+--- a/main/fopen_wrappers.c
++++ b/main/fopen_wrappers.c
+@@ -487,7 +487,7 @@ PHPAPI zend_string *php_resolve_path(const char *filename, size_t filename_lengt
+ }
+
+ /* Don't resolve paths which contain protocol (except of file://) */
+- for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
++ for (p = filename; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
+ wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE);
+ if (wrapper == &php_plain_files_wrapper) {
+@@ -519,7 +519,7 @@ PHPAPI zend_string *php_resolve_path(const char *filename, size_t filename_lengt
+ /* Check for stream wrapper */
+ int is_stream_wrapper = 0;
+
+- for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
++ for (p = ptr; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
+ /* .:// or ..:// is not a stream wrapper */
+ if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
+@@ -588,7 +588,7 @@ PHPAPI zend_string *php_resolve_path(const char *filename, size_t filename_lengt
+ actual_path = trypath;
+
+ /* Check for stream wrapper */
+- for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
++ for (p = trypath; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
+ wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE);
+ if (!wrapper) {
+diff --git a/main/php_ini.c b/main/php_ini.c
+index 136942896da..f28c7db7de5 100644
+--- a/main/php_ini.c
++++ b/main/php_ini.c
+@@ -40,7 +40,7 @@
+ char *tmp = path; \
+ while (*tmp) { \
+ if (*tmp == '\\') *tmp = '/'; \
+- else *tmp = tolower(*tmp); \
++ else *tmp = tolower((unsigned char)*tmp); \
+ tmp++; \
+ } \
+ }
+diff --git a/main/php_variables.c b/main/php_variables.c
+index da7266416a5..a851c347601 100644
+--- a/main/php_variables.c
++++ b/main/php_variables.c
+@@ -185,7 +185,7 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac
+
+ ip++;
+ index_s = ip;
+- if (isspace(*ip)) {
++ if (isspace((unsigned char)*ip)) {
+ ip++;
+ }
+ if (*ip==']') {
+@@ -508,7 +508,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
+
+ if (arg == PARSE_COOKIE) {
+ /* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */
+- while (isspace(*var)) {
++ while (isspace((unsigned char)*var)) {
+ var++;
+ }
+ if (var == val || *var == '\0') {
+diff --git a/main/rfc1867.c b/main/rfc1867.c
+index 83d141d38b1..c57e26b11b9 100644
+--- a/main/rfc1867.c
++++ b/main/rfc1867.c
+@@ -413,7 +413,7 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
+ }
+
+ /* space in the beginning means same header */
+- if (!isspace(line[0])) {
++ if (!isspace((unsigned char)line[0])) {
+ value = strchr(line, ':');
+ }
+
+@@ -429,7 +429,7 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
+ }
+
+ *value = '\0';
+- do { value++; } while (isspace(*value));
++ do { value++; } while (isspace((unsigned char)*value));
+
+ key = estrdup(line);
+ smart_string_appends(&buf_value, value);
+@@ -526,7 +526,7 @@ static char *substring_conf(char *start, int len, char quote)
+
+ static char *php_ap_getword_conf(const zend_encoding *encoding, char *str)
+ {
+- while (*str && isspace(*str)) {
++ while (*str && isspace((unsigned char)*str)) {
+ ++str;
+ }
+
+@@ -542,7 +542,7 @@ static char *php_ap_getword_conf(const zend_encoding *encoding, char *str)
+ } else {
+ char *strend = str;
+
+- while (*strend && !isspace(*strend)) {
++ while (*strend && !isspace((unsigned char)*strend)) {
+ ++strend;
+ }
+ return substring_conf(str, strend - str, 0);
+@@ -809,7 +809,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ goto fileupload_done;
+ }
+
+- while (isspace(*cd)) {
++ while (isspace((unsigned char)*cd)) {
+ ++cd;
+ }
+
+@@ -817,7 +817,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ {
+ char *key = NULL, *word = pair;
+
+- while (isspace(*cd)) {
++ while (isspace((unsigned char)*cd)) {
+ ++cd;
+ }
+
+diff --git a/main/snprintf.c b/main/snprintf.c
+index f082115c676..b591169012b 100644
+--- a/main/snprintf.c
++++ b/main/snprintf.c
+@@ -286,7 +286,7 @@ PHPAPI char * php_conv_fp(char format, double num,
+ /*
+ * Check for Infinity and NaN
+ */
+- if (isalpha((int)*p)) {
++ if (isalpha((unsigned char)*p)) {
+ *len = strlen(p);
+ memcpy(buf, p, *len + 1);
+ *is_negative = false;
+@@ -433,11 +433,11 @@ typedef struct buf_area buffy;
+ #define NUM( c ) ( c - '0' )
+
+ #define STR_TO_DEC( str, num ) \
+- num = NUM( *str++ ) ; \
+- while ( isdigit((int)*str ) ) \
++ num = NUM( *(str)++ ) ; \
++ while ( isdigit((unsigned char)*(str) ) ) \
+ { \
+ num *= 10 ; \
+- num += NUM( *str++ ) ; \
++ num += NUM( *(str)++ ) ; \
+ }
+
+ /*
+@@ -531,7 +531,7 @@ static size_t format_converter(buffy * odp, const char *fmt, va_list ap) /* {{{
+ /*
+ * Try to avoid checking for flags, width or precision
+ */
+- if (isascii((int)*fmt) && !islower((int)*fmt)) {
++ if (isascii((unsigned char)*fmt) && !islower((unsigned char)*fmt)) {
+ /*
+ * Recognize flags: -, #, BLANK, +
+ */
+@@ -553,7 +553,7 @@ static size_t format_converter(buffy * odp, const char *fmt, va_list ap) /* {{{
+ /*
+ * Check if a width was specified
+ */
+- if (isdigit((int)*fmt)) {
++ if (isdigit((unsigned char)*fmt)) {
+ STR_TO_DEC(fmt, min_width);
+ adjust_width = true;
+ } else if (*fmt == '*') {
+@@ -573,7 +573,7 @@ static size_t format_converter(buffy * odp, const char *fmt, va_list ap) /* {{{
+ if (*fmt == '.') {
+ adjust_precision = true;
+ fmt++;
+- if (isdigit((int)*fmt)) {
++ if (isdigit((unsigned char)*fmt)) {
+ STR_TO_DEC(fmt, precision);
+ } else if (*fmt == '*') {
+ precision = va_arg(ap, int);
+diff --git a/main/spprintf.c b/main/spprintf.c
+index 4c01347fcf4..2a31e3ae38b 100644
+--- a/main/spprintf.c
++++ b/main/spprintf.c
+@@ -146,12 +146,12 @@
+ #define NUM(c) (c - '0')
+
+ #define STR_TO_DEC(str, num) do { \
+- num = NUM(*str++); \
+- while (isdigit((int)*str)) { \
++ num = NUM(*(str)++); \
++ while (isdigit((unsigned char)*(str))) {\
+ num *= 10; \
+- num += NUM(*str++); \
++ num += NUM(*(str)++); \
+ if (num >= INT_MAX / 10) { \
+- while (isdigit((int)*str++)); \
++ while (isdigit((unsigned char)*(str)++)); \
+ break; \
+ } \
+ } \
+@@ -238,7 +238,7 @@ static void xbuf_format_converter(void *xbuf, bool is_char, const char *fmt, va_
+ /*
+ * Try to avoid checking for flags, width or precision
+ */
+- if (isascii((int)*fmt) && !islower((int)*fmt)) {
++ if (isascii((unsigned char)*fmt) && !islower((unsigned char)*fmt)) {
+ /*
+ * Recognize flags: -, #, BLANK, +
+ */
+@@ -260,7 +260,7 @@ static void xbuf_format_converter(void *xbuf, bool is_char, const char *fmt, va_
+ /*
+ * Check if a width was specified
+ */
+- if (isdigit((int)*fmt)) {
++ if (isdigit((unsigned char)*fmt)) {
+ STR_TO_DEC(fmt, min_width);
+ adjust_width = true;
+ } else if (*fmt == '*') {
+@@ -280,7 +280,7 @@ static void xbuf_format_converter(void *xbuf, bool is_char, const char *fmt, va_
+ if (*fmt == '.') {
+ adjust_precision = true;
+ fmt++;
+- if (isdigit((int)*fmt)) {
++ if (isdigit((unsigned char)*fmt)) {
+ STR_TO_DEC(fmt, precision);
+ } else if (*fmt == '*') {
+ precision = va_arg(ap, int);
+diff --git a/main/streams/streams.c b/main/streams/streams.c
+index 634c0d58348..030c2453e50 100644
+--- a/main/streams/streams.c
++++ b/main/streams/streams.c
+@@ -1739,7 +1739,7 @@ static inline int php_stream_wrapper_scheme_validate(const char *protocol, unsig
+ unsigned int i;
+
+ for(i = 0; i < protocol_len; i++) {
+- if (!isalnum((int)protocol[i]) &&
++ if (!isalnum((unsigned char)protocol[i]) &&
+ protocol[i] != '+' &&
+ protocol[i] != '-' &&
+ protocol[i] != '.') {
+@@ -1819,7 +1819,7 @@ PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, const
+ return (php_stream_wrapper*)((options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper);
+ }
+
+- for (p = path; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
++ for (p = path; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
+ n++;
+ }
+
+diff --git a/main/streams/transports.c b/main/streams/transports.c
+index 35ac4ae27ad..306f7ff5e4b 100644
+--- a/main/streams/transports.c
++++ b/main/streams/transports.c
+@@ -94,7 +94,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
+ }
+ }
+
+- for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
++ for (p = name; isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
+ n++;
+ }
+
+diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
+index 82cf5c10d15..ab0ad1d6e5c 100644
+--- a/sapi/cli/php_cli_server.c
++++ b/sapi/cli/php_cli_server.c
+@@ -633,7 +633,7 @@ static int sapi_cli_server_register_entry_cb(char **entry, int num_args, va_list
+ if (key[i] == '-') {
+ key[i] = '_';
+ } else {
+- key[i] = toupper(key[i]);
++ key[i] = toupper((unsigned char)key[i]);
+ }
+ }
+ spprintf(&real_key, 0, "%s_%s", "HTTP", key);
+diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c
+index cc7102eabbc..01c4ee2d573 100644
+--- a/sapi/fpm/fpm/fpm_conf.c
++++ b/sapi/fpm/fpm/fpm_conf.c
+@@ -932,7 +932,7 @@ static int fpm_conf_process_all_pools(void)
+ }
+
+ for (i = 0; i < strlen(status); i++) {
+- if (!isalnum(status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.' && status[i] != '~') {
++ if (!isalnum((unsigned char)status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.' && status[i] != '~') {
+ zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.~'", wp->config->name, status);
+ return -1;
+ }
+@@ -955,7 +955,7 @@ static int fpm_conf_process_all_pools(void)
+ }
+
+ for (i = 0; i < strlen(ping); i++) {
+- if (!isalnum(ping[i]) && ping[i] != '/' && ping[i] != '-' && ping[i] != '_' && ping[i] != '.' && ping[i] != '~') {
++ if (!isalnum((unsigned char)ping[i]) && ping[i] != '/' && ping[i] != '-' && ping[i] != '_' && ping[i] != '.' && ping[i] != '~') {
+ zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must contain only the following characters '[alphanum]/_-.~'", wp->config->name, ping);
+ return -1;
+ }
+diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c
+index 2b3d83ad4be..3c0c3cafe02 100644
+--- a/sapi/litespeed/lsapi_main.c
++++ b/sapi/litespeed/lsapi_main.c
+@@ -1707,12 +1707,12 @@ PHP_FUNCTION(litespeed_response_headers)
+ len = p - h->header;
+ if (p && len > 0 && len < LSAPI_RESP_HTTP_HEADER_MAX) {
+ memmove( headerBuf, h->header, len );
+- while( len > 0 && (isspace( headerBuf[len-1])) ) {
++ while( len > 0 && (isspace((unsigned char)headerBuf[len - 1])) ) {
+ --len;
+ }
+ headerBuf[len] = 0;
+ if ( len ) {
+- while( isspace(*++p));
++ while(isspace((unsigned char)*++p));
+ add_assoc_string_ex(return_value, headerBuf, len, p);
+ }
+ }
+diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c
+index 09cd2e6bf9a..038e43137f2 100644
+--- a/sapi/litespeed/lsapilib.c
++++ b/sapi/litespeed/lsapilib.c
+@@ -2242,7 +2242,7 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
+
+ while(( pKey < pKeyEnd )&&( *p ))
+ {
+- char ch = toupper( *pKey );
++ char ch = toupper( (unsigned char)*pKey );
+ if ((ch != *p )||(( *p == '_' )&&( ch != '-')))
+ break;
+ ++p; ++pKey;
+@@ -2426,7 +2426,7 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
+ if ( ch == '-' )
+ *p++ = '_';
+ else
+- *p++ = toupper( ch );
++ *p++ = toupper( (unsigned char)ch );
+ }
+ *p = 0;
+ keyLen += 5;
+@@ -2671,7 +2671,7 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
+ if ( !pBind )
+ return -1;
+
+- while( isspace( *pBind ) )
++ while(isspace( (unsigned char)*pBind ) )
+ ++pBind;
+
+ strncpy(achAddr, pBind, 255);
+diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
+index 7e6a87fcc89..2b18949e8fd 100644
+--- a/sapi/phpdbg/phpdbg_cmd.c
++++ b/sapi/phpdbg/phpdbg_cmd.c
+@@ -766,9 +766,9 @@ PHPDBG_API char *phpdbg_read_input(const char *buffered) /* {{{ */
+ }
+ }
+
+- if (buffer && isspace(*buffer)) {
++ if (buffer && isspace((unsigned char)*buffer)) {
+ char *trimmed = buffer;
+- while (isspace(*trimmed))
++ while (isspace((unsigned char)*trimmed))
+ trimmed++;
+
+ trimmed = estrdup(trimmed);
+diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
+index 8ca6d83c78c..ebf36eae781 100644
+--- a/sapi/phpdbg/phpdbg_prompt.c
++++ b/sapi/phpdbg/phpdbg_prompt.c
+@@ -213,7 +213,7 @@ static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state) {
+
+ state->line++;
+
+- while (cmd_len > 0L && isspace(cmd[cmd_len-1])) {
++ while (cmd_len > 0L && isspace((unsigned char)cmd[cmd_len-1])) {
+ cmd_len--;
+ }
+
+diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c
+index f638d608905..04bc117ffb3 100644
+--- a/sapi/phpdbg/phpdbg_utils.c
++++ b/sapi/phpdbg/phpdbg_utils.c
+@@ -82,10 +82,10 @@ PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */
+ return 0;
+
+ for (; *str; str++) {
+- if (isspace(*str) || *str == '-') {
++ if (isspace((unsigned char)*str) || *str == '-') {
+ continue;
+ }
+- return isdigit(*str);
++ return isdigit((unsigned char)*str);
+ }
+ return 0;
+ } /* }}} */
+@@ -96,7 +96,7 @@ PHPDBG_API int phpdbg_is_empty(const char *str) /* {{{ */
+ return 1;
+
+ for (; *str; str++) {
+- if (isspace(*str)) {
++ if (isspace((unsigned char)*str)) {
+ continue;
+ }
+ return 0;
+@@ -199,12 +199,12 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{
+ const char *p = str;
+ char *new = NULL;
+
+- while (p && isspace(*p)) {
++ while (p && isspace((unsigned char)*p)) {
+ ++p;
+ --len;
+ }
+
+- while (*p && isspace(*(p + len -1))) {
++ while (*p && isspace((unsigned char)p[len - 1])) {
+ --len;
+ }
+
+diff --git a/win32/sendmail.c b/win32/sendmail.c
+index d4de4645d67..e08424bf058 100644
+--- a/win32/sendmail.c
++++ b/win32/sendmail.c
+@@ -57,7 +57,7 @@
+ efree(response); \
+ } \
+ }
+-#define SMTP_SKIP_SPACE(str) { while (isspace(*str)) { str++; } }
++#define SMTP_SKIP_SPACE(str) { while (isspace((unsigned char)*(str))) { (str)++; } }
+
+
+ char seps[] = " ,\t\n";
+@@ -725,7 +725,7 @@ static int PostHeader(char *RPath, const char *Subject, const char *mailTo, char
+ headers_lc_len = strlen(headers_lc);
+
+ for (i = 0; i < headers_lc_len; i++) {
+- headers_lc[i] = tolower(headers_lc[i]);
++ headers_lc[i] = tolower((unsigned char)headers_lc[i]);
+ }
+ }
+
+@@ -853,7 +853,7 @@ return 0;
+
+ /* Resolve the servers IP */
+ /*
+- if (!isdigit(PW32G(mail_host)[0])||!gethostbyname(PW32G(mail_host)))
++ if (!isdigit((unsigned char)PW32G(mail_host)[0])||!gethostbyname(PW32G(mail_host)))
+ {
+ return (FAILED_TO_RESOLVE_HOST);
+ }
+--
+2.54.0
+
+From 7dff10e9a31d469fcd436e10b06f8b2bf2758a68 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 7 May 2026 09:01:35 +0200
+Subject: [PATCH 10/10] NEWS from 8.2.31
+
+---
+ NEWS | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 9d420d24da6..c245d3e757e 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,5 +1,35 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
++
++Backported from 8.2.31
++
++- FPM:
++ . Fixed GHSA-7qg2-v9fj-4mwv (XSS within status endpoint). (CVE-2026-6735)
++ (Jakub Zelenka)
++
++- MBString:
++ . Fixed GHSA-wm6j-2649-pv75 (Null pointer dereference in
++ php_mb_check_encoding() via mb_ereg_search_init()). (CVE-2026-7259)
++ (vi3tL0u1s)
++
++- PDO_Firebird:
++ . Fixed GHSA-w476-322c-wpvm (SQL injection via NUL bytes in quoted strings).
++ (CVE-2025-14179) (SakiTakamachi)
++
++- SOAP:
++ . Fixed GHSA-85c2-q967-79q5 (Stale SOAP_GLOBAL(ref_map) pointer with Apache
++ Map). (CVE-2026-6722) (ilutov)
++ . Fixed GHSA-m33r-qmcv-p97q (Use-after-free after header parsing failure with
++ SOAP_PERSISTENCE_SESSION). (CVE-2026-7261) (ilutov)
++ . Fixed GHSA-hmxp-6pc4-f3vv (Broken Apache map value NULL check).
++ (CVE-2026-7262) (ilutov)
++
++- Standard:
++ . Fixed GHSA-96wq-48vp-hh57 (Signed integer overflow of char array offset).
++ (CVE-2026-7568) (TimWolla)
++ . Fixed GHSA-m8rr-4c36-8gq4 (Consistently pass unsigned char to ctype.h
++ functions). (CVE-2026-7258) (ilutov)
++
+ 18 Dec 2025, PHP 8.1.34
+
+ - Curl:
+--
+2.54.0
+
diff --git a/php-cve-2026-7259.patch b/php-cve-2026-7259.patch
new file mode 100644
index 0000000..13393af
--- /dev/null
+++ b/php-cve-2026-7259.patch
@@ -0,0 +1,66 @@
+From 785bcb5dd5980a4f3173ab0b80c70a5602bc9339 Mon Sep 17 00:00:00 2001
+From: vi3tL0u1s <luuviethoang.attt@gmail.com>
+Date: Sun, 3 May 2026 20:02:21 +0200
+Subject: [PATCH 05/10] GHSA-wm6j-2649-pv75: [mbstring] Fix null pointer
+ dereference in php_mb_check_encoding() via mb_ereg_search_init()
+
+Fixes GHSA-wm6j-2649-pv75
+Fixes CVE-2026-7259
+
+(cherry picked from commit 79a054eae016c56409432e69aebc8ca908a88838)
+---
+ Zend/tests/GHSA-wm6j-2649-pv75.phpt | 22 ++++++++++++++++++++++
+ ext/mbstring/php_mbregex.c | 7 ++++++-
+ 2 files changed, 28 insertions(+), 1 deletion(-)
+ create mode 100644 Zend/tests/GHSA-wm6j-2649-pv75.phpt
+
+diff --git a/Zend/tests/GHSA-wm6j-2649-pv75.phpt b/Zend/tests/GHSA-wm6j-2649-pv75.phpt
+new file mode 100644
+index 00000000000..7257af27cb8
+--- /dev/null
++++ b/Zend/tests/GHSA-wm6j-2649-pv75.phpt
+@@ -0,0 +1,22 @@
++--TEST--
++GHSA-wm6j-2649-pv75: Null pointer dereference in php_mb_check_encoding() via mb_ereg_search_init()
++--CREDITS--
++vi3tL0u1s
++--EXTENSIONS--
++mbstring
++--SKIPIF--
++<?php
++if (!function_exists('mb_regex_encoding')) die('skip No mbregex support');
++?>
++--FILE--
++<?php
++// iso-8859-11 is supported by Oniguruma but not by mbfl
++mb_regex_encoding('iso-8859-11');
++mb_ereg_search_init('x');
++?>
++--EXPECTF--
++Fatal error: Uncaught ValueError: mb_regex_encoding(): Argument #1 ($encoding) must be a valid encoding, "iso-8859-11" given in %s:%d
++Stack trace:
++#0 %s(%d): mb_regex_encoding('iso-8859-11')
++#1 {main}
++ thrown in %s on line %d
+diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c
+index 06f65f5c567..0734011f9fb 100644
+--- a/ext/mbstring/php_mbregex.c
++++ b/ext/mbstring/php_mbregex.c
+@@ -409,8 +409,13 @@ int php_mb_regex_set_mbctype(const char *encname)
+ if (mbctype == ONIG_ENCODING_UNDEF) {
+ return FAILURE;
+ }
++ const mbfl_encoding *mbfl_enc = mbfl_name2encoding(encname);
++ if (mbfl_enc == NULL) {
++ /* Encoding supported by Oniguruma but not by mbfl */
++ return FAILURE;
++ }
+ MBREX(current_mbctype) = mbctype;
+- MBREX(current_mbctype_mbfl_encoding) = mbfl_name2encoding(encname);
++ MBREX(current_mbctype_mbfl_encoding) = mbfl_enc;
+ return SUCCESS;
+ }
+ /* }}} */
+--
+2.54.0
+
diff --git a/php-cve-2026-7261.patch b/php-cve-2026-7261.patch
new file mode 100644
index 0000000..aa5c835
--- /dev/null
+++ b/php-cve-2026-7261.patch
@@ -0,0 +1,111 @@
+From 5dd8dd8493d49bb6fcd810a6e9d2ffb6fdc15714 Mon Sep 17 00:00:00 2001
+From: Ilija Tovilo <ilija.tovilo@me.com>
+Date: Sun, 3 May 2026 19:57:16 +0200
+Subject: [PATCH 02/10] GHSA-m33r-qmcv-p97q: [soap] Fix use-after-free after
+ header parsing failure with SOAP_PERSISTENCE_SESSION
+
+Fixes GHSA-m33r-qmcv-p97q
+Fixes CVE-2026-7261
+
+(cherry picked from commit db2a7f9348fd5dda5fd162061786a664c417bf5b)
+---
+ ext/soap/soap.c | 12 ++++-
+ ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt | 58 +++++++++++++++++++++++++
+ 2 files changed, 68 insertions(+), 2 deletions(-)
+ create mode 100644 ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt
+
+diff --git a/ext/soap/soap.c b/ext/soap/soap.c
+index 3bc713ca76b..bb8b664af58 100644
+--- a/ext/soap/soap.c
++++ b/ext/soap/soap.c
+@@ -1477,13 +1477,21 @@ PHP_METHOD(SoapServer, handle)
+ php_output_discard();
+ soap_server_fault_ex(function, &h->retval, h);
+ zend_string_release(fn_name);
+- if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
++ if (service->type == SOAP_CLASS && soap_obj) {
++ if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
++ zval_ptr_dtor(soap_obj);
++ }
++ }
+ goto fail;
+ } else if (EG(exception)) {
+ php_output_discard();
+ _soap_server_exception(service, function, ZEND_THIS);
+ zend_string_release(fn_name);
+- if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
++ if (service->type == SOAP_CLASS && soap_obj) {
++ if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
++ zval_ptr_dtor(soap_obj);
++ }
++ }
+ goto fail;
+ }
+ } else if (h->mustUnderstand) {
+diff --git a/ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt b/ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt
+new file mode 100644
+index 00000000000..bcf441ccd18
+--- /dev/null
++++ b/ext/soap/tests/GHSA-m33r-qmcv-p97q.phpt
+@@ -0,0 +1,58 @@
++--TEST--
++GHSA-m33r-qmcv-p97q: Use-after-free after header parsing failure with SOAP_PERSISTENCE_SESSION
++--CREDITS--
++Ilia Alshanetsky (iliaal)
++--EXTENSIONS--
++soap
++session
++--FILE--
++<?php
++
++class Handler {
++ public function return() {
++ return new SoapFault('Server', 'denied');
++ }
++ public function throw() {
++ throw new SoapFault('Server', 'denied');
++ }
++ public function hello() {
++ return 'ok';
++ }
++}
++
++session_start();
++
++$srv = new SoapServer(null, ['uri' => 'urn:a']);
++$srv->setClass(Handler::class);
++$srv->setPersistence(SOAP_PERSISTENCE_SESSION);
++
++$srv->handle(<<<XML
++<?xml version="1.0" encoding="UTF-8"?>
++<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:a">
++ <soap:Header>
++ <a:return/>
++ </soap:Header>
++ <soap:Body>
++ <a:hello/>
++ </soap:Body>
++</soap:Envelope>
++XML);
++
++$srv->handle(<<<XML
++<?xml version="1.0" encoding="UTF-8"?>
++<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="urn:a">
++ <soap:Header>
++ <a:throw/>
++ </soap:Header>
++ <soap:Body>
++ <a:hello/>
++ </soap:Body>
++</soap:Envelope>
++XML);
++
++?>
++--EXPECT--
++<?xml version="1.0" encoding="UTF-8"?>
++<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
++<?xml version="1.0" encoding="UTF-8"?>
++<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
+--
+2.54.0
+
diff --git a/php-cve-2026-7262.patch b/php-cve-2026-7262.patch
new file mode 100644
index 0000000..84623f2
--- /dev/null
+++ b/php-cve-2026-7262.patch
@@ -0,0 +1,77 @@
+From aed3e63e282235b32a07ca28cc20728eedfcfec3 Mon Sep 17 00:00:00 2001
+From: Ilija Tovilo <ilija.tovilo@me.com>
+Date: Sat, 25 Apr 2026 00:44:37 +0200
+Subject: [PATCH 03/10] GHSA-hmxp-6pc4-f3vv: [soap] Fix broken Apache map value
+ NULL check
+
+Fixes GHSA-hmxp-6pc4-f3vv
+Fixes CVE-2026-7262
+
+(cherry picked from commit 79551ab8b1a97760c739e372f9bc359619f3554d)
+---
+ ext/soap/php_encoding.c | 2 +-
+ ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt | 39 +++++++++++++++++++++++++
+ 2 files changed, 40 insertions(+), 1 deletion(-)
+ create mode 100644 ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt
+
+diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
+index bf394f7ea92..9bd6f50834e 100644
+--- a/ext/soap/php_encoding.c
++++ b/ext/soap/php_encoding.c
+@@ -2711,7 +2711,7 @@ static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data)
+ }
+
+ xmlValue = get_node(item->children, "value");
+- if (!xmlKey) {
++ if (!xmlValue) {
+ soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing value");
+ }
+
+diff --git a/ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt b/ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt
+new file mode 100644
+index 00000000000..e46ab2e4607
+--- /dev/null
++++ b/ext/soap/tests/GHSA-hmxp-6pc4-f3vv.phpt
+@@ -0,0 +1,39 @@
++--TEST--
++GHSA-hmxp-6pc4-f3vv: Null pointer dereference on missing Apache map value
++--CREDITS--
++Ilia Alshanetsky (iliaal)
++--EXTENSIONS--
++soap
++--FILE--
++<?php
++
++$request = <<<XML
++<?xml version="1.0" encoding="UTF-8"?>
++<soap:Envelope
++ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
++ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
++ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
++ xmlns:apache="http://xml.apache.org/xml-soap">
++
++ <soap:Body>
++ <test>
++ <map xsi:type="apache:Map">
++ <item><key>hello</key></item>
++ </map>
++ </test>
++ </soap:Body>
++</soap:Envelope>
++XML;
++
++$server = new SoapServer(null, [
++ 'uri' => 'urn:test',
++ 'typemap' => [['type_name' => 'anything']],
++]);
++$server->addFunction('test');
++function test($m) { return null; }
++$server->handle($request);
++
++?>
++--EXPECT--
++<?xml version="1.0" encoding="UTF-8"?>
++<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>SOAP-ERROR: Encoding: Can't decode apache map, missing value</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
+--
+2.54.0
+
diff --git a/php-cve-2026-7568.patch b/php-cve-2026-7568.patch
new file mode 100644
index 0000000..68c1de6
--- /dev/null
+++ b/php-cve-2026-7568.patch
@@ -0,0 +1,101 @@
+From e4fc187a011d91f26178f6dfbccdb07041b99153 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@tideways-gmbh.com>
+Date: Sun, 3 May 2026 20:02:57 +0200
+Subject: [PATCH 06/10] GHSA-96wq-48vp-hh57: [metaphone] Fix signed integer
+ overflow of char array offset
+
+Fixes GHSA-96wq-48vp-hh57
+Fixes CVE-2026-7568
+
+(cherry picked from commit 47def8ce1db1fdbffcfc1f5bb11877a0e22d4b32)
+---
+ ext/standard/metaphone.c | 6 +++---
+ ext/standard/tests/GHSA-96wq-48vp-hh57.phpt | 22 +++++++++++++++++++++
+ 2 files changed, 25 insertions(+), 3 deletions(-)
+ create mode 100644 ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
+
+diff --git a/ext/standard/metaphone.c b/ext/standard/metaphone.c
+index 2ba7a839c88..7affde44de1 100644
+--- a/ext/standard/metaphone.c
++++ b/ext/standard/metaphone.c
+@@ -117,10 +117,10 @@ static const char _codes[26] =
+
+ /* Allows us to safely look ahead an arbitrary # of letters */
+ /* I probably could have just used strlen... */
+-static char Lookahead(char *word, int how_far)
++static char Lookahead(char *word, size_t how_far)
+ {
+ char letter_ahead = '\0'; /* null by default */
+- int idx;
++ size_t idx;
+ for (idx = 0; word[idx] != '\0' && idx < how_far; idx++);
+ /* Edge forward in the string... */
+
+@@ -161,7 +161,7 @@ static char Lookahead(char *word, int how_far)
+ /* {{{ metaphone */
+ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonemes, zend_string **phoned_word, int traditional)
+ {
+- int w_idx = 0; /* point in the phonization we're at. */
++ size_t w_idx = 0; /* point in the phonization we're at. */
+ size_t p_idx = 0; /* end of the phoned phrase */
+ size_t max_buffer_len = 0; /* maximum length of the destination buffer */
+ ZEND_ASSERT(word != NULL);
+diff --git a/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
+new file mode 100644
+index 00000000000..79c6b656733
+--- /dev/null
++++ b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
+@@ -0,0 +1,22 @@
++--TEST--
++GHSA-96wq-48vp-hh57: signed integer overflow of char array offset
++--CREDITS--
++012git012
++--INI--
++memory_limit=3G
++--SKIPIF--
++<?php
++if (!getenv('RUN_RESOURCE_HEAVY_TESTS')) die('skip resource-heavy test');
++if (getenv('SKIP_SLOW_TESTS')) die('skip slow test');
++if (PHP_INT_SIZE != 8) echo 'skip 64-bit only';
++?>
++--FILE--
++<?php
++
++$str = str_repeat('0', 2 * (1024 ** 3) - 2) . 'AE';
++metaphone($str, 1);
++
++?>
++===DONE===
++--EXPECT--
++===DONE===
+--
+2.54.0
+
+From 101e93900888ef43d42ec0e33866bca3824f51a8 Mon Sep 17 00:00:00 2001
+From: Ilija Tovilo <ilija.tovilo@me.com>
+Date: Wed, 6 May 2026 16:33:44 +0200
+Subject: [PATCH 09/10] [skip ci] Adjust credits for GHSA-96wq-48vp-hh57.phpt
+
+As requested by the reporter.
+
+(cherry picked from commit fee84dd8c7699e4e7f9b2e864a393ee5a372f974)
+---
+ ext/standard/tests/GHSA-96wq-48vp-hh57.phpt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
+index 79c6b656733..cf9a40062f8 100644
+--- a/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
++++ b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt
+@@ -1,7 +1,7 @@
+ --TEST--
+ GHSA-96wq-48vp-hh57: signed integer overflow of char array offset
+ --CREDITS--
+-012git012
++Aleksey Solovev (Positive Technologies)
+ --INI--
+ memory_limit=3G
+ --SKIPIF--
+--
+2.54.0
+
diff --git a/php81.spec b/php81.spec
index 0c28af4..5ec5ad8 100644
--- a/php81.spec
+++ b/php81.spec
@@ -24,7 +24,7 @@
%global mysql_sock %(mysql_config --socket 2>/dev/null || echo /var/lib/mysql/mysql.sock)
-%global oraclever 23.9
+%global oraclever 23.26.1
%global oraclemax 24
%global oraclelib 23.1
%global oracledir 23
@@ -124,7 +124,7 @@
Summary: PHP scripting language for creating dynamic web sites
Name: php
Version: %{upver}%{?rcver:~%{rcver}}
-Release: 1%{?dist}
+Release: 2%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -187,6 +187,14 @@ Patch91: php-7.2.0-oci8conf.patch
# Upstream fixes (100+)
# Security fixes (200+)
+Patch200: php-cve-2026-14179.patch
+Patch201: php-cve-2026-6722.patch
+Patch202: php-cve-2026-7261.patch
+Patch203: php-cve-2026-7262.patch
+Patch204: php-cve-2026-6735.patch
+Patch205: php-cve-2026-7259.patch
+Patch206: php-cve-2026-7568.patch
+Patch207: php-cve-2026-7258.patch
# Fixes for tests (300+)
# Factory is droped from system tzdata
@@ -1205,6 +1213,14 @@ in pure PHP.
# upstream patches
# security patches
+%patch -P200 -p1 -b .cve14179
+%patch -P201 -p1 -b .cve6722
+%patch -P202 -p1 -b .cve7261
+%patch -P203 -p1 -b .cve7262
+%patch -P204 -p1 -b .cve6735
+%patch -P205 -p1 -b .cve7259
+%patch -P206 -p1 -b .cve7268
+%patch -P207 -p1 -b .cve7258
# Fixes for tests related to tzdata
%if %{with tzdata}
@@ -2037,6 +2053,19 @@ fi
%endif
+%posttrans common
+cat << EOF
+=====================================================================
+
+ WARNING : PHP 8.1 have reached its "End of Life" in
+ December 2025. Even, if this package includes some of
+ the important security fixes, backported from 8.2, the
+ UPGRADE to a maintained version is very strongly RECOMMENDED.
+
+=====================================================================
+EOF
+
+
%{!?_licensedir:%global license %%doc}
%files
@@ -2201,6 +2230,24 @@ fi
%changelog
+* Thu May 7 2026 Remi Collet <remi@remirepo.net> - 8.1.34-2
+- Fix XSS within status endpoint
+ CVE-2026-6735
+- Fix Null pointer dereference in php_mb_check_encoding() via mb_ereg_search_init()
+ CVE-2026-7259
+- Fix SQL injection via NUL bytes in quoted strings
+ CVE-2025-14179
+- Fix Stale SOAP_GLOBAL(ref_map) pointer with Apache Map
+ CVE-2026-6722
+- Fix Use-after-free after header parsing failure with SOAP_PERSISTENCE_SESSION
+ CVE-2026-7261
+- Fix Broken Apache map value NULL check
+ CVE-2026-7262
+- Fix Signed integer overflow of char array offset
+ CVE-2026-7568
+- Fix Consistently pass unsigned char to ctype.h functions
+ CVE-2026-7258
+
* Wed Dec 17 2025 Remi Collet <remi@remirepo.net> - 8.1.34-1
- Update to 8.1.34 - http://www.php.net/releases/8_1_34.php