Commit f8c854e82fa for php.net
commit f8c854e82faec850981a4a65e6c64a822ec580af
Author: Gina Peter Banyard <girgias@php.net>
Date: Wed Aug 5 15:48:24 2026 +0100
zlib: deprecate passing objects as array
Implements RFCs:
- https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_options_parameter_of_deflate_init_and_inflate_init
- https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_as_parameters_to_the_zlibinflate_and_zlibdeflate_stream_filters
diff --git a/ext/zlib/tests/filter_broken_object_options.phpt b/ext/zlib/tests/filter_broken_object_options.phpt
index beb0fef9fb1..a43c85f3671 100644
--- a/ext/zlib/tests/filter_broken_object_options.phpt
+++ b/ext/zlib/tests/filter_broken_object_options.phpt
@@ -17,5 +17,8 @@ class Params {
fwrite($fp, "Hello world, hopefully not broken\n");
?>
---EXPECT--
+--EXPECTF--
+Deprecated: stream_filter_append(): Passing an object for filter parameters for zlib.deflate is deprecated, call get_object_vars() first instead in %s on line %d
+
+Deprecated: stream_filter_append(): Passing an object for filter parameters for zlib.inflate is deprecated, call get_object_vars() first instead in %s on line %d
Hello world, hopefully not broken
diff --git a/ext/zlib/tests/gh17745.phpt b/ext/zlib/tests/gh17745.phpt
index 64331269dcd..5e522ee9614 100644
--- a/ext/zlib/tests/gh17745.phpt
+++ b/ext/zlib/tests/gh17745.phpt
@@ -13,8 +13,11 @@ class Options {
}
var_dump(deflate_init(ZLIB_ENCODING_RAW, new Options));
?>
---EXPECT--
+--EXPECTF--
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
object(DeflateContext)#2 (0) {
}
+
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
object(DeflateContext)#3 (0) {
}
diff --git a/ext/zlib/tests/gh17745_inflate.phpt b/ext/zlib/tests/gh17745_inflate.phpt
new file mode 100644
index 00000000000..c87f0fbea9d
--- /dev/null
+++ b/ext/zlib/tests/gh17745_inflate.phpt
@@ -0,0 +1,23 @@
+--TEST--
+GH-17745 (zlib extension incorrectly handles object arguments)
+--EXTENSIONS--
+zlib
+--FILE--
+<?php
+$obj = new stdClass;
+$obj->level = 3;
+var_dump(inflate_init(ZLIB_ENCODING_RAW, $obj));
+
+class Options {
+ public int $level = 3;
+}
+var_dump(inflate_init(ZLIB_ENCODING_RAW, new Options));
+?>
+--EXPECTF--
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+object(InflateContext)#2 (0) {
+}
+
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+object(InflateContext)#3 (0) {
+}
diff --git a/ext/zlib/tests/gh22142.phpt b/ext/zlib/tests/gh22142.phpt
index 9bbb9332df3..481ffef342a 100644
--- a/ext/zlib/tests/gh22142.phpt
+++ b/ext/zlib/tests/gh22142.phpt
@@ -16,5 +16,6 @@ class Options {
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
TypeError: deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, null given
diff --git a/ext/zlib/tests/gh22142_inflate.phpt b/ext/zlib/tests/gh22142_inflate.phpt
new file mode 100644
index 00000000000..853099e4911
--- /dev/null
+++ b/ext/zlib/tests/gh22142_inflate.phpt
@@ -0,0 +1,21 @@
+--TEST--
+GH-22142 (Assertion failure in zendi_try_get_long() on IS_UNDEF)
+--EXTENSIONS--
+zlib
+--FILE--
+<?php
+
+class Options {
+ public int $window;
+}
+
+try {
+ inflate_init(ZLIB_ENCODING_DEFLATE, new Options());
+} catch (TypeError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECTF--
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+TypeError: inflate_init(): Argument #2 ($options) the value for option "window" must be of type int, null given
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 5b630d74c88..44ab23233ac 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -881,12 +881,24 @@ PHP_FUNCTION(inflate_init)
zend_long encoding, window = 15;
char *dict = NULL;
size_t dictlen = 0;
+ zval *options_zv = NULL;
HashTable *options = (HashTable *) &zend_empty_array;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|A", &encoding, &options_zv)) {
RETURN_THROWS();
}
+ if (options_zv) {
+ if (Z_TYPE_P(options_zv) == IS_OBJECT) {
+ php_error_docref(NULL, E_DEPRECATED,
+ "Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead");
+ if (UNEXPECTED(EG(exception))) {
+ RETURN_THROWS();
+ }
+ }
+ options = HASH_OF(options_zv);
+ }
+
if (!zlib_get_long_option(options, ZEND_STRL("window"), &window)) {
RETURN_THROWS();
}
@@ -1100,12 +1112,24 @@ PHP_FUNCTION(deflate_init)
zend_long encoding, level = -1, memory = 8, window = 15, strategy = Z_DEFAULT_STRATEGY;
char *dict = NULL;
size_t dictlen = 0;
+ zval *options_zv = NULL;
HashTable *options = (HashTable*)&zend_empty_array;
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|A", &encoding, &options_zv)) {
RETURN_THROWS();
}
+ if (options_zv) {
+ if (Z_TYPE_P(options_zv) == IS_OBJECT) {
+ php_error_docref(NULL, E_DEPRECATED,
+ "Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead");
+ if (UNEXPECTED(EG(exception))) {
+ RETURN_THROWS();
+ }
+ }
+ options = HASH_OF(options_zv);
+ }
+
if (!zlib_get_long_option(options, ZEND_STRL("level"), &level)) {
RETURN_THROWS();
}
diff --git a/ext/zlib/zlib_filter.c b/ext/zlib/zlib_filter.c
index 2d0e4fbb7fa..4e6c1a54c0f 100644
--- a/ext/zlib/zlib_filter.c
+++ b/ext/zlib/zlib_filter.c
@@ -361,6 +361,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
php_zlib_filter_data *data;
int status;
+ if (filterparams && Z_TYPE_P(filterparams) == IS_OBJECT) {
+ php_error_docref("filters.compression", E_DEPRECATED,
+ "Passing an object for filter parameters for %s is deprecated, call get_object_vars() first instead", filtername);
+ if (UNEXPECTED(EG(exception))) {
+ return NULL;
+ }
+ }
+
if (php_stream_filter_parse_write_seek_mode(filterparams, &write_seekable) == FAILURE) {
return NULL;
}
@@ -368,7 +376,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
/* Create this filter */
data = pecalloc(1, sizeof(php_zlib_filter_data), persistent);
if (!data) {
- php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
+ php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
return NULL;
}
@@ -380,14 +388,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
data->strm.avail_out = data->outbuf_len = data->inbuf_len = 0x8000;
data->strm.next_in = data->inbuf = (Bytef *) pemalloc(data->inbuf_len, persistent);
if (!data->inbuf) {
- php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
+ php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
pefree(data, persistent);
return NULL;
}
data->strm.avail_in = 0;
data->strm.next_out = data->outbuf = (Bytef *) pemalloc(data->outbuf_len, persistent);
if (!data->outbuf) {
- php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
+ php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
pefree(data->inbuf, persistent);
pefree(data, persistent);
return NULL;
@@ -407,7 +415,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
/* log-2 base of history window (9 - 15) */
zend_long tmp = zval_get_long(tmpzval);
if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 32) {
- php_error_docref(NULL, E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
+ php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
} else {
windowBits = tmp;
}
@@ -444,7 +452,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
/* Memory Level (1 - 9) */
tmp = zval_get_long(tmpzval);
if (tmp < 1 || tmp > MAX_MEM_LEVEL) {
- php_error_docref(NULL, E_WARNING, "Invalid parameter given for memory level (" ZEND_LONG_FMT ")", tmp);
+ php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for memory level (" ZEND_LONG_FMT ")", tmp);
} else {
memLevel = tmp;
}
@@ -454,7 +462,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
/* log-2 base of history window (9 - 15) */
tmp = zval_get_long(tmpzval);
if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 16) {
- php_error_docref(NULL, E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
+ php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
} else {
windowBits = tmp;
}
@@ -475,13 +483,13 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
factory_setlevel:
/* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */
if (tmp < -1 || tmp > 9) {
- php_error_docref(NULL, E_WARNING, "Invalid compression level specified. (" ZEND_LONG_FMT ")", tmp);
+ php_error_docref("filters.compression", E_WARNING, "Invalid compression level specified. (" ZEND_LONG_FMT ")", tmp);
} else {
level = tmp;
}
break;
default:
- php_error_docref(NULL, E_WARNING, "Invalid filter parameter, ignored");
+ php_error_docref("filters.compression", E_WARNING, "Invalid filter parameter, ignored");
}
}