COMPLETELY rework filename extension detection. Now the only requirements are:

1 - executable phars must contain '.phar' in the filename
2 - non-executable phars must not contain '.phar' and must have an extension of at least 1 character

In addition, phar filenames must exist if opened for read, and the directory containing the phar must exist if opened for creation
if opened for creation, the file must not already exist
[DOC]
This commit is contained in:
Greg Beaver 2008-04-18 04:13:13 +00:00
parent bd6696c639
commit c4f502fae0
13 changed files with 319 additions and 143 deletions

View File

@ -411,7 +411,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
uint host_len;
/* 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, &entry2, &entry_len TSRMLS_CC)) {
if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
return FAILURE;
}
@ -536,8 +536,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
uint host_len;
/* pre-readonly check, we need to know if this is a data phar */
if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified", url);
if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
return FAILURE;
}
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {

View File

@ -45,7 +45,7 @@ PHAR_FUNC(phar_opendir) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
php_stream_context *context = NULL;
php_stream *stream;
char *name;
@ -109,7 +109,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
char *name, *old;
phar_archive_data **pphar;
@ -223,7 +223,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
goto skip_phar;
}
@ -303,7 +303,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
goto skip_phar;
}
@ -573,7 +573,7 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
efree(entry);
@ -827,7 +827,7 @@ PHAR_FUNC(phar_is_file) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
efree(entry);
@ -875,7 +875,7 @@ PHAR_FUNC(phar_is_link) /* {{{ */
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
phar_archive_data **pphar;
efree(entry);

View File

@ -1014,60 +1014,53 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int
/**
* Create or open a phar for writing
*/
int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, char *objname, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
{
const char *ext_str;
int ext_len, is_data = 0, zip = 0, tar = 0;
const char *ext_str, *z;
int ext_len;
if (error) {
*error = NULL;
}
if (phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len) == SUCCESS) {
if (ext_len >= sizeof(".zip")-1 && !memcmp((void *) ext_str, (void *) ".zip", sizeof(".zip")-1)) {
zip = 1;
/* first try to open an existing file */
if (phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
goto check_file;
}
/* next try to create a new file */
if (FAILURE == phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
if (error) {
spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised", fname);
}
if ((ext_len >= sizeof(".tar")-1 && !memcmp((void *) ext_str, (void *) ".tar", sizeof(".tar")-1)) || (ext_len >= sizeof(".tgz")-1 && !memcmp((void *) ext_str, (void *) ".tgz", sizeof(".tgz")-1))) {
tar = 1;
}
if (tar || zip) {
if (objname && strncmp(objname, "PharData", 8) != 0) {
/* Nested exception causes memleak here */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open '%s' as a Phar object. Use PharData::__construct() for a standard %s archive", fname, tar ? "tar" : "zip");
return FAILURE;
}
is_data = 1;
} else {
if (objname && strncmp(objname, "PharData", 8) == 0) {
/* Nested exception causes memleak here */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open '%s' as a PharData object. Use Phar::__construct() for archives named other than .zip or .tar", fname);
return FAILURE;
}
}
} else {
/* Nested exception causes memleak here */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open '%s' as a %s object, file extension (or combination) not recognised", fname, objname);
return FAILURE;
}
check_file:
if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, pphar, 0 TSRMLS_CC) == SUCCESS) {
if (is_data && !((*pphar)->is_tar || (*pphar)->is_zip)) {
if (error) {
spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
}
}
if (PHAR_G(readonly) && !is_data && ((*pphar)->is_tar || (*pphar)->is_zip)) {
phar_entry_info *stub;
if (FAILURE == zend_hash_find(&((*pphar)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
return FAILURE;
}
}
if (pphar && (!PHAR_G(readonly) || is_data)) {
(*pphar)->is_writeable = 1;
}
return SUCCESS;
}
if ((ext_len >= sizeof(".phar.zip")-1 && !memcmp((void *) ext_str, (void *) ".phar.zip", sizeof(".phar.zip")-1)) || zip) {
if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
// assume zip-based phar
return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
}
if ((ext_len >= sizeof(".phar.tar")-1 && !memcmp((void *) ext_str, (void *) ".phar.tar", sizeof(".phar.tar")-1)) || tar) {
if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
// assume tar-based phar
return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
}
@ -1399,67 +1392,234 @@ static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias,
}
/* }}} */
int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len) /* {{{ */
/*
* given the location of the file extension and the start of the file path,
* determine the end of the portion of the path (i.e. /path/to/file.ext/blah
* grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
* stat it to determine if it exists.
* if so, check to see if it is a directory and fail if so
* if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
* succeed if we are creating the file, otherwise fail.
*/
static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC)
{
int i;
char end;
php_stream_statbuf ssb;
char *realpath, old, *a = (char *)(ext + ext_len);
old = *a;
*a = '\0';
if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
*a = old;
efree(realpath);
return SUCCESS;
}
efree(realpath);
}
if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) {
*a = old;
if (ssb.sb.st_mode & S_IFDIR) {
return FAILURE;
}
if (for_create == 1) {
return FAILURE;
}
return SUCCESS;
} else {
char *slash;
if (!for_create) {
*a = old;
return FAILURE;
}
slash = (char *) strrchr(fname, '/');
*a = old;
if (slash) {
old = *slash;
*slash = '\0';
}
if (SUCCESS != php_stream_stat_path((char *) fname, &ssb)) {
if (slash) {
*slash = old;
} else {
if (!(realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
return FAILURE;
}
a = strstr(realpath, fname) + ((ext - fname) + ext_len);
*a = '\0';
slash = strrchr(realpath, '/');
if (slash) {
*slash = '\0';
} else {
efree(realpath);
return FAILURE;
}
if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
efree(realpath);
return FAILURE;
}
efree(realpath);
if (ssb.sb.st_mode & S_IFDIR) {
return SUCCESS;
}
}
return FAILURE;
}
if (slash) {
*slash = old;
}
if (ssb.sb.st_mode & S_IFDIR) {
return SUCCESS;
}
return FAILURE;
}
}
/* check for ".phar" in extension */
static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC)
{
char test[51];
const char *pos;
#define EXTINF(check, ext) { check, ext, sizeof(ext)-1 }
const struct {
int check;
const char * const ext;
int len;
} ext_info[] = {
/* longer exts must be specified later */
EXTINF(1, ".php"),
EXTINF(0, ".phar"),
EXTINF(0, ".tgz"),
EXTINF(0, ".zip"),
EXTINF(0, ".tar"),
EXTINF(0, ".tar.gz"),
EXTINF(0, ".tar.bz2"),
EXTINF(0, ".phar.gz"),
EXTINF(0, ".phar.bz2"),
EXTINF(0, ".phar.php"),
EXTINF(0, ".phar.tar"),
EXTINF(0, ".phar.zip"),
EXTINF(0, ".phar.tar.gz"),
EXTINF(0, ".phar.tar.bz2"),
EXTINF(0, ".phar.tar.php"),
EXTINF(0, ".phar.zip.php")};
if (ext_len >= 50) {
return FAILURE;
}
if (executable == 1) {
/* copy "." as well */
memcpy(test, ext_str - 1, ext_len + 1);
test[ext_len + 1] = '\0';
/* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
/* (phar://hi/there/.phar/oops is also invalid) */
if ((pos = strstr(test, ".phar")) && (*(pos - 1) != '/')
&& (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
} else {
return FAILURE;
}
}
/* data phars need only contain a single non-"." to be valid */
if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
}
return FAILURE;
}
/*
* if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
* if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
* the first extension as the filename extension
*
* if an extension is found, it sets ext_str to the location of the file extension in filename,
* and ext_len to the length of the extension.
* for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
* the calling function to use "alias" as the phar alias
*
* the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
* extension rules, not to iterate.
*/
int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC) /* {{{ */
{
const char *pos, *slash;
int filename_len = strlen(filename);
*ext_str = NULL;
for (i = 0; i < sizeof(ext_info) / sizeof(ext_info[0]); ++i) {
pos = strstr(filename, ext_info[i].ext);
/* If pos is not NULL then we found the extension. But we have to check
* to more things. First some extensions cannot be the end of the string
* (e.g. .php). Second when we already found an extension at an earlier
* position, we ignore the new one. In case we found one at the same
* place, we probably found a longer one. As the list is ordered that
* way we do not need to check for a greater length.
*/
if (pos && (/*1*/ !ext_info[i].check || pos[ext_info[i].len] != '\0')
&& (/*2*/ !*ext_str || pos <= *ext_str)) {
if (!filename_len || filename_len == 1) {
return FAILURE;
}
phar_request_initialize(TSRMLS_C);
/* first check for extract_list */
if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_plain_map))) {
for (zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_plain_map));
zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_plain_map)) == SUCCESS;
zend_hash_move_forward(&(PHAR_GLOBALS->phar_plain_map))) {
char *key;
uint keylen;
ulong intkey;
if (HASH_KEY_IS_STRING != zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_plain_map), &key, &keylen, &intkey, 0, NULL)) {
continue;
}
if (keylen <= filename_len && !memcmp(key, filename, keylen - 1)) {
/* found plain map, so we grab the extension, if any */
if (is_complete && keylen != filename_len + 1) {
continue;
}
if (for_create == 1) {
return FAILURE;
}
if (!executable == 1) {
return FAILURE;
}
pos = strrchr(key, '/');
if (pos) {
pos = filename + (pos - key);
slash = strchr(pos, '.');
if (slash) {
*ext_str = slash;
*ext_len = keylen - (slash - filename);
return SUCCESS;
}
*ext_str = pos;
*ext_len = -1;
return FAILURE;
}
*ext_str = filename + keylen - 1;
*ext_len = -1;
return FAILURE;
}
}
}
/* next check for alias in first segment */
pos = strchr(filename, '/');
if (pos) {
if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), filename, pos - filename)) {
*ext_str = pos;
*ext_len = ext_info[i].len;
}
}
if (!*ext_str) {
/* We have an alias with no extension, so locate the first / and fail */
*ext_str = strstr(filename, "/");
if (*ext_str) {
*ext_len = -1;
return FAILURE;
}
}
pos = strchr(filename + 1, '.');
next_extension:
if (!pos) {
return FAILURE;
}
if (check_length && (*ext_str)[*ext_len] != '\0') {
return FAILURE;
slash = strchr(pos, '/');
if (!slash) {
/* this is a url like "phar://blah.phar" with no directory */
*ext_str = pos;
*ext_len = strlen(pos);
/* file extension must contain "phar" */
switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
case SUCCESS :
return SUCCESS;
case FAILURE :
/* we are at the end of the string, so we fail */
return FAILURE;
}
}
end = (*ext_str)[*ext_len];
if (end != '\0' && end != '/' && end != '\\') {
return FAILURE;
/* we've found an extension that ends at a directory separator */
*ext_str = pos;
*ext_len = slash - pos;
switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
case SUCCESS :
return SUCCESS;
case FAILURE :
/* look for more extensions */
if (is_complete) {
return FAILURE;
}
pos = strchr(pos + 1, '.');
if (pos) {
*ext_str = NULL;
*ext_len = 0;
}
goto next_extension;
}
return SUCCESS;
return FAILURE;
}
/* }}} */
@ -1612,7 +1772,7 @@ char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{
*
* This is used by phar_open_url()
*/
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC) /* {{{ */
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
{
const char *ext_str;
int ext_len;
@ -1623,7 +1783,7 @@ int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_le
}
ext_len = 0;
if (phar_detect_phar_fname_ext(filename, 0, &ext_str, &ext_len) == FAILURE) {
if (phar_detect_phar_fname_ext(filename, 0, &ext_str, &ext_len, executable, for_create, 0) == FAILURE) {
if (ext_len != -1) {
if (!ext_str) {
/* no / detected, restore arch for error message */
@ -2698,7 +2858,7 @@ int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /*
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
efree(arch);
efree(entry);

View File

@ -386,7 +386,7 @@ void phar_object_init(TSRMLS_D);
int phar_open_entry_file(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, char *objname, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
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);
@ -436,8 +436,8 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in
phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC);
int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC);
int phar_flush(phar_archive_data *archive, char *user_stub, long len, int convert, char **error TSRMLS_DC);
int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len);
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC);
int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC);
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC);
typedef enum {
pcr_use_query,

View File

@ -442,7 +442,7 @@ PHP_METHOD(Phar, running)
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
efree(entry);
if (retphar) {
RETVAL_STRINGL(fname, arch_len + 7, 1);
@ -475,7 +475,7 @@ PHP_METHOD(Phar, mount)
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
efree(entry);
if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
@ -1076,19 +1076,21 @@ PHP_METHOD(Phar, canWrite)
}
/* }}} */
/* {{{ proto bool Phar::isValidPharFilename(string filename)
/* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
* Returns whether the given filename is a valid phar filename */
PHP_METHOD(Phar, isValidPharFilename)
{
char *fname;
const char *ext_str;
int fname_len, ext_len;
zend_bool executable = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len, &executable) == FAILURE) {
return;
}
RETURN_BOOL(phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len) == SUCCESS);
fname_len = executable;
RETURN_BOOL(phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, fname_len, 1, 1) == SUCCESS);
}
/* }}} */
@ -1148,7 +1150,18 @@ PHP_METHOD(Phar, __construct)
return;
}
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
#if PHP_VERSION_ID >= 60000
objname = phar_obj->std.ce->name.s;
#else
objname = phar_obj->std.ce->name;
#endif
if (!strncmp(objname, "PharData", 8)) {
is_data = 1;
} else {
is_data = 0;
}
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2 TSRMLS_CC)) {
/* use arch (the basename for the archive) for fname instead of fname */
/* this allows support for RecursiveDirectoryIterator of subdirectories */
save_fname = fname;
@ -1166,13 +1179,7 @@ PHP_METHOD(Phar, __construct)
#endif
}
#if PHP_VERSION_ID >= 60000
objname = phar_obj->std.ce->name.s;
#else
objname = phar_obj->std.ce->name;
#endif
if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, objname, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
if (fname == arch) {
efree(arch);
@ -3326,7 +3333,7 @@ PHP_METHOD(PharFileInfo, __construct)
return;
}
if (phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC) == FAILURE) {
if (phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC) == FAILURE) {
efree(arch);
efree(entry);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,

View File

@ -71,13 +71,13 @@ php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode,
}
return NULL;
}
if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len TSRMLS_CC) == FAILURE) {
if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
if (arch && !entry) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "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;
} else {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\" (cannot contain .phar.php and .phar.gz/.phar.bz2)", filename);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url or non-existent phar \"%s\"", filename);
}
}
return NULL;
@ -116,7 +116,7 @@ php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, NULL, options, NULL, &error TSRMLS_CC) == FAILURE)
if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
{
if (error) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
@ -741,12 +741,10 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
error = NULL;
if ((resource_from = phar_open_url(wrapper, url_from, "rb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from);
if ((resource_from = phar_open_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from);
return 0;
}
if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
pfrom = NULL;
if (error) {
@ -758,9 +756,21 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
return 0;
}
if ((resource_to = phar_open_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
php_url_free(resource_from);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to);
return 0;
}
if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
if (error) {
efree(error);
}
pto = NULL;
}
if (PHAR_G(readonly) && (!pto || !pto->is_data)) {
php_url_free(resource_from);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
return 0;
}
@ -771,13 +781,6 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
return 0;
}
if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
if (error) {
efree(error);
}
pto = NULL;
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if (!resource_from->scheme || !resource_from->host || !resource_from->path) {
php_url_free(resource_from);

View File

@ -108,7 +108,8 @@ Warning: opendir(phar://): failed to open dir: phar error: no directory in "phar
phar url "phar://" is unknown in %s027.php on line %d
bool(false)
Warning: opendir(phar://foo.phar/hi): failed to open dir: phar url "phar://foo.phar/hi" is unknown in %s027.php on line %d
Warning: opendir(phar://foo.phar/hi): failed to open dir: phar error: invalid url or non-existent phar "phar://foo.phar/hi"
phar url "phar://foo.phar/hi" is unknown in %s027.php on line %d
bool(false)
extract_list test
.

View File

@ -85,7 +85,7 @@ Warning: mkdir(): internal corruption of phar "%soops.phar" (truncated manifest
Warning: mkdir(): phar error: cannot create directory "phar://", no phar archive specified in %sdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified in %sdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified, or phar archive does not exist in %sdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "hi" in phar "%sunknown.phar", directory does not exist in %sdir.php on line %d

View File

@ -38,5 +38,5 @@ include $fname;
--EXPECTF--
Warning: fopen() expects at least 2 parameters, 0 given in %sfopen.php on line %d
hihi
Warning: fopen(phar://%sfopen.phar.php/notfound.txt): failed to open stream: phar error: "notfound.txt" is not a file in phar "%sfopen.phar.php" in phar://%sfopen.phar.php/index.php on line %d
Warning: fopen(notfound.txt): failed to open stream: No such file or directory in phar://%sfopen.phar.php/index.php on line %d
===DONE===

View File

@ -14,6 +14,9 @@ $pname = 'phar://' . $fname;
$pname2 = 'phar://' . $fname2;
$pname3 = 'phar://' . $fname3;
// create in cwd
chdir(dirname(__FILE__));
file_put_contents('phar://fopen_edgetest.phar/hi', 'hi');
// append
$a = fopen($pname . '/b/c.php', 'a');
// invalid pharname
@ -71,10 +74,11 @@ rename('phar://test.phar/' . basename(__FILE__), 'phar://test.phar/hi');
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
<?php unlink(dirname(__FILE__) . '/fopen_edgetest.phar');
--EXPECTF--
Warning: fopen(phar://%sfopen_edgecases.phar.php/b/c.php): failed to open stream: phar error: open mode append not supported in %sfopen_edgecases.php on line %d
Warning: fopen(phar://%sfopen_edgecases.phar.php.phar.gz): failed to open stream: phar error: invalid url "phar://%sfopen_edgecases.phar.php.phar.gz" (cannot contain .phar.php and .phar.gz/.phar.bz2) in %sfopen_edgecases.php on line %d
Warning: fopen(phar://%sfopen_edgecases.phar.php.phar.gz): failed to open stream: phar error: invalid url or non-existent phar "phar://%sfopen_edgecases.phar.php.phar.gz" in %sfopen_edgecases.php on line %d
bool(false)
Warning: fopen(phar://%sfopen_edgecases.2.phar.php/hi): failed to open stream: internal corruption of phar "%sfopen_edgecases.2.phar.php" (truncated manifest at stub end) in %sfopen_edgecases.php on line %d
@ -107,7 +111,7 @@ Warning: unlink(): phar error: no directory in "phar://", must have at least pha
Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d
Warning: unlink(): unable to open phar for reading "foo.phar" in %sfopen_edgecases.php on line %d
Warning: unlink(): phar error: invalid url or non-existent phar "phar://foo.phar" in %sfopen_edgecases.php on line %d
Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d
@ -115,15 +119,15 @@ Warning: unlink(): phar error: "phar://test.phar/fopen_edgecases.php" cannot be
Warning: unlink(): unlink of "phar://%sfopen_edgecases.phar.php/oops" failed, file does not exist in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://" to "phar://": invalid url "phar://" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://": invalid url "phar://" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://foo.phar/hi" to "phar://": invalid url "phar://foo.phar/hi" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://foo.phar/hi" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://foo.phar/hi", not within the same phar archive in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: write operations disabled by phar.readonly INI setting in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://%sfopen_edgecases.phar.php/there": invalid or non-writable url "phar://%sfopen_edgecases.phar.php/hi" in %sfopen_edgecases.php on line %d
Warning: rename(): phar error: cannot rename "phar://test.phar/fopen_edgecases.php" to "phar://test.phar/hi" from extracted phar archive in %sfopen_edgecases.php on line %d

View File

@ -31,7 +31,7 @@ Warning: mkdir(): phar error: cannot create directory "" in phar "foo.phar", pha
Warning: mkdir(): phar error: cannot create directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified in %smkdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified, or phar archive does not exist in %smkdir.php on line %d
Warning: rmdir(): phar error: cannot remove directory "" in phar "foo.phar", directory does not exist in %smkdir.php on line %d

View File

@ -39,7 +39,8 @@ file1.txtfile2.txtfile3.txt
Warning: opendir(phar://): failed to open dir: phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar)
phar url "phar://" is unknown in %sopendir.php on line %d
Warning: opendir(phar://hi.phar): failed to open dir: phar url "phar://hi.phar" is unknown in %sopendir.php on line %d
Warning: opendir(phar://hi.phar): failed to open dir: phar error: invalid url or non-existent phar "phar://hi.phar"
phar url "phar://hi.phar" is unknown in %sopendir.php on line %d
Warning: opendir(phar://hi.phar/oopsie/daisy/): failed to open dir: phar error: file "%soopsie/daisy" extracted from "hi.phar" could not be opened in %sopendir.php on line %d
===DONE===

View File

@ -161,7 +161,7 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
fname = zend_get_executed_filename(TSRMLS_C);
if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
if (*filename == '.') {
@ -193,7 +193,7 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
ret_len = strlen(ret);
/* found phar:// */
if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
return ret;
}
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
@ -219,7 +219,7 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
goto doit;
}
fname = zend_get_executed_filename(TSRMLS_C);
if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
goto doit;
}
@ -333,7 +333,7 @@ not_stream:
ret_len = strlen(trypath);
/* found phar:// */
if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
return estrndup(trypath, ret_len);
}
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);