php_stream_close(phar->fp);
phar->fp = NULL;
}
+ if (!zend_hash_num_elements(&phar->manifest)) {
+ /* this is a new phar that has perhaps had an alias/metadata set, but has never
+ been flushed */
+ if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
+ phar_destroy_phar_data(phar TSRMLS_CC);
+ }
+ return 1;
+ }
}
return 0;
}
/* }}} */
#define MAPPHAR_ALLOC_FAIL(msg) \
- php_stream_close(fp);\
+ if (fp) {\
+ php_stream_close(fp);\
+ }\
if (error) {\
spprintf(error, 0, msg, fname);\
}\
if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
{
buffer[tmp_len] = '\0';
- efree(savebuf);
php_stream_close(fp);
if (signature) {
efree(signature);
if (error) {
spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
}
+ efree(savebuf);
return FAILURE;
}
alias_len = tmp_len;
mydata->sig_len = sig_len;
mydata->signature = signature;
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) {
+ phar_archive_data **fd_ptr;
+
mydata->is_temporary_alias = temp_alias;
+ if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
+ signature = NULL;
+ fp = NULL;
+ MAPPHAR_FAIL("Cannot open archive \"%s\", 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)) {
+ signature = NULL;
+ fp = NULL;
+ MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
+ }
+ }
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
} else {
mydata->is_temporary_alias = 1;
}
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
efree(savebuf);
if (pphar) {
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_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC);
int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC);
int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
}
if (alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
spprintf(&error, 0, "alias \"%s\" is already used for archive \"%s\" and cannot be used for other archives", alias, (*fd_ptr)->fname);
+ if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ efree(error);
+ goto valid_alias;
+ }
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
RETURN_FALSE;
"Invalid alias \"%s\" specified for phar \"%s\"", alias, phar_obj->arc.archive->fname);
RETURN_FALSE;
}
+valid_alias:
if (phar_obj->arc.archive->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, (void**)&fd_ptr)) {
zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len);
readd = 1;
}
myphar = *actual;
if (actual_alias) {
+ 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)) {
+ 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);
} else {
myphar->alias = estrndup(myphar->fname, fname_len);
$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
$pname = 'phar://hio';
$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+$alias = '';
$files = array();
$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
$fname1 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
$fname = $fname1;
+$alias = '';
$pname = 'phar://hio';
$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
include 'files/phar_test.inc';
-file_put_contents($fname2, $file);
+copy($fname1, $fname2);
var_dump(Phar::loadPhar($fname1, 'hio'));
var_dump(Phar::loadPhar($fname1, 'copy'));
+$a = new Phar($fname1);
try
{
var_dump(Phar::loadPhar($fname2, 'copy'));
$files[$name] = $comp;
}
-$alias = 'hio';
+if (!isset($alias)) $alias = 'hio';
if (isset($pmeta)) $pmeta = serialize($pmeta); else $pmeta = '';
$manifest = pack('VnVV', count($files), isset($hasdir) ? 0x1110 : 0x1000, $gflags, strlen($alias)) . $alias . pack('V', strlen($pmeta)) . $pmeta . $manifest;
$a = new Phar($fname);
$a['test'] = 'hi';
copy($fname, $fname2);
+$a->setAlias('another');
$b = new Phar($fname2);
var_dump($b->isFileFormat(Phar::PHAR));
var_dump($b->isCompressed() == Phar::BZ2);
$a = new Phar($fname);
$a['test'] = 'hi';
copy($fname, $fname2);
+$a->setAlias('another');
$b = new Phar($fname2);
var_dump($b->isFileFormat(Phar::PHAR));
var_dump($b->isCompressed() == Phar::GZ);
echo $phar->getAlias() . "\n";
$phar->setAlias('test');
echo $phar->getAlias() . "\n";
+$b = $phar;
$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
try {
$phar->setAlias('test');
$phar->addEmptyDir('test');
$phar->stopBuffering();
copy($fname, $tname);
+$phar->setAlias('hio2');
try {
$p = new Phar($tname);
echo $phar->getAlias() . "\n";
$phar->setAlias('test');
echo $phar->getAlias() . "\n";
-
+$b = $phar;
$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
try {
--- /dev/null
+--TEST--
+Phar: test for the odd case where we intend to remove an archive from memory
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname2 = 'phar://' . $fname2;
+
+$phar = new Phar($fname);
+$phar->setAlias('first');
+$phar['file1.txt'] = 'hi';
+unset($phar);
+
+$phar2 = new Phar($fname2);
+$phar2->setAlias('first'); // this works because there are no references to $fname open
+$phar2['file1.txt'] = 'hi';
+unset($phar2);
+
+$a = fopen($pname . '/file1.txt', 'r'); // this works because there are no references to $fname2 open
+try {
+$phar2 = new Phar($fname2); // fails because references open to $fname
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+fclose($a);
+$phar2 = new Phar($fname2); // succeeds because all refs are closed
+var_dump($phar2->getAlias());
+
+$a = file_get_contents($pname . '/file1.txt'); // this fails because $fname2 ref exists
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECTF--
+Cannot open archive "%stest_alias_unset.2.phar.php", alias is already in use by existing archive
+string(5) "first"
+
+Warning: file_get_contents(phar://%sfile1.txt): failed to open stream: Cannot open archive "%stest_alias_unset.phar.php", alias is already in use by existing archive in %stest_alias_unset.php on line %d
+===DONE===
\ No newline at end of file
$phar->addEmptyDir('test');
$phar->stopBuffering();
copy($fname, $tname);
+$phar->setAlias('hio2');
try {
$p = new Phar($tname);
echo $phar->getAlias() . "\n";
$phar->setAlias('test');
echo $phar->getAlias() . "\n";
-
+$b = $phar;
$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
try {
$phar->setAlias('test');
return entry;
}
+int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
+{
+ if (phar->refcount) {
+ return FAILURE;
+ }
+ /* this archive has no open references, so emit an E_STRICT and remove it */
+ if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
/**
* Looks up a phar archive in the filename map, connecting it to the alias
* (if any) or returns null
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
}
+ if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ efree(*error);
+ *error = NULL;
+ }
return FAILURE;
}
*archive = *fd_ptr;
*archive = *fd_ptr;
fd = *fd_ptr;
if (alias && alias_len) {
+ 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);
+ }
zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
}
return SUCCESS;
if (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. */
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)) {
+ 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);