diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index d5f7b019eb9ea..ffb235ff8ae72 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1483,6 +1483,47 @@ PHP_METHOD(ZipArchive, open) } /* }}} */ +/* {{{ Create new read-only zip using given buffer */ +PHP_METHOD(ZipArchive, openBuffer) +{ + struct zip *intern; + zend_string *buffer; + zval *self = ZEND_THIS; + ze_zip_object *ze_obj; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &buffer) == FAILURE) { + RETURN_THROWS(); + } + + zip_error_t err; + zip_error_init(&err); + + zip_source_t * zip_source = zip_source_buffer_create(ZSTR_VAL(buffer), ZSTR_LEN(buffer), 0, &err); + + if (!zip_source) { + zend_throw_error(NULL, "Cannot open zip: %s", zip_error_strerror(&err)); + zip_error_fini(&err); + RETURN_THROWS(); + } + + ze_obj = Z_ZIP_P(self); + + intern = zip_open_from_source(zip_source, ZIP_RDONLY, &err); + if (!intern) { + zip_source_free(zip_source); + zend_throw_error(NULL, "Cannot open zip: %s", zip_error_strerror(&err)); + zip_error_fini(&err); + RETURN_THROWS(); + } + + zip_source_keep(zip_source); + zip_error_fini(&err); + + ze_obj->za = intern; + ze_obj->source = zip_source; +} +/* }}} */ + /* {{{ Set the password for the active archive */ PHP_METHOD(ZipArchive, setPassword) { @@ -1548,12 +1589,22 @@ PHP_METHOD(ZipArchive, close) ze_obj->err_sys = 0; } - /* clear cache as empty zip are not created but deleted */ - php_clear_stat_cache(1, ze_obj->filename, ze_obj->filename_len); + // if we have a filename, we need to free it + if (ze_obj->filename) { + /* clear cache as empty zip are not created but deleted */ + php_clear_stat_cache(1, ze_obj->filename, ze_obj->filename_len); + + efree(ze_obj->filename); + ze_obj->filename = NULL; + ze_obj->filename_len = 0; + } + + if (ze_obj->source) { + zip_source_close(ze_obj->source); + zip_source_free(ze_obj->source); + ze_obj->source = NULL; + } - efree(ze_obj->filename); - ze_obj->filename = NULL; - ze_obj->filename_len = 0; ze_obj->za = NULL; if (!err) { diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 01d6c3d10133e..903dc1336d445 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -68,6 +68,7 @@ typedef struct _ze_zip_read_rsrc { /* Extends zend object */ typedef struct _ze_zip_object { struct zip *za; + zip_source_t *source; char **buffers; HashTable *prop_handler; char *filename; diff --git a/ext/zip/php_zip.stub.php b/ext/zip/php_zip.stub.php index 3473d27bf2050..b5fbb9e4fc0bc 100644 --- a/ext/zip/php_zip.stub.php +++ b/ext/zip/php_zip.stub.php @@ -648,6 +648,8 @@ class ZipArchive implements Countable /** @tentative-return-type */ public function open(string $filename, int $flags = 0): bool|int {} + public function openBuffer(string $data): void {} + /** * @tentative-return-type */ diff --git a/ext/zip/php_zip_arginfo.h b/ext/zip/php_zip_arginfo.h index 2a24750142c95..240c11ad40a19 100644 --- a/ext/zip/php_zip_arginfo.h +++ b/ext/zip/php_zip_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 53e04d9b2c25cc8a0c9fe51914b5a47280834fb8 */ + * Stub hash: 06851d8732afa5357e6721776226fc641d2f8b34 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_open, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -45,6 +45,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_ZipArchive_open, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ZipArchive_openBuffer, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ZipArchive_setPassword, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -315,6 +319,7 @@ ZEND_FUNCTION(zip_entry_compressedsize); ZEND_FUNCTION(zip_entry_filesize); ZEND_FUNCTION(zip_entry_compressionmethod); ZEND_METHOD(ZipArchive, open); +ZEND_METHOD(ZipArchive, openBuffer); ZEND_METHOD(ZipArchive, setPassword); ZEND_METHOD(ZipArchive, close); ZEND_METHOD(ZipArchive, count); @@ -395,6 +400,7 @@ static const zend_function_entry ext_functions[] = { static const zend_function_entry class_ZipArchive_methods[] = { ZEND_ME(ZipArchive, open, arginfo_class_ZipArchive_open, ZEND_ACC_PUBLIC) + ZEND_ME(ZipArchive, openBuffer, arginfo_class_ZipArchive_openBuffer, ZEND_ACC_PUBLIC) ZEND_ME(ZipArchive, setPassword, arginfo_class_ZipArchive_setPassword, ZEND_ACC_PUBLIC) ZEND_ME(ZipArchive, close, arginfo_class_ZipArchive_close, ZEND_ACC_PUBLIC) ZEND_ME(ZipArchive, count, arginfo_class_ZipArchive_count, ZEND_ACC_PUBLIC) diff --git a/ext/zip/tests/ziparchive_openbuffer.phpt b/ext/zip/tests/ziparchive_openbuffer.phpt new file mode 100644 index 0000000000000..87b471d3bc5f2 --- /dev/null +++ b/ext/zip/tests/ziparchive_openbuffer.phpt @@ -0,0 +1,28 @@ +--TEST-- +ZipArchive::openBuffer() method +--EXTENSIONS-- +zip +--FILE-- +openBuffer(file_get_contents(__DIR__."/test_procedural.zip")); + +for ($i = 0; $i < $zip->numFiles; $i++) { + $stat = $zip->statIndex($i); + echo $stat['name'] . "\n"; +} + +// Zip is read-only, not allowed +var_dump($zip->addFromString("foobar/baz", "baz")); +var_dump($zip->addEmptyDir("blub")); + +var_dump($zip->close()); +?> +--EXPECTF-- +foo +bar +foobar/ +foobar/baz +bool(false) +bool(false) +bool(true)