if (pphar) {
*pphar = NULL;
}
- if (phar && alias && (options & REPORT_ERRORS)) {
- if (error) {
- spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, phar->fname, fname);
- }
+ if (phar && error && !(options & REPORT_ERRORS)) {
+ efree(error);
}
return FAILURE;
}
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, *z;
+ char *my_error;
int ext_len;
phar_archive_data **test, *unused = NULL;
}
check_file:
- if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, test, 0 TSRMLS_CC) == SUCCESS) {
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
if (pphar) {
*pphar = *test;
}
(*test)->is_writeable = 1;
}
return SUCCESS;
+ } else if (my_error) {
+ if (error) {
+ *error = my_error;
+ } else {
+ efree(my_error);
+ }
+ return FAILURE;
}
if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
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) /* {{{ */
{
phar_archive_data *mydata;
- int register_alias;
php_stream *fp;
char *actual = NULL, *p;
zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
zend_get_hash_value, NULL, 0);
mydata->fname_len = fname_len;
- if (is_data) {
- alias = NULL;
- alias_len = 0;
- } else {
- mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
- mydata->alias_len = alias ? alias_len : fname_len;
- }
snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
mydata->is_temporary_alias = alias ? 0 : 1;
mydata->internal_file_start = -1;
mydata->fp = NULL;
mydata->is_writeable = 1;
mydata->is_brandnew = 1;
- if (!alias_len || !alias) {
- /* if we neither have an explicit nor an implicit alias, we use the filename */
+ phar_request_initialize(TSRMLS_C);
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ if (is_data) {
alias = NULL;
alias_len = 0;
- register_alias = 0;
} else {
- register_alias = 1;
+ phar_archive_data **fd_ptr;
+
+ if (alias && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ if (pphar) {
+ *pphar = NULL;
+ }
+ return FAILURE;
+ }
+ }
+ mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
+ mydata->alias_len = alias ? alias_len : fname_len;
}
- phar_request_initialize(TSRMLS_C);
- zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
- if (register_alias) {
+ if (alias_len && alias) {
if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
if (options & REPORT_ERRORS) {
if (error) {
spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
}
}
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ if (pphar) {
+ *pphar = NULL;
+ }
return FAILURE;
}
}
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"%s", error);
efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Phar creation or opening failed");
}
return;
}
phar_archive_data **fd_ptr;
myphar->is_temporary_alias = 0;
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
- if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) {
if (error) {
spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
}
}
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
} else {
- myphar->alias = estrndup(myphar->fname, fname_len);
- myphar->alias_len = fname_len;
+ phar_archive_data **fd_ptr;
+
+ if (alias_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
+ myphar->alias = estrndup(alias, alias_len);
+ myphar->alias_len = alias_len;
+ } else {
+ myphar->alias = estrndup(myphar->fname, fname_len);
+ myphar->alias_len = fname_len;
+ }
myphar->is_temporary_alias = 1;
}
if (pphar) {
--- /dev/null
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar" cannot be overloaded with "%salias_acrobatics.2.phar"
+2
+Cannot open archive "%salias_acrobatics.2.phar", alias is already in use by existing archive
+alias "another" is already used for archive "%salias_acrobatics.phar" cannot be overloaded with "%salias_acrobatics.phar"
+===DONE===
hio
test
alias "test" is already used for archive "%sphar_setalias2.phar.php" and cannot be used for other archives
-archive "%snope.phar" cannot be associated with alias "test", already in use
+alias "test" is already used for archive "%sphar_setalias2.phar.php" cannot be overloaded with "%snope.phar"
===DONE===
--- /dev/null
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar.tar" cannot be overloaded with "%salias_acrobatics.2.phar.tar"
+2
+phar error: Unable to add tar-based phar "%salias_acrobatics.2.phar.tar", alias is already in use
+alias "another" is already used for archive "%salias_acrobatics.phar.tar" cannot be overloaded with "%salias_acrobatics.phar.tar"
+===DONE===
var_dump($phar['a.php']->isExecutable());
$phar['a.php']->chmod(0777);
copy($fname, $fname2);
+ $phar->setAlias('unused');
$phar2 = new Phar($fname2);
var_dump($phar2['a.php']->isExecutable());
$phar['a.php']->chmod(0666);
--- /dev/null
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar.zip" cannot be overloaded with "%salias_acrobatics.2.phar.zip"
+2
+phar error: Unable to add zip-based phar "%salias_acrobatics.2.phar.zip" with implicit alias, alias is already in use
+alias "another" is already used for archive "%salias_acrobatics.phar.zip" cannot be overloaded with "%salias_acrobatics.phar.zip"
+===DONE===
?>
===DONE===
--EXPECTF--
-phar error: invalid alias in zip-based phar "%sbadalias1.phar.zip"
-phar error: invalid alias in zip-based phar "%sbadalias2.phar.zip"
-phar error: invalid alias in zip-based phar "%sbadalias3.phar.zip"
-phar error: invalid alias in zip-based phar "%sbadalias4.phar.zip"
-phar error: invalid alias in zip-based phar "%sbadalias5.phar.zip"
+phar error: invalid alias "hi/there" in zip-based phar "%sbadalias1.phar.zip"
+phar error: invalid alias "hi\there" in zip-based phar "%sbadalias2.phar.zip"
+phar error: invalid alias "hi\there" in zip-based phar "%sbadalias3.phar.zip"
+phar error: invalid alias "hi;there" in zip-based phar "%sbadalias4.phar.zip"
+phar error: invalid alias "hi:there" in zip-based phar "%sbadalias5.phar.zip"
===DONE===
*archive = *fd_ptr;
fd = *fd_ptr;
if (alias && alias_len) {
+ if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
+ }
+ return FAILURE;
+ }
if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
}
php_uint16 i;
phar_archive_data *mydata = NULL;
phar_entry_info entry = {0};
- char *p = buf, *ext;
+ char *p = buf, *ext, *actual_alias = NULL;
size = php_stream_tell(fp);
if (size > sizeof(locator) + 65536) {
mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
}
}
- if (!alias_len) {
- mydata->alias = estrndup(fname, fname_len);
-#ifdef PHP_WIN32
- phar_unixify_path_separators(mydata->alias, fname_len);
-#endif
- mydata->alias_len = fname_len;
- }
/* clean up on big-endian systems */
/* seek to central directory */
php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
} else {
entry.metadata = NULL;
}
- if (entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
+ if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
php_stream_filter *filter;
off_t saveloc;
- phar_archive_data **fd_ptr;
/* archive alias found, seek to file contents, do not validate local header. Potentially risky, but
not very. */
saveloc = php_stream_tell(fp);
php_stream_seek(fp, PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
+ mydata->alias_len = entry.uncompressed_filesize;
if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
if (!filter) {
PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
}
php_stream_filter_append(&fp->readfilters, filter);
- efree(mydata->alias);
- mydata->alias = NULL;
- if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &(mydata->alias), entry.uncompressed_filesize, 0)) || !mydata->alias) {
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
efree(entry.filename);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
}
php_stream_filter_append(&fp->readfilters, filter);
php_stream_filter_append(&fp->readfilters, filter);
- efree(mydata->alias);
- mydata->alias = NULL;
- if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &(mydata->alias), entry.uncompressed_filesize, 0)) || !mydata->alias) {
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
efree(entry.filename);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
} else {
- efree(mydata->alias);
- mydata->alias = NULL;
- if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &(mydata->alias), entry.uncompressed_filesize, 0)) || !mydata->alias) {
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
efree(entry.filename);
PHAR_ZIP_FAIL("unable to read in alias, truncated");
}
}
- mydata->is_temporary_alias = 0;
- mydata->alias_len = PHAR_GET_32(zipentry.uncompsize);
- if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
- efree(entry.filename);
- PHAR_ZIP_FAIL("invalid alias");
- }
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
- if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
- PHAR_ZIP_FAIL("alias is already in use by existing archive");
- }
- }
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), mydata->alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
/* return to central directory parsing */
php_stream_seek(fp, saveloc, SEEK_SET);
}
}
mydata->fp = fp;
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ if (actual_alias) {
+ phar_archive_data **fd_ptr;
+
+ if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
+ }
+ efree(actual_alias);
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ mydata->is_temporary_alias = 0;
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname);
+ }
+ efree(actual_alias);
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ mydata->alias = actual_alias;
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ } else {
+ phar_archive_data **fd_ptr;
+
+ if (alias_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ mydata->alias = estrndup(alias, alias_len);
+ mydata->alias_len = alias_len;
+ } else {
+ mydata->alias = estrndup(mydata->fname, fname_len);
+ mydata->alias_len = fname_len;
+ }
+ mydata->is_temporary_alias = 1;
+ }
if (pphar) {
*pphar = mydata;
}