Skip to content

Commit 3b22e10

Browse files
committed
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
1 parent bb43a38 commit 3b22e10

File tree

2 files changed

+152
-32
lines changed

2 files changed

+152
-32
lines changed

ext/zip/php_zip.c

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -331,18 +331,60 @@ static int php_zip_add_file(ze_zip_object *obj, const char *filename, size_t fil
331331
}
332332
/* }}} */
333333

334-
static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
335-
char **remove_path, size_t *remove_path_len,
336-
char **add_path, size_t *add_path_len,
337-
zend_long *flags
338-
) /* {{{ */
334+
typedef struct {
335+
zend_long remove_all_path;
336+
char *remove_path;
337+
size_t remove_path_len;
338+
char *add_path;
339+
size_t add_path_len;
340+
zip_flags_t flags;
341+
zip_int32_t comp_method;
342+
zip_uint32_t comp_flags;
343+
#ifdef HAVE_ENCRYPTION
344+
zip_int16_t enc_method;
345+
char *enc_password;
346+
#endif
347+
} zip_options;
348+
349+
static int php_zip_parse_options(zval *options, zip_options *opts)
350+
/* {{{ */
339351
{
340352
zval *option;
353+
354+
/* default values */
355+
memset(opts, 0, sizeof(zip_options));
356+
opts->flags = ZIP_FL_OVERWRITE;
357+
opts->comp_method = -1; /* -1 to not change default */
358+
#ifdef HAVE_ENCRYPTION
359+
opts->enc_method = -1; /* -1 to not change default */
360+
#endif
361+
341362
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_all_path", sizeof("remove_all_path") - 1)) != NULL) {
342-
*remove_all_path = zval_get_long(option);
363+
opts->remove_all_path = zval_get_long(option);
364+
}
365+
366+
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_method", sizeof("comp_method") - 1)) != NULL) {
367+
opts->comp_method = zval_get_long(option);
368+
369+
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_flags", sizeof("comp_flags") - 1)) != NULL) {
370+
opts->comp_flags = zval_get_long(option);
371+
}
372+
}
373+
374+
#ifdef HAVE_ENCRYPTION
375+
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_method", sizeof("enc_method") - 1)) != NULL) {
376+
opts->enc_method = zval_get_long(option);
377+
378+
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_password", sizeof("enc_password") - 1)) != NULL) {
379+
if (Z_TYPE_P(option) != IS_STRING) {
380+
php_error_docref(NULL, E_WARNING, "enc_password option expected to be a string");
381+
return -1;
382+
}
383+
opts->enc_password = Z_STRVAL_P(option);
384+
}
343385
}
386+
#endif
344387

345-
/* If I add more options, it would make sense to create a nice static struct and loop over it. */
346388
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_path", sizeof("remove_path") - 1)) != NULL) {
347389
if (Z_TYPE_P(option) != IS_STRING) {
348390
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,
359401
MAXPATHLEN - 1, Z_STRLEN_P(option));
360402
return -1;
361403
}
362-
*remove_path_len = Z_STRLEN_P(option);
363-
*remove_path = Z_STRVAL_P(option);
404+
opts->remove_path_len = Z_STRLEN_P(option);
405+
opts->remove_path = Z_STRVAL_P(option);
364406
}
365407

366408
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "add_path", sizeof("add_path") - 1)) != NULL) {
@@ -379,16 +421,16 @@ static int php_zip_parse_options(zval *options, zend_long *remove_all_path,
379421
MAXPATHLEN - 1, Z_STRLEN_P(option));
380422
return -1;
381423
}
382-
*add_path_len = Z_STRLEN_P(option);
383-
*add_path = Z_STRVAL_P(option);
424+
opts->add_path_len = Z_STRLEN_P(option);
425+
opts->add_path = Z_STRVAL_P(option);
384426
}
385427

386428
if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "flags", sizeof("flags") - 1)) != NULL) {
387429
if (Z_TYPE_P(option) != IS_LONG) {
388430
php_error_docref(NULL, E_WARNING, "flags option expected to be a integer");
389431
return -1;
390432
}
391-
*flags = Z_LVAL_P(option);
433+
opts->flags = Z_LVAL_P(option);
392434
}
393435

394436
return 1;
@@ -1652,13 +1694,10 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
16521694
{
16531695
zval *self = ZEND_THIS;
16541696
char *path = ".";
1655-
char *remove_path = NULL;
1656-
char *add_path = NULL;
1657-
size_t add_path_len, remove_path_len = 0, path_len = 1;
1658-
zend_long remove_all_path = 0;
1697+
size_t path_len = 1;
16591698
zend_long glob_flags = 0;
1660-
zend_long zip_flags = ZIP_FL_OVERWRITE;
16611699
zval *options = NULL;
1700+
zip_options opts;
16621701
int found;
16631702
zend_string *pattern;
16641703

@@ -1679,8 +1718,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
16791718
php_error_docref(NULL, E_NOTICE, "Empty string as pattern");
16801719
RETURN_FALSE;
16811720
}
1682-
if (options && (php_zip_parse_options(options, &remove_all_path, &remove_path, &remove_path_len,
1683-
&add_path, &add_path_len, &zip_flags) < 0)) {
1721+
if (options && (php_zip_parse_options(options, &opts) < 0)) {
16841722
RETURN_FALSE;
16851723
}
16861724

@@ -1693,6 +1731,9 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
16931731
if (found > 0) {
16941732
int i;
16951733
zval *zval_file;
1734+
ze_zip_object *ze_obj;
1735+
1736+
ze_obj = Z_ZIP_P(self);
16961737

16971738
for (i = 0; i < found; i++) {
16981739
char *file_stripped, *entry_name;
@@ -1701,31 +1742,31 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
17011742
zend_string *basename = NULL;
17021743

17031744
if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
1704-
if (remove_all_path) {
1745+
if (opts.remove_all_path) {
17051746
basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
17061747
file_stripped = ZSTR_VAL(basename);
17071748
file_stripped_len = ZSTR_LEN(basename);
1708-
} else if (remove_path && strstr(Z_STRVAL_P(zval_file), remove_path) != NULL) {
1709-
if (IS_SLASH(Z_STRVAL_P(zval_file)[remove_path_len])) {
1710-
file_stripped = Z_STRVAL_P(zval_file) + remove_path_len + 1;
1711-
file_stripped_len = Z_STRLEN_P(zval_file) - remove_path_len - 1;
1749+
} else if (opts.remove_path && strstr(Z_STRVAL_P(zval_file), opts.remove_path) != NULL) {
1750+
if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
1751+
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
1752+
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
17121753
} else {
1713-
file_stripped = Z_STRVAL_P(zval_file) + remove_path_len;
1714-
file_stripped_len = Z_STRLEN_P(zval_file) - remove_path_len;
1754+
file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
1755+
file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
17151756
}
17161757
} else {
17171758
file_stripped = Z_STRVAL_P(zval_file);
17181759
file_stripped_len = Z_STRLEN_P(zval_file);
17191760
}
17201761

1721-
if (add_path) {
1722-
if ((add_path_len + file_stripped_len) > MAXPATHLEN) {
1762+
if (opts.add_path) {
1763+
if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) {
17231764
php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)",
1724-
MAXPATHLEN - 1, (add_path_len + file_stripped_len));
1765+
MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len));
17251766
zend_array_destroy(Z_ARR_P(return_value));
17261767
RETURN_FALSE;
17271768
}
1728-
snprintf(entry_name_buf, MAXPATHLEN, "%s%s", add_path, file_stripped);
1769+
snprintf(entry_name_buf, MAXPATHLEN, "%s%s", opts.add_path, file_stripped);
17291770
} else {
17301771
snprintf(entry_name_buf, MAXPATHLEN, "%s", file_stripped);
17311772
}
@@ -1737,11 +1778,25 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
17371778
basename = NULL;
17381779
}
17391780

1740-
if (php_zip_add_file(Z_ZIP_P(self), Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
1741-
entry_name, entry_name_len, 0, 0, -1, zip_flags) < 0) {
1781+
if (php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
1782+
entry_name, entry_name_len, 0, 0, -1, opts.flags) < 0) {
17421783
zend_array_destroy(Z_ARR_P(return_value));
17431784
RETURN_FALSE;
17441785
}
1786+
if (opts.comp_method >= 0) {
1787+
if (zip_set_file_compression(ze_obj->za, ze_obj->last_id, opts.comp_method, opts.comp_flags)) {
1788+
zend_array_destroy(Z_ARR_P(return_value));
1789+
RETURN_FALSE;
1790+
}
1791+
}
1792+
#ifdef HAVE_ENCRYPTION
1793+
if (opts.enc_method >= 0) {
1794+
if (zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) {
1795+
zend_array_destroy(Z_ARR_P(return_value));
1796+
RETURN_FALSE;
1797+
}
1798+
}
1799+
#endif
17451800
}
17461801
}
17471802
}

ext/zip/tests/oo_addglob2.phpt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
ZipArchive::addGlob() method with more compression and encryption
3+
--SKIPIF--
4+
<?php
5+
/* $Id$ */
6+
if(!extension_loaded('zip')) die('skip');
7+
if (!method_exists('ZipArchive', 'setEncryptionName')) die('skip encrytion not supported');
8+
?>
9+
--FILE--
10+
<?php
11+
$dirname = __DIR__ . '/';
12+
include $dirname . 'utils.inc';
13+
14+
$dirname = __DIR__ . '/__tmp_oo_addglob2/';
15+
$file = $dirname . 'test.zip';
16+
17+
@mkdir($dirname);
18+
copy(__FILE__, $dirname . 'foo.txt');
19+
copy(__FILE__, $dirname . 'bar.txt');
20+
21+
$zip = new ZipArchive();
22+
if (!$zip->open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
23+
exit('failed');
24+
}
25+
$options = [
26+
'remove_all_path' => true,
27+
];
28+
if (!$zip->addGlob($dirname . 'foo.*', GLOB_BRACE, $options)) {
29+
echo "failed 1\n";
30+
}
31+
32+
$options = [
33+
'remove_all_path' => true,
34+
'comp_method' => ZipArchive::CM_STORE,
35+
'comp_password' => 5,
36+
'enc_method' => ZipArchive::EM_AES_256,
37+
'enc_password' => 'secret',
38+
];
39+
if (!$zip->addGlob($dirname . 'bar.*', GLOB_BRACE, $options)) {
40+
echo "failed 2\n";
41+
}
42+
if ($zip->status == ZIPARCHIVE::ER_OK) {
43+
$zip->close();
44+
45+
$zip = new ZipArchive();
46+
$zip->open($file);
47+
for($i=0; $i<$zip->numFiles; $i++) {
48+
$sb = $zip->statIndex($i);
49+
echo "$i: " . $sb['name'] .
50+
", comp=" . $sb['comp_method'] .
51+
", enc=" . $sb['encryption_method'] . "\n";
52+
}
53+
} else {
54+
echo "failed 3\n";
55+
}
56+
?>
57+
--CLEAN--
58+
<?php
59+
$dirname = __DIR__ . '/';
60+
include $dirname . 'utils.inc';
61+
rmdir_rf(__DIR__ . '/__tmp_oo_addglob2/');
62+
?>
63+
--EXPECTF--
64+
0: foo.txt, comp=8, enc=0
65+
1: bar.txt, comp=0, enc=259

0 commit comments

Comments
 (0)