xref: /PHP-8.0/ext/zip/php_zip.c (revision 390538af)
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