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