*/
static void phar_destroy_phar_data(phar_archive_data *data TSRMLS_DC) /* {{{ */
{
+ if (!PHAR_G(request_ends)) {
+ if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_web_map))) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_web_map), data->fname, data->fname_len);
+ }
+ }
if (data->alias && data->alias != data->fname) {
efree(data->alias);
data->alias = NULL;
*error = NULL;
}
+ if (!path_len && !dir) {
+ if (error) {
+ spprintf(error, 0, "phar error: invalid path \"%s\" must not be empty", path);
+ }
+ return NULL;
+ }
if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
if (error) {
spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
uint keylen;
ulong unused;
+ if (!path_len) {
+ path = "/";
+ }
manifest = &phar->manifest;
zend_hash_internal_pointer_reset(manifest);
while (FAILURE != zend_hash_has_more_elements(manifest)) {
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
return FAILURE;
}
+ if (!path_len) {
+ if (error) {
+ spprintf(error, 0, "phar error: file \"\" cannot be empty");
+ }
+ return FAILURE;
+ }
if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) ? NULL : error TSRMLS_CC)) == NULL) {
if (for_create && !PHAR_G(readonly)) {
return SUCCESS;
mydata->sig_len = sig_len;
mydata->signature = signature;
phar_request_initialize(TSRMLS_C);
+ if ((manifest_flags & PHAR_HDR_WEB) != 0) {
+ mydata->is_web = 1;
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_mimes))) {
+ phar_init_mime_list(TSRMLS_C);
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_web_map), mydata->fname, fname_len, (void*)&mydata, sizeof(void*), NULL);
+ }
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
if (register_alias) {
mydata->is_explicit_alias = 1;
static int php_check_dots(const char *element, int n)
{
- while (n-- > 0) if (element[n] != '.') break;
-
- return (n != -1);
+ for(n--; n >= 0; --n) {
+ if (element[n] != '.') {
+ return 1;
+ }
+ }
+ return 0;
}
#define IS_DIRECTORY_UP(element, len) \
efree(free_path);
- if (path[path_length-1] == '/') {
+ if (path[path_length-1] == '/' && new_phar_len > 1) {
new_phar = (char*)erealloc(new_phar, new_phar_len + 2);
new_phar[new_phar_len++] = '/';
new_phar[new_phar_len] = 0;
#ifdef PHP_WIN32
phar_unixify_path_separators(*entry, *entry_len);
#endif
- *entry = phar_fix_filepath(*entry, entry_len);
+ *entry = phar_fix_filepath(*entry, entry_len);
} else {
*entry_len = 1;
*entry = estrndup("/", 1);
/* use our proxy position */
php_stream_seek(data->fp, data->position + data->zero, SEEK_SET);
-
+
if (!data->zero) {
got = php_stream_read(data->fp, buf, count);
if (data->fp->eof) {
manifest_len = offset + archive->alias_len + sizeof(manifest) + main_metadata_str.len;
phar_set_32(manifest, manifest_len);
phar_set_32(manifest+4, new_manifest_count);
- *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
- *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
+ if (archive->is_web) {
+ *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NOWEB) >> 8) & 0xFF);
+ *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NOWEB) & 0xF0));
+ } else {
+ *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
+ *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
+ }
phar_set_32(manifest+10, global_flags);
phar_set_32(manifest+14, archive->alias_len);
phar_globals->readonly = 1;
}
/* }}} */
+
+static void phar_init_mime_list(TSRMLS_D)
+{
+ phar_mime_type mime;
+#define PHAR_SET_MIME(mimetype, ret, ...) \
+ mime.mime = mimetype; \
+ mime.len = sizeof((mimetype))+1; \
+ mime.type = ret; \
+ { \
+ char mimes[][5] = {__VA_ARGS__, "\0"}; \
+ int i = 0; \
+ for (; mimes[i][0]; i++) { \
+ zend_hash_add(&(PHAR_GLOBALS->phar_mimes), mimes[i], strlen(mimes[i]), (void *)&mime, sizeof(phar_mime_type), NULL); \
+ } \
+ }
+
+ PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c", "cc", "cpp", "c++", "dtd", "h", "log", "rng", "txt", "xsd")
+ PHAR_SET_MIME("", PHAR_MIME_PHP, "php", "inc")
+ PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
+ PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
+ PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
+ PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm", "html", "htmls")
+ PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe", "jpg", "jpeg")
+ PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
+ PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid", "midi")
+ PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
+ PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
+ PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
+ PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg", "mpeg")
+ PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
+ PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
+ PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
+ PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif", "tiff")
+ PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
+ PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
+ PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
+}
+
+static int phar_file_type(char *file, char **mime_type TSRMLS_DC)
+{
+ char *ext;
+ phar_mime_type *mime;
+ if (!mime_type) {
+ /* assume PHP */
+ return 0;
+ }
+ ext = strrchr(file, '.');
+ if (!ext) {
+ *mime_type = "text/plain";
+ /* no file extension = assume text/plain */
+ return PHAR_MIME_OTHER;
+ }
+ ext++;
+ if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_mimes), ext, strlen(ext), (void **) &mime)) {
+ *mime_type = "application/octet-stream";
+ return PHAR_MIME_OTHER;
+ }
+ *mime_type = mime->mime;
+ return mime->type;
+}
+/* }}} */
+
+static zend_op_array *phar_file_action(char *entry, int entry_len, char *arch, int arch_len, char **ourname TSRMLS_DC)
+{
+ char *mime_type, *name = NULL, buf[8192], *error;
+ zend_syntax_highlighter_ini syntax_highlighter_ini;
+ sapi_header_line ctr = {0};
+ zend_op_array *nada;
+ zend_op *opline;
+ phar_entry_data *phar;
+ size_t got;
+
+ *ourname = name;
+
+#define PHAR_NOP() \
+ nada = (zend_op_array *) emalloc(sizeof(zend_op_array)); \
+ init_op_array(nada, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); \
+ opline = get_next_op(nada TSRMLS_CC); \
+ opline->opcode = ZEND_RETURN; \
+ opline->op1.op_type = IS_CONST; \
+ INIT_ZVAL(opline->op1.u.constant); \
+ SET_UNUSED(opline->op2); \
+ ZEND_VM_SET_OPCODE_HANDLER(opline); \
+ nada->done_pass_two = 1; \
+ return nada;
+
+ switch (phar_file_type(entry, &mime_type TSRMLS_CC)) {
+ case PHAR_MIME_PHPS:
+ /* highlight source */
+ spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ efree(arch);
+ php_get_highlight_struct(&syntax_highlighter_ini);
+
+ if (highlight_file(name, &syntax_highlighter_ini TSRMLS_CC) == FAILURE) {
+ }
+
+ PHAR_NOP();
+ case PHAR_MIME_OTHER:
+ /* send headers, output file contents */
+ if (FAILURE == phar_get_entry_data(&phar, arch, arch_len, entry, entry_len, "r", &error TSRMLS_CC)) {
+ ctr.response_code = 404;
+ ctr.line_len = sizeof("HTTP/1.0 404")+1;
+ ctr.line = "HTTP/1.0 404";
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+
+ PHAR_NOP();
+ }
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ efree(ctr.line);
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", phar->internal_file->uncompressed_filesize);
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ efree(ctr.line);
+ if (FAILURE == sapi_send_headers(TSRMLS_C)) {
+ phar_entry_delref(phar TSRMLS_CC);
+ zend_bailout();
+ }
+
+ /* prepare to output */
+ if (!phar->fp) {
+ phar->internal_file->fp_refcount++;
+ phar->fp = phar->phar->fp;
+ phar->zero = phar->phar->internal_file_start + phar->internal_file->offset_within_phar;
+ }
+ php_stream_seek(phar->fp, phar->position + phar->zero, SEEK_SET);
+ do {
+ if (!phar->zero) {
+ got = php_stream_read(phar->fp, buf, 8192);
+ PHPWRITE(buf, got);
+ if (phar->fp->eof) {
+ break;
+ }
+ } else {
+ got = php_stream_read(phar->fp, buf, MIN(8192, phar->internal_file->uncompressed_filesize - phar->position));
+ PHPWRITE(buf, got);
+ phar->position = php_stream_tell(phar->fp) - phar->zero;
+ if (phar->position == (off_t) phar->internal_file->uncompressed_filesize) {
+ break;
+ }
+ }
+ } while (1);
+
+ phar_entry_delref(phar TSRMLS_CC);
+ PHAR_NOP();
+ case PHAR_MIME_PHP:
+ /* fall through */
+ break;
+ }
+ return NULL;
+}
+
static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
{
zend_op_array *res;
char *s, *name = NULL;
char *fname = NULL;
- int fname_len;
+ int fname_len, failed;
zend_op_array *(*save)(zend_file_handle *file_handle, int type TSRMLS_DC);
save = zend_compile_file; /* restore current handler or we cause trouble */
char *arch, *entry;
int arch_len, entry_len;
fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+ /* check for web front controller phars */
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_web_map), fname, fname_len)) {
+ zend_op_array *retval;
+ if (strncasecmp(file_handle->filename, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(file_handle->filename);
+ if (SUCCESS == phar_split_fname(file_handle->filename, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+ if ((retval = phar_file_action(entry, entry_len, arch, arch_len, &name TSRMLS_CC))) {
+ return retval;
+ }
+ }
+ }
if (strncasecmp(fname, "phar://", 7)) {
goto skip_phar;
}
fname_len = strlen(fname);
if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-
efree(entry);
entry = file_handle->filename;
/* include within phar, if :// is not in the url, then prepend phar://<archive>/ */
}
}
skip_phar:
- res = zend_compile_file(file_handle, type TSRMLS_CC);
+ zend_try {
+ failed = 0;
+ res = zend_compile_file(file_handle, type TSRMLS_CC);
+ } zend_catch {
+ failed = 1;
+ } zend_end_try();
if (name) {
efree(name);
}
zend_compile_file = save;
+ if (failed) {
+ zend_bailout();
+ }
return res;
}
/* }}} */
PHAR_GLOBALS->request_done = 0;
zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 0);
zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_web_map), sizeof(void *), zend_get_hash_value, NULL, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_mimes), sizeof(phar_mime_type *), zend_get_hash_value, NULL, 0);
zend_hash_init(&(PHAR_GLOBALS->phar_plain_map), sizeof(const char *), zend_get_hash_value, NULL, 0);
phar_split_extract_list(TSRMLS_C);
if (SUCCESS == zend_hash_find(CG(function_table), "fopen", 6, (void **)&orig)) {
}
zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_web_map));
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_mimes));
zend_hash_destroy(&(PHAR_GLOBALS->phar_plain_map));
PHAR_GLOBALS->request_init = 0;
}