--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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
+ */
#define PHAR_MAIN 1
#include "phar_internal.h"
#include "SAPI.h"
+#include "func_interceptors.h"
ZEND_DECLARE_MODULE_GLOBALS(phar)
/**
* 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);
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);
}
/* }}} */
-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"));
{
if (!PHAR_GLOBALS->request_init)
{
- zend_function *orig;
PHAR_GLOBALS->request_init = 1;
PHAR_GLOBALS->request_ends = 0;
PHAR_GLOBALS->request_done = 0;
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);
}
}
/* }}} */
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));