Note: two tests currently fail. IMHO we should be throwing E_ERROR on encountering a corrupted archive, not trying to throw a trail of exceptions...
New tests still to be written, not all functionality is in place yet.
/**
* Open an already loaded phar
*/
-int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, 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) /* {{{ */
{
phar_archive_data *phar;
#ifdef PHP_WIN32
if (pphar) {
*pphar = phar;
}
+ phar->is_data = is_data;
return SUCCESS;
} else {
#ifdef PHP_WIN32
/**
* Create or open a phar for writing
*/
-int phar_open_or_create_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) /* {{{ */
{
char *ext_str;
- int ext_len;
+ int ext_len, is_data = 0, zip = 0, tar = 0;
if (error) {
*error = NULL;
}
- if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar, 0 TSRMLS_CC) == SUCCESS) {
- if (pphar && !PHAR_G(readonly)) {
+ 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;
+ }
+
+ if (ext_len >= sizeof(".tar")-1 && !memcmp((void *) ext_str, (void *) ".tar", sizeof(".tar")-1)) {
+ tar = 1;
+ }
+
+ if (tar || zip) {
+ if (objname && strncmp(objname, "PharData", 8) != 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Cannot open '%s' as a Phar object. Use PharData::__construct() for a standard zip or tar archive", fname);
+ return FAILURE;
+ }
+ is_data = 1;
+ } else {
+ if (objname && strncmp(objname, "PharData", 8) == 0) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Cannot open '%s' as a PharData object. Use Phar::__construct() for archives other than .zip and .tar", fname);
+ return FAILURE;
+ }
+ }
+
+ } else {
+
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Cannot open '%s' as a %s object, file extension (or combination) not recognised", fname, objname);
+ return FAILURE;
+ }
+
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, pphar, 0 TSRMLS_CC) == SUCCESS) {
+ if (pphar && (!PHAR_G(readonly) || is_data)) {
(*pphar)->is_writeable = 1;
}
return SUCCESS;
}
- if (phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len) == SUCCESS) {
- if (ext_len >= sizeof(".phar.zip")-1 && !memcmp((void *) ext_str, (void *) ".phar.zip", sizeof(".phar.zip")-1)) {
- /* assume zip-based phar */
- return phar_open_or_create_zip(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
- }
- if (ext_len >= sizeof(".phar.tar")-1 && !memcmp((void *) ext_str, (void *) ".phar.tar", sizeof(".phar.tar")-1)) {
- /* assume tar-based phar */
- return phar_open_or_create_tar(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
- }
+ if ((ext_len >= sizeof(".phar.zip")-1 && !memcmp((void *) ext_str, (void *) ".phar.zip", sizeof(".phar.zip")-1)) || zip) {
+ // 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) {
+ // assume tar-based phar
+ return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
+ }
+
return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
+
}
int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
*error = NULL;
}
- if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) {
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, 0, options, pphar, error TSRMLS_CC) == SUCCESS) {
return SUCCESS;
} else if (error && *error) {
return FAILURE;
int phar_detect_phar_fname_ext(const char *filename, int check_length, char **ext_str, int *ext_len) /* {{{ */
{
char end;
- char *pos_p = strstr(filename, ".phar.php");
- char *pos_zi = strstr(filename, ".phar.zip");
- char *pos_zi2 = strstr(filename, ".phar.zip.php");
- char *pos_t = strstr(filename, ".phar.tar");
- char *pos_t2 = strstr(filename, ".phar.tar.php");
- char *pos_z = strstr(filename, ".phar.gz");
- char *pos_b = strstr(filename, ".phar.bz2");
-
- if (pos_p) {
- if (pos_z) {
- return FAILURE;
- }
- *ext_str = pos_p;
+ char *pos_t = strstr(filename, ".tar");
+ char *pos_z = strstr(filename, ".zip");
+ char *pos_tg = strstr(filename, ".tar.gz");
+ char *pos_tb = strstr(filename, ".tar.bz2");
+ char *pos_pg = strstr(filename, ".phar.gz");
+ char *pos_pb = strstr(filename, ".phar.bz2");
+ char *pos_pp = strstr(filename, ".phar.php");
+ char *pos_pt = strstr(filename, ".phar.tar");
+ char *pos_pz = strstr(filename, ".phar.zip");
+ char *pos_ptg = strstr(filename, ".phar.tar.gz");
+ char *pos_ptb = strstr(filename, ".phar.tar.bz2");
+ char *pos_ptp = strstr(filename, ".phar.tar.php");
+ char *pos_pzp = strstr(filename, ".phar.zip.php");
+
+ if (pos_pzp) {
+ *ext_str = pos_pzp;
+ *ext_len = 13;
+ } else if (pos_ptp) {
+ *ext_str = pos_ptp;
+ *ext_len = 13;
+ } else if (pos_ptb) {
+ *ext_str = pos_ptb;
+ *ext_len = 13;
+ } else if (pos_ptg) {
+ *ext_str = pos_ptg;
+ *ext_len = 12;
+ } else if (pos_pz) {
+ *ext_str = pos_pz;
*ext_len = 9;
- } else if (pos_z) {
- *ext_str = pos_z;
- *ext_len = 8;
- } else if (pos_b) {
- *ext_str = pos_b;
+ } else if (pos_pt) {
+ *ext_str = pos_pt;
*ext_len = 9;
- } else if (pos_zi2) {
- *ext_str = pos_zi2;
- *ext_len = 13;
- } else if (pos_zi) {
- *ext_str = pos_zi;
+ } else if (pos_pp) {
+ *ext_str = pos_pp;
*ext_len = 9;
- } else if (pos_t2) {
- *ext_str = pos_t2;
- *ext_len = 13;
+ } else if (pos_pb) {
+ *ext_str = pos_pb;
+ *ext_len = 9;
+ } else if (pos_pg) {
+ *ext_str = pos_pg;
+ *ext_len = 8;
+ } else if (pos_tb) {
+ *ext_str = pos_tb;
+ *ext_len = 8;
+ } else if (pos_tg) {
+ *ext_str = pos_tg;
+ *ext_len = 7;
+ } else if (pos_z) {
+ *ext_str = pos_z;
+ *ext_len = 4;
} else if (pos_t) {
*ext_str = pos_t;
- *ext_len = 9;
- } else if ((pos_p = strstr(filename, ".phar")) != NULL && pos_p[4] != '\0') {
- *ext_str = pos_p;
+ *ext_len = 4;
+ } else if ((pos_pp = strstr(filename, ".phar")) != NULL && pos_pp[4] != '\0') {
+ *ext_str = pos_pp;
*ext_len = 5;
- } else if ((pos_p = strstr(filename, ".php")) != NULL && pos_p[4] != '\0') {
- *ext_str = pos_p;
+ } else if ((pos_pp = strstr(filename, ".php")) != NULL && pos_pp[4] != '\0') {
+ *ext_str = pos_pp;
*ext_len = 4;
} else {
/* We have an alias with no extension, so locate the first / and fail */
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
- if (phar_open_loaded(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
return SUCCESS;
}
int is_zip:1;
/* tar-based phar variables */
int is_tar:1;
+ /* PharData variables */
+ int is_data:1;
};
#define PHAR_MIME_PHP '\0'
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, 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_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, 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);
-int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, 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);
/* utility functions */
char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC);
/* tar functions in tar.c */
int phar_is_tar(char *buf);
int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC);
-int phar_open_or_create_tar(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_tar(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_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC);
/* zip functions in zip.c */
int phar_open_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error TSRMLS_DC);
-int phar_open_or_create_zip(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_zip(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_zip_flush(phar_archive_data *archive, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC);
#ifdef PHAR_MAIN
#include "func_interceptors.h"
static zend_class_entry *phar_ce_archive;
+static zend_class_entry *phar_ce_data;
static zend_class_entry *phar_ce_PharException;
#if HAVE_SPL
/* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
* Construct a Phar archive object
+ * {{{ proto void PharData::__construct(string fname [, int flags [, string alias]])
+ * Construct a PharData archive object
*/
PHP_METHOD(Phar, __construct)
{
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
#else
char *fname, *alias = NULL, *error, *arch, *entry = NULL, *save_fname;
- int fname_len, alias_len = 0, arch_len, entry_len;
+ int fname_len, alias_len = 0, arch_len, entry_len, is_data;
long flags = 0;
phar_archive_object *phar_obj;
phar_archive_data *phar_data;
}
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
- /* use arch for fname instead of fname */
+ /* use arch (the basename for the archive) for fname instead of fname */
/* this allows support for RecursiveDirectoryIterator of subdirectories */
save_fname = fname;
#ifdef PHP_WIN32
phar_unixify_path_separators(arch, arch_len);
#endif
}
- if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
+
+ if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, phar_obj->std.ce->name, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
+
if (fname == arch) {
efree(arch);
fname = save_fname;
efree(arch);
fname = save_fname;
}
+
+ is_data = phar_data->is_data;
phar_data->refcount++;
phar_obj->arc.archive = phar_data;
phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
} else {
fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
}
+
INIT_PZVAL(&arg1);
ZVAL_STRINGL(&arg1, fname, fname_len, 0);
&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1);
}
+ phar_obj->arc.archive->is_data = is_data;
phar_obj->spl.info_class = phar_ce_entry;
efree(fname);
{
phar_archive_data phar = {0};
char *error;
+ int is_data;
phar_entry_info *entry, newentry;
- /* set whole-archive compression from parameter */
+ /* set whole-archive compression and type from parameter */
phar.flags = flags;
+
switch (convert) {
case 1 :
phar.is_tar = 1;
if (source->fp && source->refcount == 1) {
php_stream_close(source->fp);
}
+
source->fp = phar.fp;
/* don't free stuff */
phar.manifest.pDestructor = NULL;
zend_hash_destroy(&(phar.manifest));
source->is_zip = phar.is_zip;
source->is_tar = phar.is_tar;
+
if (phar.is_zip || phar.is_tar) {
source->internal_file_start = source->halt_offset = 0;
}
int ext_len = 0;
PHAR_ARCHIVE_OBJECT();
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A plain %s archive cannot be converted to a Phar archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &method, &ext, &ext_len) == FAILURE) {
return;
}
return;
}
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar alias cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &alias, &alias_len) == SUCCESS) {
if (alias_len == phar_obj->arc.archive->alias_len && memcmp(phar_obj->arc.archive->alias, alias, alias_len) == 0) {
RETURN_TRUE;
return;
}
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zstub, &len) == SUCCESS) {
if ((php_stream_from_zval_no_verify(stream, &zstub)) != NULL) {
if (len > 0) {
size_t stub_len = 0;
PHAR_ARCHIVE_OBJECT();
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
RETURN_FALSE;
}
zend_class_implements(phar_ce_archive TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
+ INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
+ phar_ce_data = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL TSRMLS_CC);
+
+ zend_class_implements(phar_ce_data TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
+
INIT_CLASS_ENTRY(ce, "PharFileInfo", php_entry_methods);
phar_ce_entry = zend_register_internal_class_ex(&ce, spl_ce_SplFileInfo, NULL TSRMLS_CC);
#else
INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
phar_ce_archive = zend_register_internal_class(&ce TSRMLS_CC);
phar_ce_archive->ce_flags |= ZEND_ACC_FINAL_CLASS;
+
+ INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
+ phar_ce_data = zend_register_internal_class(&ce TSRMLS_CC);
+ phar_ce_data->ce_flags |= ZEND_ACC_FINAL_CLASS;
#endif
REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "BZ2", PHAR_ENT_COMPRESSED_BZ2)
php_url_free(resource);
return NULL;
}
- if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
+ if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, NULL, options, NULL, &error TSRMLS_CC) == FAILURE)
{
if (error) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
return ret;
}
-int phar_open_or_create_tar(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_tar(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 *phar;
int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, &phar, error TSRMLS_CC);
if (pphar) {
*pphar = phar;
}
+
+ phar->is_data = is_data;
+
+ if (is_data) {
+ phar->is_writeable;
+ phar->alias = NULL;
+ phar->alias_len = 0;
+ }
+
if (FAILURE == ret) {
return FAILURE;
}
+
if (phar->is_tar) {
return ret;
}
+
if (phar->is_brandnew) {
phar->is_tar = 1;
phar->internal_file_start = 0;
entry.phar = phar;
entry.fp_type = PHAR_MOD;
+ if (phar->is_data) {
+ goto nostub;
+ }
+
/* set alias */
if (!phar->is_temporary_alias && phar->alias_len) {
entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
}
}
+nostub:
+
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
if (!ext) {
if (phar->is_zip) {
- ext = "phar.zip";
+ if (phar->is_data) {
+ ext = "zip";
+ } else {
+ ext = "phar.zip";
+ }
} else if (phar->is_tar) {
switch (phar->flags) {
case PHAR_FILE_COMPRESSED_GZ:
- ext = "phar.tar.gz";
+ if (phar->is_data) {
+ ext = "tar.gz";
+ } else {
+ ext = "phar.tar.gz";
+ }
break;
case PHAR_FILE_COMPRESSED_BZ2:
- ext = "phar.tar.bz2";
+ if (phar->is_data) {
+ ext = "tar.bz2";
+ } else {
+ ext = "phar.tar.bz2";
+ }
break;
default:
- ext = "phar.tar";
+ if (phar->is_data) {
+ ext = "tar";
+ } else {
+ ext = "phar.tar";
+ }
}
} else {
switch (phar->flags) {
efree(basepath);
efree(newname);
- if (!phar->is_zip && !phar->is_tar) {
+ if (!strncmp(ext, "zip", 3) && !strncmp(ext, "tar", 3)) {
phar->alias = estrndup(newpath, strlen(newpath));
phar->alias_len = strlen(newpath);
zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, strlen(newpath), (void*)&phar, sizeof(phar_archive_data*), NULL);
/**
* Create or open a zip-based phar for writing
*/
-int phar_open_or_create_zip(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_zip(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 *phar;
int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, &phar, error TSRMLS_CC);
if (pphar) {
*pphar = phar;
}
+
+ phar->is_data = is_data;
+
+ if (is_data) {
+ phar->is_writeable;
+ phar->alias = NULL;
+ phar->alias_len = 0;
+ }
+
if (FAILURE == ret) {
return FAILURE;
}
+
if (phar->is_zip) {
return ret;
}
entry.phar = phar;
entry.fp_type = PHAR_MOD;
+ if (phar->is_data) {
+ goto nostub;
+ }
+
/* set alias */
if (!phar->is_temporary_alias && phar->alias_len) {
entry.fp = php_stream_fopen_tmpfile();
}
}
+nostub:
+
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;