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