Fix bug #77960 add compr. /encr. options for ZipArchive::addGlob and ZipArchive::addPattern

options parameter now accepts:
- comp_method
- comp_flags
- enc_method
- enc_password
This commit is contained in:
Remi Collet 2020-03-18 11:55:16 +01:00 committed by Remi Collet
parent bb43a3822e
commit 3b22e10535
2 changed files with 152 additions and 32 deletions

View file

@ -331,18 +331,60 @@ static int php_zip_add_file(ze_zip_object *obj, const char *filename, size_t fil
}
/* }}} */
static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
char **remove_path, size_t *remove_path_len,
char **add_path, size_t *add_path_len,
zend_long *flags
) /* {{{ */
typedef struct {
zend_long remove_all_path;
char *remove_path;
size_t remove_path_len;
char *add_path;
size_t add_path_len;
zip_flags_t flags;
zip_int32_t comp_method;
zip_uint32_t comp_flags;
#ifdef HAVE_ENCRYPTION
zip_int16_t enc_method;
char *enc_password;
#endif
} zip_options;
static int php_zip_parse_options(zval *options, zip_options *opts)
/* {{{ */
{
zval *option;
/* default values */
memset(opts, 0, sizeof(zip_options));
opts->flags = ZIP_FL_OVERWRITE;
opts->comp_method = -1; /* -1 to not change default */
#ifdef HAVE_ENCRYPTION
opts->enc_method = -1; /* -1 to not change default */
#endif
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_all_path", sizeof("remove_all_path") - 1)) != NULL) {
*remove_all_path = zval_get_long(option);
opts->remove_all_path = zval_get_long(option);
}
/* If I add more options, it would make sense to create a nice static struct and loop over it. */
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_method", sizeof("comp_method") - 1)) != NULL) {
opts->comp_method = zval_get_long(option);
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_flags", sizeof("comp_flags") - 1)) != NULL) {
opts->comp_flags = zval_get_long(option);
}
}
#ifdef HAVE_ENCRYPTION
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_method", sizeof("enc_method") - 1)) != NULL) {
opts->enc_method = zval_get_long(option);
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_password", sizeof("enc_password") - 1)) != NULL) {
if (Z_TYPE_P(option) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "enc_password option expected to be a string");
return -1;
}
opts->enc_password = Z_STRVAL_P(option);
}
}
#endif
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_path", sizeof("remove_path") - 1)) != NULL) {
if (Z_TYPE_P(option) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "remove_path option expected to be a string");
@ -359,8 +401,8 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
MAXPATHLEN - 1, Z_STRLEN_P(option));
return -1;
}
*remove_path_len = Z_STRLEN_P(option);
*remove_path = Z_STRVAL_P(option);
opts->remove_path_len = Z_STRLEN_P(option);
opts->remove_path = Z_STRVAL_P(option);
}
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "add_path", sizeof("add_path") - 1)) != NULL) {
@ -379,8 +421,8 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
MAXPATHLEN - 1, Z_STRLEN_P(option));
return -1;
}
*add_path_len = Z_STRLEN_P(option);
*add_path = Z_STRVAL_P(option);
opts->add_path_len = Z_STRLEN_P(option);
opts->add_path = Z_STRVAL_P(option);
}
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "flags", sizeof("flags") - 1)) != NULL) {
@ -388,7 +430,7 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
php_error_docref(NULL, E_WARNING, "flags option expected to be a integer");
return -1;
}
*flags = Z_LVAL_P(option);
opts->flags = Z_LVAL_P(option);
}
return 1;
@ -1652,13 +1694,10 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
{
zval *self = ZEND_THIS;
char *path = ".";
char *remove_path = NULL;
char *add_path = NULL;
size_t add_path_len, remove_path_len = 0, path_len = 1;
zend_long remove_all_path = 0;
size_t path_len = 1;
zend_long glob_flags = 0;
zend_long zip_flags = ZIP_FL_OVERWRITE;
zval *options = NULL;
zip_options opts;
int found;
zend_string *pattern;
@ -1679,8 +1718,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
php_error_docref(NULL, E_NOTICE, "Empty string as pattern");
RETURN_FALSE;
}
if (options && (php_zip_parse_options(options, &remove_all_path, &remove_path, &remove_path_len,
&add_path, &add_path_len, &zip_flags) < 0)) {
if (options && (php_zip_parse_options(options, &opts) < 0)) {
RETURN_FALSE;
}
@ -1693,6 +1731,9 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
if (found > 0) {
int i;
zval *zval_file;
ze_zip_object *ze_obj;
ze_obj = Z_ZIP_P(self);
for (i = 0; i < found; i++) {
char *file_stripped, *entry_name;
@ -1701,31 +1742,31 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
zend_string *basename = NULL;
if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
if (remove_all_path) {
if (opts.remove_all_path) {
basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
file_stripped = ZSTR_VAL(basename);
file_stripped_len = ZSTR_LEN(basename);
} else if (remove_path && strstr(Z_STRVAL_P(zval_file), remove_path) != NULL) {
if (IS_SLASH(Z_STRVAL_P(zval_file)[remove_path_len])) {
file_stripped = Z_STRVAL_P(zval_file) + remove_path_len + 1;
file_stripped_len = Z_STRLEN_P(zval_file) - remove_path_len - 1;
} else if (opts.remove_path && strstr(Z_STRVAL_P(zval_file), opts.remove_path) != NULL) {
if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
} else {
file_stripped = Z_STRVAL_P(zval_file) + remove_path_len;
file_stripped_len = Z_STRLEN_P(zval_file) - remove_path_len;
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
}
} else {
file_stripped = Z_STRVAL_P(zval_file);
file_stripped_len = Z_STRLEN_P(zval_file);
}
if (add_path) {
if ((add_path_len + file_stripped_len) > MAXPATHLEN) {
if (opts.add_path) {
if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) {
php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)",
MAXPATHLEN - 1, (add_path_len + file_stripped_len));
MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len));
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
snprintf(entry_name_buf, MAXPATHLEN, "%s%s", add_path, file_stripped);
snprintf(entry_name_buf, MAXPATHLEN, "%s%s", opts.add_path, file_stripped);
} else {
snprintf(entry_name_buf, MAXPATHLEN, "%s", file_stripped);
}
@ -1737,11 +1778,25 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
basename = NULL;
}
if (php_zip_add_file(Z_ZIP_P(self), Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
entry_name, entry_name_len, 0, 0, -1, zip_flags) < 0) {
if (php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
entry_name, entry_name_len, 0, 0, -1, opts.flags) < 0) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
if (opts.comp_method >= 0) {
if (zip_set_file_compression(ze_obj->za, ze_obj->last_id, opts.comp_method, opts.comp_flags)) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
}
#ifdef HAVE_ENCRYPTION
if (opts.enc_method >= 0) {
if (zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
}
#endif
}
}
}

View file

@ -0,0 +1,65 @@
--TEST--
ZipArchive::addGlob() method with more compression and encryption
--SKIPIF--
<?php
/* $Id$ */
if(!extension_loaded('zip')) die('skip');
if (!method_exists('ZipArchive', 'setEncryptionName')) die('skip encrytion not supported');
?>
--FILE--
<?php
$dirname = __DIR__ . '/';
include $dirname . 'utils.inc';
$dirname = __DIR__ . '/__tmp_oo_addglob2/';
$file = $dirname . 'test.zip';
@mkdir($dirname);
copy(__FILE__, $dirname . 'foo.txt');
copy(__FILE__, $dirname . 'bar.txt');
$zip = new ZipArchive();
if (!$zip->open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
exit('failed');
}
$options = [
'remove_all_path' => true,
];
if (!$zip->addGlob($dirname . 'foo.*', GLOB_BRACE, $options)) {
echo "failed 1\n";
}
$options = [
'remove_all_path' => true,
'comp_method' => ZipArchive::CM_STORE,
'comp_password' => 5,
'enc_method' => ZipArchive::EM_AES_256,
'enc_password' => 'secret',
];
if (!$zip->addGlob($dirname . 'bar.*', GLOB_BRACE, $options)) {
echo "failed 2\n";
}
if ($zip->status == ZIPARCHIVE::ER_OK) {
$zip->close();
$zip = new ZipArchive();
$zip->open($file);
for($i=0; $i<$zip->numFiles; $i++) {
$sb = $zip->statIndex($i);
echo "$i: " . $sb['name'] .
", comp=" . $sb['comp_method'] .
", enc=" . $sb['encryption_method'] . "\n";
}
} else {
echo "failed 3\n";
}
?>
--CLEAN--
<?php
$dirname = __DIR__ . '/';
include $dirname . 'utils.inc';
rmdir_rf(__DIR__ . '/__tmp_oo_addglob2/');
?>
--EXPECTF--
0: foo.txt, comp=8, enc=0
1: bar.txt, comp=0, enc=259