]> granicus.if.org Git - php/commitdiff
Fix bug #77960 add compr. /encr. options for ZipArchive::addGlob and ZipArchive:...
authorRemi Collet <remi@remirepo.net>
Wed, 18 Mar 2020 10:55:16 +0000 (11:55 +0100)
committerRemi Collet <remi@php.net>
Wed, 18 Mar 2020 13:05:09 +0000 (14:05 +0100)
options parameter now accepts:
- comp_method
- comp_flags
- enc_method
- enc_password

ext/zip/php_zip.c
ext/zip/tests/oo_addglob2.phpt [new file with mode: 0644]

index a63bef6b7bf26da60f668f879e487d2523d840bc..f9a9a8d74f4e8d58ef9c613b4419f5aec79be834 100644 (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 ((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 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), "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
                        }
                }
        }
diff --git a/ext/zip/tests/oo_addglob2.phpt b/ext/zip/tests/oo_addglob2.phpt
new file mode 100644 (file)
index 0000000..35fe7f2
--- /dev/null
@@ -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