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