Commit 8d28c0562b7 for php.net
commit 8d28c0562b70f6b0512ad7c05780cc51a43709bc
Author: Gina Peter Banyard <girgias@php.net>
Date: Fri Apr 17 18:53:08 2026 +0100
ext/phar: refactor phar_split_fname() to return zend_string* rather than out params (#21777)
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
index c486fd41abf..64cace88992 100644
--- a/ext/phar/dirstream.c
+++ b/ext/phar/dirstream.c
@@ -345,21 +345,21 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo
{
phar_entry_info entry, *e;
phar_archive_data *phar = NULL;
- char *error, *arch;
- size_t arch_len;
+ char *error;
php_url *resource = NULL;
/* pre-readonly check, we need to know if this is a data phar */
- if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, NULL, 2, 2)) {
+ zend_string *arch = phar_split_fname(url_from, strlen(url_from), NULL, 2, 2);
+ if (!arch) {
php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
return 0;
}
- if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
+ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) {
phar = NULL;
}
- efree(arch);
+ zend_string_release_ex(arch, false);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
@@ -471,21 +471,21 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options
{
phar_entry_info *entry;
phar_archive_data *phar = NULL;
- char *error, *arch;
- size_t arch_len;
+ char *error;
php_url *resource = NULL;
/* pre-readonly check, we need to know if this is a data phar */
- if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, NULL, 2, 2)) {
+ zend_string *arch = phar_split_fname(url, strlen(url), NULL, 2, 2);
+ if (!arch) {
php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
return 0;
}
- if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
+ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) {
phar = NULL;
}
- efree(arch);
+ zend_string_release_ex(arch, false);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
index 0e7d2df0db6..20ce0e8d725 100644
--- a/ext/phar/func_interceptors.c
+++ b/ext/phar/func_interceptors.c
@@ -38,8 +38,6 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
- char *arch;
- size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -48,7 +46,8 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
goto skip_phar;
}
- if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (arch) {
php_stream_context *context = NULL;
php_stream *stream;
char *name;
@@ -58,12 +57,12 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
zend_string *entry = phar_fix_filepath(filename, filename_len, true);
if (ZSTR_VAL(entry)[0] == '/') {
- spprintf(&name, 4096, "phar://%s%s", arch, ZSTR_VAL(entry));
+ spprintf(&name, 4096, "phar://%s%s", ZSTR_VAL(arch), ZSTR_VAL(entry));
} else {
- spprintf(&name, 4096, "phar://%s/%s", arch, ZSTR_VAL(entry));
+ spprintf(&name, 4096, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(entry));
}
zend_string_release_ex(entry, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
if (zcontext) {
context = php_stream_context_from_zval(zcontext, 0);
}
@@ -84,8 +83,6 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool using_include_path)
{
- char *arch;
- size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -94,15 +91,16 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool
return NULL;
}
- if (FAILURE == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (!arch) {
return NULL;
}
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
/* 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);
+ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) {
+ zend_string_release_ex(arch, false);
return NULL;
}
@@ -110,7 +108,7 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool
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);
+ zend_string_release_ex(arch, false);
return NULL;
}
} else {
@@ -124,24 +122,24 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool
/* this file is not in the phar, use the original path */
if (!is_in_phar) {
zend_string_release_ex(entry, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
return NULL;
}
/* auto-convert to phar:// */
if (ZSTR_VAL(entry)[0] == '/') {
- ZEND_ASSERT(strlen("phar://") + arch_len + ZSTR_LEN(entry) < 4096);
+ ZEND_ASSERT(strlen("phar://") + ZSTR_LEN(arch) + ZSTR_LEN(entry) < 4096);
name = zend_string_concat3(
"phar://", strlen("phar://"),
- arch, arch_len,
+ ZSTR_VAL(arch), ZSTR_LEN(arch),
ZSTR_VAL(entry), ZSTR_LEN(entry)
);
} else {
- name = strpprintf(4096, "phar://%s/%s", arch, ZSTR_VAL(entry));
+ name = strpprintf(4096, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(entry));
}
zend_string_release_ex(entry, false);
}
- efree(arch);
+ zend_string_release_ex(arch, false);
return name;
}
@@ -492,12 +490,12 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ
phar = PHAR_G(last_phar);
goto splitted;
}
- char *arch;
- size_t arch_len;
- if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) {
+
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (arch) {
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- zend_result has_archive = phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL);
- efree(arch);
+ zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL);
+ zend_string_release_ex(arch, false);
if (FAILURE == has_archive) {
goto skip_phar;
}
@@ -721,8 +719,6 @@ PHP_FUNCTION(phar_is_file) /* {{{ */
goto skip_phar;
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
- char *arch;
- size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -731,12 +727,15 @@ PHP_FUNCTION(phar_is_file) /* {{{ */
goto skip_phar;
}
- if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (arch) {
phar_archive_data *phar;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
/* retrieving a file within the current directory, so use this if possible */
- if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
+ zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL);
+ zend_string_release_ex(arch, false);
+ if (has_archive == SUCCESS) {
phar_entry_info *etemp;
zend_string *entry = phar_fix_filepath(filename, filename_len, true);
@@ -747,12 +746,10 @@ PHP_FUNCTION(phar_is_file) /* {{{ */
}
zend_string_release_ex(entry, false);
if (etemp) {
- efree(arch);
RETURN_BOOL(!etemp->is_dir);
}
/* this file is not in the current directory, use the original path */
}
- efree(arch);
RETURN_FALSE;
}
}
@@ -779,8 +776,6 @@ PHP_FUNCTION(phar_is_link) /* {{{ */
goto skip_phar;
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
- char *arch;
- size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -789,12 +784,15 @@ PHP_FUNCTION(phar_is_link) /* {{{ */
goto skip_phar;
}
- if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (arch) {
phar_archive_data *phar;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
/* retrieving a file within the current directory, so use this if possible */
- if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
+ zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL);
+ zend_string_release_ex(arch, false);
+ if (has_archive == SUCCESS) {
phar_entry_info *etemp;
zend_string *entry = phar_fix_filepath(filename, filename_len, true);
@@ -805,11 +803,9 @@ PHP_FUNCTION(phar_is_link) /* {{{ */
}
zend_string_release_ex(entry, false);
if (etemp) {
- efree(arch);
RETURN_BOOL(etemp->link);
}
}
- efree(arch);
RETURN_FALSE;
}
}
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 5fb6c864be7..3008316f627 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -2164,7 +2164,7 @@ zend_string* phar_fix_filepath(const char *path, size_t path_length, bool use_cw
*
* This is used by phar_parse_url()
*/
-zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, zend_string **entry, int executable, int for_create) /* {{{ */
+zend_string* phar_split_fname_ex(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create, const char **error) /* {{{ */
{
const char *ext_str;
#ifdef PHP_WIN32
@@ -2172,8 +2172,11 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a
#endif
size_t ext_len;
+ if (error) {
+ *error = NULL;
+ }
if (zend_char_has_nul_byte(filename, filename_len)) {
- return FAILURE;
+ return NULL;
}
if (!strncasecmp(filename, "phar://", 7)) {
@@ -2191,12 +2194,12 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a
#endif
if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, false) == FAILURE) {
if (ext_len != -1) {
- if (!ext_str) {
+ if (!ext_str && error) {
/* no / detected, restore arch for error message */
#ifdef PHP_WIN32
- *arch = save;
+ *error = save;
#else
- *arch = (char*)filename;
+ *error = filename;
#endif
}
@@ -2205,19 +2208,19 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a
efree((char *)filename);
}
#endif
- return FAILURE;
+ return NULL;
}
ext_len = 0;
/* no extension detected - instead we are dealing with an alias */
}
- *arch_len = ext_str - filename + ext_len;
- *arch = estrndup(filename, *arch_len);
+ size_t arch_len = ext_str - filename + ext_len;
+ zend_string *arch = zend_string_init(filename, arch_len, false);
if (entry) {
if (ext_str[ext_len]) {
- size_t computed_entry_len = filename_len - *arch_len;
+ size_t computed_entry_len = filename_len - arch_len;
/* We don't need to unixify the path on Windows,
* as ext_str is derived from filename that was already unixify */
*entry = phar_fix_filepath(ext_str+ext_len, computed_entry_len, false);
@@ -2232,10 +2235,14 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a
}
#endif
- return SUCCESS;
+ return arch;
}
/* }}} */
+zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create) {
+ return phar_split_fname_ex(filename, filename_len, entry, executable, for_create, NULL);
+}
+
/**
* Invoked when a user calls Phar::mapPhar() from within an executing .phar
* to set up its manifest directly
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index a60c5ed5d43..34f221f43e0 100644
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -474,7 +474,8 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error);
ZEND_ATTRIBUTE_NONNULL int phar_flush(phar_archive_data *archive, char **error);
zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, bool is_complete);
-zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, zend_string **entry, int executable, int for_create);
+zend_string* phar_split_fname_ex(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create, const char **error);
+zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create);
typedef enum {
pcr_use_query,
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
index f97240010d4..07058eefc46 100644
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -403,33 +403,27 @@ static void phar_postprocess_ru_web(char *fname, size_t fname_len, char *entry,
*/
PHP_METHOD(Phar, running)
{
- zend_string *fname;
- char *arch;
- size_t arch_len;
bool retphar = true;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &retphar) == FAILURE) {
RETURN_THROWS();
}
- fname = zend_get_executed_filename_ex();
+ const zend_string *fname = zend_get_executed_filename_ex();
if (!fname) {
RETURN_EMPTY_STRING();
}
- if (
- zend_string_starts_with_literal_ci(fname, "phar://")
- && SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)
- ) {
- if (retphar) {
- RETVAL_STRINGL(ZSTR_VAL(fname), arch_len + 7);
- efree(arch);
- return;
- } else {
- // TODO: avoid reallocation ???
- RETVAL_STRINGL(arch, arch_len);
- efree(arch);
- return;
+ if (zend_string_starts_with_literal_ci(fname, "phar://")) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0);
+ if (arch) {
+ if (retphar) {
+ RETVAL_STRINGL(ZSTR_VAL(fname), ZSTR_LEN(arch) + 7);
+ zend_string_release_ex(arch, false);
+ return;
+ } else {
+ RETURN_STR(arch);
+ }
}
}
@@ -444,8 +438,8 @@ PHP_METHOD(Phar, running)
*/
PHP_METHOD(Phar, mount)
{
- char *fname, *arch = NULL, *path, *actual;
- size_t fname_len, arch_len;
+ char *fname, *path, *actual;
+ size_t fname_len;
size_t path_len, actual_len;
phar_archive_data *pphar;
#ifdef PHP_WIN32
@@ -477,31 +471,29 @@ PHP_METHOD(Phar, mount)
#endif
zend_string *entry = NULL;
- if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, NULL, 2, 0)) {
+ zend_string *arch = NULL;
+ if (fname_len > 7 && !memcmp(fname, "phar://", 7) && (arch = phar_split_fname(fname, fname_len, NULL, 2, 0))) {
if (path_len > 7 && !memcmp(path, "phar://", 7)) {
zend_throw_exception_ex(phar_ce_PharException, 0, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path);
- efree(arch);
+ zend_string_release_ex(arch, false);
goto finish;
}
carry_on2:
- if (NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len))) {
- if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len))) {
+ if (NULL == (pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), arch))) {
+ if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_find_ptr(&cached_phars, arch))) {
if (SUCCESS == phar_copy_on_write(&pphar)) {
goto carry_on;
}
}
- zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", arch);
-
- if (arch) {
- efree(arch);
- }
+ zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", ZSTR_VAL(arch));
+ zend_string_release_ex(arch, false);
goto finish;
}
carry_on:
if (SUCCESS != phar_mount_entry(pphar, actual, actual_len, path, path_len)) {
- zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, arch);
+ zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, ZSTR_VAL(arch));
}
if (entry && path == ZSTR_VAL(entry)) {
@@ -509,7 +501,7 @@ PHP_METHOD(Phar, mount)
}
if (arch) {
- efree(arch);
+ zend_string_release_ex(arch, false);
}
goto finish;
@@ -521,7 +513,7 @@ PHP_METHOD(Phar, mount)
}
goto carry_on;
- } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, 2, 0)) {
+ } else if ((arch = phar_split_fname(path, path_len, &entry, 2, 0))) {
path = ZSTR_VAL(entry);
path_len = ZSTR_LEN(entry);
goto carry_on2;
@@ -1077,9 +1069,8 @@ static const spl_other_handler phar_spl_foreign_handler = {
*/
PHP_METHOD(Phar, __construct)
{
- char *fname, *alias = NULL, *error, *arch = NULL, *save_fname;
+ char *fname, *alias = NULL, *error, *save_fname;
size_t fname_len, alias_len = 0;
- size_t arch_len;
bool is_data;
zend_long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
zend_long format = 0;
@@ -1108,27 +1099,19 @@ PHP_METHOD(Phar, __construct)
save_fname = fname;
zend_string *entry = NULL;
- if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, !is_data, 2)) {
+ /* phar_split_fname() will unixify the path */
+ zend_string *arch = phar_split_fname(fname, fname_len, &entry, !is_data, 2);
+ if (arch) {
/* use arch (the basename for the archive) for fname instead of fname */
/* this allows support for RecursiveDirectoryIterator of subdirectories */
-#ifdef PHP_WIN32
- phar_unixify_path_separators(arch, arch_len);
-#endif
- fname = arch;
- fname_len = arch_len;
-#ifdef PHP_WIN32
- } else {
- arch = estrndup(fname, fname_len);
- arch_len = fname_len;
- fname = arch;
- phar_unixify_path_separators(arch, arch_len);
-#endif
+ fname = ZSTR_VAL(arch);
+ fname_len = ZSTR_LEN(arch);
}
if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error) == FAILURE) {
- if (fname == arch && fname != save_fname) {
- efree(arch);
+ if (arch && fname == ZSTR_VAL(arch) && fname != save_fname) {
+ zend_string_release_ex(arch, false);
fname = save_fname;
}
@@ -1153,8 +1136,8 @@ PHP_METHOD(Phar, __construct)
phar_data->is_tar = false;
}
- if (fname == arch) {
- efree(arch);
+ if (arch && fname == ZSTR_VAL(arch)) {
+ zend_string_release_ex(arch, false);
fname = save_fname;
}
@@ -1260,9 +1243,8 @@ PHP_METHOD(Phar, getSupportedCompression)
/* {{{ Completely remove a phar archive from memory and disk */
PHP_METHOD(Phar, unlinkArchive)
{
- char *fname, *error, *arch;
+ char *fname, *error;
size_t fname_len;
- size_t arch_len;
phar_archive_data *phar;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
@@ -1284,19 +1266,17 @@ PHP_METHOD(Phar, unlinkArchive)
RETURN_THROWS();
}
- zend_string *zend_file_name = zend_get_executed_filename_ex();
-
- if (
- zend_file_name
- && zend_string_starts_with_literal_ci(zend_file_name, "phar://")
- && SUCCESS == phar_split_fname(ZSTR_VAL(zend_file_name), ZSTR_LEN(zend_file_name), &arch, &arch_len, NULL, 2, 0)
- ) {
- if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
- zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname);
- efree(arch);
- RETURN_THROWS();
+ const zend_string *zend_file_name = zend_get_executed_filename_ex();
+ if (zend_file_name && zend_string_starts_with_literal_ci(zend_file_name, "phar://")) {
+ zend_string *arch = phar_split_fname(ZSTR_VAL(zend_file_name), ZSTR_LEN(zend_file_name), NULL, 2, 0);
+ if (arch) {
+ if (ZSTR_LEN(arch) == fname_len && !memcmp(ZSTR_VAL(arch), fname, ZSTR_LEN(arch))) {
+ zend_string_release_ex(arch, false);
+ zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname);
+ RETURN_THROWS();
+ }
+ zend_string_release_ex(arch, false);
}
- efree(arch);
}
if (phar->is_persistent) {
@@ -4395,9 +4375,8 @@ PHP_METHOD(Phar, extractTo)
/* {{{ Construct a Phar entry object */
PHP_METHOD(PharFileInfo, __construct)
{
- char *fname, *arch, *error;
+ char *fname, *error;
size_t fname_len;
- size_t arch_len;
phar_entry_object *entry_obj;
phar_archive_data *phar_data;
zval arg1;
@@ -4413,15 +4392,22 @@ PHP_METHOD(PharFileInfo, __construct)
RETURN_THROWS();
}
+ if (fname_len < 7 || memcmp(fname, "phar://", 7)) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0,
+ "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
+ RETURN_THROWS();
+ }
+
zend_string *entry = NULL;
- if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, 2, 0) == FAILURE) {
+ zend_string *arch = phar_split_fname(fname, fname_len, &entry, 2, 0);
+ if (!arch) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0,
"'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
RETURN_THROWS();
}
- if (phar_open_from_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error) == FAILURE) {
- efree(arch);
+ if (phar_open_from_filename(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, REPORT_ERRORS, &phar_data, &error) == FAILURE) {
+ zend_string_release_ex(arch, false);
efree(entry);
if (error) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0,
@@ -4437,14 +4423,15 @@ PHP_METHOD(PharFileInfo, __construct)
phar_entry_info *entry_info = phar_get_entry_info_dir(phar_data, ZSTR_VAL(entry), ZSTR_LEN(entry), 1, &error, true);
if (UNEXPECTED(!entry_info)) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0,
- "Cannot access phar file entry '%s' in archive '%s'%s%s", ZSTR_VAL(entry), arch, error ? ", " : "", error ? error : "");
+ "Cannot access phar file entry '%s' in archive '%s'%s%s",
+ ZSTR_VAL(entry), ZSTR_VAL(arch), error ? ", " : "", error ? error : "");
zend_string_release_ex(entry, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
RETURN_THROWS();
}
zend_string_release_ex(entry, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
entry_obj->entry = entry_info;
if (!entry_info->is_persistent && !entry_info->is_temp_dir) {
diff --git a/ext/phar/stream.c b/ext/phar/stream.c
index 4b49703b4ab..455f403b597 100644
--- a/ext/phar/stream.c
+++ b/ext/phar/stream.c
@@ -58,8 +58,7 @@ const php_stream_wrapper php_stream_phar_wrapper = {
php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options) /* {{{ */
{
php_url *resource;
- char *arch = NULL, *error;
- size_t arch_len;
+ char *error;
if (strncasecmp(filename, "phar://", 7)) {
return NULL;
@@ -70,12 +69,14 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const
}
return NULL;
}
+
zend_string *entry = NULL;
- if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) {
+ const char *arch_error = NULL;
+ zend_string *arch = phar_split_fname_ex(filename, strlen(filename), &entry, 2, (mode[0] == 'w' ? 2 : 0), &arch_error);
+ if (!arch) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
- if (arch && !entry) {
- php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch);
- arch = NULL;
+ if (arch_error && !entry) {
+ php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch_error);
} else {
php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url or non-existent phar \"%s\"", filename);
}
@@ -84,8 +85,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const
}
resource = ecalloc(1, sizeof(php_url));
resource->scheme = ZSTR_INIT_LITERAL("phar", 0);
- resource->host = zend_string_init(arch, arch_len, 0);
- efree(arch);
+ resource->host = arch;
resource->path = entry;
#ifdef MBO_0
diff --git a/ext/phar/util.c b/ext/phar/util.c
index 8af0c488f5c..ef07460559c 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -266,8 +266,8 @@ zend_result phar_mount_entry(phar_archive_data *phar, const char *filename, size
zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */
{
zend_string *ret;
- char *path, *arch;
- size_t arch_len;
+ char *path;
+ zend_string *arch;
phar_archive_data *phar;
if (pphar) {
@@ -294,19 +294,22 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data
&& ZSTR_LEN(fname) - length_phar_protocol >= PHAR_G(last_phar_name_len)
&& !memcmp(ZSTR_VAL(fname) + length_phar_protocol, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))
) {
- arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
- arch_len = PHAR_G(last_phar_name_len);
+ arch = zend_string_init(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len), false);
phar = PHAR_G(last_phar);
goto splitted;
}
- if (!is_file_a_phar_wrapper || SUCCESS != phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 1, 0)) {
+ if (!is_file_a_phar_wrapper) {
+ return NULL;
+ }
+ arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 1, 0);
+ if (!arch) {
return NULL;
}
if (*ZSTR_VAL(filename) == '.') {
- if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
- efree(arch);
+ if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) {
+ zend_string_release_ex(arch, false);
return NULL;
}
splitted:
@@ -319,42 +322,43 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data
if (zend_hash_str_exists(&(phar->manifest), ZSTR_VAL(test) + 1, ZSTR_LEN(test) - 1)) {
ret = zend_string_concat3(
"phar://", strlen("phar://"),
- arch, arch_len,
+ ZSTR_VAL(arch), ZSTR_LEN(arch),
ZSTR_VAL(test), ZSTR_LEN(test)
);
zend_string_release_ex(test, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
return ret;
}
} else {
if (zend_hash_exists(&(phar->manifest), test)) {
- ret = strpprintf(0, "phar://%s/%s", arch, ZSTR_VAL(test));
+ ret = strpprintf(0, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(test));
zend_string_release_ex(test, false);
- efree(arch);
+ zend_string_release_ex(arch, false);
return ret;
}
}
zend_string_release_ex(test, false);
}
- 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);
+ spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", ZSTR_VAL(arch), PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
+ zend_string_release_ex(arch, false);
ret = php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), path);
efree(path);
if (ret && zend_string_starts_with_literal_ci(ret, "phar://")) {
/* found phar:// */
- if (SUCCESS != phar_split_fname(ZSTR_VAL(ret), ZSTR_LEN(ret), &arch, &arch_len, NULL, 1, 0)) {
+ arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 1, 0);
+ if (!arch) {
return ret;
}
- *pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len);
+ *pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), arch);
if (!*pphar && PHAR_G(manifest_cached)) {
- *pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len);
+ *pphar = zend_hash_find_ptr(&cached_phars, arch);
}
- efree(arch);
+ zend_string_release_ex(arch, false);
}
return ret;