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