Commit 6d95a2238d5 for php.net
commit 6d95a2238d5f3305d2e5ae05c19288cbb6753596
Author: Jorg Adam Sowa <jorg.sowa@gmail.com>
Date: Mon Jan 26 17:02:15 2026 +0100
ext/standard: validate mode in array_filter() (#15647)
And add the missing ARRAY_FILTER_USE_VALUE for the default case.
diff --git a/NEWS b/NEWS
index 86a2174a986..bf00d8f663b 100644
--- a/NEWS
+++ b/NEWS
@@ -99,6 +99,8 @@ PHP NEWS
- Standard:
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)
+ . Invalid mode values now throw in array_filter() instead of being silently
+ defaulted to 0. (Jorg Sowa)
- Streams:
. Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream
diff --git a/UPGRADING b/UPGRADING
index 0d24268b787..fec4b15c102 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -23,6 +23,10 @@ PHP 8.6 UPGRADE NOTES
. Invalid values now throw in Phar::mungServer() instead of being silently
ignored.
+- Standard:
+ . Invalid mode values now throw in array_filter() instead of being silently
+ defaulted to 0.
+
========================================
2. New Features
========================================
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 893e07dd8f9..f8dd7d891dd 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -6453,7 +6453,7 @@ PHP_FUNCTION(array_filter)
zval args[2];
zval retval;
bool have_callback = 0;
- zend_long use_type = 0;
+ zend_long use_type = ARRAY_FILTER_USE_VALUE;
zend_string *string_key;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fci_cache;
@@ -6466,6 +6466,16 @@ PHP_FUNCTION(array_filter)
Z_PARAM_LONG(use_type)
ZEND_PARSE_PARAMETERS_END();
+ switch (use_type) {
+ case ARRAY_FILTER_USE_VALUE:
+ case ARRAY_FILTER_USE_BOTH:
+ case ARRAY_FILTER_USE_KEY:
+ break;
+ default:
+ zend_argument_value_error(3, "must be one of ARRAY_FILTER_USE_VALUE, ARRAY_FILTER_USE_KEY, or ARRAY_FILTER_USE_BOTH");
+ RETURN_THROWS();
+ }
+
if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
RETVAL_EMPTY_ARRAY();
return;
@@ -6486,7 +6496,7 @@ PHP_FUNCTION(array_filter)
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) {
if (have_callback) {
- if (use_type) {
+ if (use_type != ARRAY_FILTER_USE_VALUE) {
/* Set up the key */
if (!string_key) {
ZVAL_LONG(key, num_key);
diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php
index e27dca069c5..4ad26063a67 100644
--- a/ext/standard/basic_functions.stub.php
+++ b/ext/standard/basic_functions.stub.php
@@ -109,6 +109,11 @@
*/
const COUNT_RECURSIVE = UNKNOWN;
+/**
+ * @var int
+ * @cvalue ARRAY_FILTER_USE_VALUE
+ */
+const ARRAY_FILTER_USE_VALUE = UNKNOWN;
/**
* @var int
* @cvalue ARRAY_FILTER_USE_BOTH
diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h
index 9f5d89991da..2a1aa634fcd 100644
Binary files a/ext/standard/basic_functions_arginfo.h and b/ext/standard/basic_functions_arginfo.h differ
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index 2a35af60380..2205082e91d 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -59,6 +59,7 @@ PHPAPI bool php_array_pick_keys(php_random_algo_with_state engine, zval *input,
#define PHP_COUNT_NORMAL 0
#define PHP_COUNT_RECURSIVE 1
+#define ARRAY_FILTER_USE_VALUE 0
#define ARRAY_FILTER_USE_BOTH 1
#define ARRAY_FILTER_USE_KEY 2
diff --git a/ext/standard/tests/array/array_filter_invalid_mode.phpt b/ext/standard/tests/array/array_filter_invalid_mode.phpt
new file mode 100644
index 00000000000..b312bcfe5a2
--- /dev/null
+++ b/ext/standard/tests/array/array_filter_invalid_mode.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Test array_filter() function : usage variations - mode exception
+--FILE--
+<?php
+
+try {
+ var_dump(array_filter([], mode: 999));
+} catch (Throwable $e) {
+ echo $e::class . ': '.$e->getMessage(), "\n";
+}
+
+echo "Done"
+?>
+--EXPECT--
+ValueError: array_filter(): Argument #3 ($mode) must be one of ARRAY_FILTER_USE_VALUE, ARRAY_FILTER_USE_KEY, or ARRAY_FILTER_USE_BOTH
+Done