From 003fc48e6297e1554b8dc649a98936c00483c44f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Jul 2026 12:53:27 +0100 Subject: [PATCH 1/2] zlib: Add test with invalid levels --- ext/zlib/tests/zlib_wrapper_level_errors.phpt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 ext/zlib/tests/zlib_wrapper_level_errors.phpt diff --git a/ext/zlib/tests/zlib_wrapper_level_errors.phpt b/ext/zlib/tests/zlib_wrapper_level_errors.phpt new file mode 100644 index 000000000000..cc586da568b1 --- /dev/null +++ b/ext/zlib/tests/zlib_wrapper_level_errors.phpt @@ -0,0 +1,45 @@ +--TEST-- +compress.zlib:// wrapper with invalid compression level +--EXTENSIONS-- +zlib +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +int(%d) + +Warning: Object of class stdClass could not be converted to int in %s on line %d +int(%d) +int(0) From 42638fa392bc053f7225c640acec7ce23d27b976 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Jul 2026 12:53:39 +0100 Subject: [PATCH 2/2] zlib: use new stream error API --- ext/zlib/tests/gzseek_variation6.phpt | 2 +- ext/zlib/tests/gzseek_variation7.phpt | 2 +- ext/zlib/tests/zlib_wrapper_level_errors.phpt | 3 +- ext/zlib/zlib_fopen_wrapper.c | 43 ++++++++++++------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/ext/zlib/tests/gzseek_variation6.phpt b/ext/zlib/tests/gzseek_variation6.phpt index 58994ada56a1..8a1a3500df52 100644 --- a/ext/zlib/tests/gzseek_variation6.phpt +++ b/ext/zlib/tests/gzseek_variation6.phpt @@ -26,7 +26,7 @@ move 40 bytes tell=int(40) move to the end -Warning: gzseek(): SEEK_END is not supported in %s on line %d +Warning: gzseek(): SEEK_END is not supported on this stream in %s on line %d int(-1) tell=int(40) eof=bool(false) diff --git a/ext/zlib/tests/gzseek_variation7.phpt b/ext/zlib/tests/gzseek_variation7.phpt index 01994514a25b..03c622a8a1e8 100644 --- a/ext/zlib/tests/gzseek_variation7.phpt +++ b/ext/zlib/tests/gzseek_variation7.phpt @@ -32,7 +32,7 @@ unlink($f); tell=int(23) move to the end of the file -Warning: gzseek(): SEEK_END is not supported in %s on line %d +Warning: gzseek(): SEEK_END is not supported on this stream in %s on line %d int(-1) tell=int(23) tell=int(47) diff --git a/ext/zlib/tests/zlib_wrapper_level_errors.phpt b/ext/zlib/tests/zlib_wrapper_level_errors.phpt index cc586da568b1..cdc4fff502e3 100644 --- a/ext/zlib/tests/zlib_wrapper_level_errors.phpt +++ b/ext/zlib/tests/zlib_wrapper_level_errors.phpt @@ -38,8 +38,9 @@ var_dump($size_oob); ?> --EXPECTF-- +Warning: fopen(): zlib "level" context option must be of type int, string given in %s on line %d int(%d) -Warning: Object of class stdClass could not be converted to int in %s on line %d +Warning: fopen(): zlib "level" context option must be of type int, stdClass given in %s on line %d int(%d) int(0) diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index aebf368a16ed..85a02e3389ad 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -31,11 +31,13 @@ struct php_gz_stream_data_t { static void php_gziop_report_errors(php_stream *stream, size_t count, const char *verb) { if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { - struct php_gz_stream_data_t *self = stream->abstract; + const struct php_gz_stream_data_t *self = stream->abstract; int error = 0; gzerror(self->gz_file, &error); if (error == Z_ERRNO) { - php_error_docref(NULL, E_NOTICE, "%s of %zu bytes failed with errno=%d %s", verb, count, errno, strerror(errno)); + php_stream_notice(stream, ReadFailed, + "%s of %zu bytes failed with errno=%d %s", + verb, count, errno, strerror(errno)); } } } @@ -98,12 +100,13 @@ static ssize_t php_gziop_write(php_stream *stream, const char *buf, size_t count static int php_gziop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs) { - struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; + const struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; - assert(self != NULL); + ZEND_ASSERT(self != NULL); if (whence == SEEK_END) { - php_error_docref(NULL, E_WARNING, "SEEK_END is not supported"); + php_stream_wrapper_warn(NULL, PHP_STREAM_CONTEXT(stream), REPORT_ERRORS, + SeekNotSupported, "SEEK_END is not supported on this stream"); return -1; } @@ -171,14 +174,12 @@ const php_stream_ops php_stream_gzio_ops = { php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) { - struct php_gz_stream_data_t *self; php_stream *stream = NULL, *innerstream = NULL; /* sanity check the stream: it can be either read-only or write-only */ if (strchr(mode, '+')) { - if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "Cannot open a zlib stream for reading and writing at the same time!"); - } + php_stream_wrapper_log_warn(wrapper, context, REPORT_ERRORS, ModeNotSupported, + "Cannot open a zlib stream for reading and writing at the same time!"); return NULL; } @@ -194,14 +195,24 @@ php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, const char *path, con php_socket_t fd; if (SUCCESS == php_stream_cast(innerstream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) { - self = emalloc(sizeof(*self)); + struct php_gz_stream_data_t *self = emalloc(sizeof(*self)); self->stream = innerstream; self->gz_file = gzdopen(dup(fd), mode); if (self->gz_file) { - zval *zlevel = context ? php_stream_context_get_option(context, "zlib", "level") : NULL; - if (zlevel && (Z_OK != gzsetparams(self->gz_file, zval_get_long(zlevel), Z_DEFAULT_STRATEGY))) { - php_error(E_WARNING, "failed setting compression level"); + const zval *zlevel = context ? php_stream_context_get_option(context, "zlib", "level") : NULL; + + if (zlevel) { + bool failed = true; + const zend_long level = zval_try_get_long(zlevel, &failed); + if (UNEXPECTED(failed)) { + /* TODO: keep options arg instead of REPORT_ERRORS? Fix _php_stream_open_wrapper_ex() to not clear report errors flag? */ + php_stream_wrapper_log_warn(wrapper, context, REPORT_ERRORS, InvalidParam, + "zlib \"level\" context option must be of type int, %s given", zend_zval_type_name(zlevel)); + } else if (Z_OK != gzsetparams(self->gz_file, level, Z_DEFAULT_STRATEGY)) { + php_stream_wrapper_log_warn(wrapper, context, REPORT_ERRORS, Generic, + "failed setting compression level"); + } } stream = php_stream_alloc_rel(&php_stream_gzio_ops, self, 0, mode); @@ -214,9 +225,9 @@ php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, const char *path, con } efree(self); - if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "gzopen failed"); - } + + php_stream_wrapper_log_warn(wrapper, context, options, OpenFailed, + "gzopen failed"); } php_stream_close(innerstream);