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