1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Piere-Alain Joye <pierre@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_ini.h"
24 #include "ext/standard/info.h"
25 #include "ext/standard/file.h"
26 #include "ext/standard/php_string.h"
27 #include "ext/pcre/php_pcre.h"
28 #include "ext/standard/php_filestat.h"
29 #include "zend_interfaces.h"
30 #include "php_zip.h"
31 #include "php_zip_arginfo.h"
32
33 #ifdef HAVE_GLOB
34 #ifndef PHP_WIN32
35 #include <glob.h>
36 #else
37 #include "win32/glob.h"
38 #endif
39 #endif
40
41 /* {{{ Resource le */
42 static int le_zip_dir;
43 #define le_zip_dir_name "Zip Directory"
44 static int le_zip_entry;
45 #define le_zip_entry_name "Zip Entry"
46 /* }}} */
47
48 /* {{{ PHP_ZIP_STAT_INDEX(za, index, flags, sb) */
49 #define PHP_ZIP_STAT_INDEX(za, index, flags, sb) \
50 if (zip_stat_index(za, index, flags, &sb) != 0) { \
51 RETURN_FALSE; \
52 }
53 /* }}} */
54
55 /* {{{ PHP_ZIP_STAT_PATH(za, path, path_len, flags, sb)
56 This is always used for the first argument*/
57 #define PHP_ZIP_STAT_PATH(za, path, path_len, flags, sb) \
58 if (path_len == 0) { \
59 zend_argument_value_error(1, "cannot be empty"); \
60 RETURN_THROWS(); \
61 } \
62 if (zip_stat(za, path, flags, &sb) != 0) { \
63 RETURN_FALSE; \
64 }
65 /* }}} */
66
67 /* {{{ PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) */
68 #define PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) \
69 if (comment_len == 0) { \
70 /* Passing NULL remove the existing comment */ \
71 if (zip_file_set_comment(za, index, NULL, 0, 0) < 0) { \
72 RETURN_FALSE; \
73 } \
74 } else if (zip_file_set_comment(za, index, comment, comment_len, 0) < 0) { \
75 RETURN_FALSE; \
76 } \
77 RETURN_TRUE;
78 /* }}} */
79
80 # define add_ascii_assoc_string add_assoc_string
81 # define add_ascii_assoc_long add_assoc_long
82
83 /* Flatten a path by making a relative path (to .)*/
php_zip_make_relative_path(char * path,size_t path_len)84 static char * php_zip_make_relative_path(char *path, size_t path_len) /* {{{ */
85 {
86 char *path_begin = path;
87 size_t i;
88
89 if (path_len < 1 || path == NULL) {
90 return NULL;
91 }
92
93 if (IS_ABSOLUTE_PATH(path, path_len)) {
94 return path + COPY_WHEN_ABSOLUTE(path) + 1;
95 }
96
97 i = path_len;
98
99 while (1) {
100 while (i > 0 && !IS_SLASH(path[i])) {
101 i--;
102 }
103
104 if (!i) {
105 return path;
106 }
107
108 if (i >= 2 && path[i -1] == '.') {
109 /* i is the position of ., add 1 for / */
110 path_begin = path + i + 1;
111 break;
112 }
113 i--;
114 }
115
116 return path_begin;
117 }
118 /* }}} */
119
120 # define CWD_STATE_ALLOC(l) emalloc(l)
121 # define CWD_STATE_FREE(s) efree(s)
122
123 /* {{{ php_zip_extract_file */
php_zip_extract_file(struct zip * za,char * dest,char * file,size_t file_len)124 static int php_zip_extract_file(struct zip * za, char *dest, char *file, size_t file_len)
125 {
126 php_stream_statbuf ssb;
127 struct zip_file *zf;
128 struct zip_stat sb;
129 char b[8192];
130 int n, ret;
131 php_stream *stream;
132 char *fullpath;
133 char *file_dirname_fullpath;
134 char file_dirname[MAXPATHLEN];
135 size_t dir_len, len;
136 int is_dir_only = 0;
137 char *path_cleaned;
138 size_t path_cleaned_len;
139 cwd_state new_state;
140 zend_string *file_basename;
141
142 new_state.cwd = CWD_STATE_ALLOC(1);
143 new_state.cwd[0] = '\0';
144 new_state.cwd_length = 0;
145
146 /* Clean/normlize the path and then transform any path (absolute or relative)
147 to a path relative to cwd (../../mydir/foo.txt > mydir/foo.txt)
148 */
149 virtual_file_ex(&new_state, file, NULL, CWD_EXPAND);
150 path_cleaned = php_zip_make_relative_path(new_state.cwd, new_state.cwd_length);
151 if(!path_cleaned) {
152 CWD_STATE_FREE(new_state.cwd);
153 return 0;
154 }
155 path_cleaned_len = strlen(path_cleaned);
156
157 if (path_cleaned_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) {
158 CWD_STATE_FREE(new_state.cwd);
159 return 0;
160 }
161
162 /* it is a directory only, see #40228 */
163 if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) {
164 len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, path_cleaned);
165 is_dir_only = 1;
166 } else {
167 memcpy(file_dirname, path_cleaned, path_cleaned_len);
168 dir_len = php_dirname(file_dirname, path_cleaned_len);
169
170 if (!dir_len || (dir_len == 1 && file_dirname[0] == '.')) {
171 len = spprintf(&file_dirname_fullpath, 0, "%s", dest);
172 } else {
173 len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file_dirname);
174 }
175
176 file_basename = php_basename(path_cleaned, path_cleaned_len, NULL, 0);
177
178 if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname_fullpath)) {
179 efree(file_dirname_fullpath);
180 zend_string_release_ex(file_basename, 0);
181 CWD_STATE_FREE(new_state.cwd);
182 return 0;
183 }
184 }
185
186 /* let see if the path already exists */
187 if (php_stream_stat_path_ex(file_dirname_fullpath, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL) < 0) {
188 ret = php_stream_mkdir(file_dirname_fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE|REPORT_ERRORS, NULL);
189 if (!ret) {
190 efree(file_dirname_fullpath);
191 if (!is_dir_only) {
192 zend_string_release_ex(file_basename, 0);
193 }
194 CWD_STATE_FREE(new_state.cwd);
195 return 0;
196 }
197 }
198
199 /* it is a standalone directory, job done */
200 if (is_dir_only) {
201 efree(file_dirname_fullpath);
202 CWD_STATE_FREE(new_state.cwd);
203 return 1;
204 }
205
206 len = spprintf(&fullpath, 0, "%s/%s", file_dirname_fullpath, ZSTR_VAL(file_basename));
207 if (!len) {
208 efree(file_dirname_fullpath);
209 zend_string_release_ex(file_basename, 0);
210 CWD_STATE_FREE(new_state.cwd);
211 return 0;
212 } else if (len > MAXPATHLEN) {
213 php_error_docref(NULL, E_WARNING, "Full extraction path exceed MAXPATHLEN (%i)", MAXPATHLEN);
214 efree(file_dirname_fullpath);
215 zend_string_release_ex(file_basename, 0);
216 CWD_STATE_FREE(new_state.cwd);
217 return 0;
218 }
219
220 /* check again the full path, not sure if it
221 * is required, does a file can have a different
222 * safemode status as its parent folder?
223 */
224 if (ZIP_OPENBASEDIR_CHECKPATH(fullpath)) {
225 efree(fullpath);
226 efree(file_dirname_fullpath);
227 zend_string_release_ex(file_basename, 0);
228 CWD_STATE_FREE(new_state.cwd);
229 return 0;
230 }
231
232 zf = zip_fopen(za, file, 0);
233 if (zf == NULL) {
234 n = -1;
235 goto done;
236 }
237
238 stream = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS, NULL);
239
240 if (stream == NULL) {
241 n = -1;
242 zip_fclose(zf);
243 goto done;
244 }
245
246 n = 0;
247
248 while ((n=zip_fread(zf, b, sizeof(b))) > 0) {
249 php_stream_write(stream, b, n);
250 }
251
252 if (stream->wrapper->wops->stream_metadata) {
253 struct utimbuf ut;
254
255 ut.modtime = ut.actime = sb.mtime;
256 stream->wrapper->wops->stream_metadata(stream->wrapper, fullpath, PHP_STREAM_META_TOUCH, &ut, NULL);
257 }
258
259 php_stream_close(stream);
260 n = zip_fclose(zf);
261
262 done:
263 efree(fullpath);
264 zend_string_release_ex(file_basename, 0);
265 efree(file_dirname_fullpath);
266 CWD_STATE_FREE(new_state.cwd);
267
268 if (n<0) {
269 return 0;
270 } else {
271 return 1;
272 }
273 }
274 /* }}} */
275
php_zip_add_file(ze_zip_object * obj,const char * filename,size_t filename_len,char * entry_name,size_t entry_name_len,zip_uint64_t offset_start,zip_uint64_t offset_len,zend_long replace,zip_flags_t flags)276 static int php_zip_add_file(ze_zip_object *obj, const char *filename, size_t filename_len,
277 char *entry_name, size_t entry_name_len, /* unused if replace >= 0 */
278 zip_uint64_t offset_start, zip_uint64_t offset_len,
279 zend_long replace, /* index to replace, add new file if < 0 */
280 zip_flags_t flags
281 ) /* {{{ */
282 {
283 struct zip_source *zs;
284 char resolved_path[MAXPATHLEN];
285 php_stream_statbuf ssb;
286
287 if (ZIP_OPENBASEDIR_CHECKPATH(filename)) {
288 return -1;
289 }
290
291 if (!expand_filepath(filename, resolved_path)) {
292 php_error_docref(NULL, E_WARNING, "No such file or directory");
293 return -1;
294 }
295
296 if (php_stream_stat_path_ex(resolved_path, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL)) {
297 php_error_docref(NULL, E_WARNING, "No such file or directory");
298 return -1;
299 }
300
301 zs = zip_source_file(obj->za, resolved_path, offset_start, offset_len);
302 if (!zs) {
303 return -1;
304 }
305 /* Replace */
306 if (replace >= 0) {
307 if (zip_file_replace(obj->za, replace, zs, flags) < 0) {
308 zip_source_free(zs);
309 return -1;
310 }
311 zip_error_clear(obj->za);
312 return 1;
313 }
314 /* Add */
315 obj->last_id = zip_file_add(obj->za, entry_name, zs, flags);
316 if (obj->last_id < 0) {
317 zip_source_free(zs);
318 return -1;
319 }
320 zip_error_clear(obj->za);
321 return 1;
322 }
323 /* }}} */
324
325 typedef struct {
326 zend_long remove_all_path;
327 char *remove_path;
328 size_t remove_path_len;
329 char *add_path;
330 size_t add_path_len;
331 zip_flags_t flags;
332 zip_int32_t comp_method;
333 zip_uint32_t comp_flags;
334 #ifdef HAVE_ENCRYPTION
335 zip_int16_t enc_method;
336 char *enc_password;
337 #endif
338 } zip_options;
339
php_zip_parse_options(HashTable * options,zip_options * opts)340 static int php_zip_parse_options(HashTable *options, zip_options *opts)
341 /* {{{ */
342 {
343 zval *option;
344
345 /* default values */
346 memset(opts, 0, sizeof(zip_options));
347 opts->flags = ZIP_FL_OVERWRITE;
348 opts->comp_method = -1; /* -1 to not change default */
349 #ifdef HAVE_ENCRYPTION
350 opts->enc_method = -1; /* -1 to not change default */
351 #endif
352
353 if ((option = zend_hash_str_find(options, "remove_all_path", sizeof("remove_all_path") - 1)) != NULL) {
354 if (Z_TYPE_P(option) != IS_FALSE && Z_TYPE_P(option) != IS_TRUE) {
355 php_error_docref(NULL, E_WARNING, "Option \"remove_all_path\" must be of type bool, %s given",
356 zend_zval_type_name(option));
357 }
358 opts->remove_all_path = zval_get_long(option);
359 }
360
361 if ((option = zend_hash_str_find(options, "comp_method", sizeof("comp_method") - 1)) != NULL) {
362 if (Z_TYPE_P(option) != IS_LONG) {
363 php_error_docref(NULL, E_WARNING, "Option \"comp_method\" must be of type int, %s given",
364 zend_zval_type_name(option));
365 }
366 opts->comp_method = zval_get_long(option);
367
368 if ((option = zend_hash_str_find(options, "comp_flags", sizeof("comp_flags") - 1)) != NULL) {
369 if (Z_TYPE_P(option) != IS_LONG) {
370 php_error_docref(NULL, E_WARNING, "Option \"comp_flags\" must be of type int, %s given",
371 zend_zval_type_name(option));
372 }
373 opts->comp_flags = zval_get_long(option);
374 }
375 }
376
377 #ifdef HAVE_ENCRYPTION
378 if ((option = zend_hash_str_find(options, "enc_method", sizeof("enc_method") - 1)) != NULL) {
379 if (Z_TYPE_P(option) != IS_LONG) {
380 php_error_docref(NULL, E_WARNING, "Option \"enc_method\" must be of type int, %s given",
381 zend_zval_type_name(option));
382 }
383 opts->enc_method = zval_get_long(option);
384
385 if ((option = zend_hash_str_find(options, "enc_password", sizeof("enc_password") - 1)) != NULL) {
386 if (Z_TYPE_P(option) != IS_STRING) {
387 zend_type_error("Option \"enc_password\" must be of type string, %s given",
388 zend_zval_type_name(option));
389 return -1;
390 }
391 opts->enc_password = Z_STRVAL_P(option);
392 }
393 }
394 #endif
395
396 if ((option = zend_hash_str_find(options, "remove_path", sizeof("remove_path") - 1)) != NULL) {
397 if (Z_TYPE_P(option) != IS_STRING) {
398 zend_type_error("Option \"remove_path\" must be of type string, %s given",
399 zend_zval_type_name(option));
400 return -1;
401 }
402
403 if (Z_STRLEN_P(option) == 0) {
404 zend_value_error("Option \"remove_path\" cannot be empty");
405 return -1;
406 }
407
408 if (Z_STRLEN_P(option) >= MAXPATHLEN) {
409 zend_value_error("Option \"remove_path\" must be less than %d bytes", MAXPATHLEN - 1);
410 return -1;
411 }
412 opts->remove_path_len = Z_STRLEN_P(option);
413 opts->remove_path = Z_STRVAL_P(option);
414 }
415
416 if ((option = zend_hash_str_find(options, "add_path", sizeof("add_path") - 1)) != NULL) {
417 if (Z_TYPE_P(option) != IS_STRING) {
418 zend_type_error("Option \"add_path\" must be of type string, %s given",
419 zend_zval_type_name(option));
420 return -1;
421 }
422
423 if (Z_STRLEN_P(option) == 0) {
424 zend_value_error("Option \"add_path\" cannot be empty");
425 return -1;
426 }
427
428 if (Z_STRLEN_P(option) >= MAXPATHLEN) {
429 zend_value_error("Option \"add_path\" must be less than %d bytes", MAXPATHLEN - 1);
430 return -1;
431 }
432 opts->add_path_len = Z_STRLEN_P(option);
433 opts->add_path = Z_STRVAL_P(option);
434 }
435
436 if ((option = zend_hash_str_find(options, "flags", sizeof("flags") - 1)) != NULL) {
437 if (Z_TYPE_P(option) != IS_LONG) {
438 zend_type_error("Option \"flags\" must be of type int, %s given",
439 zend_zval_type_name(option));
440 return -1;
441 }
442 opts->flags = Z_LVAL_P(option);
443 }
444
445 return 1;
446 }
447 /* }}} */
448
449 /* {{{ REGISTER_ZIP_CLASS_CONST_LONG */
450 #define REGISTER_ZIP_CLASS_CONST_LONG(const_name, value) \
451 zend_declare_class_constant_long(zip_class_entry, const_name, sizeof(const_name)-1, (zend_long)value);
452 /* }}} */
453
454 /* {{{ ZIP_FROM_OBJECT */
455 #define ZIP_FROM_OBJECT(intern, object) \
456 { \
457 ze_zip_object *obj = Z_ZIP_P(object); \
458 intern = obj->za; \
459 if (!intern) { \
460 zend_value_error("Invalid or uninitialized Zip object"); \
461 RETURN_THROWS(); \
462 } \
463 }
464 /* }}} */
465
466 /* {{{ RETURN_SB(sb) */
467 #ifdef HAVE_ENCRYPTION
468 #define RETURN_SB(sb) \
469 { \
470 array_init(return_value); \
471 add_ascii_assoc_string(return_value, "name", (char *)(sb)->name); \
472 add_ascii_assoc_long(return_value, "index", (zend_long) (sb)->index); \
473 add_ascii_assoc_long(return_value, "crc", (zend_long) (sb)->crc); \
474 add_ascii_assoc_long(return_value, "size", (zend_long) (sb)->size); \
475 add_ascii_assoc_long(return_value, "mtime", (zend_long) (sb)->mtime); \
476 add_ascii_assoc_long(return_value, "comp_size", (zend_long) (sb)->comp_size); \
477 add_ascii_assoc_long(return_value, "comp_method", (zend_long) (sb)->comp_method); \
478 add_ascii_assoc_long(return_value, "encryption_method", (zend_long) (sb)->encryption_method); \
479 }
480 #else
481 #define RETURN_SB(sb) \
482 { \
483 array_init(return_value); \
484 add_ascii_assoc_string(return_value, "name", (char *)(sb)->name); \
485 add_ascii_assoc_long(return_value, "index", (zend_long) (sb)->index); \
486 add_ascii_assoc_long(return_value, "crc", (zend_long) (sb)->crc); \
487 add_ascii_assoc_long(return_value, "size", (zend_long) (sb)->size); \
488 add_ascii_assoc_long(return_value, "mtime", (zend_long) (sb)->mtime); \
489 add_ascii_assoc_long(return_value, "comp_size", (zend_long) (sb)->comp_size); \
490 add_ascii_assoc_long(return_value, "comp_method", (zend_long) (sb)->comp_method); \
491 }
492 #endif
493 /* }}} */
494
php_zip_status(ze_zip_object * obj)495 static zend_long php_zip_status(ze_zip_object *obj) /* {{{ */
496 {
497 int zep = obj->err_zip; /* saved err if closed */
498
499 if (obj->za) {
500 #if LIBZIP_VERSION_MAJOR < 1
501 int syp;
502
503 zip_error_get(obj->za, &zep, &syp);
504 #else
505 zip_error_t *err;
506
507 err = zip_get_error(obj->za);
508 zep = zip_error_code_zip(err);
509 zip_error_fini(err);
510 #endif
511 }
512 return zep;
513 }
514 /* }}} */
515
php_zip_last_id(ze_zip_object * obj)516 static zend_long php_zip_last_id(ze_zip_object *obj) /* {{{ */
517 {
518 return obj->last_id;
519 }
520 /* }}} */
521
php_zip_status_sys(ze_zip_object * obj)522 static zend_long php_zip_status_sys(ze_zip_object *obj) /* {{{ */
523 {
524 int syp = obj->err_sys; /* saved err if closed */
525
526 if (obj->za) {
527 #if LIBZIP_VERSION_MAJOR < 1
528 int zep;
529
530 zip_error_get(obj->za, &zep, &syp);
531 #else
532 zip_error_t *err;
533
534 err = zip_get_error(obj->za);
535 syp = zip_error_code_system(err);
536 zip_error_fini(err);
537 #endif
538 }
539 return syp;
540 }
541 /* }}} */
542
php_zip_get_num_files(ze_zip_object * obj)543 static zend_long php_zip_get_num_files(ze_zip_object *obj) /* {{{ */
544 {
545 if (obj->za) {
546 zip_int64_t num = zip_get_num_entries(obj->za, 0);
547 return MIN(num, ZEND_LONG_MAX);
548 }
549 return 0;
550 }
551 /* }}} */
552
php_zipobj_get_filename(ze_zip_object * obj,int * len)553 static char * php_zipobj_get_filename(ze_zip_object *obj, int *len) /* {{{ */
554 {
555 if (obj && obj->filename) {
556 *len = strlen(obj->filename);
557 return obj->filename;
558 }
559 return NULL;
560 }
561 /* }}} */
562
php_zipobj_get_zip_comment(ze_zip_object * obj,int * len)563 static char * php_zipobj_get_zip_comment(ze_zip_object *obj, int *len) /* {{{ */
564 {
565 if (obj->za) {
566 return (char *)zip_get_archive_comment(obj->za, len, 0);
567 }
568 return NULL;
569 }
570 /* }}} */
571
572 #ifdef HAVE_GLOB /* {{{ */
573 #ifndef GLOB_ONLYDIR
574 #define GLOB_ONLYDIR (1<<30)
575 #define GLOB_EMULATE_ONLYDIR
576 #define GLOB_FLAGMASK (~GLOB_ONLYDIR)
577 #else
578 #define GLOB_FLAGMASK (~0)
579 #endif
580 #ifndef GLOB_BRACE
581 # define GLOB_BRACE 0
582 #endif
583 #ifndef GLOB_MARK
584 # define GLOB_MARK 0
585 #endif
586 #ifndef GLOB_NOSORT
587 # define GLOB_NOSORT 0
588 #endif
589 #ifndef GLOB_NOCHECK
590 # define GLOB_NOCHECK 0
591 #endif
592 #ifndef GLOB_NOESCAPE
593 # define GLOB_NOESCAPE 0
594 #endif
595 #ifndef GLOB_ERR
596 # define GLOB_ERR 0
597 #endif
598
599 /* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
600 #define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
601
602 #endif /* }}} */
603
php_zip_glob(char * pattern,int pattern_len,zend_long flags,zval * return_value)604 int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_value) /* {{{ */
605 {
606 #ifdef HAVE_GLOB
607 int cwd_skip = 0;
608 #ifdef ZTS
609 char cwd[MAXPATHLEN];
610 char work_pattern[MAXPATHLEN];
611 char *result;
612 #endif
613 glob_t globbuf;
614 size_t n;
615 int ret;
616
617 if (pattern_len >= MAXPATHLEN) {
618 php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
619 return -1;
620 }
621
622 if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
623
624 php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
625 return -1;
626 }
627
628 #ifdef ZTS
629 if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
630 result = VCWD_GETCWD(cwd, MAXPATHLEN);
631 if (!result) {
632 cwd[0] = '\0';
633 }
634 #ifdef PHP_WIN32
635 if (IS_SLASH(*pattern)) {
636 cwd[2] = '\0';
637 }
638 #endif
639 cwd_skip = strlen(cwd)+1;
640
641 snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
642 pattern = work_pattern;
643 }
644 #endif
645
646 globbuf.gl_offs = 0;
647 if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
648 #ifdef GLOB_NOMATCH
649 if (GLOB_NOMATCH == ret) {
650 /* Some glob implementation simply return no data if no matches
651 were found, others return the GLOB_NOMATCH error code.
652 We don't want to treat GLOB_NOMATCH as an error condition
653 so that PHP glob() behaves the same on both types of
654 implementations and so that 'foreach (glob() as ...'
655 can be used for simple glob() calls without further error
656 checking.
657 */
658 array_init(return_value);
659 return 0;
660 }
661 #endif
662 return 0;
663 }
664
665 /* now catch the FreeBSD style of "no matches" */
666 if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
667 array_init(return_value);
668 return 0;
669 }
670
671 /* we assume that any glob pattern will match files from one directory only
672 so checking the dirname of the first match should be sufficient */
673 if (ZIP_OPENBASEDIR_CHECKPATH(globbuf.gl_pathv[0])) {
674 return -1;
675 }
676
677 array_init(return_value);
678 for (n = 0; n < globbuf.gl_pathc; n++) {
679 /* we need to do this every time since GLOB_ONLYDIR does not guarantee that
680 * all directories will be filtered. GNU libc documentation states the
681 * following:
682 * If the information about the type of the file is easily available
683 * non-directories will be rejected but no extra work will be done to
684 * determine the information for each file. I.e., the caller must still be
685 * able to filter directories out.
686 */
687 if (flags & GLOB_ONLYDIR) {
688 zend_stat_t s;
689
690 if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
691 continue;
692 }
693
694 if (S_IFDIR != (s.st_mode & S_IFMT)) {
695 continue;
696 }
697 }
698 add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip);
699 }
700
701 ret = globbuf.gl_pathc;
702 globfree(&globbuf);
703 return ret;
704 #else
705 zend_throw_error(NULL, "Glob support is not available");
706 return 0;
707 #endif /* HAVE_GLOB */
708 }
709 /* }}} */
710
php_zip_pcre(zend_string * regexp,char * path,int path_len,zval * return_value)711 int php_zip_pcre(zend_string *regexp, char *path, int path_len, zval *return_value) /* {{{ */
712 {
713 #ifdef ZTS
714 char cwd[MAXPATHLEN];
715 char work_path[MAXPATHLEN];
716 char *result;
717 #endif
718 int files_cnt;
719 zend_string **namelist;
720 pcre2_match_context *mctx = php_pcre_mctx();
721
722 #ifdef ZTS
723 if (!IS_ABSOLUTE_PATH(path, path_len)) {
724 result = VCWD_GETCWD(cwd, MAXPATHLEN);
725 if (!result) {
726 cwd[0] = '\0';
727 }
728 #ifdef PHP_WIN32
729 if (IS_SLASH(*path)) {
730 cwd[2] = '\0';
731 }
732 #endif
733 snprintf(work_path, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, path);
734 path = work_path;
735 }
736 #endif
737
738 if (ZIP_OPENBASEDIR_CHECKPATH(path)) {
739 return -1;
740 }
741
742 files_cnt = php_stream_scandir(path, &namelist, NULL, (void *) php_stream_dirent_alphasort);
743
744 if (files_cnt > 0) {
745 pcre2_code *re = NULL;
746 pcre2_match_data *match_data = NULL;
747 uint32_t i, capture_count;
748 int rc;
749
750 re = pcre_get_compiled_regex(regexp, &capture_count);
751 if (!re) {
752 php_error_docref(NULL, E_WARNING, "Invalid expression");
753 return -1;
754 }
755
756 array_init(return_value);
757
758 /* only the files, directories are ignored */
759 for (i = 0; i < files_cnt; i++) {
760 zend_stat_t s;
761 char fullpath[MAXPATHLEN];
762 size_t namelist_len = ZSTR_LEN(namelist[i]);
763
764 if ((namelist_len == 1 && ZSTR_VAL(namelist[i])[0] == '.') ||
765 (namelist_len == 2 && ZSTR_VAL(namelist[i])[0] == '.' && ZSTR_VAL(namelist[i])[1] == '.')) {
766 zend_string_release_ex(namelist[i], 0);
767 continue;
768 }
769
770 if ((path_len + namelist_len + 1) >= MAXPATHLEN) {
771 php_error_docref(NULL, E_WARNING, "add_path string too long (max: %u, %zu given)",
772 MAXPATHLEN - 1, (path_len + namelist_len + 1));
773 zend_string_release_ex(namelist[i], 0);
774 break;
775 }
776
777 match_data = php_pcre_create_match_data(capture_count, re);
778 if (!match_data) {
779 /* Allocation failed, but can proceed to the next pattern. */
780 zend_string_release_ex(namelist[i], 0);
781 continue;
782 }
783 rc = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(namelist[i]), ZSTR_LEN(namelist[i]), 0, 0, match_data, mctx);
784 php_pcre_free_match_data(match_data);
785 /* 0 means that the vector is too small to hold all the captured substring offsets */
786 if (rc < 0) {
787 zend_string_release_ex(namelist[i], 0);
788 continue;
789 }
790
791 snprintf(fullpath, MAXPATHLEN, "%s%c%s", path, DEFAULT_SLASH, ZSTR_VAL(namelist[i]));
792
793 if (0 != VCWD_STAT(fullpath, &s)) {
794 php_error_docref(NULL, E_WARNING, "Cannot read <%s>", fullpath);
795 zend_string_release_ex(namelist[i], 0);
796 continue;
797 }
798
799 if (S_IFDIR == (s.st_mode & S_IFMT)) {
800 zend_string_release_ex(namelist[i], 0);
801 continue;
802 }
803
804 add_next_index_string(return_value, fullpath);
805 zend_string_release_ex(namelist[i], 0);
806 }
807 efree(namelist);
808 }
809 return files_cnt;
810 }
811 /* }}} */
812
813 /* {{{ ZE2 OO definitions */
814 static zend_class_entry *zip_class_entry;
815 static zend_object_handlers zip_object_handlers;
816
817 static HashTable zip_prop_handlers;
818
819 typedef zend_long (*zip_read_int_t)(ze_zip_object *obj);
820 typedef char *(*zip_read_const_char_t)(ze_zip_object *obj, int *len);
821
822 typedef struct _zip_prop_handler {
823 zip_read_int_t read_int_func;
824 zip_read_const_char_t read_const_char_func;
825
826 int type;
827 } zip_prop_handler;
828 /* }}} */
829
php_zip_register_prop_handler(HashTable * prop_handler,char * name,zip_read_int_t read_int_func,zip_read_const_char_t read_char_func,int rettype)830 static void php_zip_register_prop_handler(HashTable *prop_handler, char *name, zip_read_int_t read_int_func, zip_read_const_char_t read_char_func, int rettype) /* {{{ */
831 {
832 zip_prop_handler hnd;
833 zend_string *str;
834
835 hnd.read_const_char_func = read_char_func;
836 hnd.read_int_func = read_int_func;
837 hnd.type = rettype;
838 str = zend_string_init_interned(name, strlen(name), 1);
839 zend_hash_add_mem(prop_handler, str, &hnd, sizeof(zip_prop_handler));
840 zend_string_release_ex(str, 1);
841 }
842 /* }}} */
843
php_zip_property_reader(ze_zip_object * obj,zip_prop_handler * hnd,zval * rv)844 static zval *php_zip_property_reader(ze_zip_object *obj, zip_prop_handler *hnd, zval *rv) /* {{{ */
845 {
846 const char *retchar = NULL;
847 zend_long retint = 0;
848 int len = 0;
849
850 if (hnd->read_const_char_func) {
851 retchar = hnd->read_const_char_func(obj, &len);
852 } else if (hnd->read_int_func) {
853 retint = hnd->read_int_func(obj);
854 }
855
856 switch (hnd->type) {
857 case IS_STRING:
858 if (retchar) {
859 ZVAL_STRINGL(rv, (char *) retchar, len);
860 } else {
861 ZVAL_EMPTY_STRING(rv);
862 }
863 break;
864 case IS_LONG:
865 ZVAL_LONG(rv, retint);
866 break;
867 default:
868 ZVAL_NULL(rv);
869 }
870
871 return rv;
872 }
873 /* }}} */
874
php_zip_get_property_ptr_ptr(zend_object * object,zend_string * name,int type,void ** cache_slot)875 static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
876 {
877 ze_zip_object *obj;
878 zval *retval = NULL;
879 zip_prop_handler *hnd = NULL;
880
881 obj = php_zip_fetch_object(object);
882
883 if (obj->prop_handler != NULL) {
884 hnd = zend_hash_find_ptr(obj->prop_handler, name);
885 }
886
887 if (hnd == NULL) {
888 retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
889 }
890
891 return retval;
892 }
893 /* }}} */
894
895
php_zip_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)896 static zval *php_zip_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
897 {
898 ze_zip_object *obj;
899 zip_prop_handler *hnd = NULL;
900
901 obj = php_zip_fetch_object(object);
902
903 if (obj->prop_handler != NULL) {
904 hnd = zend_hash_find_ptr(obj->prop_handler, name);
905 }
906
907 if (hnd != NULL) {
908 zend_throw_error(NULL, "Cannot write read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
909 return &EG(error_zval);
910 }
911
912 return zend_std_write_property(object, name, value, cache_slot);
913 }
914
php_zip_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)915 static zval *php_zip_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
916 {
917 ze_zip_object *obj;
918 zval *retval = NULL;
919 zip_prop_handler *hnd = NULL;
920
921 obj = php_zip_fetch_object(object);
922
923 if (obj->prop_handler != NULL) {
924 hnd = zend_hash_find_ptr(obj->prop_handler, name);
925 }
926
927 if (hnd != NULL) {
928 retval = php_zip_property_reader(obj, hnd, rv);
929 if (retval == NULL) {
930 retval = &EG(uninitialized_zval);
931 }
932 } else {
933 retval = zend_std_read_property(object, name, type, cache_slot, rv);
934 }
935
936 return retval;
937 }
938 /* }}} */
939
php_zip_has_property(zend_object * object,zend_string * name,int type,void ** cache_slot)940 static int php_zip_has_property(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
941 {
942 ze_zip_object *obj;
943 zip_prop_handler *hnd = NULL;
944 int retval = 0;
945
946 obj = php_zip_fetch_object(object);
947
948 if (obj->prop_handler != NULL) {
949 hnd = zend_hash_find_ptr(obj->prop_handler, name);
950 }
951
952 if (hnd != NULL) {
953 zval tmp, *prop;
954
955 if (type == 2) {
956 retval = 1;
957 } else if ((prop = php_zip_property_reader(obj, hnd, &tmp)) != NULL) {
958 if (type == 1) {
959 retval = zend_is_true(&tmp);
960 } else if (type == 0) {
961 retval = (Z_TYPE(tmp) != IS_NULL);
962 }
963 }
964
965 zval_ptr_dtor(&tmp);
966 } else {
967 retval = zend_std_has_property(object, name, type, cache_slot);
968 }
969
970 return retval;
971 }
972 /* }}} */
973
php_zip_get_gc(zend_object * object,zval ** gc_data,int * gc_data_count)974 static HashTable *php_zip_get_gc(zend_object *object, zval **gc_data, int *gc_data_count) /* {{{ */
975 {
976 *gc_data = NULL;
977 *gc_data_count = 0;
978 return zend_std_get_properties(object);
979 }
980 /* }}} */
981
php_zip_get_properties(zend_object * object)982 static HashTable *php_zip_get_properties(zend_object *object)/* {{{ */
983 {
984 ze_zip_object *obj;
985 HashTable *props;
986 zip_prop_handler *hnd;
987 zend_string *key;
988
989 obj = php_zip_fetch_object(object);
990 props = zend_std_get_properties(object);
991
992 if (obj->prop_handler == NULL) {
993 return NULL;
994 }
995
996 ZEND_HASH_FOREACH_STR_KEY_PTR(obj->prop_handler, key, hnd) {
997 zval *ret, val;
998 ret = php_zip_property_reader(obj, hnd, &val);
999 if (ret == NULL) {
1000 ret = &EG(uninitialized_zval);
1001 }
1002 zend_hash_update(props, key, ret);
1003 } ZEND_HASH_FOREACH_END();
1004
1005 return props;
1006 }
1007 /* }}} */
1008
1009 #ifdef HAVE_PROGRESS_CALLBACK
_php_zip_progress_callback_free(void * ptr)1010 static void _php_zip_progress_callback_free(void *ptr)
1011 {
1012 ze_zip_object *obj = ptr;
1013
1014 if (!Z_ISUNDEF(obj->progress_callback)) {
1015 zval_ptr_dtor(&obj->progress_callback);
1016 ZVAL_UNDEF(&obj->progress_callback);
1017 }
1018 }
1019 #endif
1020
1021 #ifdef HAVE_CANCEL_CALLBACK
_php_zip_cancel_callback_free(void * ptr)1022 static void _php_zip_cancel_callback_free(void *ptr)
1023 {
1024 ze_zip_object *obj = ptr;
1025
1026 if (!Z_ISUNDEF(obj->cancel_callback)) {
1027 zval_ptr_dtor(&obj->cancel_callback);
1028 ZVAL_UNDEF(&obj->cancel_callback);
1029 }
1030 }
1031 #endif
1032
php_zip_object_free_storage(zend_object * object)1033 static void php_zip_object_free_storage(zend_object *object) /* {{{ */
1034 {
1035 ze_zip_object * intern = php_zip_fetch_object(object);
1036 int i;
1037
1038 if (!intern) {
1039 return;
1040 }
1041 if (intern->za) {
1042 if (zip_close(intern->za) != 0) {
1043 php_error_docref(NULL, E_WARNING, "Cannot destroy the zip context: %s", zip_strerror(intern->za));
1044 zip_discard(intern->za);
1045 }
1046 }
1047
1048 if (intern->buffers_cnt>0) {
1049 for (i=0; i<intern->buffers_cnt; i++) {
1050 efree(intern->buffers[i]);
1051 }
1052 efree(intern->buffers);
1053 }
1054
1055 #ifdef HAVE_PROGRESS_CALLBACK
1056 /* if not properly called by libzip */
1057 _php_zip_progress_callback_free(intern);
1058 #endif
1059
1060 #ifdef HAVE_CANCEL_CALLBACK
1061 /* if not properly called by libzip */
1062 _php_zip_cancel_callback_free(intern);
1063 #endif
1064
1065 intern->za = NULL;
1066 zend_object_std_dtor(&intern->zo);
1067
1068 if (intern->filename) {
1069 efree(intern->filename);
1070 }
1071 }
1072 /* }}} */
1073
php_zip_object_new(zend_class_entry * class_type)1074 static zend_object *php_zip_object_new(zend_class_entry *class_type) /* {{{ */
1075 {
1076 ze_zip_object *intern;
1077
1078 intern = zend_object_alloc(sizeof(ze_zip_object), class_type);
1079 intern->prop_handler = &zip_prop_handlers;
1080 zend_object_std_init(&intern->zo, class_type);
1081 object_properties_init(&intern->zo, class_type);
1082 intern->zo.handlers = &zip_object_handlers;
1083 intern->last_id = -1;
1084
1085 return &intern->zo;
1086 }
1087 /* }}} */
1088
1089 /* {{{ Resource dtors */
1090
1091 /* {{{ php_zip_free_dir */
php_zip_free_dir(zend_resource * rsrc)1092 static void php_zip_free_dir(zend_resource *rsrc)
1093 {
1094 zip_rsrc * zip_int = (zip_rsrc *) rsrc->ptr;
1095
1096 if (zip_int) {
1097 if (zip_int->za) {
1098 if (zip_close(zip_int->za) != 0) {
1099 php_error_docref(NULL, E_WARNING, "Cannot destroy the zip context");
1100 }
1101 zip_int->za = NULL;
1102 }
1103
1104 efree(rsrc->ptr);
1105
1106 rsrc->ptr = NULL;
1107 }
1108 }
1109 /* }}} */
1110
1111 /* {{{ php_zip_free_entry */
php_zip_free_entry(zend_resource * rsrc)1112 static void php_zip_free_entry(zend_resource *rsrc)
1113 {
1114 zip_read_rsrc *zr_rsrc = (zip_read_rsrc *) rsrc->ptr;
1115
1116 if (zr_rsrc) {
1117 if (zr_rsrc->zf) {
1118 zip_fclose(zr_rsrc->zf);
1119 zr_rsrc->zf = NULL;
1120 }
1121 efree(zr_rsrc);
1122 rsrc->ptr = NULL;
1123 }
1124 }
1125 /* }}} */
1126
1127 /* }}}*/
1128
1129 /* reset macro */
1130
1131 /* {{{ function prototypes */
1132 static PHP_MINIT_FUNCTION(zip);
1133 static PHP_MSHUTDOWN_FUNCTION(zip);
1134 static PHP_MINFO_FUNCTION(zip);
1135 /* }}} */
1136
1137 /* {{{ zip_module_entry */
1138 zend_module_entry zip_module_entry = {
1139 STANDARD_MODULE_HEADER,
1140 "zip",
1141 ext_functions,
1142 PHP_MINIT(zip),
1143 PHP_MSHUTDOWN(zip),
1144 NULL,
1145 NULL,
1146 PHP_MINFO(zip),
1147 PHP_ZIP_VERSION,
1148 STANDARD_MODULE_PROPERTIES
1149 };
1150 /* }}} */
1151
1152 #ifdef COMPILE_DL_ZIP
1153 ZEND_GET_MODULE(zip)
1154 #endif
1155 /* set macro */
1156
1157 /* {{{ Create new zip using source uri for output */
PHP_FUNCTION(zip_open)1158 PHP_FUNCTION(zip_open)
1159 {
1160 char resolved_path[MAXPATHLEN + 1];
1161 zip_rsrc *rsrc_int;
1162 int err = 0;
1163 zend_string *filename;
1164
1165 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &filename) == FAILURE) {
1166 RETURN_THROWS();
1167 }
1168
1169 if (ZSTR_LEN(filename) == 0) {
1170 zend_argument_value_error(1, "cannot be empty");
1171 RETURN_THROWS();
1172 }
1173
1174 if (ZIP_OPENBASEDIR_CHECKPATH(ZSTR_VAL(filename))) {
1175 RETURN_FALSE;
1176 }
1177
1178 if(!expand_filepath(ZSTR_VAL(filename), resolved_path)) {
1179 php_error_docref(NULL, E_WARNING, "No such file or directory");
1180 RETURN_FALSE;
1181 }
1182
1183 rsrc_int = (zip_rsrc *)emalloc(sizeof(zip_rsrc));
1184
1185 rsrc_int->za = zip_open(resolved_path, 0, &err);
1186 if (rsrc_int->za == NULL) {
1187 efree(rsrc_int);
1188 RETURN_LONG((zend_long)err);
1189 }
1190
1191 rsrc_int->index_current = 0;
1192 rsrc_int->num_files = zip_get_num_entries(rsrc_int->za, 0);
1193
1194 RETURN_RES(zend_register_resource(rsrc_int, le_zip_dir));
1195 }
1196 /* }}} */
1197
1198 /* {{{ Close a Zip archive */
PHP_FUNCTION(zip_close)1199 PHP_FUNCTION(zip_close)
1200 {
1201 zval * zip;
1202 zip_rsrc *z_rsrc = NULL;
1203
1204 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip) == FAILURE) {
1205 RETURN_THROWS();
1206 }
1207
1208 if ((z_rsrc = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip), le_zip_dir_name, le_zip_dir)) == NULL) {
1209 RETURN_THROWS();
1210 }
1211
1212 /* really close the zip will break BC :-D */
1213 zend_list_close(Z_RES_P(zip));
1214 }
1215 /* }}} */
1216
1217 /* {{{ Returns the next file in the archive */
PHP_FUNCTION(zip_read)1218 PHP_FUNCTION(zip_read)
1219 {
1220 zval *zip_dp;
1221 zip_read_rsrc *zr_rsrc;
1222 int ret;
1223 zip_rsrc *rsrc_int;
1224
1225 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_dp) == FAILURE) {
1226 RETURN_THROWS();
1227 }
1228
1229 if ((rsrc_int = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip_dp), le_zip_dir_name, le_zip_dir)) == NULL) {
1230 RETURN_THROWS();
1231 }
1232
1233 if (rsrc_int && rsrc_int->za) {
1234 if (rsrc_int->index_current >= rsrc_int->num_files) {
1235 RETURN_FALSE;
1236 }
1237
1238 zr_rsrc = emalloc(sizeof(zip_read_rsrc));
1239
1240 ret = zip_stat_index(rsrc_int->za, rsrc_int->index_current, 0, &zr_rsrc->sb);
1241
1242 if (ret != 0) {
1243 efree(zr_rsrc);
1244 RETURN_FALSE;
1245 }
1246
1247 zr_rsrc->zf = zip_fopen_index(rsrc_int->za, rsrc_int->index_current, 0);
1248 if (zr_rsrc->zf) {
1249 rsrc_int->index_current++;
1250 RETURN_RES(zend_register_resource(zr_rsrc, le_zip_entry));
1251 } else {
1252 efree(zr_rsrc);
1253 RETURN_FALSE;
1254 }
1255
1256 } else {
1257 RETURN_FALSE;
1258 }
1259 }
1260 /* }}} */
1261
1262 /* {{{ Open a Zip File, pointed by the resource entry */
1263 /* Dummy function to follow the old API */
PHP_FUNCTION(zip_entry_open)1264 PHP_FUNCTION(zip_entry_open)
1265 {
1266 zval * zip;
1267 zval * zip_entry;
1268 char *mode = NULL;
1269 size_t mode_len = 0;
1270 zip_read_rsrc * zr_rsrc;
1271 zip_rsrc *z_rsrc;
1272
1273 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|s", &zip, &zip_entry, &mode, &mode_len) == FAILURE) {
1274 RETURN_THROWS();
1275 }
1276
1277 if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
1278 RETURN_THROWS();
1279 }
1280
1281 if ((z_rsrc = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip), le_zip_dir_name, le_zip_dir)) == NULL) {
1282 RETURN_THROWS();
1283 }
1284
1285 if (zr_rsrc->zf != NULL) {
1286 RETURN_TRUE;
1287 } else {
1288 RETURN_FALSE;
1289 }
1290 }
1291 /* }}} */
1292
1293 /* {{{ Close a zip entry */
PHP_FUNCTION(zip_entry_close)1294 PHP_FUNCTION(zip_entry_close)
1295 {
1296 zval * zip_entry;
1297 zip_read_rsrc * zr_rsrc;
1298
1299 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_entry) == FAILURE) {
1300 RETURN_THROWS();
1301 }
1302
1303 if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
1304 RETURN_THROWS();
1305 }
1306
1307 zend_list_close(Z_RES_P(zip_entry));
1308 RETURN_TRUE;
1309 }
1310 /* }}} */
1311
1312 /* {{{ Read from an open directory entry */
PHP_FUNCTION(zip_entry_read)1313 PHP_FUNCTION(zip_entry_read)
1314 {
1315 zval * zip_entry;
1316 zend_long len = 0;
1317 zip_read_rsrc * zr_rsrc;
1318 zend_string *buffer;
1319 int n = 0;
1320
1321 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zip_entry, &len) == FAILURE) {
1322 RETURN_THROWS();
1323 }
1324
1325 if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
1326 RETURN_THROWS();
1327 }
1328
1329 if (len <= 0) {
1330 len = 1024;
1331 }
1332
1333 if (zr_rsrc->zf) {
1334 buffer = zend_string_safe_alloc(1, len, 0, 0);
1335 n = zip_fread(zr_rsrc->zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer));
1336 if (n > 0) {
1337 ZSTR_VAL(buffer)[n] = '\0';
1338 ZSTR_LEN(buffer) = n;
1339 RETURN_NEW_STR(buffer);
1340 } else {
1341 zend_string_efree(buffer);
1342 RETURN_EMPTY_STRING();
1343 }
1344 } else {
1345 RETURN_FALSE;
1346 }
1347 }
1348 /* }}} */
1349
php_zip_entry_get_info(INTERNAL_FUNCTION_PARAMETERS,int opt)1350 static void php_zip_entry_get_info(INTERNAL_FUNCTION_PARAMETERS, int opt) /* {{{ */
1351 {
1352 zval * zip_entry;
1353 zip_read_rsrc * zr_rsrc;
1354
1355 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_entry) == FAILURE) {
1356 RETURN_THROWS();
1357 }
1358
1359 if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
1360 RETURN_THROWS();
1361 }
1362
1363 if (!zr_rsrc->zf) {
1364 RETURN_FALSE;
1365 }
1366
1367 switch (opt) {
1368 case 0:
1369 RETURN_STRING((char *)zr_rsrc->sb.name);
1370 case 1:
1371 RETURN_LONG((zend_long) (zr_rsrc->sb.comp_size));
1372 case 2:
1373 RETURN_LONG((zend_long) (zr_rsrc->sb.size));
1374 case 3:
1375 switch (zr_rsrc->sb.comp_method) {
1376 case 0:
1377 RETURN_STRING("stored");
1378 case 1:
1379 RETURN_STRING("shrunk");
1380 case 2:
1381 case 3:
1382 case 4:
1383 case 5:
1384 RETURN_STRING("reduced");
1385 case 6:
1386 RETURN_STRING("imploded");
1387 case 7:
1388 RETURN_STRING("tokenized");
1389 break;
1390 case 8:
1391 RETURN_STRING("deflated");
1392 case 9:
1393 RETURN_STRING("deflatedX");
1394 break;
1395 case 10:
1396 RETURN_STRING("implodedX");
1397 default:
1398 RETURN_FALSE;
1399 }
1400 }
1401
1402 }
1403 /* }}} */
1404
1405 /* {{{ Return the name given a ZZip entry */
PHP_FUNCTION(zip_entry_name)1406 PHP_FUNCTION(zip_entry_name)
1407 {
1408 php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1409 }
1410 /* }}} */
1411
1412 /* {{{ Return the compressed size of a ZZip entry */
PHP_FUNCTION(zip_entry_compressedsize)1413 PHP_FUNCTION(zip_entry_compressedsize)
1414 {
1415 php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1416 }
1417 /* }}} */
1418
1419 /* {{{ Return the actual filesize of a ZZip entry */
PHP_FUNCTION(zip_entry_filesize)1420 PHP_FUNCTION(zip_entry_filesize)
1421 {
1422 php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
1423 }
1424 /* }}} */
1425
1426 /* {{{ Return a string containing the compression method used on a particular entry */
PHP_FUNCTION(zip_entry_compressionmethod)1427 PHP_FUNCTION(zip_entry_compressionmethod)
1428 {
1429 php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
1430 }
1431 /* }}} */
1432
1433 /* {{{ Create new zip using source uri for output, return TRUE on success or the error code */
PHP_METHOD(ZipArchive,open)1434 PHP_METHOD(ZipArchive, open)
1435 {
1436 struct zip *intern;
1437 int err = 0;
1438 zend_long flags = 0;
1439 char *resolved_path;
1440 zend_string *filename;
1441 zval *self = ZEND_THIS;
1442 ze_zip_object *ze_obj;
1443
1444 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &filename, &flags) == FAILURE) {
1445 RETURN_THROWS();
1446 }
1447
1448 /* We do not use ZIP_FROM_OBJECT, zip init function here */
1449 ze_obj = Z_ZIP_P(self);
1450
1451 if (ZSTR_LEN(filename) == 0) {
1452 zend_argument_value_error(1, "cannot be empty");
1453 RETURN_THROWS();
1454 }
1455
1456 if (ZIP_OPENBASEDIR_CHECKPATH(ZSTR_VAL(filename))) {
1457 RETURN_FALSE;
1458 }
1459
1460 if (!(resolved_path = expand_filepath(ZSTR_VAL(filename), NULL))) {
1461 php_error_docref(NULL, E_WARNING, "No such file or directory");
1462 RETURN_FALSE;
1463 }
1464
1465 if (ze_obj->za) {
1466 /* we already have an opened zip, free it */
1467 if (zip_close(ze_obj->za) != 0) {
1468 php_error_docref(NULL, E_WARNING, "Empty string as source");
1469 efree(resolved_path);
1470 RETURN_FALSE;
1471 }
1472 ze_obj->za = NULL;
1473 }
1474 if (ze_obj->filename) {
1475 efree(ze_obj->filename);
1476 ze_obj->filename = NULL;
1477 }
1478
1479 /* open for write without option to empty the archive */
1480 #ifdef ZIP_RDONLY
1481 if ((flags & (ZIP_TRUNCATE | ZIP_RDONLY)) == 0) {
1482 #else
1483 if ((flags & ZIP_TRUNCATE) == 0) {
1484 #endif
1485 zend_stat_t st;
1486
1487 /* exists and is empty */
1488 if (VCWD_STAT(resolved_path, &st) == 0 && st.st_size == 0) {
1489 php_error_docref(NULL, E_DEPRECATED, "Using empty file as ZipArchive is deprecated");
1490
1491 /* reduce BC break introduced in libzip 1.6.0
1492 "Do not accept empty files as valid zip archives any longer" */
1493 flags |= ZIP_TRUNCATE;
1494 }
1495 }
1496
1497 intern = zip_open(resolved_path, flags, &err);
1498 if (!intern || err) {
1499 efree(resolved_path);
1500 RETURN_LONG((zend_long)err);
1501 }
1502 ze_obj->filename = resolved_path;
1503 ze_obj->filename_len = strlen(resolved_path);
1504 ze_obj->za = intern;
1505 RETURN_TRUE;
1506 }
1507 /* }}} */
1508
1509 /* {{{ Set the password for the active archive */
1510 PHP_METHOD(ZipArchive, setPassword)
1511 {
1512 struct zip *intern;
1513 zval *self = ZEND_THIS;
1514 char *password;
1515 size_t password_len;
1516
1517 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &password, &password_len) == FAILURE) {
1518 RETURN_THROWS();
1519 }
1520
1521 ZIP_FROM_OBJECT(intern, self);
1522
1523 if (password_len < 1) {
1524 RETURN_FALSE;
1525 }
1526
1527 int res = zip_set_default_password(intern, (const char *)password);
1528 if (res == 0) {
1529 RETURN_TRUE;
1530 } else {
1531 RETURN_FALSE;
1532 }
1533 }
1534 /* }}} */
1535
1536 /* {{{ close the zip archive */
1537 PHP_METHOD(ZipArchive, close)
1538 {
1539 struct zip *intern;
1540 zval *self = ZEND_THIS;
1541 ze_zip_object *ze_obj;
1542 int err;
1543
1544 if (zend_parse_parameters_none() == FAILURE) {
1545 RETURN_THROWS();
1546 }
1547
1548 ZIP_FROM_OBJECT(intern, self);
1549
1550 ze_obj = Z_ZIP_P(self);
1551
1552 err = zip_close(intern);
1553 if (err) {
1554 php_error_docref(NULL, E_WARNING, "%s", zip_strerror(intern));
1555 /* Save error for property reader */
1556 #if LIBZIP_VERSION_MAJOR < 1
1557 zip_error_get(intern, &ze_obj->err_zip, &ze_obj->err_sys);
1558 #else
1559 {
1560 zip_error_t *ziperr;
1561
1562 ziperr = zip_get_error(intern);
1563 ze_obj->err_zip = zip_error_code_zip(ziperr);
1564 ze_obj->err_sys = zip_error_code_system(ziperr);
1565 zip_error_fini(ziperr);
1566 }
1567 #endif
1568 zip_discard(intern);
1569 } else {
1570 ze_obj->err_zip = 0;
1571 ze_obj->err_sys = 0;
1572 }
1573
1574 /* clear cache as empty zip are not created but deleted */
1575 php_clear_stat_cache(1, ze_obj->filename, ze_obj->filename_len);
1576
1577 efree(ze_obj->filename);
1578 ze_obj->filename = NULL;
1579 ze_obj->filename_len = 0;
1580 ze_obj->za = NULL;
1581
1582 if (!err) {
1583 RETURN_TRUE;
1584 } else {
1585 RETURN_FALSE;
1586 }
1587 }
1588 /* }}} */
1589
1590 /* {{{ close the zip archive */
1591 PHP_METHOD(ZipArchive, count)
1592 {
1593 struct zip *intern;
1594 zval *self = ZEND_THIS;
1595 zip_int64_t num;
1596
1597 if (zend_parse_parameters_none() == FAILURE) {
1598 RETURN_THROWS();
1599 }
1600
1601 ZIP_FROM_OBJECT(intern, self);
1602
1603 num = zip_get_num_entries(intern, 0);
1604 RETVAL_LONG(MIN(num, ZEND_LONG_MAX));
1605 }
1606 /* }}} */
1607
1608 /* {{{ Returns the status error message, system and/or zip messages */
1609 PHP_METHOD(ZipArchive, getStatusString)
1610 {
1611 zval *self = ZEND_THIS;
1612 #if LIBZIP_VERSION_MAJOR < 1
1613 int zep, syp, len;
1614 char error_string[128];
1615 #endif
1616 ze_zip_object *ze_obj;
1617
1618 if (zend_parse_parameters_none() == FAILURE) {
1619 RETURN_THROWS();
1620 }
1621
1622 ze_obj = Z_ZIP_P(self); /* not ZIP_FROM_OBJECT as we can use saved error after close */
1623
1624 #if LIBZIP_VERSION_MAJOR < 1
1625 if (ze_obj->za) {
1626 zip_error_get(ze_obj->za, &zep, &syp);
1627 len = zip_error_to_str(error_string, 128, zep, syp);
1628 } else {
1629 len = zip_error_to_str(error_string, 128, ze_obj->err_zip, ze_obj->err_sys);
1630 }
1631 RETVAL_STRINGL(error_string, len);
1632 #else
1633 if (ze_obj->za) {
1634 zip_error_t *err;
1635
1636 err = zip_get_error(ze_obj->za);
1637 RETVAL_STRING(zip_error_strerror(err));
1638 zip_error_fini(err);
1639 } else {
1640 zip_error_t err;
1641
1642 zip_error_init(&err);
1643 zip_error_set(&err, ze_obj->err_zip, ze_obj->err_sys);
1644 RETVAL_STRING(zip_error_strerror(&err));
1645 zip_error_fini(&err);
1646 }
1647 #endif
1648 }
1649 /* }}} */
1650
1651 /* {{{ Returns the index of the entry named filename in the archive */
1652 PHP_METHOD(ZipArchive, addEmptyDir)
1653 {
1654 struct zip *intern;
1655 zval *self = ZEND_THIS;
1656 char *dirname;
1657 size_t dirname_len;
1658 char *s;
1659 zend_long flags = 0;
1660
1661 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
1662 &dirname, &dirname_len, &flags) == FAILURE) {
1663 RETURN_THROWS();
1664 }
1665
1666 ZIP_FROM_OBJECT(intern, self);
1667
1668 if (dirname_len<1) {
1669 RETURN_FALSE;
1670 }
1671
1672 if (dirname[dirname_len-1] != '/') {
1673 s=(char *)safe_emalloc(dirname_len, 1, 2);
1674 strcpy(s, dirname);
1675 s[dirname_len] = '/';
1676 s[dirname_len+1] = '\0';
1677 } else {
1678 s = dirname;
1679 }
1680
1681 if ((Z_ZIP_P(self)->last_id = zip_dir_add(intern, (const char *)s, flags)) == -1) {
1682 RETVAL_FALSE;
1683 } else {
1684 zip_error_clear(intern);
1685 RETVAL_TRUE;
1686 }
1687
1688 if (s != dirname) {
1689 efree(s);
1690 }
1691 }
1692 /* }}} */
1693
1694 static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1695 {
1696 zval *self = ZEND_THIS;
1697 char *path = ".";
1698 size_t path_len = 1;
1699 zend_long glob_flags = 0;
1700 HashTable *options = NULL;
1701 zip_options opts;
1702 int found;
1703 zend_string *pattern;
1704
1705 /* 1 == glob, 2 == pcre */
1706 if (type == 1) {
1707 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|lh",
1708 &pattern, &glob_flags, &options) == FAILURE) {
1709 RETURN_THROWS();
1710 }
1711 } else {
1712 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|sh",
1713 &pattern, &path, &path_len, &options) == FAILURE) {
1714 RETURN_THROWS();
1715 }
1716 }
1717
1718 if (ZSTR_LEN(pattern) == 0) {
1719 zend_argument_value_error(1, "cannot be empty");
1720 RETURN_THROWS();
1721 }
1722 if (options && zend_hash_num_elements(options) > 0 && (php_zip_parse_options(options, &opts) < 0)) {
1723 RETURN_THROWS();
1724 }
1725
1726 if (type == 1) {
1727 found = php_zip_glob(ZSTR_VAL(pattern), ZSTR_LEN(pattern), glob_flags, return_value);
1728 } else {
1729 found = php_zip_pcre(pattern, path, path_len, return_value);
1730 }
1731
1732 if (found > 0) {
1733 int i;
1734 zval *zval_file;
1735 ze_zip_object *ze_obj;
1736
1737 ze_obj = Z_ZIP_P(self);
1738
1739 for (i = 0; i < found; i++) {
1740 char *file_stripped, *entry_name;
1741 size_t entry_name_len, file_stripped_len;
1742 char entry_name_buf[MAXPATHLEN];
1743 zend_string *basename = NULL;
1744
1745 if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
1746 if (opts.remove_all_path) {
1747 basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
1748 file_stripped = ZSTR_VAL(basename);
1749 file_stripped_len = ZSTR_LEN(basename);
1750 } else if (opts.remove_path && !memcmp(Z_STRVAL_P(zval_file), opts.remove_path, opts.remove_path_len)) {
1751 if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
1752 file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
1753 file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
1754 } else {
1755 file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
1756 file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
1757 }
1758 } else {
1759 file_stripped = Z_STRVAL_P(zval_file);
1760 file_stripped_len = Z_STRLEN_P(zval_file);
1761 }
1762
1763 if (opts.add_path) {
1764 if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) {
1765 php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)",
1766 MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len));
1767 zend_array_destroy(Z_ARR_P(return_value));
1768 RETURN_FALSE;
1769 }
1770 snprintf(entry_name_buf, MAXPATHLEN, "%s%s", opts.add_path, file_stripped);
1771 } else {
1772 snprintf(entry_name_buf, MAXPATHLEN, "%s", file_stripped);
1773 }
1774
1775 entry_name = entry_name_buf;
1776 entry_name_len = strlen(entry_name);
1777 if (basename) {
1778 zend_string_release_ex(basename, 0);
1779 basename = NULL;
1780 }
1781
1782 if (php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
1783 entry_name, entry_name_len, 0, 0, -1, opts.flags) < 0) {
1784 zend_array_destroy(Z_ARR_P(return_value));
1785 RETURN_FALSE;
1786 }
1787 if (opts.comp_method >= 0) {
1788 if (zip_set_file_compression(ze_obj->za, ze_obj->last_id, opts.comp_method, opts.comp_flags)) {
1789 zend_array_destroy(Z_ARR_P(return_value));
1790 RETURN_FALSE;
1791 }
1792 }
1793 #ifdef HAVE_ENCRYPTION
1794 if (opts.enc_method >= 0) {
1795 if (zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) {
1796 zend_array_destroy(Z_ARR_P(return_value));
1797 RETURN_FALSE;
1798 }
1799 }
1800 #endif
1801 }
1802 }
1803 }
1804 }
1805 /* }}} */
1806
1807 /* {{{ Add files matching the glob pattern. See php's glob for the pattern syntax. */
1808 PHP_METHOD(ZipArchive, addGlob)
1809 {
1810 php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1811 }
1812 /* }}} */
1813
1814 /* {{{ Add files matching the pcre pattern. See php's pcre for the pattern syntax. */
1815 PHP_METHOD(ZipArchive, addPattern)
1816 {
1817 php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
1818 }
1819 /* }}} */
1820
1821 /* {{{ Add a file in a Zip archive using its path and the name to use. */
1822 PHP_METHOD(ZipArchive, addFile)
1823 {
1824 zval *self = ZEND_THIS;
1825 char *entry_name = NULL;
1826 size_t entry_name_len = 0;
1827 zend_long offset_start = 0, offset_len = 0;
1828 zend_string *filename;
1829 zend_long flags = ZIP_FL_OVERWRITE;
1830
1831 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|slll",
1832 &filename, &entry_name, &entry_name_len, &offset_start, &offset_len, &flags) == FAILURE) {
1833 RETURN_THROWS();
1834 }
1835
1836 if (ZSTR_LEN(filename) == 0) {
1837 zend_argument_value_error(1, "cannot be empty");
1838 RETURN_THROWS();
1839 }
1840
1841 if (entry_name_len == 0) {
1842 entry_name = ZSTR_VAL(filename);
1843 entry_name_len = ZSTR_LEN(filename);
1844 }
1845
1846 if (php_zip_add_file(Z_ZIP_P(self), ZSTR_VAL(filename), ZSTR_LEN(filename),
1847 entry_name, entry_name_len, offset_start, offset_len, -1, flags) < 0) {
1848 RETURN_FALSE;
1849 } else {
1850 RETURN_TRUE;
1851 }
1852 }
1853 /* }}} */
1854
1855 /* {{{ Add a file in a Zip archive using its path and the name to use. */
1856 PHP_METHOD(ZipArchive, replaceFile)
1857 {
1858 zval *self = ZEND_THIS;
1859 zend_long index;
1860 zend_long offset_start = 0, offset_len = 0;
1861 zend_string *filename;
1862 zend_long flags = 0;
1863
1864 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Pl|lll",
1865 &filename, &index, &offset_start, &offset_len, &flags) == FAILURE) {
1866 RETURN_THROWS();
1867 }
1868
1869 if (ZSTR_LEN(filename) == 0) {
1870 zend_argument_value_error(1, "cannot be empty");
1871 RETURN_THROWS();
1872 }
1873
1874 if (index < 0) {
1875 zend_argument_value_error(2, "must be greater than or equal to 0");
1876 RETURN_THROWS();
1877 }
1878
1879 if (php_zip_add_file(Z_ZIP_P(self), ZSTR_VAL(filename), ZSTR_LEN(filename),
1880 NULL, 0, offset_start, offset_len, index, flags) < 0) {
1881 RETURN_FALSE;
1882 } else {
1883 RETURN_TRUE;
1884 }
1885 }
1886 /* }}} */
1887
1888 /* {{{ Add a file using content and the entry name */
1889 PHP_METHOD(ZipArchive, addFromString)
1890 {
1891 struct zip *intern;
1892 zval *self = ZEND_THIS;
1893 zend_string *buffer;
1894 char *name;
1895 size_t name_len;
1896 ze_zip_object *ze_obj;
1897 struct zip_source *zs;
1898 int pos = 0;
1899 zend_long flags = ZIP_FL_OVERWRITE;
1900
1901 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS|l",
1902 &name, &name_len, &buffer, &flags) == FAILURE) {
1903 RETURN_THROWS();
1904 }
1905
1906 ZIP_FROM_OBJECT(intern, self);
1907
1908 ze_obj = Z_ZIP_P(self);
1909 if (ze_obj->buffers_cnt) {
1910 ze_obj->buffers = (char **)safe_erealloc(ze_obj->buffers, sizeof(char *), (ze_obj->buffers_cnt+1), 0);
1911 pos = ze_obj->buffers_cnt++;
1912 } else {
1913 ze_obj->buffers = (char **)emalloc(sizeof(char *));
1914 ze_obj->buffers_cnt++;
1915 pos = 0;
1916 }
1917 ze_obj->buffers[pos] = (char *)safe_emalloc(ZSTR_LEN(buffer), 1, 1);
1918 memcpy(ze_obj->buffers[pos], ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1);
1919
1920 zs = zip_source_buffer(intern, ze_obj->buffers[pos], ZSTR_LEN(buffer), 0);
1921
1922 if (zs == NULL) {
1923 RETURN_FALSE;
1924 }
1925
1926 ze_obj->last_id = zip_file_add(intern, name, zs, flags);
1927 if (ze_obj->last_id == -1) {
1928 zip_source_free(zs);
1929 RETURN_FALSE;
1930 } else {
1931 zip_error_clear(intern);
1932 RETURN_TRUE;
1933 }
1934 }
1935 /* }}} */
1936
1937 /* {{{ Returns the information about a the zip entry filename */
1938 PHP_METHOD(ZipArchive, statName)
1939 {
1940 struct zip *intern;
1941 zval *self = ZEND_THIS;
1942 zend_long flags = 0;
1943 struct zip_stat sb;
1944 zend_string *name;
1945
1946 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &name, &flags) == FAILURE) {
1947 RETURN_THROWS();
1948 }
1949
1950 ZIP_FROM_OBJECT(intern, self);
1951
1952 PHP_ZIP_STAT_PATH(intern, ZSTR_VAL(name), ZSTR_LEN(name), flags, sb);
1953
1954 RETURN_SB(&sb);
1955 }
1956 /* }}} */
1957
1958 /* {{{ Returns the zip entry information using its index */
1959 PHP_METHOD(ZipArchive, statIndex)
1960 {
1961 struct zip *intern;
1962 zval *self = ZEND_THIS;
1963 zend_long index, flags = 0;
1964
1965 struct zip_stat sb;
1966
1967 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l",
1968 &index, &flags) == FAILURE) {
1969 RETURN_THROWS();
1970 }
1971
1972 ZIP_FROM_OBJECT(intern, self);
1973
1974 if (zip_stat_index(intern, index, flags, &sb) != 0) {
1975 RETURN_FALSE;
1976 }
1977 RETURN_SB(&sb);
1978 }
1979 /* }}} */
1980
1981 /* {{{ Returns the index of the entry named filename in the archive */
1982 PHP_METHOD(ZipArchive, locateName)
1983 {
1984 struct zip *intern;
1985 zval *self = ZEND_THIS;
1986 zend_long flags = 0;
1987 zend_long idx = -1;
1988 zend_string *name;
1989
1990 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &name, &flags) == FAILURE) {
1991 RETURN_THROWS();
1992 }
1993
1994 ZIP_FROM_OBJECT(intern, self);
1995
1996 if (ZSTR_LEN(name) < 1) {
1997 RETURN_FALSE;
1998 }
1999
2000 idx = (zend_long)zip_name_locate(intern, (const char *)ZSTR_VAL(name), flags);
2001
2002 if (idx >= 0) {
2003 RETURN_LONG(idx);
2004 } else {
2005 RETURN_FALSE;
2006 }
2007 }
2008 /* }}} */
2009
2010 /* {{{ Returns the name of the file at position index */
2011 PHP_METHOD(ZipArchive, getNameIndex)
2012 {
2013 struct zip *intern;
2014 zval *self = ZEND_THIS;
2015 const char *name;
2016 zend_long flags = 0, index = 0;
2017
2018 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l",
2019 &index, &flags) == FAILURE) {
2020 RETURN_THROWS();
2021 }
2022
2023 ZIP_FROM_OBJECT(intern, self);
2024
2025 name = zip_get_name(intern, (int) index, flags);
2026
2027 if (name) {
2028 RETVAL_STRING((char *)name);
2029 } else {
2030 RETURN_FALSE;
2031 }
2032 }
2033 /* }}} */
2034
2035 /* {{{ Set or remove (NULL/'') the comment of the archive */
2036 PHP_METHOD(ZipArchive, setArchiveComment)
2037 {
2038 struct zip *intern;
2039 zval *self = ZEND_THIS;
2040 size_t comment_len;
2041 char * comment;
2042
2043 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &comment, &comment_len) == FAILURE) {
2044 RETURN_THROWS();
2045 }
2046
2047 ZIP_FROM_OBJECT(intern, self);
2048
2049 if (comment_len > 0xffff) {
2050 zend_argument_value_error(1, "must be less than 65535 bytes");
2051 RETURN_THROWS();
2052 }
2053
2054 if (zip_set_archive_comment(intern, (const char *)comment, comment_len)) {
2055 RETURN_FALSE;
2056 } else {
2057 RETURN_TRUE;
2058 }
2059 }
2060 /* }}} */
2061
2062 /* {{{ Returns the comment of an entry using its index */
2063 PHP_METHOD(ZipArchive, getArchiveComment)
2064 {
2065 struct zip *intern;
2066 zval *self = ZEND_THIS;
2067 zend_long flags = 0;
2068 const char * comment;
2069 int comment_len = 0;
2070
2071 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
2072 RETURN_THROWS();
2073 }
2074
2075 ZIP_FROM_OBJECT(intern, self);
2076
2077 comment = zip_get_archive_comment(intern, &comment_len, (int)flags);
2078 if(comment==NULL) {
2079 RETURN_FALSE;
2080 }
2081 RETURN_STRINGL((char *)comment, (zend_long)comment_len);
2082 }
2083 /* }}} */
2084
2085 /* {{{ Set or remove (NULL/'') the comment of an entry using its Name */
2086 PHP_METHOD(ZipArchive, setCommentName)
2087 {
2088 struct zip *intern;
2089 zval *self = ZEND_THIS;
2090 size_t comment_len, name_len;
2091 char * comment, *name;
2092 int idx;
2093
2094 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2095 &name, &name_len, &comment, &comment_len) == FAILURE) {
2096 RETURN_THROWS();
2097 }
2098
2099 if (name_len == 0) {
2100 zend_argument_value_error(1, "cannot be empty");
2101 RETURN_THROWS();
2102 }
2103
2104 ZIP_FROM_OBJECT(intern, self);
2105
2106 if (comment_len > 0xffff) {
2107 zend_argument_value_error(2, "must be less than 65535 bytes");
2108 RETURN_THROWS();
2109 }
2110
2111 idx = zip_name_locate(intern, name, 0);
2112 if (idx < 0) {
2113 RETURN_FALSE;
2114 }
2115 PHP_ZIP_SET_FILE_COMMENT(intern, idx, comment, comment_len);
2116 }
2117 /* }}} */
2118
2119 /* {{{ Set or remove (NULL/'') the comment of an entry using its index */
2120 PHP_METHOD(ZipArchive, setCommentIndex)
2121 {
2122 struct zip *intern;
2123 zval *self = ZEND_THIS;
2124 zend_long index;
2125 size_t comment_len;
2126 char * comment;
2127 struct zip_stat sb;
2128
2129 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls",
2130 &index, &comment, &comment_len) == FAILURE) {
2131 RETURN_THROWS();
2132 }
2133
2134 ZIP_FROM_OBJECT(intern, self);
2135
2136 if (comment_len > 0xffff) {
2137 zend_argument_value_error(2, "must be less than 65535 bytes");
2138 RETURN_THROWS();
2139 }
2140
2141 PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
2142 PHP_ZIP_SET_FILE_COMMENT(intern, index, comment, comment_len);
2143 }
2144 /* }}} */
2145
2146 /* those constants/functions are only available in libzip since 0.11.2 */
2147 #ifdef ZIP_OPSYS_DEFAULT
2148
2149 /* {{{ Set external attributes for file in zip, using its name */
2150 PHP_METHOD(ZipArchive, setExternalAttributesName)
2151 {
2152 struct zip *intern;
2153 zval *self = ZEND_THIS;
2154 size_t name_len;
2155 char *name;
2156 zend_long flags=0, opsys, attr;
2157 zip_int64_t idx;
2158
2159 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|l",
2160 &name, &name_len, &opsys, &attr, &flags) == FAILURE) {
2161 RETURN_THROWS();
2162 }
2163
2164 ZIP_FROM_OBJECT(intern, self);
2165
2166 if (name_len == 0) {
2167 zend_argument_value_error(1, "cannot be empty");
2168 RETURN_THROWS();
2169 }
2170
2171 idx = zip_name_locate(intern, name, 0);
2172
2173 if (idx < 0) {
2174 RETURN_FALSE;
2175 }
2176 if (zip_file_set_external_attributes(intern, idx, (zip_flags_t)flags,
2177 (zip_uint8_t)(opsys&0xff), (zip_uint32_t)attr) < 0) {
2178 RETURN_FALSE;
2179 }
2180 RETURN_TRUE;
2181 }
2182 /* }}} */
2183
2184 /* {{{ Set external attributes for file in zip, using its index */
2185 PHP_METHOD(ZipArchive, setExternalAttributesIndex)
2186 {
2187 struct zip *intern;
2188 zval *self = ZEND_THIS;
2189 zend_long index, flags=0, opsys, attr;
2190 struct zip_stat sb;
2191
2192 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll|l",
2193 &index, &opsys, &attr, &flags) == FAILURE) {
2194 RETURN_THROWS();
2195 }
2196
2197 ZIP_FROM_OBJECT(intern, self);
2198
2199 PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
2200 if (zip_file_set_external_attributes(intern, (zip_uint64_t)index,
2201 (zip_flags_t)flags, (zip_uint8_t)(opsys&0xff), (zip_uint32_t)attr) < 0) {
2202 RETURN_FALSE;
2203 }
2204 RETURN_TRUE;
2205 }
2206 /* }}} */
2207
2208 /* {{{ Get external attributes for file in zip, using its name */
2209 PHP_METHOD(ZipArchive, getExternalAttributesName)
2210 {
2211 struct zip *intern;
2212 zval *self = ZEND_THIS, *z_opsys, *z_attr;
2213 size_t name_len;
2214 char *name;
2215 zend_long flags=0;
2216 zip_uint8_t opsys;
2217 zip_uint32_t attr;
2218 zip_int64_t idx;
2219
2220 if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l",
2221 &name, &name_len, &z_opsys, &z_attr, &flags) == FAILURE) {
2222 RETURN_THROWS();
2223 }
2224
2225 ZIP_FROM_OBJECT(intern, self);
2226
2227 if (name_len == 0) {
2228 zend_argument_value_error(1, "cannot be empty");
2229 RETURN_THROWS();
2230 }
2231
2232 idx = zip_name_locate(intern, name, 0);
2233
2234 if (idx < 0) {
2235 RETURN_FALSE;
2236 }
2237 if (zip_file_get_external_attributes(intern, idx,
2238 (zip_flags_t)flags, &opsys, &attr) < 0) {
2239 RETURN_FALSE;
2240 }
2241 ZEND_TRY_ASSIGN_REF_LONG(z_opsys, opsys);
2242 ZEND_TRY_ASSIGN_REF_LONG(z_attr, attr);
2243 RETURN_TRUE;
2244 }
2245 /* }}} */
2246
2247 /* {{{ Get external attributes for file in zip, using its index */
2248 PHP_METHOD(ZipArchive, getExternalAttributesIndex)
2249 {
2250 struct zip *intern;
2251 zval *self = ZEND_THIS, *z_opsys, *z_attr;
2252 zend_long index, flags=0;
2253 zip_uint8_t opsys;
2254 zip_uint32_t attr;
2255 struct zip_stat sb;
2256
2257 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lzz|l",
2258 &index, &z_opsys, &z_attr, &flags) == FAILURE) {
2259 RETURN_THROWS();
2260 }
2261
2262 ZIP_FROM_OBJECT(intern, self);
2263
2264 PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
2265 if (zip_file_get_external_attributes(intern, (zip_uint64_t)index,
2266 (zip_flags_t)flags, &opsys, &attr) < 0) {
2267 RETURN_FALSE;
2268 }
2269 ZEND_TRY_ASSIGN_REF_LONG(z_opsys, opsys);
2270 ZEND_TRY_ASSIGN_REF_LONG(z_attr, attr);
2271 RETURN_TRUE;
2272 }
2273 /* }}} */
2274 #endif /* ifdef ZIP_OPSYS_DEFAULT */
2275
2276 #ifdef HAVE_ENCRYPTION
2277 /* {{{ Set encryption method for file in zip, using its name */
2278 PHP_METHOD(ZipArchive, setEncryptionName)
2279 {
2280 struct zip *intern;
2281 zval *self = ZEND_THIS;
2282 zend_long method;
2283 zip_int64_t idx;
2284 char *name, *password = NULL;
2285 size_t name_len, password_len;
2286
2287 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s!",
2288 &name, &name_len, &method, &password, &password_len) == FAILURE) {
2289 RETURN_THROWS();
2290 }
2291
2292 ZIP_FROM_OBJECT(intern, self);
2293
2294 if (name_len == 0) {
2295 zend_argument_value_error(1, "cannot be empty");
2296 RETURN_THROWS();
2297 }
2298
2299 idx = zip_name_locate(intern, name, 0);
2300
2301 if (idx < 0) {
2302 RETURN_FALSE;
2303 }
2304
2305 if (zip_file_set_encryption(intern, idx, (zip_uint16_t)method, password)) {
2306 RETURN_FALSE;
2307 }
2308 RETURN_TRUE;
2309 }
2310 /* }}} */
2311
2312 /* {{{ Set encryption method for file in zip, using its index */
2313 PHP_METHOD(ZipArchive, setEncryptionIndex)
2314 {
2315 struct zip *intern;
2316 zval *self = ZEND_THIS;
2317 zend_long index, method;
2318 char *password = NULL;
2319 size_t password_len;
2320
2321 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|s!",
2322 &index, &method, &password, &password_len) == FAILURE) {
2323 RETURN_THROWS();
2324 }
2325
2326 ZIP_FROM_OBJECT(intern, self);
2327
2328 if (zip_file_set_encryption(intern, index, (zip_uint16_t)method, password)) {
2329 RETURN_FALSE;
2330 }
2331 RETURN_TRUE;
2332 }
2333 /* }}} */
2334 #endif
2335
2336 /* {{{ Returns the comment of an entry using its name */
2337 PHP_METHOD(ZipArchive, getCommentName)
2338 {
2339 struct zip *intern;
2340 zval *self = ZEND_THIS;
2341 size_t name_len;
2342 int idx;
2343 zend_long flags = 0;
2344 zip_uint32_t comment_len = 0;
2345 const char * comment;
2346 char *name;
2347
2348 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
2349 &name, &name_len, &flags) == FAILURE) {
2350 RETURN_THROWS();
2351 }
2352
2353 ZIP_FROM_OBJECT(intern, self);
2354
2355 if (name_len == 0) {
2356 zend_argument_value_error(1, "cannot be empty");
2357 RETURN_THROWS();
2358 }
2359
2360 idx = zip_name_locate(intern, name, 0);
2361
2362 if (idx < 0) {
2363 RETURN_FALSE;
2364 }
2365
2366 comment = zip_file_get_comment(intern, idx, &comment_len, (zip_flags_t)flags);
2367 RETURN_STRINGL((char *)comment, comment_len);
2368 }
2369 /* }}} */
2370
2371 /* {{{ Returns the comment of an entry using its index */
2372 PHP_METHOD(ZipArchive, getCommentIndex)
2373 {
2374 struct zip *intern;
2375 zval *self = ZEND_THIS;
2376 zend_long index, flags = 0;
2377 const char * comment;
2378 zip_uint32_t comment_len = 0;
2379 struct zip_stat sb;
2380
2381 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l",
2382 &index, &flags) == FAILURE) {
2383 RETURN_THROWS();
2384 }
2385
2386 ZIP_FROM_OBJECT(intern, self);
2387
2388 PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
2389 comment = zip_file_get_comment(intern, index, &comment_len, (zip_flags_t)flags);
2390 RETURN_STRINGL((char *)comment, comment_len);
2391 }
2392 /* }}} */
2393
2394 /* {{{ Set the compression of a file in zip, using its name */
2395 PHP_METHOD(ZipArchive, setCompressionName)
2396 {
2397 struct zip *intern;
2398 zval *this = ZEND_THIS;
2399 size_t name_len;
2400 char *name;
2401 zip_int64_t idx;
2402 zend_long comp_method, comp_flags = 0;
2403
2404 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l",
2405 &name, &name_len, &comp_method, &comp_flags) == FAILURE) {
2406 RETURN_THROWS();
2407 }
2408
2409 ZIP_FROM_OBJECT(intern, this);
2410
2411 if (name_len == 0) {
2412 zend_argument_value_error(1, "cannot be empty");
2413 RETURN_THROWS();
2414 }
2415
2416 idx = zip_name_locate(intern, name, 0);
2417
2418 if (idx < 0) {
2419 RETURN_FALSE;
2420 }
2421
2422 if (zip_set_file_compression(intern, (zip_uint64_t)idx,
2423 (zip_int32_t)comp_method, (zip_uint32_t)comp_flags) != 0) {
2424 RETURN_FALSE;
2425 }
2426 RETURN_TRUE;
2427 }
2428 /* }}} */
2429
2430 /* {{{ Set the compression of a file in zip, using its index */
2431 PHP_METHOD(ZipArchive, setCompressionIndex)
2432 {
2433 struct zip *intern;
2434 zval *this = ZEND_THIS;
2435 zend_long index;
2436 zend_long comp_method, comp_flags = 0;
2437
2438 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|l",
2439 &index, &comp_method, &comp_flags) == FAILURE) {
2440 RETURN_THROWS();
2441 }
2442
2443 ZIP_FROM_OBJECT(intern, this);
2444
2445 if (zip_set_file_compression(intern, (zip_uint64_t)index,
2446 (zip_int32_t)comp_method, (zip_uint32_t)comp_flags) != 0) {
2447 RETURN_FALSE;
2448 }
2449 RETURN_TRUE;
2450 }
2451 /* }}} */
2452
2453 #ifdef HAVE_SET_MTIME
2454 /* {{{ Set the modification time of a file in zip, using its name */
2455 PHP_METHOD(ZipArchive, setMtimeName)
2456 {
2457 struct zip *intern;
2458 zval *this = ZEND_THIS;
2459 size_t name_len;
2460 char *name;
2461 zip_int64_t idx;
2462 zend_long mtime, flags = 0;
2463
2464 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|l",
2465 &name, &name_len, &mtime, &flags) == FAILURE) {
2466 RETURN_THROWS();
2467 }
2468
2469 ZIP_FROM_OBJECT(intern, this);
2470
2471 if (name_len == 0) {
2472 zend_argument_value_error(1, "cannot be empty");
2473 RETURN_THROWS();
2474 }
2475
2476 idx = zip_name_locate(intern, name, 0);
2477
2478 if (idx < 0) {
2479 RETURN_FALSE;
2480 }
2481
2482 if (zip_file_set_mtime(intern, (zip_uint64_t)idx,
2483 (time_t)mtime, (zip_uint32_t)flags) != 0) {
2484 RETURN_FALSE;
2485 }
2486 RETURN_TRUE;
2487 }
2488 /* }}} */
2489
2490 /* {{{ Set the modification time of a file in zip, using its index */
2491 PHP_METHOD(ZipArchive, setMtimeIndex)
2492 {
2493 struct zip *intern;
2494 zval *this = ZEND_THIS;
2495 zend_long index;
2496 zend_long mtime, flags = 0;
2497
2498 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|l",
2499 &index, &mtime, &flags) == FAILURE) {
2500 RETURN_THROWS();
2501 }
2502
2503 ZIP_FROM_OBJECT(intern, this);
2504
2505 if (zip_file_set_mtime(intern, (zip_uint64_t)index,
2506 (time_t)mtime, (zip_uint32_t)flags) != 0) {
2507 RETURN_FALSE;
2508 }
2509 RETURN_TRUE;
2510 }
2511 /* }}} */
2512 #endif
2513
2514 /* {{{ Delete a file using its index */
2515 PHP_METHOD(ZipArchive, deleteIndex)
2516 {
2517 struct zip *intern;
2518 zval *self = ZEND_THIS;
2519 zend_long index;
2520
2521 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
2522 RETURN_THROWS();
2523 }
2524
2525 ZIP_FROM_OBJECT(intern, self);
2526
2527 if (index < 0) {
2528 RETURN_FALSE;
2529 }
2530
2531 if (zip_delete(intern, index) < 0) {
2532 RETURN_FALSE;
2533 }
2534
2535 RETURN_TRUE;
2536 }
2537 /* }}} */
2538
2539 /* {{{ Delete a file using its index */
2540 PHP_METHOD(ZipArchive, deleteName)
2541 {
2542 struct zip *intern;
2543 zval *self = ZEND_THIS;
2544 size_t name_len;
2545 char *name;
2546 struct zip_stat sb;
2547
2548 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
2549 RETURN_THROWS();
2550 }
2551
2552 ZIP_FROM_OBJECT(intern, self);
2553
2554 if (name_len < 1) {
2555 RETURN_FALSE;
2556 }
2557
2558 PHP_ZIP_STAT_PATH(intern, name, name_len, 0, sb);
2559 if (zip_delete(intern, sb.index)) {
2560 RETURN_FALSE;
2561 }
2562 RETURN_TRUE;
2563 }
2564 /* }}} */
2565
2566 /* {{{ Rename an entry selected by its index to new_name */
2567 PHP_METHOD(ZipArchive, renameIndex)
2568 {
2569 struct zip *intern;
2570 zval *self = ZEND_THIS;
2571 char *new_name;
2572 size_t new_name_len;
2573 zend_long index;
2574
2575 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &index, &new_name, &new_name_len) == FAILURE) {
2576 RETURN_THROWS();
2577 }
2578
2579 if (index < 0) {
2580 RETURN_FALSE;
2581 }
2582
2583 ZIP_FROM_OBJECT(intern, self);
2584
2585 if (new_name_len == 0) {
2586 zend_argument_value_error(2, "cannot be empty");
2587 RETURN_THROWS();
2588 }
2589
2590 if (zip_file_rename(intern, index, (const char *)new_name, 0) != 0) {
2591 RETURN_FALSE;
2592 }
2593
2594 RETURN_TRUE;
2595 }
2596 /* }}} */
2597
2598 /* {{{ Rename an entry selected by its name to new_name */
2599 PHP_METHOD(ZipArchive, renameName)
2600 {
2601 struct zip *intern;
2602 zval *self = ZEND_THIS;
2603 struct zip_stat sb;
2604 char *name, *new_name;
2605 size_t name_len, new_name_len;
2606
2607 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name, &name_len, &new_name, &new_name_len) == FAILURE) {
2608 RETURN_THROWS();
2609 }
2610
2611 ZIP_FROM_OBJECT(intern, self);
2612
2613 if (new_name_len == 0) {
2614 zend_argument_value_error(2, "cannot be empty");
2615 RETURN_THROWS();
2616 }
2617
2618 PHP_ZIP_STAT_PATH(intern, name, name_len, 0, sb);
2619
2620 if (zip_file_rename(intern, sb.index, (const char *)new_name, 0)) {
2621 RETURN_FALSE;
2622 }
2623
2624 RETURN_TRUE;
2625 }
2626 /* }}} */
2627
2628 /* {{{ Changes to the file at position index are reverted */
2629 PHP_METHOD(ZipArchive, unchangeIndex)
2630 {
2631 struct zip *intern;
2632 zval *self = ZEND_THIS;
2633 zend_long index;
2634
2635 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
2636 RETURN_THROWS();
2637 }
2638
2639 ZIP_FROM_OBJECT(intern, self);
2640
2641 if (index < 0) {
2642 RETURN_FALSE;
2643 }
2644
2645 if (zip_unchange(intern, index) != 0) {
2646 RETURN_FALSE;
2647 } else {
2648 RETURN_TRUE;
2649 }
2650 }
2651 /* }}} */
2652
2653 /* {{{ Changes to the file named 'name' are reverted */
2654 PHP_METHOD(ZipArchive, unchangeName)
2655 {
2656 struct zip *intern;
2657 zval *self = ZEND_THIS;
2658 struct zip_stat sb;
2659 char *name;
2660 size_t name_len;
2661
2662 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
2663 RETURN_THROWS();
2664 }
2665
2666 ZIP_FROM_OBJECT(intern, self);
2667
2668 if (name_len < 1) {
2669 RETURN_FALSE;
2670 }
2671
2672 PHP_ZIP_STAT_PATH(intern, name, name_len, 0, sb);
2673
2674 if (zip_unchange(intern, sb.index) != 0) {
2675 RETURN_FALSE;
2676 } else {
2677 RETURN_TRUE;
2678 }
2679 }
2680 /* }}} */
2681
2682 /* {{{ All changes to files and global information in archive are reverted */
2683 PHP_METHOD(ZipArchive, unchangeAll)
2684 {
2685 struct zip *intern;
2686 zval *self = ZEND_THIS;
2687
2688 if (zend_parse_parameters_none() == FAILURE) {
2689 RETURN_THROWS();
2690 }
2691
2692 ZIP_FROM_OBJECT(intern, self);
2693
2694 if (zip_unchange_all(intern) != 0) {
2695 RETURN_FALSE;
2696 } else {
2697 RETURN_TRUE;
2698 }
2699 }
2700 /* }}} */
2701
2702 /* {{{ Revert all global changes to the archive archive. For now, this only reverts archive comment changes. */
2703 PHP_METHOD(ZipArchive, unchangeArchive)
2704 {
2705 struct zip *intern;
2706 zval *self = ZEND_THIS;
2707
2708 if (zend_parse_parameters_none() == FAILURE) {
2709 RETURN_THROWS();
2710 }
2711
2712 ZIP_FROM_OBJECT(intern, self);
2713
2714 if (zip_unchange_archive(intern) != 0) {
2715 RETURN_FALSE;
2716 } else {
2717 RETURN_TRUE;
2718 }
2719 }
2720 /* }}} */
2721
2722 /* {{{ Extract one or more file from a zip archive */
2723 /* TODO:
2724 * - allow index or array of indices
2725 * - replace path
2726 * - patterns
2727 */
2728 PHP_METHOD(ZipArchive, extractTo)
2729 {
2730 struct zip *intern;
2731
2732 zval *self = ZEND_THIS;
2733 zend_string *files_str = NULL;
2734 HashTable *files_ht = NULL;
2735
2736 php_stream_statbuf ssb;
2737 char *pathto;
2738 size_t pathto_len;
2739 int ret;
2740
2741 ZEND_PARSE_PARAMETERS_START(1, 2)
2742 Z_PARAM_PATH(pathto, pathto_len)
2743 Z_PARAM_OPTIONAL
2744 Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(files_ht, files_str)
2745 ZEND_PARSE_PARAMETERS_END();
2746
2747 ZIP_FROM_OBJECT(intern, self);
2748
2749 if (pathto_len < 1) {
2750 RETURN_FALSE;
2751 }
2752
2753 if (php_stream_stat_path_ex(pathto, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL) < 0) {
2754 ret = php_stream_mkdir(pathto, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL);
2755 if (!ret) {
2756 RETURN_FALSE;
2757 }
2758 }
2759
2760 uint32_t nelems, i;
2761
2762 if (files_str) {
2763 if (!php_zip_extract_file(intern, pathto, ZSTR_VAL(files_str), ZSTR_LEN(files_str))) {
2764 RETURN_FALSE;
2765 }
2766 } else if (files_ht) {
2767 nelems = zend_hash_num_elements(files_ht);
2768 if (nelems == 0 ) {
2769 RETURN_FALSE;
2770 }
2771 for (i = 0; i < nelems; i++) {
2772 zval *zval_file;
2773 if ((zval_file = zend_hash_index_find_deref(files_ht, i)) != NULL) {
2774 switch (Z_TYPE_P(zval_file)) {
2775 case IS_LONG:
2776 break;
2777 case IS_STRING:
2778 if (!php_zip_extract_file(intern, pathto, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file))) {
2779 RETURN_FALSE;
2780 }
2781 break;
2782 }
2783 }
2784 }
2785 } else {
2786 /* Extract all files */
2787 zip_int64_t i, filecount = zip_get_num_entries(intern, 0);
2788
2789 if (filecount == -1) {
2790 php_error_docref(NULL, E_WARNING, "Illegal archive");
2791 RETURN_FALSE;
2792 }
2793
2794 for (i = 0; i < filecount; i++) {
2795 char *file = (char*)zip_get_name(intern, i, ZIP_FL_UNCHANGED);
2796 if (!file || !php_zip_extract_file(intern, pathto, file, strlen(file))) {
2797 RETURN_FALSE;
2798 }
2799 }
2800 }
2801
2802 RETURN_TRUE;
2803 }
2804 /* }}} */
2805
2806 static void php_zip_get_from(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
2807 {
2808 struct zip *intern;
2809 zval *self = ZEND_THIS;
2810
2811 struct zip_stat sb;
2812 struct zip_file *zf;
2813
2814 zend_long index = -1;
2815 zend_long flags = 0;
2816 zend_long len = 0;
2817
2818 zend_string *filename;
2819 zend_string *buffer;
2820
2821 int n = 0;
2822
2823 if (type == 1) {
2824 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|ll", &filename, &len, &flags) == FAILURE) {
2825 RETURN_THROWS();
2826 }
2827
2828 ZIP_FROM_OBJECT(intern, self);
2829
2830 PHP_ZIP_STAT_PATH(intern, ZSTR_VAL(filename), ZSTR_LEN(filename), flags, sb);
2831 } else {
2832 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|ll", &index, &len, &flags) == FAILURE) {
2833 RETURN_THROWS();
2834 }
2835
2836 ZIP_FROM_OBJECT(intern, self);
2837
2838 PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
2839 }
2840
2841 if (sb.size < 1) {
2842 RETURN_EMPTY_STRING();
2843 }
2844
2845 if (len < 1) {
2846 len = sb.size;
2847 }
2848 if (index >= 0) {
2849 zf = zip_fopen_index(intern, index, flags);
2850 } else {
2851 zf = zip_fopen(intern, ZSTR_VAL(filename), flags);
2852 }
2853
2854 if (zf == NULL) {
2855 RETURN_FALSE;
2856 }
2857
2858 buffer = zend_string_safe_alloc(1, len, 0, 0);
2859 n = zip_fread(zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer));
2860 if (n < 1) {
2861 zend_string_efree(buffer);
2862 RETURN_EMPTY_STRING();
2863 }
2864
2865 zip_fclose(zf);
2866 ZSTR_VAL(buffer)[n] = '\0';
2867 ZSTR_LEN(buffer) = n;
2868 RETURN_NEW_STR(buffer);
2869 }
2870 /* }}} */
2871
2872 /* {{{ get the contents of an entry using its name */
2873 PHP_METHOD(ZipArchive, getFromName)
2874 {
2875 php_zip_get_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2876 }
2877 /* }}} */
2878
2879 /* {{{ get the contents of an entry using its index */
2880 PHP_METHOD(ZipArchive, getFromIndex)
2881 {
2882 php_zip_get_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2883 }
2884 /* }}} */
2885
2886 /* {{{ get a stream for an entry using its name */
2887 PHP_METHOD(ZipArchive, getStream)
2888 {
2889 struct zip *intern;
2890 zval *self = ZEND_THIS;
2891 struct zip_stat sb;
2892 char *mode = "rb";
2893 zend_string *filename;
2894 php_stream *stream;
2895
2896 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &filename) == FAILURE) {
2897 RETURN_THROWS();
2898 }
2899
2900 ZIP_FROM_OBJECT(intern, self);
2901
2902 if (zip_stat(intern, ZSTR_VAL(filename), 0, &sb) != 0) {
2903 RETURN_FALSE;
2904 }
2905
2906 stream = php_stream_zip_open(intern, ZSTR_VAL(filename), mode STREAMS_CC);
2907 if (stream) {
2908 php_stream_to_zval(stream, return_value);
2909 } else {
2910 RETURN_FALSE;
2911 }
2912 }
2913 /* }}} */
2914
2915 #ifdef HAVE_PROGRESS_CALLBACK
2916 static void _php_zip_progress_callback(zip_t *arch, double state, void *ptr)
2917 {
2918 zval cb_args[1];
2919 zval cb_retval;
2920 ze_zip_object *obj = ptr;
2921
2922 ZVAL_DOUBLE(&cb_args[0], state);
2923 if (call_user_function(EG(function_table), NULL, &obj->progress_callback, &cb_retval, 1, cb_args) == SUCCESS && !Z_ISUNDEF(cb_retval)) {
2924 zval_ptr_dtor(&cb_retval);
2925 }
2926 }
2927
2928 /* {{{ register a progression callback: void callback(double state); */
2929 PHP_METHOD(ZipArchive, registerProgressCallback)
2930 {
2931 struct zip *intern;
2932 zval *self = ZEND_THIS;
2933 double rate;
2934 zend_fcall_info fci;
2935 zend_fcall_info_cache fcc;
2936 ze_zip_object *obj;
2937
2938 if (zend_parse_parameters(ZEND_NUM_ARGS(), "df", &rate, &fci, &fcc) == FAILURE) {
2939 RETURN_THROWS();
2940 }
2941
2942 ZIP_FROM_OBJECT(intern, self);
2943
2944 obj = Z_ZIP_P(self);
2945
2946 /* free if called twice */
2947 _php_zip_progress_callback_free(obj);
2948
2949 /* register */
2950 ZVAL_COPY(&obj->progress_callback, &fci.function_name);
2951 if (zip_register_progress_callback_with_state(intern, rate, _php_zip_progress_callback, _php_zip_progress_callback_free, obj)) {
2952 RETURN_FALSE;
2953 }
2954
2955 RETURN_TRUE;
2956 }
2957 /* }}} */
2958 #endif
2959
2960 #ifdef HAVE_CANCEL_CALLBACK
2961 static int _php_zip_cancel_callback(zip_t *arch, void *ptr)
2962 {
2963 zval cb_retval;
2964 int retval = 0;
2965 ze_zip_object *obj = ptr;
2966
2967 if (call_user_function(EG(function_table), NULL, &obj->cancel_callback, &cb_retval, 0, NULL) == SUCCESS && !Z_ISUNDEF(cb_retval)) {
2968 retval = zval_get_long(&cb_retval);
2969 zval_ptr_dtor(&cb_retval);
2970 }
2971
2972 return retval;
2973 }
2974
2975 /* {{{ register a progression callback: int callback(double state); */
2976 PHP_METHOD(ZipArchive, registerCancelCallback)
2977 {
2978 struct zip *intern;
2979 zval *self = ZEND_THIS;
2980 zend_fcall_info fci;
2981 zend_fcall_info_cache fcc;
2982 ze_zip_object *obj;
2983 if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fcc) == FAILURE) {
2984 RETURN_THROWS();
2985 }
2986
2987 ZIP_FROM_OBJECT(intern, self);
2988
2989 obj = Z_ZIP_P(self);
2990
2991 /* free if called twice */
2992 _php_zip_cancel_callback_free(obj);
2993
2994 /* register */
2995 ZVAL_COPY(&obj->cancel_callback, &fci.function_name);
2996 if (zip_register_cancel_callback_with_state(intern, _php_zip_cancel_callback, _php_zip_cancel_callback_free, obj)) {
2997 RETURN_FALSE;
2998 }
2999
3000 RETURN_TRUE;
3001 }
3002 /* }}} */
3003 #endif
3004
3005 #ifdef HAVE_METHOD_SUPPORTED
3006 /* {{{ check if a compression method is available in used libzip */
3007 PHP_METHOD(ZipArchive, isCompressionMethodSupported)
3008 {
3009 zend_long method;
3010 bool enc = 1;
3011
3012 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &method, &enc) == FAILURE) {
3013 return;
3014 }
3015 RETVAL_BOOL(zip_compression_method_supported((zip_int32_t)method, enc));
3016 }
3017 /* }}} */
3018
3019 /* {{{ check if a encryption method is available in used libzip */
3020 PHP_METHOD(ZipArchive, isEncryptionMethodSupported)
3021 {
3022 zend_long method;
3023 bool enc = 1;
3024
3025 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &method, &enc) == FAILURE) {
3026 return;
3027 }
3028 RETVAL_BOOL(zip_encryption_method_supported((zip_uint16_t)method, enc));
3029 }
3030 /* }}} */
3031 #endif
3032
3033 static void php_zip_free_prop_handler(zval *el) /* {{{ */ {
3034 pefree(Z_PTR_P(el), 1);
3035 } /* }}} */
3036
3037 /* {{{ PHP_MINIT_FUNCTION */
3038 static PHP_MINIT_FUNCTION(zip)
3039 {
3040 memcpy(&zip_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
3041 zip_object_handlers.offset = XtOffsetOf(ze_zip_object, zo);
3042 zip_object_handlers.free_obj = php_zip_object_free_storage;
3043 zip_object_handlers.clone_obj = NULL;
3044 zip_object_handlers.get_property_ptr_ptr = php_zip_get_property_ptr_ptr;
3045
3046 zip_object_handlers.get_gc = php_zip_get_gc;
3047 zip_object_handlers.get_properties = php_zip_get_properties;
3048 zip_object_handlers.read_property = php_zip_read_property;
3049 zip_object_handlers.has_property = php_zip_has_property;
3050 zip_object_handlers.write_property = php_zip_write_property;
3051
3052 zip_class_entry = register_class_ZipArchive(zend_ce_countable);
3053 zip_class_entry->create_object = php_zip_object_new;
3054
3055 zend_hash_init(&zip_prop_handlers, 0, NULL, php_zip_free_prop_handler, 1);
3056 php_zip_register_prop_handler(&zip_prop_handlers, "lastId", php_zip_last_id, NULL, IS_LONG);
3057 php_zip_register_prop_handler(&zip_prop_handlers, "status", php_zip_status, NULL, IS_LONG);
3058 php_zip_register_prop_handler(&zip_prop_handlers, "statusSys", php_zip_status_sys, NULL, IS_LONG);
3059 php_zip_register_prop_handler(&zip_prop_handlers, "numFiles", php_zip_get_num_files, NULL, IS_LONG);
3060 php_zip_register_prop_handler(&zip_prop_handlers, "filename", NULL, php_zipobj_get_filename, IS_STRING);
3061 php_zip_register_prop_handler(&zip_prop_handlers, "comment", NULL, php_zipobj_get_zip_comment, IS_STRING);
3062
3063 REGISTER_ZIP_CLASS_CONST_LONG("CREATE", ZIP_CREATE);
3064 REGISTER_ZIP_CLASS_CONST_LONG("EXCL", ZIP_EXCL);
3065 REGISTER_ZIP_CLASS_CONST_LONG("CHECKCONS", ZIP_CHECKCONS);
3066 REGISTER_ZIP_CLASS_CONST_LONG("OVERWRITE", ZIP_OVERWRITE);
3067 #ifdef ZIP_RDONLY
3068 REGISTER_ZIP_CLASS_CONST_LONG("RDONLY", ZIP_RDONLY);
3069 #endif
3070
3071 REGISTER_ZIP_CLASS_CONST_LONG("FL_NOCASE", ZIP_FL_NOCASE);
3072 REGISTER_ZIP_CLASS_CONST_LONG("FL_NODIR", ZIP_FL_NODIR);
3073 REGISTER_ZIP_CLASS_CONST_LONG("FL_COMPRESSED", ZIP_FL_COMPRESSED);
3074 REGISTER_ZIP_CLASS_CONST_LONG("FL_UNCHANGED", ZIP_FL_UNCHANGED);
3075 REGISTER_ZIP_CLASS_CONST_LONG("FL_RECOMPRESS", ZIP_FL_RECOMPRESS);
3076 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENCRYPTED", ZIP_FL_ENCRYPTED);
3077 REGISTER_ZIP_CLASS_CONST_LONG("FL_OVERWRITE", ZIP_FL_OVERWRITE);
3078 REGISTER_ZIP_CLASS_CONST_LONG("FL_LOCAL", ZIP_FL_LOCAL);
3079 REGISTER_ZIP_CLASS_CONST_LONG("FL_CENTRAL", ZIP_FL_CENTRAL);
3080
3081 /* Default filename encoding policy. */
3082 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENC_GUESS", ZIP_FL_ENC_GUESS);
3083 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENC_RAW", ZIP_FL_ENC_RAW);
3084 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENC_STRICT", ZIP_FL_ENC_STRICT);
3085 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENC_UTF_8", ZIP_FL_ENC_UTF_8);
3086 REGISTER_ZIP_CLASS_CONST_LONG("FL_ENC_CP437", ZIP_FL_ENC_CP437);
3087
3088 REGISTER_ZIP_CLASS_CONST_LONG("CM_DEFAULT", ZIP_CM_DEFAULT);
3089 REGISTER_ZIP_CLASS_CONST_LONG("CM_STORE", ZIP_CM_STORE);
3090 REGISTER_ZIP_CLASS_CONST_LONG("CM_SHRINK", ZIP_CM_SHRINK);
3091 REGISTER_ZIP_CLASS_CONST_LONG("CM_REDUCE_1", ZIP_CM_REDUCE_1);
3092 REGISTER_ZIP_CLASS_CONST_LONG("CM_REDUCE_2", ZIP_CM_REDUCE_2);
3093 REGISTER_ZIP_CLASS_CONST_LONG("CM_REDUCE_3", ZIP_CM_REDUCE_3);
3094 REGISTER_ZIP_CLASS_CONST_LONG("CM_REDUCE_4", ZIP_CM_REDUCE_4);
3095 REGISTER_ZIP_CLASS_CONST_LONG("CM_IMPLODE", ZIP_CM_IMPLODE);
3096 REGISTER_ZIP_CLASS_CONST_LONG("CM_DEFLATE", ZIP_CM_DEFLATE);
3097 REGISTER_ZIP_CLASS_CONST_LONG("CM_DEFLATE64", ZIP_CM_DEFLATE64);
3098 REGISTER_ZIP_CLASS_CONST_LONG("CM_PKWARE_IMPLODE", ZIP_CM_PKWARE_IMPLODE);
3099 REGISTER_ZIP_CLASS_CONST_LONG("CM_BZIP2", ZIP_CM_BZIP2);
3100 REGISTER_ZIP_CLASS_CONST_LONG("CM_LZMA", ZIP_CM_LZMA);
3101 #ifdef ZIP_CM_LZMA2
3102 REGISTER_ZIP_CLASS_CONST_LONG("CM_LZMA2", ZIP_CM_LZMA2);
3103 #endif
3104 #ifdef ZIP_CM_ZSTD
3105 REGISTER_ZIP_CLASS_CONST_LONG("CM_ZSTD", ZIP_CM_ZSTD);
3106 #endif
3107 #ifdef ZIP_CM_XZ
3108 REGISTER_ZIP_CLASS_CONST_LONG("CM_XZ", ZIP_CM_XZ);
3109 #endif
3110 REGISTER_ZIP_CLASS_CONST_LONG("CM_TERSE", ZIP_CM_TERSE);
3111 REGISTER_ZIP_CLASS_CONST_LONG("CM_LZ77", ZIP_CM_LZ77);
3112 REGISTER_ZIP_CLASS_CONST_LONG("CM_WAVPACK", ZIP_CM_WAVPACK);
3113 REGISTER_ZIP_CLASS_CONST_LONG("CM_PPMD", ZIP_CM_PPMD);
3114
3115 /* Error code */
3116 REGISTER_ZIP_CLASS_CONST_LONG("ER_OK", ZIP_ER_OK); /* N No error */
3117 REGISTER_ZIP_CLASS_CONST_LONG("ER_MULTIDISK", ZIP_ER_MULTIDISK); /* N Multi-disk zip archives not supported */
3118 REGISTER_ZIP_CLASS_CONST_LONG("ER_RENAME", ZIP_ER_RENAME); /* S Renaming temporary file failed */
3119 REGISTER_ZIP_CLASS_CONST_LONG("ER_CLOSE", ZIP_ER_CLOSE); /* S Closing zip archive failed */
3120 REGISTER_ZIP_CLASS_CONST_LONG("ER_SEEK", ZIP_ER_SEEK); /* S Seek error */
3121 REGISTER_ZIP_CLASS_CONST_LONG("ER_READ", ZIP_ER_READ); /* S Read error */
3122 REGISTER_ZIP_CLASS_CONST_LONG("ER_WRITE", ZIP_ER_WRITE); /* S Write error */
3123 REGISTER_ZIP_CLASS_CONST_LONG("ER_CRC", ZIP_ER_CRC); /* N CRC error */
3124 REGISTER_ZIP_CLASS_CONST_LONG("ER_ZIPCLOSED", ZIP_ER_ZIPCLOSED); /* N Containing zip archive was closed */
3125 REGISTER_ZIP_CLASS_CONST_LONG("ER_NOENT", ZIP_ER_NOENT); /* N No such file */
3126 REGISTER_ZIP_CLASS_CONST_LONG("ER_EXISTS", ZIP_ER_EXISTS); /* N File already exists */
3127 REGISTER_ZIP_CLASS_CONST_LONG("ER_OPEN", ZIP_ER_OPEN); /* S Can't open file */
3128 REGISTER_ZIP_CLASS_CONST_LONG("ER_TMPOPEN", ZIP_ER_TMPOPEN); /* S Failure to create temporary file */
3129 REGISTER_ZIP_CLASS_CONST_LONG("ER_ZLIB", ZIP_ER_ZLIB); /* Z Zlib error */
3130 REGISTER_ZIP_CLASS_CONST_LONG("ER_MEMORY", ZIP_ER_MEMORY); /* N Malloc failure */
3131 REGISTER_ZIP_CLASS_CONST_LONG("ER_CHANGED", ZIP_ER_CHANGED); /* N Entry has been changed */
3132 REGISTER_ZIP_CLASS_CONST_LONG("ER_COMPNOTSUPP", ZIP_ER_COMPNOTSUPP);/* N Compression method not supported */
3133 REGISTER_ZIP_CLASS_CONST_LONG("ER_EOF", ZIP_ER_EOF); /* N Premature EOF */
3134 REGISTER_ZIP_CLASS_CONST_LONG("ER_INVAL", ZIP_ER_INVAL); /* N Invalid argument */
3135 REGISTER_ZIP_CLASS_CONST_LONG("ER_NOZIP", ZIP_ER_NOZIP); /* N Not a zip archive */
3136 REGISTER_ZIP_CLASS_CONST_LONG("ER_INTERNAL", ZIP_ER_INTERNAL); /* N Internal error */
3137 REGISTER_ZIP_CLASS_CONST_LONG("ER_INCONS", ZIP_ER_INCONS); /* N Zip archive inconsistent */
3138 REGISTER_ZIP_CLASS_CONST_LONG("ER_REMOVE", ZIP_ER_REMOVE); /* S Can't remove file */
3139 REGISTER_ZIP_CLASS_CONST_LONG("ER_DELETED", ZIP_ER_DELETED); /* N Entry has been deleted */
3140 REGISTER_ZIP_CLASS_CONST_LONG("ER_ENCRNOTSUPP", ZIP_ER_ENCRNOTSUPP);/* N Encryption method not supported */
3141 REGISTER_ZIP_CLASS_CONST_LONG("ER_RDONLY", ZIP_ER_RDONLY); /* N Read-only archive */
3142 REGISTER_ZIP_CLASS_CONST_LONG("ER_NOPASSWD", ZIP_ER_NOPASSWD); /* N Entry has been deleted */
3143 REGISTER_ZIP_CLASS_CONST_LONG("ER_WRONGPASSWD", ZIP_ER_WRONGPASSWD);/* N Wrong password provided */
3144 /* since 1.0.0 */
3145 #ifdef ZIP_ER_OPNOTSUPP
3146 REGISTER_ZIP_CLASS_CONST_LONG("ER_OPNOTSUPP", ZIP_ER_OPNOTSUPP); /* N Operation not supported */
3147 #endif
3148 #ifdef ZIP_ER_INUSE
3149 REGISTER_ZIP_CLASS_CONST_LONG("ER_INUSE", ZIP_ER_INUSE); /* N Resource still in use */
3150 #endif
3151 #ifdef ZIP_ER_TELL
3152 REGISTER_ZIP_CLASS_CONST_LONG("ER_TELL", ZIP_ER_TELL); /* S Tell error */
3153 #endif
3154 /* since 1.6.0 */
3155 #ifdef ZIP_ER_COMPRESSED_DATA
3156 REGISTER_ZIP_CLASS_CONST_LONG("ER_COMPRESSED_DATA", ZIP_ER_COMPRESSED_DATA);/* N Compressed data invalid */
3157 #endif
3158 #ifdef ZIP_ER_CANCELLED
3159 REGISTER_ZIP_CLASS_CONST_LONG("ER_CANCELLED", ZIP_ER_CANCELLED); /* N Operation cancelled */
3160 #endif
3161
3162 #ifdef ZIP_OPSYS_DEFAULT
3163 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_DOS", ZIP_OPSYS_DOS);
3164 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_AMIGA", ZIP_OPSYS_AMIGA);
3165 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_OPENVMS", ZIP_OPSYS_OPENVMS);
3166 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_UNIX", ZIP_OPSYS_UNIX);
3167 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_VM_CMS", ZIP_OPSYS_VM_CMS);
3168 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_ATARI_ST", ZIP_OPSYS_ATARI_ST);
3169 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_OS_2", ZIP_OPSYS_OS_2);
3170 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_MACINTOSH", ZIP_OPSYS_MACINTOSH);
3171 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_Z_SYSTEM", ZIP_OPSYS_Z_SYSTEM);
3172 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_CPM", ZIP_OPSYS_CPM);
3173 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_WINDOWS_NTFS", ZIP_OPSYS_WINDOWS_NTFS);
3174 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_MVS", ZIP_OPSYS_MVS);
3175 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_VSE", ZIP_OPSYS_VSE);
3176 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_ACORN_RISC", ZIP_OPSYS_ACORN_RISC);
3177 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_VFAT", ZIP_OPSYS_VFAT);
3178 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_ALTERNATE_MVS", ZIP_OPSYS_ALTERNATE_MVS);
3179 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_BEOS", ZIP_OPSYS_BEOS);
3180 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_TANDEM", ZIP_OPSYS_TANDEM);
3181 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_OS_400", ZIP_OPSYS_OS_400);
3182 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_OS_X", ZIP_OPSYS_OS_X);
3183
3184 REGISTER_ZIP_CLASS_CONST_LONG("OPSYS_DEFAULT", ZIP_OPSYS_DEFAULT);
3185 #endif /* ifdef ZIP_OPSYS_DEFAULT */
3186
3187 REGISTER_ZIP_CLASS_CONST_LONG("EM_NONE", ZIP_EM_NONE);
3188 REGISTER_ZIP_CLASS_CONST_LONG("EM_TRAD_PKWARE", ZIP_EM_TRAD_PKWARE);
3189 #ifdef HAVE_ENCRYPTION
3190 REGISTER_ZIP_CLASS_CONST_LONG("EM_AES_128", ZIP_EM_AES_128);
3191 REGISTER_ZIP_CLASS_CONST_LONG("EM_AES_192", ZIP_EM_AES_192);
3192 REGISTER_ZIP_CLASS_CONST_LONG("EM_AES_256", ZIP_EM_AES_256);
3193 #endif
3194 REGISTER_ZIP_CLASS_CONST_LONG("EM_UNKNOWN", ZIP_EM_UNKNOWN);
3195
3196 #ifdef HAVE_LIBZIP_VERSION
3197 zend_declare_class_constant_string(zip_class_entry, "LIBZIP_VERSION", sizeof("LIBZIP_VERSION")-1, zip_libzip_version());
3198 #else
3199 zend_declare_class_constant_string(zip_class_entry, "LIBZIP_VERSION", sizeof("LIBZIP_VERSION")-1, LIBZIP_VERSION);
3200 #endif
3201
3202 php_register_url_stream_wrapper("zip", &php_stream_zip_wrapper);
3203
3204 le_zip_dir = zend_register_list_destructors_ex(php_zip_free_dir, NULL, le_zip_dir_name, module_number);
3205 le_zip_entry = zend_register_list_destructors_ex(php_zip_free_entry, NULL, le_zip_entry_name, module_number);
3206
3207 return SUCCESS;
3208 }
3209 /* }}} */
3210
3211 /* {{{ PHP_MSHUTDOWN_FUNCTION */
3212 static PHP_MSHUTDOWN_FUNCTION(zip)
3213 {
3214 zend_hash_destroy(&zip_prop_handlers);
3215 php_unregister_url_stream_wrapper("zip");
3216 return SUCCESS;
3217 }
3218 /* }}} */
3219
3220 /* {{{ PHP_MINFO_FUNCTION */
3221 static PHP_MINFO_FUNCTION(zip)
3222 {
3223 php_info_print_table_start();
3224
3225 php_info_print_table_row(2, "Zip", "enabled");
3226 php_info_print_table_row(2, "Zip version", PHP_ZIP_VERSION);
3227 #ifdef HAVE_LIBZIP_VERSION
3228 if (strcmp(LIBZIP_VERSION, zip_libzip_version())) {
3229 php_info_print_table_row(2, "Libzip headers version", LIBZIP_VERSION);
3230 php_info_print_table_row(2, "Libzip library version", zip_libzip_version());
3231 } else
3232 #endif
3233 {
3234 php_info_print_table_row(2, "Libzip version", LIBZIP_VERSION);
3235 }
3236 #ifdef HAVE_METHOD_SUPPORTED
3237 php_info_print_table_row(2, "BZIP2 compression",
3238 zip_compression_method_supported(ZIP_CM_BZIP2, 1) ? "Yes" : "No");
3239 php_info_print_table_row(2, "XZ compression",
3240 zip_compression_method_supported(ZIP_CM_XZ, 1) ? "Yes" : "No");
3241 #ifdef ZIP_CM_ZSTD
3242 php_info_print_table_row(2, "ZSTD compression",
3243 zip_compression_method_supported(ZIP_CM_ZSTD, 1) ? "Yes" : "No");
3244 #else
3245 php_info_print_table_row(2, "ZSTD compression", "No");
3246 #endif
3247 php_info_print_table_row(2, "AES-128 encryption",
3248 zip_encryption_method_supported(ZIP_EM_AES_128, 1) ? "Yes" : "No");
3249 php_info_print_table_row(2, "AES-192 encryption",
3250 zip_encryption_method_supported(ZIP_EM_AES_128, 1) ? "Yes" : "No");
3251 php_info_print_table_row(2, "AES-256 encryption",
3252 zip_encryption_method_supported(ZIP_EM_AES_128, 1) ? "Yes" : "No");
3253 #endif
3254
3255 php_info_print_table_end();
3256 }
3257 /* }}} */
3258