Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions ext/zlib/tests/zlib_wrapper_level_errors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
compress.zlib:// wrapper with invalid compression level
--EXTENSIONS--
zlib
--SKIPIF--
<?php
in_array('compress.zlib', stream_get_wrappers()) || die('skip No zlib wrapper');
?>
--FILE--
<?php declare(strict_types=1);

$filename = tempnam(sys_get_temp_dir(), "php-zlib-test-wrapper-level-error");
$thisfile = file_get_contents(__FILE__);

function write_at_level(mixed $level) {
global $filename, $thisfile;

$ctx = stream_context_create();
stream_context_set_option($ctx, 'zlib', 'level', $level);
$fp = fopen("compress.zlib://$filename", 'w', false, $ctx);
for ($i = 0; $i < 10; ++$i) {
fwrite($fp, $thisfile);
}
fclose($fp);
$size = filesize($filename);
unlink($filename);
return $size;
}

$size_string_type = write_at_level("not a number");
var_dump($size_string_type);

$size_array_type = write_at_level(new stdClass());
var_dump($size_array_type);

$size_oob = write_at_level(10000);
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: fopen(): zlib "level" context option must be of type int, stdClass given in %s on line %d
int(%d)
int(0)
42 changes: 26 additions & 16 deletions ext/zlib/zlib_fopen_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
Expand Down Expand Up @@ -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");
return -1;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -194,14 +195,23 @@ 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)) {
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");
}
Comment thread
Girgias marked this conversation as resolved.
}

stream = php_stream_alloc_rel(&php_stream_gzio_ops, self, 0, mode);
Expand All @@ -214,9 +224,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);
Expand Down
Loading