]> granicus.if.org Git - php/commitdiff
add Phar::interceptFileFuncs()
authorGreg Beaver <cellog@php.net>
Fri, 11 Jan 2008 07:30:03 +0000 (07:30 +0000)
committerGreg Beaver <cellog@php.net>
Fri, 11 Jan 2008 07:30:03 +0000 (07:30 +0000)
To intercept fopen(), file_get_contents(), opendir(), and all the stat-based functions so that
code like "if (is_readable('./config.inc.php'))" actually works inside of a phar
[DOC]

ext/phar/config.m4
ext/phar/config.w32
ext/phar/func_interceptors.c [new file with mode: 0644]
ext/phar/func_interceptors.h [new file with mode: 0644]
ext/phar/package.php
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/phar_object.c
ext/phar/stream.c
ext/phar/tar.c

index 742923994f1778906906b9a92caf5f91f5df5304..b60e121714b757c74d9efc62b4496b3feda82a4e 100644 (file)
@@ -32,7 +32,7 @@ if test "$PHP_PHAR" != "no"; then
        else
                AC_MSG_RESULT([no])
        fi
-  PHP_NEW_EXTENSION(phar, tar.c zip.c stream.c dirstream.c phar.c phar_object.c phar_path_check.c $PHP_PHAR_SOURCES, $ext_shared)
+  PHP_NEW_EXTENSION(phar, tar.c zip.c stream.c func_interceptors.c dirstream.c phar.c phar_object.c phar_path_check.c $PHP_PHAR_SOURCES, $ext_shared)
   PHP_ADD_BUILD_DIR($ext_builddir/lib, 1)
   PHP_SUBST(PHAR_SHARED_LIBADD)
   PHP_ADD_EXTENSION_DEP(phar, zlib, true)
index ac7c5460565cf8a2a1ee37b3a62389a25a3ae904..e4c52e75e547ddf3e60096818b37d58f38fd4488 100644 (file)
@@ -4,7 +4,7 @@
 ARG_ENABLE("phar", "enable phar support", "no");
 
 if (PHP_PHAR != "no") {
-       EXTENSION("phar", "tar.c zip.c stream.c dirstream.c phar.c phar_object.c phar_path_check.c");
+       EXTENSION("phar", "tar.c zip.c stream.c dirstream.c func_interceptors.c phar.c phar_object.c phar_path_check.c");
                ADD_SOURCES(configure_module_dirname + "/lib", "zip_add.c zip_error.c zip_fclose.c \
                      zip_fread.c zip_open.c zip_source_filep.c  \
                      zip_strerror.c zip_close.c zip_error_get.c \
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
new file mode 100644 (file)
index 0000000..f80f39a
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+  +----------------------------------------------------------------------+
+  | phar php single-file executable PHP extension                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2005-2008 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt.                                 |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Gregory Beaver <cellog@php.net>                             |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+#define PHAR_FUNC(name) \
+       static PHP_NAMED_FUNCTION(name)
+
+PHAR_FUNC(phar_fopen);
+PHAR_FUNC(phar_file_get_contents);
+PHAR_FUNC(phar_is_file);
+PHAR_FUNC(phar_is_link);
+PHAR_FUNC(phar_is_dir);
+PHAR_FUNC(phar_opendir);
+PHAR_FUNC(phar_file_exists);
+PHAR_FUNC(phar_fileperms);
+PHAR_FUNC(phar_fileinode);
+PHAR_FUNC(phar_filesize);
+PHAR_FUNC(phar_fileowner);
+PHAR_FUNC(phar_filegroup);
+PHAR_FUNC(phar_fileatime);
+PHAR_FUNC(phar_filemtime);
+PHAR_FUNC(phar_filectime);
+PHAR_FUNC(phar_filetype);
+PHAR_FUNC(phar_is_writable);
+PHAR_FUNC(phar_is_readable);
+PHAR_FUNC(phar_is_executable);
+PHAR_FUNC(phar_lstat);
+PHAR_FUNC(phar_stat);
+
+#define PHAR_INTERCEPT(func) \
+       PHAR_G(orig_##func) = NULL; \
+       if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
+               PHAR_G(orig_##func) = orig->internal_function.handler; \
+               orig->internal_function.handler = phar_##func; \
+       }
+
+
+void phar_intercept_functions(TSRMLS_D) /* {{{ */
+{
+       zend_function *orig;
+
+       if (!PHAR_G(request_init)) {
+               PHAR_G(cwd) = NULL;
+               PHAR_G(cwd_len) = 0;
+       } else if (PHAR_G(orig_fopen)) {
+               /* don't double-intercept */
+               return;
+       }
+       PHAR_INTERCEPT(fopen);
+       PHAR_INTERCEPT(file_get_contents);
+       PHAR_INTERCEPT(is_file);
+       PHAR_INTERCEPT(is_link);
+       PHAR_INTERCEPT(is_dir);
+       PHAR_INTERCEPT(opendir);
+       PHAR_INTERCEPT(file_exists);
+       PHAR_INTERCEPT(fileperms);
+       PHAR_INTERCEPT(fileinode);
+       PHAR_INTERCEPT(filesize);
+       PHAR_INTERCEPT(fileowner);
+       PHAR_INTERCEPT(filegroup);
+       PHAR_INTERCEPT(fileatime);
+       PHAR_INTERCEPT(filemtime);
+       PHAR_INTERCEPT(filectime);
+       PHAR_INTERCEPT(filetype);
+       PHAR_INTERCEPT(is_writable);
+       PHAR_INTERCEPT(is_readable);
+       PHAR_INTERCEPT(is_executable);
+       PHAR_INTERCEPT(lstat);
+       PHAR_INTERCEPT(stat);
+}
+
+#define PHAR_RELEASE(func) \
+       if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
+               orig->internal_function.handler = PHAR_G(orig_##func); \
+       } \
+       PHAR_G(orig_##func) = NULL;
+
+
+void phar_release_functions(TSRMLS_D) /* {{{ */
+{
+       zend_function *orig;
+
+       PHAR_RELEASE(fopen);
+       PHAR_RELEASE(file_get_contents);
+       PHAR_RELEASE(is_file);
+       PHAR_RELEASE(is_dir);
+       PHAR_RELEASE(opendir);
+       PHAR_RELEASE(file_exists);
+       PHAR_RELEASE(fileperms);
+       PHAR_RELEASE(fileinode);
+       PHAR_RELEASE(filesize);
+       PHAR_RELEASE(fileowner);
+       PHAR_RELEASE(filegroup);
+       PHAR_RELEASE(fileatime);
+       PHAR_RELEASE(filemtime);
+       PHAR_RELEASE(filectime);
+       PHAR_RELEASE(filetype);
+       PHAR_RELEASE(is_writable);
+       PHAR_RELEASE(is_readable);
+       PHAR_RELEASE(is_executable);
+       PHAR_RELEASE(lstat);
+       PHAR_RELEASE(stat);
+}
+/* }}} */
+
+PHAR_FUNC(phar_opendir)
+{
+       char *filename;
+       int filename_len;
+       zval *zcontext = NULL;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
+               return;
+       }
+
+       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len;
+               fname = zend_get_executed_filename(TSRMLS_C);
+
+               /* we are checking for existence of a file within the relative path.  Chances are good that this is
+                  retrieving something from within the phar archive */
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       php_stream_context *context = NULL;
+                       php_stream *stream;
+                       char *name;
+
+                       efree(entry);
+                       entry = filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = filename_len;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               goto skip_phar;
+                       }
+                       /* retrieving a file within the current directory, so use this if possible */
+                       entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+
+                       spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+                       efree(entry);
+                       efree(arch);
+                       if (zcontext) {
+                               context = php_stream_context_from_zval(zcontext, 0);
+                       }
+                       stream = php_stream_opendir(name, REPORT_ERRORS, context);
+                       efree(name);
+                       if (!stream) {
+                               RETURN_FALSE;
+                       }
+                       php_stream_to_zval(stream, return_value);
+                       efree(entry);
+                       return;
+               }
+       }
+skip_phar:
+       PHAR_G(orig_opendir)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+PHAR_FUNC(phar_file_get_contents)
+{
+       char *filename;
+       int filename_len;
+       char *contents;
+       zend_bool use_include_path = 0;
+       php_stream *stream;
+       int len, newlen;
+       long offset = -1;
+       long maxlen = PHP_STREAM_COPY_ALL;
+       zval *zcontext = NULL;
+
+       /* Parse arguments */
+       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
+               return;
+       }
+       if (use_include_path || !IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len, free_filename = 0;
+               php_stream_context *context = NULL;
+               fname = zend_get_executed_filename(TSRMLS_C);
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       char *name;
+                       phar_archive_data **pphar;
+
+                       efree(entry);
+                       entry = filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = filename_len;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               if (free_filename) {
+                                       efree(filename);
+                               }
+                               goto skip_phar;
+                       }
+
+                       if (ZEND_NUM_ARGS() == 5 && maxlen < 0) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero");
+                               RETURN_FALSE;
+                       }
+
+                       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
+                               /* retrieving a file defaults to within the current directory, so use this if possible */
+                               if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+                                       name = entry;
+                                       entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                                       if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                                               /* this file is not in the current directory, use the original path */
+                                               efree(entry);
+                                               entry = name;
+                                       }
+                               }
+                       }
+                       /* auto-convert to phar:// */
+                       spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+                       if (entry != filename) {
+                               efree(entry);
+                       }
+                       efree(arch);
+                       if (zcontext) {
+                               context = php_stream_context_from_zval(zcontext, 0);
+                       }
+                       stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
+                       if (free_filename) {
+                               efree(filename);
+                       }
+                       efree(name);
+
+
+                       if (!stream) {
+                               RETURN_FALSE;
+                       }
+
+                       if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
+                               php_stream_close(stream);
+                               RETURN_FALSE;
+                       }
+
+                       /* uses mmap if possible */
+                       if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
+               
+                               if (PG(magic_quotes_runtime)) {
+                                       contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
+                                       len = newlen;
+                               }
+               
+                               RETVAL_STRINGL(contents, len, 0);
+                       } else if (len == 0) {
+                               RETVAL_EMPTY_STRING();
+                       } else {
+                               RETVAL_FALSE;
+                       }
+
+                       php_stream_close(stream);
+                       return;
+               }
+       }
+skip_phar:
+       PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+PHAR_FUNC(phar_fopen)
+{
+       char *filename, *mode;
+       int filename_len, mode_len;
+       zend_bool use_include_path = 0;
+       zval *zcontext = NULL;
+       php_stream *stream;
+
+       if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+               /* no need to check, include_path not even specified in fopen/ no active phars */
+               goto skip_phar;
+       }
+       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
+               goto skip_phar;
+       }
+       if (use_include_path || !IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len, free_filename = 0;
+               php_stream_context *context = NULL;
+               fname = zend_get_executed_filename(TSRMLS_C);
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       char *name;
+                       phar_archive_data **pphar;
+
+                       efree(entry);
+                       entry = filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = filename_len;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               if (free_filename) {
+                                       efree(filename);
+                               }
+                               goto skip_phar;
+                       }
+                       /* retrieving a file defaults to within the current directory, so use this if possible */
+                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+                               name = entry;
+                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                               if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                                       /* this file is not in the current directory, use the original path */
+                                       efree(entry);
+                                       entry = name;
+                               }
+                       }
+                       /* auto-convert to phar:// */
+                       spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+                       if (entry != filename) {
+                               efree(entry);
+                       }
+                       efree(arch);
+                       context = php_stream_context_from_zval(zcontext, 0);
+                       stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context);
+                       efree(name);
+                       if (stream == NULL) {
+                               RETURN_FALSE;
+                       }
+                       php_stream_to_zval(stream, return_value);
+                       if (zcontext) {
+                               zend_list_addref(Z_RESVAL_P(zcontext));
+                       }
+                       if (free_filename) {
+                               efree(filename);
+                       }
+                       return;
+               }
+       }
+skip_phar:
+       PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+#define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT)
+#define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS  || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK)
+#define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X)
+#define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS)
+
+/* {{{ php_stat
+ */
+PHPAPI void phar_fancy_stat(struct stat *stat_sb, int type, zval *return_value TSRMLS_DC)
+{
+       zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev,
+                *stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks;
+       php_stream_statbuf ssb;
+       int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */
+       char *stat_sb_names[13] = {
+               "dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
+               "size", "atime", "mtime", "ctime", "blksize", "blocks"
+       };
+
+#ifndef NETWARE
+       if (type >= FS_IS_W && type <= FS_IS_X) {
+               if(stat_sb->st_uid==getuid()) {
+                       rmask=S_IRUSR;
+                       wmask=S_IWUSR;
+                       xmask=S_IXUSR;
+               } else if(stat_sb->st_gid==getgid()) {
+                       rmask=S_IRGRP;
+                       wmask=S_IWGRP;
+                       xmask=S_IXGRP;
+               } else {
+                       int   groups, n, i;
+                       gid_t *gids;
+
+                       groups = getgroups(0, NULL);
+                       if(groups > 0) {
+                               gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0);
+                               n=getgroups(groups, gids);
+                               for(i=0;i<n;i++){
+                                       if(stat_sb->st_gid==gids[i]) {
+                                               rmask=S_IRGRP;
+                                               wmask=S_IWGRP;
+                                               xmask=S_IXGRP;
+                                               break;
+                                       }
+                               }
+                               efree(gids);
+                       }
+               }
+       }
+#endif
+
+       switch (type) {
+       case FS_PERMS:
+               RETURN_LONG((long)stat_sb->st_mode);
+       case FS_INODE:
+               RETURN_LONG((long)stat_sb->st_ino);
+       case FS_SIZE:
+               RETURN_LONG((long)stat_sb->st_size);
+       case FS_OWNER:
+               RETURN_LONG((long)stat_sb->st_uid);
+       case FS_GROUP:
+               RETURN_LONG((long)stat_sb->st_gid);
+       case FS_ATIME:
+#ifdef NETWARE
+               RETURN_LONG((long)stat_sb->st_atime.tv_sec);
+#else
+               RETURN_LONG((long)stat_sb->st_atime);
+#endif
+       case FS_MTIME:
+#ifdef NETWARE
+               RETURN_LONG((long)stat_sb->st_mtime.tv_sec);
+#else
+               RETURN_LONG((long)stat_sb->st_mtime);
+#endif
+       case FS_CTIME:
+#ifdef NETWARE
+               RETURN_LONG((long)stat_sb->st_ctime.tv_sec);
+#else
+               RETURN_LONG((long)stat_sb->st_ctime);
+#endif
+       case FS_TYPE:
+               if (S_ISLNK(stat_sb->st_mode)) {
+                       RETURN_STRING("link", 1);
+               }
+               switch(stat_sb->st_mode & S_IFMT) {
+               case S_IFIFO: RETURN_STRING("fifo", 1);
+               case S_IFCHR: RETURN_STRING("char", 1);
+               case S_IFDIR: RETURN_STRING("dir", 1);
+               case S_IFBLK: RETURN_STRING("block", 1);
+               case S_IFREG: RETURN_STRING("file", 1);
+#if defined(S_IFSOCK) && !defined(ZEND_WIN32)&&!defined(__BEOS__)
+               case S_IFSOCK: RETURN_STRING("socket", 1);
+#endif
+               }
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%d)", stat_sb->st_mode&S_IFMT);
+               RETURN_STRING("unknown", 1);
+       case FS_IS_W:
+               RETURN_BOOL((stat_sb->st_mode & wmask) != 0);
+       case FS_IS_R:
+               RETURN_BOOL((stat_sb->st_mode&rmask)!=0);
+       case FS_IS_X:
+               RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode));
+       case FS_IS_FILE:
+               RETURN_BOOL(S_ISREG(stat_sb->st_mode));
+       case FS_IS_DIR:
+               RETURN_BOOL(S_ISDIR(stat_sb->st_mode));
+       case FS_IS_LINK:
+               RETURN_BOOL(S_ISLNK(stat_sb->st_mode));
+       case FS_EXISTS:
+               RETURN_TRUE; /* the false case was done earlier */
+       case FS_LSTAT:
+               /* FALLTHROUGH */
+       case FS_STAT:
+               array_init(return_value);
+
+               MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev);
+               MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino);
+               MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode);
+               MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink);
+               MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid);
+               MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid);
+#ifdef HAVE_ST_RDEV
+               MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev);
+#else
+               MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
+#endif
+               MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size);
+#ifdef NETWARE
+               MAKE_LONG_ZVAL_INCREF(stat_atime, (stat_sb->st_atime).tv_sec);
+               MAKE_LONG_ZVAL_INCREF(stat_mtime, (stat_sb->st_mtime).tv_sec);
+               MAKE_LONG_ZVAL_INCREF(stat_ctime, (stat_sb->st_ctime).tv_sec);
+#else
+               MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime);
+               MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime);
+               MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime);
+#endif
+#ifdef HAVE_ST_BLKSIZE
+               MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize);
+#else
+               MAKE_LONG_ZVAL_INCREF(stat_blksize,-1);
+#endif
+#ifdef HAVE_ST_BLOCKS
+               MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks);
+#else
+               MAKE_LONG_ZVAL_INCREF(stat_blocks,-1);
+#endif
+               /* Store numeric indexes in propper order */
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL);
+
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL);
+               zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL);
+
+               /* Store string indexes referencing the same zval*/
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL);
+               zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL);
+
+               return;
+       }
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call");
+       RETURN_FALSE;
+}
+/* }}} */
+
+PHPAPI void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS)
+{
+       if (!filename_length) {
+               RETURN_FALSE;
+       }
+
+       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len;
+               fname = zend_get_executed_filename(TSRMLS_C);
+               struct stat sb = {0};
+               phar_entry_info *data = NULL;
+               char *tmp;
+               int tmp_len;
+
+               /* we are checking for existence of a file within the relative path.  Chances are good that this is
+                  retrieving something from within the phar archive */
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       phar_archive_data **pphar;
+
+                       efree(entry);
+                       entry = (char *)filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = (int) filename_length;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               goto skip_phar;
+                       }
+                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                               if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
+                                       efree(entry);
+                                       goto stat_entry;
+                               } else {
+                                       char *save = PHAR_G(cwd), *save2 = entry;
+                                       int save_len = PHAR_G(cwd_len), save2_len = entry_len;
+
+                                       /* this file is not in the current directory, use the original path */
+                                       entry = (char *)filename;
+                                       PHAR_G(cwd) = "/";
+                                       PHAR_G(cwd_len) = 0;
+                                       /* clean path without cwd */
+                                       entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
+                                               PHAR_G(cwd) = save;
+                                               PHAR_G(cwd_len) = save_len;
+                                               efree(entry);
+                                               efree(save2);
+                                               goto stat_entry;
+                                       } else {
+                                               phar_archive_data *phar = *pphar;
+                                               char *key;
+                                               uint keylen;
+                                               ulong unused;
+
+                                               /* original not found either, this is possibly a directory relative to cwd */
+                                               zend_hash_internal_pointer_reset(&phar->manifest);
+                                               while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
+                                                       if (HASH_KEY_NON_EXISTANT !=
+                                                                       zend_hash_get_current_key_ex(
+                                                                               &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
+                                                               if (0 == memcmp(save2, key, save2_len)) {
+                                                                       PHAR_G(cwd) = save;
+                                                                       PHAR_G(cwd_len) = save_len;
+                                                                       efree(save2);
+                                                                       efree(entry);
+                                                                       /* directory found, all dirs have the same stat */
+                                                                       if (key[save2_len] == '/') {
+                                                                               sb.st_size = 0;
+                                                                               sb.st_mode = 0777;
+                                                                               sb.st_mode |= S_IFDIR; /* regular directory */
+#ifdef NETWARE
+                                                                               sb.st_mtime.tv_sec = phar->max_timestamp;
+                                                                               sb.st_atime.tv_sec = phar->max_timestamp;
+                                                                               sb.st_ctime.tv_sec = phar->max_timestamp;
+#else
+                                                                               sb.st_mtime = phar->max_timestamp;
+                                                                               sb.st_atime = phar->max_timestamp;
+                                                                               sb.st_ctime = phar->max_timestamp;
+#endif
+                                                                               goto statme_baby;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       PHAR_G(cwd) = save;
+                                       PHAR_G(cwd_len) = save_len;
+                                       efree(entry);
+                                       efree(save2);
+                                       /* Error Occured */
+                                       if (!IS_EXISTS_CHECK(type)) {
+                                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename);
+                                       }
+                                       RETURN_FALSE;
+                               }
+                       }
+stat_entry:
+                       if (!data->is_dir) {
+                               sb.st_size = data->uncompressed_filesize;
+                               sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+                               sb.st_mode |= S_IFREG; /* regular file */
+                               /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+                               sb.st_mtime.tv_sec = data->timestamp;
+                               sb.st_atime.tv_sec = data->timestamp;
+                               sb.st_ctime.tv_sec = data->timestamp;
+#else
+                               sb.st_mtime = data->timestamp;
+                               sb.st_atime = data->timestamp;
+                               sb.st_ctime = data->timestamp;
+#endif
+                       } else {
+                               sb.st_size = 0;
+                               sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+                               sb.st_mode |= S_IFDIR; /* regular directory */
+                               /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+                               sb.st_mtime.tv_sec = data->timestamp;
+                               sb.st_atime.tv_sec = data->timestamp;
+                               sb.st_ctime.tv_sec = data->timestamp;
+#else
+                               sb.st_mtime = data->timestamp;
+                               sb.st_atime = data->timestamp;
+                               sb.st_ctime = data->timestamp;
+#endif
+                       }
+
+statme_baby:
+                       efree(arch);
+                       if (!(*pphar)->is_writeable) {
+                               sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
+                       }
+               
+                       sb.st_nlink = 1;
+                       sb.st_rdev = -1;
+                       if (data) {
+                               tmp_len = data->filename_len + (*pphar)->alias_len;
+                       } else {
+                               tmp_len = (*pphar)->alias_len + 1;
+                       }
+                       tmp = (char *) emalloc(tmp_len);
+                       memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len);
+                       if (data) {
+                               memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len);
+                       } else {
+                               *(tmp + (*pphar)->alias_len) = '/';
+                       }
+                       /* this is only for APC, so use /dev/null device - no chance of conflict there! */
+                       sb.st_dev = 0xc;
+                       /* generate unique inode number for alias/filename, so no phars will conflict */
+                       sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
+                       efree(tmp);
+#ifndef PHP_WIN32
+                       sb.st_blksize = -1;
+                       sb.st_blocks = -1;
+#endif
+                       phar_fancy_stat(&sb, type, return_value TSRMLS_CC);
+                       return;
+               }
+       }
+skip_phar:
+       orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+#define PharFileFunction(fname, funcnum, orig) \
+void fname(INTERNAL_FUNCTION_PARAMETERS) { \
+       char *filename; \
+       int filename_len; \
+       \
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \
+               return; \
+       } \
+       \
+       phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
+}
+/* }}} */
+
+/* {{{ proto int fileperms(string filename)
+   Get file permissions */
+PharFileFunction(phar_fileperms, FS_PERMS, orig_fileperms)
+/* }}} */
+
+/* {{{ proto int fileinode(string filename)
+   Get file inode */
+PharFileFunction(phar_fileinode, FS_INODE, orig_fileinode)
+/* }}} */
+
+/* {{{ proto int filesize(string filename)
+   Get file size */
+PharFileFunction(phar_filesize, FS_SIZE, orig_filesize)
+/* }}} */
+
+/* {{{ proto int fileowner(string filename)
+   Get file owner */
+PharFileFunction(phar_fileowner, FS_OWNER, orig_fileowner)
+/* }}} */
+
+/* {{{ proto int filegroup(string filename)
+   Get file group */
+PharFileFunction(phar_filegroup, FS_GROUP, orig_filegroup)
+/* }}} */
+
+/* {{{ proto int fileatime(string filename)
+   Get last access time of file */
+PharFileFunction(phar_fileatime, FS_ATIME, orig_fileatime)
+/* }}} */
+
+/* {{{ proto int filemtime(string filename)
+   Get last modification time of file */
+PharFileFunction(phar_filemtime, FS_MTIME, orig_filemtime)
+/* }}} */
+
+/* {{{ proto int filectime(string filename)
+   Get inode modification time of file */
+PharFileFunction(phar_filectime, FS_CTIME, orig_filectime)
+/* }}} */
+
+/* {{{ proto string filetype(string filename)
+   Get file type */
+PharFileFunction(phar_filetype, FS_TYPE, orig_filetype)
+/* }}} */
+
+/* {{{ proto bool is_writable(string filename)
+   Returns true if file can be written */
+PharFileFunction(phar_is_writable, FS_IS_W, orig_is_writable)
+/* }}} */
+
+/* {{{ proto bool is_readable(string filename)
+   Returns true if file can be read */
+PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+   Returns true if file is executable */
+PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+   Returns true if file is executable */
+PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+   Returns true if file is executable */
+PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir)
+/* }}} */
+
+PHAR_FUNC(phar_is_file)
+{
+       char *filename;
+       int filename_len;
+
+       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+               goto skip_phar;
+       }
+       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len, free_filename = 0;
+               fname = zend_get_executed_filename(TSRMLS_C);
+
+               /* we are checking for existence of a file within the relative path.  Chances are good that this is
+                  retrieving something from within the phar archive */
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       phar_archive_data **pphar;
+
+                       efree(entry);
+                       entry = filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = filename_len;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               if (free_filename) {
+                                       efree(filename);
+                               }
+                               goto skip_phar;
+                       }
+                       /* retrieving a file within the current directory, so use this if possible */
+                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                               if (zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                                       /* this file is not in the current directory, use the original path */
+                                       efree(entry);
+                                       efree(arch);
+                                       RETURN_TRUE;
+                               }
+                       }
+                       efree(entry);
+                       efree(arch);
+                       RETURN_FALSE;
+               }
+       }
+skip_phar:
+       PHAR_G(orig_is_file)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+PHAR_FUNC(phar_is_link)
+{
+       char *filename;
+       int filename_len;
+
+       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+               goto skip_phar;
+       }
+       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
+               char *arch, *entry, *fname;
+               int arch_len, entry_len, fname_len, free_filename = 0;
+               fname = zend_get_executed_filename(TSRMLS_C);
+
+               /* we are checking for existence of a file within the relative path.  Chances are good that this is
+                  retrieving something from within the phar archive */
+
+               if (strncasecmp(fname, "phar://", 7)) {
+                       goto skip_phar;
+               }
+               fname_len = strlen(fname);
+               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+                       phar_archive_data **pphar;
+
+                       efree(entry);
+                       entry = filename;
+                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+                       entry_len = filename_len;
+                       if (strstr(entry, "://")) {
+                               efree(arch);
+                               if (free_filename) {
+                                       efree(filename);
+                               }
+                               goto skip_phar;
+                       }
+                       /* retrieving a file within the current directory, so use this if possible */
+                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+                               phar_entry_info *etemp;
+
+                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+                               if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
+                                       /* this file is not in the current directory, use the original path */
+                                       efree(entry);
+                                       efree(arch);
+                                       RETURN_BOOL(etemp->link);
+                               }
+                       }
+                       efree(entry);
+                       efree(arch);
+                       RETURN_FALSE;
+               }
+       }
+skip_phar:
+       PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       return;
+}
+
+/* {{{ proto array lstat(string filename)
+   Give information about a file or symbolic link */
+PharFileFunction(phar_lstat, FS_LSTAT, orig_lstat)
+/* }}} */
+
+/* {{{ proto array stat(string filename)
+   Give information about a file */
+PharFileFunction(phar_stat, FS_STAT, orig_stat)
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/func_interceptors.h b/ext/phar/func_interceptors.h
new file mode 100644 (file)
index 0000000..b48be59
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+  +----------------------------------------------------------------------+
+  | phar php single-file executable PHP extension                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2006-2007 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt.                                 |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Gregory Beaver <cellog@php.net>                             |
+  |          Marcus Boerger <helly@php.net>                              |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+BEGIN_EXTERN_C()
+void phar_intercept_functions(TSRMLS_D);
+void phar_release_functions(TSRMLS_D);
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
index 2eff70381a5a3add8bd9a8191cf22f60fb95f534..82d807e36a75eb94dab44f5859514c55355debfa 100644 (file)
@@ -6,7 +6,9 @@ Major feature functionality release
  * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg]
  * add Phar::webPhar() for running a web-based application unmodified
    directly from a phar archive [Greg]
- * include/fopen with include_path all work unmodified within a phar [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+   relative paths within a phar via Phar::interceptFileFuncs()
+ * include works unmodified within a phar [Greg]
  * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg]
  * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
  * add option to compress the entire phar file for phar/tar file format [Greg]
index b62547a50770b95490b49c0f04d3a35c4a1d0040..579697834a292a37b9c61392b0f5b38224d11c9d 100644 (file)
@@ -22,6 +22,7 @@
 #define PHAR_MAIN 1
 #include "phar_internal.h"
 #include "SAPI.h"
+#include "func_interceptors.h"
 
 ZEND_DECLARE_MODULE_GLOBALS(phar)
 
@@ -1893,13 +1894,13 @@ char *tsrm_strtok_r(char *s, const char *delim, char **last)
 /**
  * Remove .. and . references within a phar filename
  */
-static char *phar_fix_filepath(char *path, int *new_len, int cwd TSRMLS_DC) /* {{{ */
+char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
 {
        char *ptr, *free_path, *new_phar;
        char *tok;
        int ptr_length, new_phar_len = 1, path_length = *new_len;
 
-       if (cwd) {
+       if (use_cwd) {
                free_path = path = estrndup(path, path_length);
                new_phar_len = PHAR_G(cwd_len);
                new_phar = estrndup(PHAR_G(cwd), new_phar_len);
@@ -1948,9 +1949,7 @@ static char *phar_fix_filepath(char *path, int *new_len, int cwd TSRMLS_DC) /* {
                ptr = tsrm_strtok_r(NULL, "/", &tok);
        }
 
-       if (free_path) {
-               efree(free_path);
-       }
+       efree(free_path);
 
        if (path[path_length-1] == '/' && new_phar_len > 1) {
                new_phar = (char*)erealloc(new_phar, new_phar_len + 2);
@@ -3215,337 +3214,11 @@ skip_phar:
 }
 /* }}} */
 
-static void phar_is_dir(INTERNAL_FUNCTION_PARAMETERS)
-{
-       char *filename;
-       int filename_len;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
-               return;
-       }
-
-       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
-               char *arch, *entry, *fname;
-               int arch_len, entry_len, fname_len, free_filename = 0;
-               fname = zend_get_executed_filename(TSRMLS_C);
-
-               /* we are checking for existence of a file within the relative path.  Chances are good that this is
-                  retrieving something from within the phar archive */
-
-               if (strncasecmp(fname, "phar://", 7)) {
-                       goto skip_phar;
-               }
-               fname_len = strlen(fname);
-               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-                       phar_archive_data **pphar;
-
-                       efree(entry);
-                       entry = filename;
-                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
-                       entry_len = filename_len;
-                       if (strstr(entry, "://")) {
-                               efree(arch);
-                               if (free_filename) {
-                                       efree(filename);
-                               }
-                               goto skip_phar;
-                       }
-                       /* retrieving a file within the current directory, so use this if possible */
-                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
-                               phar_entry_info *etemp;
-
-                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
-                               if (zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
-                                       /* this file is not in the current directory, use the original path */
-                                       efree(entry);
-                                       efree(arch);
-                                       RETURN_BOOL(etemp->is_dir);
-                               } else {
-                                       char *key;
-                                       uint keylen;
-                                       ulong unused;
-                                       HashTable *manifest;
-                       
-                                       efree(arch);
-                                       manifest = &(*pphar)->manifest;
-                                       zend_hash_internal_pointer_reset(manifest);
-                                       while (FAILURE != zend_hash_has_more_elements(manifest)) {
-                                               if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
-                                                       break;
-                                               }
-                                               if (0 != memcmp(key, entry, entry_len)) {
-                                                       /* entry in directory not found */
-                                                       if (SUCCESS != zend_hash_move_forward(manifest)) {
-                                                               break;
-                                                       }
-                                                       continue;
-                                               } else {
-                                                       if (key[entry_len] != '/') {
-                                                               if (SUCCESS != zend_hash_move_forward(manifest)) {
-                                                                       break;
-                                                               }
-                                                               continue;
-                                                       }
-                                                       /* found a file in this path */
-                                                       efree(entry);
-                                                       RETURN_TRUE;
-                                               }
-                                       }
-                                       efree(entry);
-                                       RETURN_FALSE;
-                               }
-                       }
-               }
-       }
-skip_phar:
-       PHAR_G(orig_is_dir)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-       return;
-}
-
-static void phar_fgc(INTERNAL_FUNCTION_PARAMETERS)
-{
-       char *filename;
-       int filename_len;
-       char *contents;
-       zend_bool use_include_path = 0;
-       php_stream *stream;
-       int len, newlen;
-       long offset = -1;
-       long maxlen = PHP_STREAM_COPY_ALL;
-       zval *zcontext = NULL;
-
-       /* Parse arguments */
-       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
-               return;
-       }
-       if (use_include_path || !IS_ABSOLUTE_PATH(filename, filename_len)) {
-               char *arch, *entry, *fname;
-               int arch_len, entry_len, fname_len, free_filename = 0;
-               php_stream_context *context = NULL;
-               fname = zend_get_executed_filename(TSRMLS_C);
-
-               if (strncasecmp(fname, "phar://", 7)) {
-                       goto skip_phar;
-               }
-               fname_len = strlen(fname);
-               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-                       char *name;
-                       phar_archive_data **pphar;
-
-                       efree(entry);
-                       entry = filename;
-                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
-                       entry_len = filename_len;
-                       if (strstr(entry, "://")) {
-                               efree(arch);
-                               if (free_filename) {
-                                       efree(filename);
-                               }
-                               goto skip_phar;
-                       }
-
-                       if (ZEND_NUM_ARGS() == 5 && maxlen < 0) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero");
-                               RETURN_FALSE;
-                       }
-
-                       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
-                               /* retrieving a file defaults to within the current directory, so use this if possible */
-                               if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
-                                       name = entry;
-                                       entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
-                                       if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
-                                               /* this file is not in the current directory, use the original path */
-                                               efree(entry);
-                                               entry = name;
-                                       }
-                               }
-                       }
-                       /* auto-convert to phar:// */
-                       spprintf(&name, 4096, "phar://%s/%s", arch, entry);
-                       if (entry != filename) {
-                               efree(entry);
-                       }
-                       efree(arch);
-                       context = php_stream_context_from_zval(zcontext, 0);
-                       stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
-                       if (free_filename) {
-                               efree(filename);
-                       }
-                       efree(name);
-
-
-                       if (!stream) {
-                               RETURN_FALSE;
-                       }
-
-                       if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
-                               php_stream_close(stream);
-                               RETURN_FALSE;
-                       }
-
-                       /* uses mmap if possible */
-                       if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
-               
-                               if (PG(magic_quotes_runtime)) {
-                                       contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
-                                       len = newlen;
-                               }
-               
-                               RETVAL_STRINGL(contents, len, 0);
-                       } else if (len == 0) {
-                               RETVAL_EMPTY_STRING();
-                       } else {
-                               RETVAL_FALSE;
-                       }
-
-                       php_stream_close(stream);
-                       return;
-               }
-       }
-skip_phar:
-       PHAR_G(orig_fgc)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-       return;
-}
-
-static void phar_file_exists(INTERNAL_FUNCTION_PARAMETERS)
-{
-       char *filename;
-       int filename_len;
-
-       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
-               goto skip_phar;
-       }
-       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
-               char *arch, *entry, *fname;
-               int arch_len, entry_len, fname_len, free_filename = 0;
-               fname = zend_get_executed_filename(TSRMLS_C);
-
-               /* we are checking for existence of a file within the relative path.  Chances are good that this is
-                  retrieving something from within the phar archive */
-
-               if (strncasecmp(fname, "phar://", 7)) {
-                       goto skip_phar;
-               }
-               fname_len = strlen(fname);
-               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-                       phar_archive_data **pphar;
-
-                       efree(entry);
-                       entry = filename;
-                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
-                       entry_len = filename_len;
-                       if (strstr(entry, "://")) {
-                               efree(arch);
-                               if (free_filename) {
-                                       efree(filename);
-                               }
-                               goto skip_phar;
-                       }
-                       /* retrieving a file within the current directory, so use this if possible */
-                       if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
-                               entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
-                               if (zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
-                                       /* this file is not in the current directory, use the original path */
-                                       efree(entry);
-                                       efree(arch);
-                                       RETURN_TRUE;
-                               }
-                       }
-                       efree(entry);
-                       efree(arch);
-               }
-       }
-skip_phar:
-       PHAR_G(file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-       return;
-}
-
-static void phar_fopen(INTERNAL_FUNCTION_PARAMETERS)
-{
-       char *filename, *mode;
-       int filename_len, mode_len;
-       zend_bool use_include_path = 0;
-       zval *zcontext = NULL;
-       php_stream *stream;
-
-       if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
-               /* no need to check, include_path not even specified in fopen/ no active phars */
-               goto skip_phar;
-       }
-       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
-               goto skip_phar;
-       }
-       if (use_include_path || !IS_ABSOLUTE_PATH(filename, filename_len)) {
-               char *arch, *entry, *fname;
-               int arch_len, entry_len, fname_len, free_filename = 0;
-               php_stream_context *context = NULL;
-               fname = zend_get_executed_filename(TSRMLS_C);
-
-               if (strncasecmp(fname, "phar://", 7)) {
-                       goto skip_phar;
-               }
-               fname_len = strlen(fname);
-               if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-                       char *name;
-                       phar_archive_data **pphar;
-
-                       efree(entry);
-                       entry = filename;
-                       /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
-                       entry_len = filename_len;
-                       if (strstr(entry, "://")) {
-                               efree(arch);
-                               if (free_filename) {
-                                       efree(filename);
-                               }
-                               goto skip_phar;
-                       }
-                       if (!IS_ABSOLUTE_PATH(filename, filename_len)) {
-                               /* retrieving a file defaults to within the current directory, so use this if possible */
-                               if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
-                                       name = entry;
-                                       entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
-                                       if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
-                                               /* this file is not in the current directory, use the original path */
-                                               efree(entry);
-                                               entry = name;
-                                       }
-                               }
-                       }
-                       /* auto-convert to phar:// */
-                       spprintf(&name, 4096, "phar://%s/%s", arch, entry);
-                       if (entry != filename) {
-                               efree(entry);
-                       }
-                       efree(arch);
-                       context = php_stream_context_from_zval(zcontext, 0);
-                       stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context);
-                       efree(name);
-                       php_stream_to_zval(stream, return_value);
-                       if (free_filename) {
-                               efree(filename);
-                       }
-                       return;
-               }
-       }
-skip_phar:
-       PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
-       return;
-}
-
 PHP_MINIT_FUNCTION(phar) /* {{{ */
 {
        ZEND_INIT_MODULE_GLOBALS(phar, php_phar_init_globals_module, NULL);
        REGISTER_INI_ENTRIES();
 
-       PHAR_G(orig_fopen) = NULL;
-       PHAR_G(orig_fgc) = NULL;
-       PHAR_G(file_exists) = NULL;
-       PHAR_G(orig_is_dir) = NULL;
-       PHAR_G(cwd) = NULL;
-       PHAR_G(cwd_len) = 0;
        phar_has_gnupg = zend_hash_exists(&module_registry, "gnupg", sizeof("gnupg"));
        phar_has_bz2 = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
        phar_has_zlib = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
@@ -3578,7 +3251,6 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
 {
        if (!PHAR_GLOBALS->request_init)
        {
-               zend_function *orig;
                PHAR_GLOBALS->request_init = 1;
                PHAR_GLOBALS->request_ends = 0;
                PHAR_GLOBALS->request_done = 0;
@@ -3587,26 +3259,9 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
                zend_hash_init(&(PHAR_GLOBALS->phar_plain_map), sizeof(const char *),       zend_get_hash_value, NULL, 0);
                zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), sizeof(const char *),       zend_get_hash_value, NULL, 0);
                phar_split_extract_list(TSRMLS_C);
-               PHAR_G(orig_fopen) = PHAR_G(orig_fgc) = PHAR_G(file_exists) = NULL;
-               PHAR_G(orig_is_dir) = NULL;
                PHAR_G(cwd) = NULL;
                PHAR_G(cwd_len) = 0;
-               if (SUCCESS == zend_hash_find(CG(function_table), "fopen", 6, (void **)&orig)) {
-                       PHAR_G(orig_fopen) = orig->internal_function.handler;
-                       orig->internal_function.handler = phar_fopen;
-               }
-               if (SUCCESS == zend_hash_find(CG(function_table), "file_get_contents", 18, (void **)&orig)) {
-                       PHAR_G(orig_fgc) = orig->internal_function.handler;
-                       orig->internal_function.handler = phar_fgc;
-               }
-               if (SUCCESS == zend_hash_find(CG(function_table), "file_exists", 12, (void **)&orig)) {
-                       PHAR_G(file_exists) = orig->internal_function.handler;
-                       orig->internal_function.handler = phar_file_exists;
-               }
-               if (SUCCESS == zend_hash_find(CG(function_table), "is_dir", 7, (void **)&orig)) {
-                       PHAR_G(orig_is_dir) = orig->internal_function.handler;
-                       orig->internal_function.handler = phar_is_dir;
-               }
+               phar_intercept_functions(TSRMLS_C);
        }
 }
 /* }}} */
@@ -3616,23 +3271,7 @@ PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
        PHAR_GLOBALS->request_ends = 1;
        if (PHAR_GLOBALS->request_init)
        {
-               zend_function *orig;
-               if (PHAR_G(orig_fopen) && SUCCESS == zend_hash_find(CG(function_table), "fopen", 6, (void **)&orig)) {
-                       orig->internal_function.handler = PHAR_G(orig_fopen);
-               }
-               PHAR_G(orig_fopen) = NULL;
-               if (PHAR_G(file_exists) && SUCCESS == zend_hash_find(CG(function_table), "file_exists", 12, (void **)&orig)) {
-                       orig->internal_function.handler = PHAR_G(file_exists);
-               }
-               PHAR_G(file_exists) = NULL;
-               if (PHAR_G(orig_fgc) && SUCCESS == zend_hash_find(CG(function_table), "file_get_contents", 18, (void **)&orig)) {
-                       orig->internal_function.handler = PHAR_G(orig_fgc);
-               }
-               PHAR_G(orig_fgc) = NULL;
-               if (PHAR_G(orig_is_dir) && SUCCESS == zend_hash_find(CG(function_table), "is_dir", 7, (void **)&orig)) {
-                       orig->internal_function.handler = PHAR_G(orig_is_dir);
-               }
-               PHAR_G(orig_is_dir) = NULL;
+               phar_release_functions(TSRMLS_C);
                zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
                PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
                zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
index 16261c5dd7f327054c34004dd58f9c2569743444..9d34aff6e3b06f811b896e17474eb9db0973dace 100755 (executable)
@@ -143,9 +143,26 @@ ZEND_BEGIN_MODULE_GLOBALS(phar)
        int         request_done;
        int         request_ends;
        void        (*orig_fopen)(INTERNAL_FUNCTION_PARAMETERS);
-       void        (*orig_fgc)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_file_get_contents)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_is_link)(INTERNAL_FUNCTION_PARAMETERS);
        void        (*orig_is_dir)(INTERNAL_FUNCTION_PARAMETERS);
-       void        (*file_exists)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_opendir)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_fileperms)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_fileinode)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_filesize)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_fileowner)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_filegroup)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_fileatime)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_filemtime)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_filectime)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_filetype)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_is_writable)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_is_executable)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_lstat)(INTERNAL_FUNCTION_PARAMETERS);
+       void        (*orig_stat)(INTERNAL_FUNCTION_PARAMETERS);
        /* used for includes with . in them inside front controller */
        char*       cwd;
        int         cwd_len;
@@ -319,6 +336,7 @@ int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC);
 int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC);
 int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
 
+char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
 phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp,
                                      char **error, int for_write TSRMLS_DC);
 int phar_parse_metadata(char **buffer, zval **metadata, int is_zip TSRMLS_DC);
@@ -337,7 +355,6 @@ int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_l
 int phar_zip_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC);
 
 #ifdef PHAR_MAIN
-static void phar_fopen(INTERNAL_FUNCTION_PARAMETERS);
 static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
 extern php_stream_wrapper php_stream_phar_wrapper;
 #endif
index a19a0196637a298388a71242193b822838dc430b..50da4ebdee758393d7ccd829357cfae25f842e70 100755 (executable)
@@ -20,6 +20,7 @@
 /* $Id$ */
 
 #include "phar_internal.h"
+#include "func_interceptors.h"
 
 static zend_class_entry *phar_ce_archive;
 static zend_class_entry *phar_ce_PharException;
@@ -705,6 +706,20 @@ PHP_METHOD(Phar, mungServer)
 }
 /* }}} */
 
+/* {{{ proto void Phar::interceptFileFuncs()
+ * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
+ * and return stat on files within the phar for relative paths
+ *
+ * Once called, this cannot be reversed, and continue until the end of the request.
+ *
+ * This allows legacy scripts to be pharred unmodified
+ */
+PHP_METHOD(Phar, interceptFileFuncs)
+{
+       phar_intercept_functions(TSRMLS_C);
+}
+/* }}} */
+
 /* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
  * Reads the currently executed file (a phar) and registers its manifest */
 PHP_METHOD(Phar, mapPhar)
@@ -2852,6 +2867,7 @@ zend_function_entry php_archive_methods[] = {
        PHP_ME(Phar, mapPhar,               arginfo_phar_mapPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, webPhar,               arginfo_phar_webPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, mungServer,            arginfo_phar_mungServer,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+       PHP_ME(Phar, interceptFileFuncs,    NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, getExtractList,        NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, getSupportedSignatures,NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, getSupportedCompression,NULL,                     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
index 41b51f11f75418dbc2ccab11e6078d020321659a..ef0bdf0f5ba60281078fcb22926f4f1225d56fc2 100644 (file)
@@ -556,7 +556,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
        phar_archive_data *phar;
        phar_entry_info *entry;
        uint host_len;
-       int retval;
+       int retval, internal_file_len;
 
        if ((resource = phar_open_url(wrapper, url, "r", flags TSRMLS_CC)) == NULL) {
                return FAILURE;
@@ -611,8 +611,9 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
                php_url_free(resource);
                return SUCCESS;
        }
+       internal_file_len = strlen(internal_file);
        /* search through the manifest of files, and if we have an exact match, it's a file */
-       if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) {
+       if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
                phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
                php_url_free(resource);
                return SUCCESS;
@@ -623,9 +624,9 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
                        if (HASH_KEY_NON_EXISTANT !=
                                        zend_hash_get_current_key_ex(
                                                &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
-                               if (0 == memcmp(internal_file, key, strlen(internal_file))) {
+                               if (0 == memcmp(internal_file, key, internal_file_len)) {
                                        /* directory found, all dirs have the same stat */
-                                       if (key[strlen(internal_file)] == '/') {
+                                       if (key[internal_file_len] == '/') {
                                                phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
                                                php_url_free(resource);
                                                return SUCCESS;
index f9afe72df12109c0ceb47f19461f987ba2ca4f40..cc65a9f4728c8715c49174bead4e61afc1cabd4e 100644 (file)
@@ -554,7 +554,6 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, char **er
                /* deferred flush */
                phar->fp = newfile;
        } else {
-
                phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
                if (!phar->fp) {
                        phar->fp = newfile;
@@ -573,6 +572,9 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, char **er
                        filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
                        zval_dtor(&filterparams);
                        if (!filter) {
+                               /* copy contents uncompressed rather than lose them */
+                               php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+                               php_stream_close(newfile);
                                if (error) {
                                        spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
                                }