diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 6e545a1ff4398..d208a4c9f9cd5 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -89,13 +89,77 @@ PHAR_FUNC(phar_opendir) /* {{{ */ } /* }}} */ +static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool using_include_path) +{ + char *arch, *entry, *fname; + size_t arch_len, entry_len, fname_len; + + fname = (char*)zend_get_executed_filename(); + if (strncasecmp(fname, "phar://", 7)) { + return NULL; + } + fname_len = strlen(fname); + if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + return NULL; + } + + efree(entry); + entry = NULL; + entry_len = 0; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + /* retrieving a file defaults to within the current directory, so use this if possible */ + phar_archive_data *phar; + if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + efree(arch); + return NULL; + } + + zend_string *name = NULL; + if (using_include_path) { + if (!(name = phar_find_in_include_path(filename, NULL))) { + /* this file is not in the phar, use the original path */ + efree(arch); + return NULL; + } + } else { + entry_len = ZSTR_LEN(filename); + entry = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &entry_len, 1); + if (entry[0] == '/') { + if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { + /* this file is not in the phar, use the original path */ +notfound: + efree(entry); + efree(arch); + return NULL; + } + } else { + if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { + goto notfound; + } + } + /* auto-convert to phar:// */ + if (entry[0] == '/') { + ZEND_ASSERT(strlen("phar://") + arch_len + entry_len < 4096); + name = zend_string_concat3( + "phar://", strlen("phar://"), + arch, arch_len, + entry, entry_len + ); + } else { + name = strpprintf(4096, "phar://%s/%s", arch, entry); + } + efree(entry); + } + + efree(arch); + return name; +} + PHAR_FUNC(phar_file_get_contents) /* {{{ */ { - char *filename; - size_t filename_len; + zend_string *filename; zend_string *contents; bool use_include_path = 0; - php_stream *stream; zend_long offset = -1; zend_long maxlen; bool maxlen_is_null = 1; @@ -111,117 +175,56 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */ } /* Parse arguments */ - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p|br!ll!", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen, &maxlen_is_null) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!ll!", &filename, &use_include_path, &zcontext, &offset, &maxlen, &maxlen_is_null) == FAILURE) { goto skip_phar; } if (maxlen_is_null) { maxlen = (ssize_t) PHP_STREAM_COPY_ALL; + } else if (maxlen < 0) { + zend_argument_value_error(5, "must be greater than or equal to 0"); + RETURN_THROWS(); } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - fname_len = strlen(fname); - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { - char *name; - phar_archive_data *phar; - - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - if (!maxlen_is_null && maxlen < 0) { - efree(arch); - zend_argument_value_error(5, "must be greater than or equal to 0"); - RETURN_THROWS(); - } - - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if ((entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - name = ZSTR_VAL(entry_str); - goto phar_it; - } else { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(arch); - efree(entry); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - if (entry != filename) { - efree(entry); - } - } - -phar_it: - 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 (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + php_stream_context *context = NULL; + php_stream *stream; - if (!stream) { - RETURN_FALSE; - } + if (zcontext) { + context = php_stream_context_from_zval(zcontext, 0); + } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context); - if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) { - php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); - php_stream_close(stream); - RETURN_FALSE; - } + zend_string_release_ex(name, false); - /* uses mmap if possible */ - contents = php_stream_copy_to_mem(stream, maxlen, 0); - if (contents && ZSTR_LEN(contents) > 0) { - RETVAL_STR(contents); - } else if (contents) { - zend_string_release_ex(contents, 0); - RETVAL_EMPTY_STRING(); - } else { - RETVAL_FALSE; - } + if (!stream) { + RETURN_FALSE; + } + if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); php_stream_close(stream); - return; + RETURN_FALSE; + } + + /* uses mmap if possible */ + contents = php_stream_copy_to_mem(stream, maxlen, 0); + if (contents && ZSTR_LEN(contents) > 0) { + RETVAL_STR(contents); + } else if (contents) { + zend_string_release_ex(contents, 0); + RETVAL_EMPTY_STRING(); + } else { + RETVAL_FALSE; } + + php_stream_close(stream); + return; } skip_phar: PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU); @@ -231,12 +234,9 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */ PHAR_FUNC(phar_readfile) /* {{{ */ { - char *filename; - size_t filename_len; - int size = 0; + zend_string *filename; bool use_include_path = 0; zval *zcontext = NULL; - php_stream *stream; if (!PHAR_G(intercepted)) { goto skip_phar; @@ -246,79 +246,25 @@ PHAR_FUNC(phar_readfile) /* {{{ */ && !HT_IS_INITIALIZED(&cached_phars)) { goto skip_phar; } - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!", &filename, &use_include_path, &zcontext) == FAILURE) { goto skip_phar; } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - char *name; - phar_archive_data *phar; - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { - goto skip_phar; - } - fname_len = strlen(fname); - if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if (!(entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } else { - name = ZSTR_VAL(entry_str); - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(entry); - efree(arch); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - efree(entry); - } + php_stream *stream; + php_stream_context *context = php_stream_context_from_zval(zcontext, 0); - efree(arch); - context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context); - if (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context); + + zend_string_release_ex(name, false); if (stream == NULL) { RETURN_FALSE; } - size = php_stream_passthru(stream); + ssize_t size = php_stream_passthru(stream); php_stream_close(stream); RETURN_LONG(size); } @@ -332,11 +278,11 @@ PHAR_FUNC(phar_readfile) /* {{{ */ PHAR_FUNC(phar_fopen) /* {{{ */ { - char *filename, *mode; - size_t filename_len, mode_len; + zend_string *filename; + char *mode; + size_t mode_len; bool use_include_path = 0; zval *zcontext = NULL; - php_stream *stream; if (!PHAR_G(intercepted)) { goto skip_phar; @@ -347,76 +293,21 @@ PHAR_FUNC(phar_fopen) /* {{{ */ /* 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(), "ps|br!", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "Ps|br!", &filename, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) { goto skip_phar; } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - char *name; - phar_archive_data *phar; - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { - goto skip_phar; - } - fname_len = strlen(fname); - if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if (!(entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } else { - name = ZSTR_VAL(entry_str); - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(entry); - efree(arch); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - /* this file is not in the phar, use the original path */ - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - efree(entry); - } + php_stream *stream; + php_stream_context *context = php_stream_context_from_zval(zcontext, 0); - efree(arch); - context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context); - if (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), mode, 0 | REPORT_ERRORS, NULL, context); + + zend_string_release_ex(name, false); if (stream == NULL) { RETURN_FALSE; } diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 8fc921ac6d273..03263e2df53d1 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -3288,7 +3288,7 @@ zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type static zend_string *phar_resolve_path(zend_string *filename) { - zend_string *ret = phar_find_in_include_path(ZSTR_VAL(filename), ZSTR_LEN(filename), NULL); + zend_string *ret = phar_find_in_include_path(filename, NULL); if (!ret) { ret = phar_save_resolve_path(filename); } diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 30b408a8c4462..9f8a46b65ec60 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -547,7 +547,7 @@ char *phar_compress_filter(phar_entry_info * entry, int return_unknown); /* void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); */ void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); int phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_len, char *path, size_t path_len); -zend_string *phar_find_in_include_path(char *file, size_t file_len, phar_archive_data **pphar); +zend_string *phar_find_in_include_path(zend_string *file, phar_archive_data **pphar); char *phar_fix_filepath(char *path, size_t *new_len, int use_cwd); phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error); void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, int persistent); diff --git a/ext/phar/util.c b/ext/phar/util.c index e2c6d9f331896..24f3ce55cd968 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -239,7 +239,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_le } /* }}} */ -zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar_archive_data **pphar) /* {{{ */ +zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */ { zend_string *ret; char *path, *fname, *arch, *entry, *test; @@ -272,7 +272,7 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar efree(entry); - if (*filename == '.') { + if (*ZSTR_VAL(filename) == '.') { size_t try_len; if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { @@ -284,8 +284,8 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar *pphar = phar; } - try_len = filename_len; - test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1); + try_len = ZSTR_LEN(filename); + test = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &try_len, 1); if (*test == '/') { if (zend_hash_str_exists(&(phar->manifest), test + 1, try_len - 1)) { @@ -307,7 +307,7 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); efree(arch); - ret = php_resolve_path(filename, filename_len, path); + ret = php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), path); efree(path); if (ret && ZSTR_LEN(ret) > 8 && !strncmp(ZSTR_VAL(ret), "phar://", 7)) {