From: SVN Migration Date: Mon, 12 May 2008 21:03:49 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'PHP_5_3'. X-Git-Tag: BEFORE_NEW_PARAMETER_PARSE~229 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=16b4d8e0e1108564fa042520171d9091af708d83;p=php This commit was manufactured by cvs2svn to create branch 'PHP_5_3'. --- diff --git a/ext/enchant/package.xml b/ext/enchant/package.xml new file mode 100755 index 0000000000..1012839382 --- /dev/null +++ b/ext/enchant/package.xml @@ -0,0 +1,162 @@ + + + enchant + pecl.php.net + libenchant binder, support near all spelling tools + Enchant is a binder for libenchant. Libenchant provides a common +API for many spell libraries: +- aspell/pspell (intended to replace ispell) +- hspell (hebrew) +- ispell +- myspell/hunspell (OpenOffice project, mozilla) +- uspell (primarily Yiddish, Hebrew, and Eastern European languages) +A plugin system allows to add custom spell support. +see www.abisource.com/enchant/ + + + Pierre-Alain Joye + pajoye + paj@pearfr.org + yes + + + Ilia Alshanetsky + iliaa + ilia@php.net + yes + + 2008-04-16 + + 1.0.2 + 1.1.0 + + + stable + stable + + PHP + - #13181, Leaving a context frees the dictionnary resources +- Fix protos descriptions in the sources + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + + 1.4.0b1 + + + + enchant + + + + + + 2006-03-21 + + 1.0.1 + 1.1.0 + + + stable + stable + + PHP + - add enchant_broker_list_dicts to get a list of available dictionaries +- fix compilation warnings +- add examples +- add tests + + + 2004-08-11 + + 1.0 + 1.0 + + + stable + stable + + PHP + - Fixed leak inside MINFO function. +- Fixed crash inside enchant_dict_suggest() when there are no suggestions. +- Added missing safe_mode/open_basedir check inside enchant_broker_request_pwl_dict(). +- Fixed various function prototypes. +- Fixed possible leak in suggestions result. + + + + + 0.2.1 + 0.2.1 + + + beta + beta + + 2004-03-11 + PHP + - Fix possible leak in suggestions result +- Move to beta status + + + + + 0.2.0 + 0.2.0 + + + alpha + alpha + + 2006-03-21 + PHP + - Add Ilia Alshanetsky as maintainer +- Cleanup sources codes (ilia) +- Add enchant_dict_quick_check (ilia) + + + + + 0.1 + 0.1 + + + alpha + alpha + + 2003-03-08 + PHP + Initial release + + + + diff --git a/ext/enchant/php_enchant.h b/ext/enchant/php_enchant.h new file mode 100644 index 0000000000..893a4c8809 --- /dev/null +++ b/ext/enchant/php_enchant.h @@ -0,0 +1,83 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Pierre-Alain Joye | + +----------------------------------------------------------------------+ + + $Id$ +*/ + +#ifndef PHP_ENCHANT_H +#define PHP_ENCHANT_H + +extern zend_module_entry enchant_module_entry; +#define phpext_enchant_ptr &enchant_module_entry + +#define PHP_ENCHANT_VERSION "1.0.2-dev" + +#ifdef PHP_WIN32 +#define PHP_ENCHANT_API __declspec(dllexport) +#else +#define PHP_ENCHANT_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +static void php_enchant_broker_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); +static void php_enchant_dict_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); + +PHP_MINIT_FUNCTION(enchant); +PHP_MSHUTDOWN_FUNCTION(enchant); +PHP_MINFO_FUNCTION(enchant); + +PHP_FUNCTION(enchant_broker_init); +PHP_FUNCTION(enchant_broker_free); +PHP_FUNCTION(enchant_broker_get_error); +PHP_FUNCTION(enchant_broker_list_dicts); +PHP_FUNCTION(enchant_broker_request_dict); +PHP_FUNCTION(enchant_broker_request_pwl_dict); +PHP_FUNCTION(enchant_broker_free_dict); +PHP_FUNCTION(enchant_broker_dict_exists); +PHP_FUNCTION(enchant_broker_set_ordering); +PHP_FUNCTION(enchant_broker_describe); + +PHP_FUNCTION(enchant_dict_check); +PHP_FUNCTION(enchant_dict_suggest); +PHP_FUNCTION(enchant_dict_add_to_personal); +PHP_FUNCTION(enchant_dict_add_to_session); +PHP_FUNCTION(enchant_dict_is_in_session); +PHP_FUNCTION(enchant_dict_store_replacement); +PHP_FUNCTION(enchant_dict_get_error); +PHP_FUNCTION(enchant_dict_describe); +PHP_FUNCTION(enchant_dict_quick_check); + +#ifdef ZTS +#define ENCHANT_G(v) TSRMG(enchant_globals_id, zend_enchant_globals *, v) +#else +#define ENCHANT_G(v) (enchant_globals.v) +#endif + +#endif /* PHP_ENCHANT_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ + diff --git a/ext/enchant/tests/bug13181.phpt b/ext/enchant/tests/bug13181.phpt new file mode 100644 index 0000000000..38aec636cf --- /dev/null +++ b/ext/enchant/tests/bug13181.phpt @@ -0,0 +1,43 @@ +--TEST-- +bug #13181, leaving a context frees the broker resources +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (enchant_dict) +resource(%d) of type (enchant_dict) +resource(%d) of type (enchant_broker) +resource(%d) of type (enchant_broker) +resource(%d) of type (enchant_dict) +resource(%d) of type (enchant_dict) diff --git a/ext/fileinfo/php_fileinfo.h b/ext/fileinfo/php_fileinfo.h new file mode 100644 index 0000000000..c8d548e656 --- /dev/null +++ b/ext/fileinfo/php_fileinfo.h @@ -0,0 +1,63 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Ilia Alshanetsky | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_FILEINFO_H +#define PHP_FILEINFO_H + +extern zend_module_entry fileinfo_module_entry; +#define phpext_fileinfo_ptr &fileinfo_module_entry + +#define PHP_FILEINFO_VERSION "1.0.5-dev" + +#ifdef PHP_WIN32 +#define PHP_FILEINFO_API __declspec(dllexport) +#else +#define PHP_FILEINFO_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +PHP_MINFO_FUNCTION(fileinfo); + +PHP_FUNCTION(finfo_open); +PHP_FUNCTION(finfo_close); +PHP_FUNCTION(finfo_set_flags); +PHP_FUNCTION(finfo_file); +PHP_FUNCTION(finfo_buffer); + +#ifdef ZTS +#define FILEINFO_G(v) TSRMG(fileinfo_globals_id, zend_fileinfo_globals *, v) +#else +#define FILEINFO_G(v) (fileinfo_globals.v) +#endif + +#endif /* PHP_FILEINFO_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/CREDITS b/ext/phar/CREDITS new file mode 100644 index 0000000000..b54c6e8e3b --- /dev/null +++ b/ext/phar/CREDITS @@ -0,0 +1,2 @@ +PHP Archive +Gregory Beaver, Marcus Boerger diff --git a/ext/phar/LICENSE b/ext/phar/LICENSE new file mode 100644 index 0000000000..50770e3a03 --- /dev/null +++ b/ext/phar/LICENSE @@ -0,0 +1,95 @@ +-------------------------------------------------------------------- + The PHP License, version 3.01 +Copyright (c) 1999 - 2005 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP software, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +PHP includes the Zend Engine, freely available at +. + +--------------------------------------------------------------------- +phar_tar_octal() based on an implementation Copyright (c) 2003-2007 Tim Kientzle +from libarchive, licensed with this license: + + Copyright (c) 2003-2007 Tim Kientzle + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/phar/Makefile.frag b/ext/phar/Makefile.frag new file mode 100755 index 0000000000..d693e8dd86 --- /dev/null +++ b/ext/phar/Makefile.frag @@ -0,0 +1,25 @@ + +$(srcdir)/phar_path_check.c: $(srcdir)/phar_path_check.re + $(RE2C) -b -o $(srcdir)/phar_path_check.c $(srcdir)/phar_path_check.re + +pharcmd: $(builddir)/phar.php $(builddir)/phar.phar + +$(builddir)/phar.php: $(srcdir)/build_precommand.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH) + if test -x "$(PHP_EXECUTABLE)"; then \ + export PHP="$(PHP_EXECUTABLE)"; \ + else \ + export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \ + fi; \ + $$PHP $(srcdir)/build_precommand.php > $(builddir)/phar.php + +$(builddir)/phar.phar: $(builddir)/phar.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH) + if test -x "$(PHP_EXECUTABLE)"; then \ + export PHP="$(PHP_EXECUTABLE)"; \ + export BANG="$(PHP_EXECUTABLE)"; \ + else \ + export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \ + export BANG="$(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT)"; \ + fi; \ + $$PHP -d phar.readonly=0 $(srcdir)/phar.php pack -f $(builddir)/phar.phar -a pharcommand -c auto -x CVS -p 0 -s $(srcdir)/phar/phar.php -h sha1 -b "$$BANG" $(srcdir)/phar/ + @chmod +x $(builddir)/phar.phar + diff --git a/ext/phar/TODO b/ext/phar/TODO new file mode 100644 index 0000000000..db001407e2 --- /dev/null +++ b/ext/phar/TODO @@ -0,0 +1,114 @@ +Version 1.0.0 + + X make permissions in the lowest bits of flags to simplify using them [Greg] + X implement ini handler for phar.readonly and phar.require_hash that allows + enabling it on PHP_INI_ALL if it is disabled in the system, but does not + allow disabling it if it is enabled in the system [Greg] + X implement reading in metadata in manifest as [Marcus] + X implement writing out of metadata to new manifest [Marcus] + X if SPL is disabled, enable only static methods of class Phar and disable + class PharFileInfo completely [Marcus] + X implement in-phar locking, so that a file that is opened for reading can't + have a handle opened for writing [Marcus/Greg] + X docs on file format/manifest description [Greg] + X docs on uses [Greg] + X stream context for specifying compression of a file [Marcus] + X stream context for specifying meta-data [Greg] + X Phar->begin()/Phar->commit() for specifying a new stub to the phar, + and deferring flush until all modifications are complete [Greg] + X Phar->getStub() for retrieving the stub of the phar [Marcus] + X add setUncompressed(), setCompressedGZ() and setCompressedBZ2() to + PharFileInfo class [Greg] + X add uncompressAllFiles(), compressAllFilesGZ() and compressAllFilesBZ2() + to Phar class [Greg] + X add PharFileInfo::setMetaData($metadata) [Marcus] + X add PharFileInfo::getMetaData() [Marcus] + X always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from + streams interface [Greg] + X Phar archive metadata Phar::setMetaData($metadata) Phar::getMetaData() + [Greg] + X support rename() in stream wrapper [Greg] + X update docs to reflect changes in error handling [Greg] + X fix 011.phpt, 029.phpt for uncaught exceptions causing bad cleanup + [Marcus/Greg] + +Version 1.1.0 + + X Ability to connect a phar file 'phar://whatever' to a directory. That way + all access to that phar archive are directed to the extracted directory. + This allows to have the installed files and the archive keep the same + includes. [Marcus] + X add SHA-2 (256, 512) support [Marcus] + X setSignatureAlgorithm() and Phar::MD5 Phar::SHA1 Phar::SHA256 Phar::SHA512 + Phar::PGP to choose the kind of signature to use (PGP falls back to SHA1) + [Greg] + +Version 1.2.0 + + X add PharFileInfo::hasMetadata(), PharFileInfo::delMetadata() [Marcus] + X add Phar::hasMetadata(), Phar::delMetadata() [Marcus] + X fix Phar::CanWrite() [Marcus] + X add preliminary phar command (phar.php) [Marcus] + X add phar command (phar.phar) [Marcus] + X list all available compression methods using + Phar::getSupportedCompression() [Marcus] + X Remove RINIT [Marcus] + +Version 1.2.1 + + X Add Phar::getAlias() [Marcus] + X Add Phar::setAlias() [Greg] + X Make -a optional in pack subcommand of phar.phar [Marcus] + X Make Phar::loadPhar() and Phar::mapPhar() ignore extracted archives + +Version 2.0.0 + + X implement webPhar() rewrite as a callback that returns FALSE to deny + access, or a string representing a file within the archive to access. If + unknown, the callback should return the original request uri [Greg] + X rework filename detection so that alias is always checked first [Greg] + X make aliases containing '/' or '\' invalid [Greg] + X implement manual mounting of external phar archives to locations inside a + phar path, $phar->mount('/path/to/external.phar', 'internal/path'); + this would traverse external.phar's manifest, and add each entry as a + virtual entry just like automatic mounting of internal phars [Greg] + X implement manual mounting of external paths to a directory inside a phar + path. Because the mapping would be to an external directory, write access + would be allowed always. This allows storing sqlite databases, cache, or + template files in a location external to the phar. Copy of the files + would need to be performed in an installation step, phar would not attempt + to do this for performance and security reasons. [Greg] + X implement opendir support for mounted paths [Greg] + X make convertToZip/convertToTar rename files [Steph] + X make convertTo*() with full file compression rename to append .gz or .bz2 + [Steph] + X don't automatically add a stub to .zip or .tar files [Steph] + X don't allow a stub or alias to be added to a .zip/.tar that does not have + ".phar" in the filename (or already have stub/alias) [Steph] + X allow read/write on .tar/.zip files that do not contain a stub or alias [Steph/Greg] + X prevent manual addition of stub via $a['.phar/stub.php'] = ' | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +#define PHAR_DIRSTREAM 1 +#include "phar_internal.h" +#include "dirstream.h" + +BEGIN_EXTERN_C() +void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, + zend_bool is_dir, char *alias, int alias_len TSRMLS_DC); +END_EXTERN_C() + +php_stream_ops phar_dir_ops = { + phar_dir_write, /* write */ + phar_dir_read, /* read */ + phar_dir_close, /* close */ + phar_dir_flush, /* flush */ + "phar dir", + phar_dir_seek, /* seek */ + NULL, /* cast */ + NULL, /* stat */ + NULL, /* set option */ +}; + +/** + * Used for closedir($fp) where $fp is an opendir('phar://...') directory handle + */ +static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ +{ + HashTable *data = (HashTable *)stream->abstract; + + if (data && data->arBuckets) + { + zend_hash_destroy(data); + data->arBuckets = 0; + FREE_HASHTABLE(data); + stream->abstract = NULL; + } + return 0; +} +/* }}} */ + +/** + * Used for seeking on a phar directory handle + */ +static int phar_dir_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */ +{ + HashTable *data = (HashTable *)stream->abstract; + + if (!data) + { + return -1; + } + if (whence == SEEK_END) { + whence = SEEK_SET; + offset = zend_hash_num_elements(data) + offset; + } + if (whence == SEEK_SET) { + zend_hash_internal_pointer_reset(data); + } + + if (offset < 0) { + return -1; + } else { + *newoffset = 0; + while (*newoffset < offset && zend_hash_move_forward(data) == SUCCESS) { + ++(*newoffset); + } + return 0; + } +} +/* }}} */ + +/** + * Used for readdir() on an opendir()ed phar directory handle + */ +static size_t phar_dir_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + size_t to_read; + HashTable *data = (HashTable *)stream->abstract; + char *key; + uint keylen; + ulong unused; + + if (FAILURE == zend_hash_has_more_elements(data)) { + return 0; + } + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) { + return 0; + } + zend_hash_move_forward(data); + to_read = MIN(keylen, count); + if (to_read == 0 || count < keylen) { + return 0; + } + memset(buf, 0, sizeof(php_stream_dirent)); + memcpy(((php_stream_dirent *) buf)->d_name, key, to_read); + ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0'; + + return sizeof(php_stream_dirent); +} +/* }}} */ + +/** + * Dummy: Used for writing to a phar directory (i.e. not used) + */ +static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + return 0; +} +/* }}} */ + +/** + * Dummy: Used for flushing writes to a phar directory (i.e. not used) + */ +static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */ +{ + return EOF; +} +/* }}} */ + +/** + * add an empty element with a char * key to a hash table, avoiding duplicates + * + * This is used to get a unique listing of virtual directories within a phar, + * for iterating over opendir()ed phar directories. + */ +static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */ +{ + void *dummy = (void *) 1; + + return zend_hash_update(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL); +} +/* }}} */ + +/** + * Used for sorting directories alphabetically + */ +static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC) /* {{{ */ +{ + Bucket *f; + Bucket *s; + int result; + + f = *((Bucket **) a); + s = *((Bucket **) b); + +#if (PHP_MAJOR_VERSION < 6) + result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength); +#else + result = zend_binary_strcmp(f->key.arKey.s, f->nKeyLength, s->key.arKey.s, s->nKeyLength); +#endif + + if (result < 0) { + return -1; + } else if (result > 0) { + return 1; + } else { + return 0; + } +} +/* }}} */ + +/** + * Create a opendir() directory stream handle by iterating over each of the + * files in a phar and retrieving its relative path. From this, construct + * a list of files/directories that are "in" the directory represented by dir + */ +static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) /* {{{ */ +{ + HashTable *data; + int dirlen = strlen(dir); + char *save, *found, *key; + uint keylen; + ulong unused; + char *entry; + ALLOC_HASHTABLE(data); + zend_hash_init(data, 64, zend_get_hash_value, NULL, 0); + + if (*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) { + /* make empty root directory for empty phar */ + efree(dir); + return php_stream_alloc(&phar_dir_ops, data, NULL, "r"); + } + zend_hash_internal_pointer_reset(manifest); + while (FAILURE != zend_hash_has_more_elements(manifest)) { + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) { + break; + } + if (keylen <= (uint)dirlen) { + if (keylen < (uint)dirlen || !strncmp(key, dir, dirlen)) { + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } + } + if (*dir == '/') { + /* root directory */ + if (NULL != (found = (char *) memchr(key, '/', keylen))) { + /* the entry has a path separator and is a subdirectory */ + entry = (char *) safe_emalloc(found - key, 1, 1); + memcpy(entry, key, found - key); + keylen = found - key; + entry[keylen] = '\0'; + } else { + entry = (char *) safe_emalloc(keylen, 1, 1); + memcpy(entry, key, keylen); + entry[keylen] = '\0'; + } + goto PHAR_ADD_ENTRY; + } else { + if (0 != memcmp(key, dir, dirlen)) { + /* entry in directory not found */ + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } else { + if (key[dirlen] != '/') { + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } + } + } + save = key; + save += dirlen + 1; /* seek to just past the path separator */ + if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) { + /* is subdirectory */ + save -= dirlen + 1; + entry = (char *) safe_emalloc(found - save + dirlen, 1, 1); + memcpy(entry, save + dirlen + 1, found - save - dirlen - 1); + keylen = found - save - dirlen - 1; + entry[keylen] = '\0'; + } else { + /* is file */ + save -= dirlen + 1; + entry = (char *) safe_emalloc(keylen - dirlen, 1, 1); + memcpy(entry, save + dirlen + 1, keylen - dirlen - 1); + entry[keylen - dirlen - 1] = '\0'; + keylen = keylen - dirlen - 1; + } +PHAR_ADD_ENTRY: + if (keylen) { + phar_add_empty(data, entry, keylen); + } + efree(entry); + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + } + if (FAILURE != zend_hash_has_more_elements(data)) { + efree(dir); + if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) { + FREE_HASHTABLE(data); + return NULL; + } + return php_stream_alloc(&phar_dir_ops, data, NULL, "r"); + } else { + efree(dir); + return php_stream_alloc(&phar_dir_ops, data, NULL, "r"); + } +} +/* }}}*/ + +/** + * Open a directory handle within a phar archive + */ +php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, + int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */ +{ + php_url *resource = NULL; + php_stream *ret; + char *internal_file, *key, *error; + uint keylen; + ulong unused; + phar_archive_data *phar; + phar_entry_info *entry = NULL; + uint host_len; + + if ((resource = phar_open_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar url \"%s\" is unknown", path); + return NULL; + } + + /* we must have at the very least phar://alias.phar/ */ + if (!resource->scheme || !resource->host || !resource->path) { + if (resource->host && !resource->path) { + 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)", path, resource->host); + php_url_free(resource); + return NULL; + } + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path); + return NULL; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar url \"%s\"", path); + return NULL; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + internal_file = resource->path + 1; /* strip leading "/" */ + if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar file \"%s\" is unknown", resource->host); + } + php_url_free(resource); + return NULL; + } + if (error) { + efree(error); + } + if (*internal_file == '\0') { + /* root directory requested */ + internal_file = estrndup(internal_file - 1, 1); + ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); + php_url_free(resource); + return ret; + } + if (!phar->manifest.arBuckets) { + php_url_free(resource); + return NULL; + } + if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) { + php_url_free(resource); + return NULL; + } else if (entry && entry->is_dir) { + if (entry->is_mounted) { + php_url_free(resource); + return php_stream_opendir(entry->tmp, options, context); + } + internal_file = estrdup(internal_file); + php_url_free(resource); + return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); + } else { + int i_len = strlen(internal_file); + + /* search for directory */ + zend_hash_internal_pointer_reset(&phar->manifest); + while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { + if (HASH_KEY_NON_EXISTANT != + zend_hash_get_current_key_ex( + &phar->manifest, &key, &keylen, &unused, 0, NULL)) { + if (keylen > (uint)i_len && 0 == memcmp(key, internal_file, i_len)) { + /* directory found */ + internal_file = estrndup(internal_file, + i_len); + php_url_free(resource); + return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); + } + } + if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { + break; + } + } + } + + php_url_free(resource); + return NULL; +} +/* }}} */ + +/** + * Make a new directory within a phar archive + */ +int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + phar_entry_info entry, *e; + phar_archive_data *phar = NULL; + char *error, *arch, *entry2; + int arch_len, entry_len; + php_url *resource = NULL; + 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, 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; + } + if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) { + phar = NULL; + } + efree(arch); + efree(entry2); + if (PHAR_G(readonly) && (!phar || !phar->is_data)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from); + return FAILURE; + } + + if ((resource = phar_open_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) { + return FAILURE; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from); + return FAILURE; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from); + return FAILURE; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + + if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error TSRMLS_CC))) { + /* directory exists, or is a subdirectory of an existing file */ + if (e->is_temp_dir) { + efree(e->filename); + efree(e); + } + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host); + php_url_free(resource); + return FAILURE; + } + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error TSRMLS_CC))) { + /* entry exists as a file */ + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host); + php_url_free(resource); + return FAILURE; + } + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + + memset((void *) &entry, 0, sizeof(phar_entry_info)); + + /* strip leading "/" */ + if (phar->is_zip) { + entry.is_zip = 1; + } + entry.filename = estrdup(resource->path + 1); + if (phar->is_tar) { + entry.is_tar = 1; + entry.tar_type = TAR_DIR; + } + entry.filename_len = strlen(resource->path + 1); + php_url_free(resource); + entry.is_dir = 1; + entry.phar = phar; + entry.is_modified = 1; + entry.is_crc_checked = 1; + entry.flags = PHAR_ENT_PERM_DEF_DIR; + entry.old_flags = PHAR_ENT_PERM_DEF_DIR; + if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname); + efree(error); + efree(entry.filename); + return FAILURE; + } + phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error); + zend_hash_del(&phar->manifest, entry.filename, entry.filename_len); + efree(error); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +/** + * Remove a directory within a phar archive + */ +int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry; + phar_archive_data *phar = NULL; + char *error, *arch, *entry2; + int arch_len, entry_len; + php_url *resource = NULL; + 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, 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)) { + phar = NULL; + } + efree(arch); + efree(entry2); + if (PHAR_G(readonly) && (!phar || !phar->is_data)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); + return FAILURE; + } + + if ((resource = phar_open_url(wrapper, url, "w", options TSRMLS_CC)) == NULL) { + return FAILURE; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url); + return FAILURE; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url); + return FAILURE; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error); + efree(error); + php_url_free(resource); + return FAILURE; + } + + if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error TSRMLS_CC))) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); + efree(error); + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host); + } + php_url_free(resource); + return FAILURE; + } + + /* now for the easy part */ + entry->is_deleted = 1; + entry->is_modified = 1; + phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error); + zend_hash_del(&phar->manifest, entry->filename, entry->filename_len); + php_url_free(resource); + efree(error); + return FAILURE; + } + php_url_free(resource); + return SUCCESS; +} +/* }}} */ diff --git a/ext/phar/dirstream.h b/ext/phar/dirstream.h new file mode 100644 index 0000000000..e7d0b40b58 --- /dev/null +++ b/ext/phar/dirstream.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +BEGIN_EXTERN_C() +int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC); +int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); + +#ifdef PHAR_DIRSTREAM +php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC); + +/* directory handlers */ +static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC); +static size_t phar_dir_read( php_stream *stream, char *buf, size_t count TSRMLS_DC); +static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC); +static int phar_dir_flush(php_stream *stream TSRMLS_DC); +static int phar_dir_seek( php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC); +#else +php_stream* phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); +#endif +END_EXTERN_C() + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c new file mode 100644 index 0000000000..b92d61a422 --- /dev/null +++ b/ext/phar/func_interceptors.c @@ -0,0 +1,1081 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" + +#define PHAR_FUNC(name) \ + static PHP_NAMED_FUNCTION(name) + +PHAR_FUNC(phar_opendir) /* {{{ */ +{ + char *filename; + int filename_len; + zval *zcontext = NULL; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + goto skip_phar; + } + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) { + return; + } + + if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + fname = zend_get_executed_filename(TSRMLS_C); + + /* we are checking for existence of a file within the relative path. Chances are good that this is + retrieving something from within the phar archive */ + + 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, 2, 0 TSRMLS_CC)) { + php_stream_context *context = NULL; + php_stream *stream; + char *name; + + efree(entry); + entry = estrndup(filename, filename_len); + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + /* retrieving a file within the current directory, so use this if possible */ + entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC); + + if (entry[0] == '/') { + spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + efree(entry); + efree(arch); + if (zcontext) { + context = php_stream_context_from_zval(zcontext, 0); + } + stream = php_stream_opendir(name, REPORT_ERRORS, context); + efree(name); + if (!stream) { + RETURN_FALSE; + } + php_stream_to_zval(stream, return_value); + return; + } + } +skip_phar: + PHAR_G(orig_opendir)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +PHAR_FUNC(phar_file_get_contents) /* {{{ */ +{ + char *filename; + int filename_len; + char *contents; + zend_bool use_include_path = 0; + php_stream *stream; + int len, newlen; + long offset = -1; + long maxlen = PHP_STREAM_COPY_ALL; + zval *zcontext = NULL; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + goto skip_phar; + } + /* Parse arguments */ + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) { + return; + } + if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + php_stream_context *context = NULL; + + fname = zend_get_executed_filename(TSRMLS_C); + + 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, 2, 0 TSRMLS_CC)) { + char *name; + phar_archive_data **pphar; + + efree(entry); + entry = filename; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + + if (ZEND_NUM_ARGS() == 5 && maxlen < 0) { + efree(arch); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero"); + RETURN_FALSE; + } + + /* retrieving a file defaults to within the current directory, so use this if possible */ + if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + goto skip_phar; + } + if (use_include_path) { + if ((entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) { + name = entry; + goto phar_it; + } else { + /* this file is not in the phar, use the original path */ + efree(arch); + goto skip_phar; + } + } else { + entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) { + /* this file is not in the phar, use the original path */ +notfound: + efree(arch); + efree(entry); + goto skip_phar; + } + } else { + if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) { + goto notfound; + } + } + /* auto-convert to phar:// */ + if (entry[0] == '/') { + spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + if (entry != filename) { + efree(entry); + } + } + +phar_it: + efree(arch); + if (zcontext) { + context = php_stream_context_from_zval(zcontext, 0); + } + stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context); + efree(name); + + if (!stream) { + RETURN_FALSE; + } + + if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset); + php_stream_close(stream); + RETURN_FALSE; + } + + /* uses mmap if possible */ + if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) { +#if PHP_MAJOR_VERSION < 6 + if (PG(magic_quotes_runtime)) { + contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */ + len = newlen; + } +#endif + RETVAL_STRINGL(contents, len, 0); + } else if (len == 0) { + RETVAL_EMPTY_STRING(); + } else { + RETVAL_FALSE; + } + + php_stream_close(stream); + return; + } + } +skip_phar: + PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +PHAR_FUNC(phar_readfile) /* {{{ */ +{ + char *filename; + int filename_len; + int size = 0; + zend_bool use_include_path = 0; + zval *zcontext = NULL; + php_stream *stream; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + goto skip_phar; + } + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) { + goto skip_phar; + } + if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + php_stream_context *context = NULL; + char *name; + phar_archive_data **pphar; + fname = zend_get_executed_filename(TSRMLS_C); + + if (strncasecmp(fname, "phar://", 7)) { + goto skip_phar; + } + fname_len = strlen(fname); + if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) { + goto skip_phar; + } + + efree(entry); + entry = filename; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + /* retrieving a file defaults to within the current directory, so use this if possible */ + if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + goto skip_phar; + } + if (use_include_path) { + if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) { + /* this file is not in the phar, use the original path */ + efree(arch); + goto skip_phar; + } else { + name = entry; + } + } else { + entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) { + /* this file is not in the phar, use the original path */ +notfound: + efree(entry); + efree(arch); + goto skip_phar; + } + } else { + if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) { + goto notfound; + } + } + /* auto-convert to phar:// */ + if (entry[0] == '/') { + spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + efree(entry); + } + + efree(arch); + context = php_stream_context_from_zval(zcontext, 0); + stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context); + efree(name); + if (stream == NULL) { + RETURN_FALSE; + } + size = php_stream_passthru(stream); + php_stream_close(stream); + RETURN_LONG(size); + } + +skip_phar: + PHAR_G(orig_readfile)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; + +} +/* }}} */ + +PHAR_FUNC(phar_fopen) /* {{{ */ +{ + char *filename, *mode; + int filename_len, mode_len; + zend_bool use_include_path = 0; + zval *zcontext = NULL; + php_stream *stream; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + /* no need to check, include_path not even specified in fopen/ no active phars */ + goto skip_phar; + } + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) { + goto skip_phar; + } + if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + php_stream_context *context = NULL; + char *name; + phar_archive_data **pphar; + fname = zend_get_executed_filename(TSRMLS_C); + + if (strncasecmp(fname, "phar://", 7)) { + goto skip_phar; + } + fname_len = strlen(fname); + if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) { + goto skip_phar; + } + + efree(entry); + entry = filename; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + /* retrieving a file defaults to within the current directory, so use this if possible */ + if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + goto skip_phar; + } + if (use_include_path) { + if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) { + /* this file is not in the phar, use the original path */ + efree(arch); + goto skip_phar; + } else { + name = entry; + } + } else { + entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) { + /* this file is not in the phar, use the original path */ +notfound: + efree(entry); + efree(arch); + goto skip_phar; + } + } else { + if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) { + /* this file is not in the phar, use the original path */ + goto notfound; + } + } + /* auto-convert to phar:// */ + if (entry[0] == '/') { + spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + efree(entry); + } + + efree(arch); + context = php_stream_context_from_zval(zcontext, 0); + stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context); + efree(name); + if (stream == NULL) { + RETURN_FALSE; + } + php_stream_to_zval(stream, return_value); + if (zcontext) { + zend_list_addref(Z_RESVAL_P(zcontext)); + } + return; + } +skip_phar: + PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#endif +#ifndef S_ISLNK +#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) +#endif + +#define S_IXROOT ( S_IXUSR | S_IXGRP | S_IXOTH ) + +#define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT) +#define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK) +#define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X) +#define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS) + +/* {{{ php_stat + */ +void phar_fancy_stat(struct stat *stat_sb, int type, zval *return_value TSRMLS_DC) +{ + zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev, + *stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks; + int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */ + char *stat_sb_names[13] = { + "dev", "ino", "mode", "nlink", "uid", "gid", "rdev", + "size", "atime", "mtime", "ctime", "blksize", "blocks" + }; + +#ifndef NETWARE + if (type >= FS_IS_W && type <= FS_IS_X) { + if(stat_sb->st_uid==getuid()) { + rmask=S_IRUSR; + wmask=S_IWUSR; + xmask=S_IXUSR; + } else if(stat_sb->st_gid==getgid()) { + rmask=S_IRGRP; + wmask=S_IWGRP; + xmask=S_IXGRP; + } else { + int groups, n, i; + gid_t *gids; + + groups = getgroups(0, NULL); + if(groups > 0) { + gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0); + n=getgroups(groups, gids); + for(i=0;ist_gid==gids[i]) { + rmask=S_IRGRP; + wmask=S_IWGRP; + xmask=S_IXGRP; + break; + } + } + efree(gids); + } + } + } +#endif + + switch (type) { + case FS_PERMS: + RETURN_LONG((long)stat_sb->st_mode); + case FS_INODE: + RETURN_LONG((long)stat_sb->st_ino); + case FS_SIZE: + RETURN_LONG((long)stat_sb->st_size); + case FS_OWNER: + RETURN_LONG((long)stat_sb->st_uid); + case FS_GROUP: + RETURN_LONG((long)stat_sb->st_gid); + case FS_ATIME: +#ifdef NETWARE + RETURN_LONG((long)stat_sb->st_atime.tv_sec); +#else + RETURN_LONG((long)stat_sb->st_atime); +#endif + case FS_MTIME: +#ifdef NETWARE + RETURN_LONG((long)stat_sb->st_mtime.tv_sec); +#else + RETURN_LONG((long)stat_sb->st_mtime); +#endif + case FS_CTIME: +#ifdef NETWARE + RETURN_LONG((long)stat_sb->st_ctime.tv_sec); +#else + RETURN_LONG((long)stat_sb->st_ctime); +#endif + case FS_TYPE: + if (S_ISLNK(stat_sb->st_mode)) { + RETURN_STRING("link", 1); + } + switch(stat_sb->st_mode & S_IFMT) { + case S_IFDIR: RETURN_STRING("dir", 1); + case S_IFREG: RETURN_STRING("file", 1); + } + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%d)", stat_sb->st_mode&S_IFMT); + RETURN_STRING("unknown", 1); + case FS_IS_W: + RETURN_BOOL((stat_sb->st_mode & wmask) != 0); + case FS_IS_R: + RETURN_BOOL((stat_sb->st_mode&rmask)!=0); + case FS_IS_X: + RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode)); + case FS_IS_FILE: + RETURN_BOOL(S_ISREG(stat_sb->st_mode)); + case FS_IS_DIR: + RETURN_BOOL(S_ISDIR(stat_sb->st_mode)); + case FS_IS_LINK: + RETURN_BOOL(S_ISLNK(stat_sb->st_mode)); + case FS_EXISTS: + RETURN_TRUE; /* the false case was done earlier */ + case FS_LSTAT: + /* FALLTHROUGH */ + case FS_STAT: + array_init(return_value); + + MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev); + MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino); + MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode); + MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink); + MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid); + MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid); +#ifdef HAVE_ST_RDEV + MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev); +#else + MAKE_LONG_ZVAL_INCREF(stat_rdev, -1); +#endif + MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size); +#ifdef NETWARE + MAKE_LONG_ZVAL_INCREF(stat_atime, (stat_sb->st_atime).tv_sec); + MAKE_LONG_ZVAL_INCREF(stat_mtime, (stat_sb->st_mtime).tv_sec); + MAKE_LONG_ZVAL_INCREF(stat_ctime, (stat_sb->st_ctime).tv_sec); +#else + MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime); + MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime); + MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime); +#endif +#ifdef HAVE_ST_BLKSIZE + MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize); +#else + MAKE_LONG_ZVAL_INCREF(stat_blksize,-1); +#endif +#ifdef HAVE_ST_BLOCKS + MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks); +#else + MAKE_LONG_ZVAL_INCREF(stat_blocks,-1); +#endif + /* Store numeric indexes in propper order */ + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL); + + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL); + zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL); + + /* Store string indexes referencing the same zval*/ + zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL); + zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL); + + return; + } + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call"); + RETURN_FALSE; +} +/* }}} */ + +void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ +{ + if (!filename_length) { + RETURN_FALSE; + } + + if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + struct stat sb = {0}; + phar_entry_info *data = NULL; + char *tmp; + int tmp_len; + + fname = zend_get_executed_filename(TSRMLS_C); + + /* we are checking for existence of a file within the relative path. Chances are good that this is + retrieving something from within the phar archive */ + + 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, 2, 0 TSRMLS_CC)) { + phar_archive_data **pphar; + + efree(entry); + entry = estrndup(filename, filename_length); + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = (int) filename_length; + if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + goto skip_phar; + } + entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) { + efree(entry); + goto stat_entry; + } + goto notfound; + } + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) { + efree(entry); + goto stat_entry; + } else { + char *save, *save2, *actual; + int save_len, save2_len, actual_len; + +notfound: + save = PHAR_G(cwd); + save2 = entry; + actual = entry[0] == '/' ? (entry + 1) : entry; + save_len = PHAR_G(cwd_len); + save2_len = entry_len; + actual_len = entry[0] == '/' ? (entry_len - 1) : entry_len; + /* this file is not in the current directory, use the original path */ + entry = estrndup(filename, filename_length); + entry_len = filename_length; + PHAR_G(cwd) = "/"; + PHAR_G(cwd_len) = 0; + /* clean path without cwd */ + entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC); + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) { + PHAR_G(cwd) = save; + PHAR_G(cwd_len) = save_len; + efree(entry); + efree(save2); + goto stat_entry; + } else { + phar_archive_data *phar = *pphar; + char *key; + uint keylen; + ulong unused; + + PHAR_G(cwd) = save; + PHAR_G(cwd_len) = save_len; + /* original not found either, this is possibly a directory relative to cwd */ + zend_hash_internal_pointer_reset(&phar->manifest); + while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { + if (HASH_KEY_NON_EXISTANT != + zend_hash_get_current_key_ex( + &phar->manifest, &key, &keylen, &unused, 0, NULL)) { + if (!memcmp(actual, key, actual_len)) { + efree(save2); + efree(entry); + /* directory found, all dirs have the same stat */ + if (key[actual_len] == '/') { + sb.st_size = 0; + sb.st_mode = 0777; + sb.st_mode |= S_IFDIR; /* regular directory */ +#ifdef NETWARE + sb.st_mtime.tv_sec = phar->max_timestamp; + sb.st_atime.tv_sec = phar->max_timestamp; + sb.st_ctime.tv_sec = phar->max_timestamp; +#else + sb.st_mtime = phar->max_timestamp; + sb.st_atime = phar->max_timestamp; + sb.st_ctime = phar->max_timestamp; +#endif + goto statme_baby; + } + } + } + if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { + break; + } + } + } + efree(entry); + efree(save2); + efree(arch); + /* Error Occured */ + if (!IS_EXISTS_CHECK(type)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename); + } + RETURN_FALSE; + } +stat_entry: + if (!data->is_dir) { + sb.st_size = data->uncompressed_filesize; + sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; + if (data->link) { + sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */ + } else { + sb.st_mode |= S_IFREG; /* regular file */ + } + /* timestamp is just the timestamp when this was added to the phar */ +#ifdef NETWARE + sb.st_mtime.tv_sec = data->timestamp; + sb.st_atime.tv_sec = data->timestamp; + sb.st_ctime.tv_sec = data->timestamp; +#else + sb.st_mtime = data->timestamp; + sb.st_atime = data->timestamp; + sb.st_ctime = data->timestamp; +#endif + } else { + sb.st_size = 0; + sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; + sb.st_mode |= S_IFDIR; /* regular directory */ + if (data->link) { + sb.st_mode |= S_IFLNK; + } + /* timestamp is just the timestamp when this was added to the phar */ +#ifdef NETWARE + sb.st_mtime.tv_sec = data->timestamp; + sb.st_atime.tv_sec = data->timestamp; + sb.st_ctime.tv_sec = data->timestamp; +#else + sb.st_mtime = data->timestamp; + sb.st_atime = data->timestamp; + sb.st_ctime = data->timestamp; +#endif + } + +statme_baby: + efree(arch); + if (!(*pphar)->is_writeable) { + sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777); + } + + sb.st_nlink = 1; + sb.st_rdev = -1; + if (data) { + tmp_len = data->filename_len + (*pphar)->alias_len; + } else { + tmp_len = (*pphar)->alias_len + 1; + } + tmp = (char *) emalloc(tmp_len); + memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len); + if (data) { + memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len); + } else { + *(tmp + (*pphar)->alias_len) = '/'; + } + /* this is only for APC, so use /dev/null device - no chance of conflict there! */ + sb.st_dev = 0xc; + /* generate unique inode number for alias/filename, so no phars will conflict */ + sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len); + efree(tmp); +#ifndef PHP_WIN32 + sb.st_blksize = -1; + sb.st_blocks = -1; +#endif + phar_fancy_stat(&sb, type, return_value TSRMLS_CC); + return; + } + } +skip_phar: + orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +#define PharFileFunction(fname, funcnum, orig) \ +void fname(INTERNAL_FUNCTION_PARAMETERS) { \ + char *filename; \ + int filename_len; \ + \ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \ + return; \ + } \ + \ + phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \ +} +/* }}} */ + +/* {{{ proto int fileperms(string filename) + Get file permissions */ +PharFileFunction(phar_fileperms, FS_PERMS, orig_fileperms) +/* }}} */ + +/* {{{ proto int fileinode(string filename) + Get file inode */ +PharFileFunction(phar_fileinode, FS_INODE, orig_fileinode) +/* }}} */ + +/* {{{ proto int filesize(string filename) + Get file size */ +PharFileFunction(phar_filesize, FS_SIZE, orig_filesize) +/* }}} */ + +/* {{{ proto int fileowner(string filename) + Get file owner */ +PharFileFunction(phar_fileowner, FS_OWNER, orig_fileowner) +/* }}} */ + +/* {{{ proto int filegroup(string filename) + Get file group */ +PharFileFunction(phar_filegroup, FS_GROUP, orig_filegroup) +/* }}} */ + +/* {{{ proto int fileatime(string filename) + Get last access time of file */ +PharFileFunction(phar_fileatime, FS_ATIME, orig_fileatime) +/* }}} */ + +/* {{{ proto int filemtime(string filename) + Get last modification time of file */ +PharFileFunction(phar_filemtime, FS_MTIME, orig_filemtime) +/* }}} */ + +/* {{{ proto int filectime(string filename) + Get inode modification time of file */ +PharFileFunction(phar_filectime, FS_CTIME, orig_filectime) +/* }}} */ + +/* {{{ proto string filetype(string filename) + Get file type */ +PharFileFunction(phar_filetype, FS_TYPE, orig_filetype) +/* }}} */ + +/* {{{ proto bool is_writable(string filename) + Returns true if file can be written */ +PharFileFunction(phar_is_writable, FS_IS_W, orig_is_writable) +/* }}} */ + +/* {{{ proto bool is_readable(string filename) + Returns true if file can be read */ +PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable) +/* }}} */ + +/* {{{ proto bool is_executable(string filename) + Returns true if file is executable */ +PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable) +/* }}} */ + +/* {{{ proto bool is_executable(string filename) + Returns true if file is executable */ +PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists) +/* }}} */ + +/* {{{ proto bool is_executable(string filename) + Returns true if file is executable */ +PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir) +/* }}} */ + +PHAR_FUNC(phar_is_file) /* {{{ */ +{ + char *filename; + int filename_len; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + goto skip_phar; + } + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + goto skip_phar; + } + if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + fname = zend_get_executed_filename(TSRMLS_C); + + /* we are checking for existence of a file within the relative path. Chances are good that this is + retrieving something from within the phar archive */ + + 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, 2, 0 TSRMLS_CC)) { + phar_archive_data **pphar; + + efree(entry); + entry = filename; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + /* retrieving a file within the current directory, so use this if possible */ + if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + phar_entry_info *etemp; + + entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) { + /* this file is not in the current directory, use the original path */ +found_it: + efree(entry); + efree(arch); + RETURN_BOOL(!etemp->is_dir); + } + } else { + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) { + goto found_it; + } + } + } + efree(entry); + efree(arch); + RETURN_FALSE; + } + } +skip_phar: + PHAR_G(orig_is_file)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +PHAR_FUNC(phar_is_link) /* {{{ */ +{ + char *filename; + int filename_len; + + if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + goto skip_phar; + } + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + goto skip_phar; + } + if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { + char *arch, *entry, *fname; + int arch_len, entry_len, fname_len; + fname = zend_get_executed_filename(TSRMLS_C); + + /* we are checking for existence of a file within the relative path. Chances are good that this is + retrieving something from within the phar archive */ + + 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, 2, 0 TSRMLS_CC)) { + phar_archive_data **pphar; + + efree(entry); + entry = filename; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + entry_len = filename_len; + /* retrieving a file within the current directory, so use this if possible */ + if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + phar_entry_info *etemp; + + entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC); + if (entry[0] == '/') { + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) { + /* this file is not in the current directory, use the original path */ +found_it: + efree(entry); + efree(arch); + RETURN_BOOL(etemp->link); + } + } else { + if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) { + goto found_it; + } + } + } + efree(entry); + efree(arch); + RETURN_FALSE; + } + } +skip_phar: + PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU); + return; +} +/* }}} */ + +/* {{{ proto array lstat(string filename) + Give information about a file or symbolic link */ +PharFileFunction(phar_lstat, FS_LSTAT, orig_lstat) +/* }}} */ + +/* {{{ proto array stat(string filename) + Give information about a file */ +PharFileFunction(phar_stat, FS_STAT, orig_stat) +/* }}} */ + +/* {{{ void phar_intercept_functions(TSRMLS_D) */ +#define PHAR_INTERCEPT(func) \ + PHAR_G(orig_##func) = NULL; \ + if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \ + PHAR_G(orig_##func) = orig->internal_function.handler; \ + orig->internal_function.handler = phar_##func; \ + } + +void phar_intercept_functions(TSRMLS_D) +{ + zend_function *orig; + + if (!PHAR_G(request_init)) { + PHAR_G(cwd) = NULL; + PHAR_G(cwd_len) = 0; + } else if (PHAR_G(orig_fopen)) { + /* don't double-intercept */ + return; + } + PHAR_INTERCEPT(fopen); + PHAR_INTERCEPT(file_get_contents); + PHAR_INTERCEPT(is_file); + PHAR_INTERCEPT(is_link); + PHAR_INTERCEPT(is_dir); + PHAR_INTERCEPT(opendir); + PHAR_INTERCEPT(file_exists); + PHAR_INTERCEPT(fileperms); + PHAR_INTERCEPT(fileinode); + PHAR_INTERCEPT(filesize); + PHAR_INTERCEPT(fileowner); + PHAR_INTERCEPT(filegroup); + PHAR_INTERCEPT(fileatime); + PHAR_INTERCEPT(filemtime); + PHAR_INTERCEPT(filectime); + PHAR_INTERCEPT(filetype); + PHAR_INTERCEPT(is_writable); + PHAR_INTERCEPT(is_readable); + PHAR_INTERCEPT(is_executable); + PHAR_INTERCEPT(lstat); + PHAR_INTERCEPT(stat); + PHAR_INTERCEPT(readfile); +} +/* }}} */ + +/* {{{ void phar_release_functions(TSRMLS_D) */ +#define PHAR_RELEASE(func) \ + if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \ + orig->internal_function.handler = PHAR_G(orig_##func); \ + } \ + PHAR_G(orig_##func) = NULL; + +void phar_release_functions(TSRMLS_D) +{ + zend_function *orig; + + PHAR_RELEASE(fopen); + PHAR_RELEASE(file_get_contents); + PHAR_RELEASE(is_file); + PHAR_RELEASE(is_dir); + PHAR_RELEASE(opendir); + PHAR_RELEASE(file_exists); + PHAR_RELEASE(fileperms); + PHAR_RELEASE(fileinode); + PHAR_RELEASE(filesize); + PHAR_RELEASE(fileowner); + PHAR_RELEASE(filegroup); + PHAR_RELEASE(fileatime); + PHAR_RELEASE(filemtime); + PHAR_RELEASE(filectime); + PHAR_RELEASE(filetype); + PHAR_RELEASE(is_writable); + PHAR_RELEASE(is_readable); + PHAR_RELEASE(is_executable); + PHAR_RELEASE(lstat); + PHAR_RELEASE(stat); + PHAR_RELEASE(readfile); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/func_interceptors.h b/ext/phar/func_interceptors.h new file mode 100644 index 0000000000..b48be591ed --- /dev/null +++ b/ext/phar/func_interceptors.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +BEGIN_EXTERN_C() +void phar_intercept_functions(TSRMLS_D); +void phar_release_functions(TSRMLS_D); +END_EXTERN_C() + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/gdbhelp b/ext/phar/gdbhelp new file mode 100644 index 0000000000..5411858671 --- /dev/null +++ b/ext/phar/gdbhelp @@ -0,0 +1,122 @@ +define ___pharglobals + if basic_functions_module.zts + set $tsrm_ls = ts_resource_ex(0, 0) + set $pharglobals = ((zend_phar_globals) (*((void ***) $tsrm_ls))[phar_globals_id-1]) + else + set $pharglobals = phar_globals + end +end + +define ____print_pharht + set $ht = $arg0 + set $p = $ht.pListHead + + while $p != 0 + set $i = $ind + while $i > 0 + printf " " + set $i = $i - 1 + end + + set $temp = *(phar_archive_data*)$p->pDataPtr + ____print_str $temp.fname $temp.fname_len + printf " => " + + if $arg1 == 0 + + printf "%i (alias ", $temp.refcount + ____print_str $temp.alias $temp.alias_len + printf ")\n" + end + + set $p = $p->pListNext + end +end + +define print_phar + set $ind = 1 + ___pharglobals + printf "{" + ____print_pharht $pharglobals.phar_fname_map 0 + printf "}\n" +end + +document display_phar_globals + display phar globals +end + +define display_phar_globals + ___pharglobals + graph display $phar_globals.$arg0 +end + +define print_pharfp + ___pharglobals + set $ht = $pharglobals.phar_fname_map + set $p = $ht.pListHead + set $fpcount = 0 + + while $p != 0 + set $pharname = (*(phar_archive_data*)$p->pDataPtr).fname + set $pharrefcount = (*(phar_archive_data*)$p->pDataPtr).refcount + if (*(phar_archive_data*)$p->pDataPtr).fp != 0 + set $fpcount = $fpcount + 1 + printf "phar %s is open (%i)\n", $pharname, $pharrefcount + end + set $manifest = (*(phar_archive_data*)$p->pDataPtr).manifest + set $m = $manifest.pListHead + while $m != 0 + if (*(phar_entry_info *)$m->pData).fp + set $fpcount = $fpcount + 1 + set $a = (*(phar_entry_info *)$m->pData).fp_refcount + printf "phar %s file %s is open (%i)\n", $pharname, (*(phar_entry_info *)$m->pData).filename, $a + end + set $m = $m->pListNext + end + + set $p = $p->pListNext + end + printf "Open file pointers: %d\n", $fpcount +end + +document print_pharfp + displays all open file pointers in phar, and the phars plus entries that are open with reference counts +end + +define dump_entry + ___pharglobals + set $ht = $pharglobals.phar_fname_map + set $p = $ht.pListHead + set $done = 0 + while $p != 0 + set $t = (*(phar_archive_data*)$p->pDataPtr) + if $t.fname[0] == $arg0[0] || $t.alias[0] == $arg0[0] + set $manifest = (*(phar_archive_data*)$p->pDataPtr).manifest + set $m = $manifest.pListHead + while $m != 0 + if (*(phar_entry_info *)$m->pData).filename[0] == $arg1[0] + if $argc == 3 + output *((phar_entry_info *)$m->pData)->fp + end + if $argc == 2 + output *(phar_entry_info *)$m->pData + end + printf "\n" + set $done = 1 + loop_break + end + set $m = $m->pListNext + end + end + if $done == 1 + loop_break + end + set $p = $p->pListNext + end +end + +document dump_entry + dump_entry "pharname"|"pharalias" "filename" [1] + display phar_entry_info for a file within a phar. If the optional third param + is passed in, displays the php_stream that is the file's fp +end \ No newline at end of file diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php new file mode 100644 index 0000000000..44e0b96337 --- /dev/null +++ b/ext/phar/makestub.php @@ -0,0 +1,109 @@ +'; +$slen = strlen($s) - strlen('index.php') - strlen("000"); +$s = str_replace('\\', '\\\\', $s); +$s = str_replace('"', '\\"', $s); +$s = str_replace("\n", '\n', $s); +// now we need to find the location of web index file +$webs = substr($s, 0, strpos($s, "000")); +$s = substr($s, strlen($webs) + strlen("000")); +$s1 = substr($s, 0, strpos($s, 'index.php')); +$s2 = substr($s, strlen($s1) + strlen('index.php')); +$s2 = substr($s2, 0, strpos($s2, 'XXXX')); +$s3 = substr($s, strlen($s2) + 4 + strlen($s1) + strlen('index.php')); + +$stub = '/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension generated stub | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-' . date('Y') . ' The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC) +{ +'; +$s1split = str_split($s1, 2046); +$s3split = str_split($s3, 2046); +$took = false; +foreach ($s1split as $i => $chunk) { + if ($took) { + $s1split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s1split[$i] .= $s1split[$i + 1][0]; + $took = true; + } +} +foreach ($s3split as $i => $chunk) { + if ($took) { + $s3split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s3split[$i] .= $s3split[$i + 1][0]; + $took = true; + } +} +$stub .= "\tstatic const char newstub0[] = \"" . $webs . '"; +'; +foreach ($s1split as $i => $chunk) { + $s1count = $i + 1; + $stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '"; +'; +} +$stub .= "\tstatic const char newstub2[] = \"" . $s2 . "\"; +"; +foreach ($s3split as $i => $chunk) { + $s3count = $i + 1; + $stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '"; +'; +} +$stub .= "\n\tstatic const int newstub_len = " . $slen . "; + +\t*len = spprintf(stub, name_len + web_len + newstub_len, \"%s%s" . str_repeat('%s', $s1count) . '%s%s%d' + . str_repeat('%s', $s3count) . '", newstub0, web'; +foreach ($s1split as $i => $unused) { + $stub .= ', newstub1_' . $i; +} +$stub .= ', index_php, newstub2'; +$stub .= ", name_len + web_len + newstub_len"; +foreach ($s3split as $i => $unused) { + $stub .= ', newstub3_' . $i; +} +$stub .= "); +}"; + +file_put_contents(dirname(__FILE__) . '/stub.h', $stub."\n"); +?> diff --git a/ext/phar/package.php b/ext/phar/package.php new file mode 100644 index 0000000000..f4d63ae21d --- /dev/null +++ b/ext/phar/package.php @@ -0,0 +1,108 @@ +compress()/decompress(). + * phar.extract_list and Phar::getExtractList() are removed + +Major feature functionality release + * new default stub allows running of phar-based phars without phar extension [Greg/Steph] + * add support for tar-based and zip-based phar archives [Greg] + * add Phar::isFileFormat() [Greg] + * add Phar::convertToExecutable(), Phar::convertToData() [Greg] + * add Phar::compress() [Greg] + * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to + decompressFiles() [Greg] + * conversion to compressed or to other file formats automatically copies the archive + to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph] + * add Phar::webPhar() for running a web-based application unmodified + directly from a phar archive [Greg] + * file functions (fopen-based and stat-based) can be instructed to only look for + relative paths within a phar via Phar::interceptFileFuncs() + * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph] + non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg] + * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg] + * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg] + * add option to compress the entire phar file for phar/tar file format [Greg] + * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg] + * implement Phar::copy(string $from, string $to) [Greg] + * implement Phar::running(), returns path or URL to currently executed phar + * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg] + * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph] + * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg] + * add Phar::delete() [Greg] + * implement Phar::unlinkArchive() [Greg] + +Security addition + * aliases are validated so that they contain no directory separators as intended + * on conversion to other formats, user-supplied aliases are validated + +Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored, + conversion API refactored +'; + +if (!class_exists("Phar") && !extension_loaded("Phar")) { + die("Extension phar not present"); +} +error_reporting(E_ALL & ~E_DEPRECATED); + +require_once 'PEAR/PackageFileManager2.php'; + +PEAR::setErrorHandling(PEAR_ERROR_DIE); + +$options = array( + 'filelistgenerator' => 'CVS', + 'changelogoldtonew' => false, + 'simpleoutput' => true, + 'baseinstalldir' => '/', + 'packagedirectory' => dirname(__FILE__), + 'packagefile' => 'package.xml', + 'clearcontents' => true, + 'ignore' => array('package*.php', 'package*.xml'), + 'dir_roles' => array( + 'docs' => 'doc', + 'examples' => 'doc', + 'tests' => 'test', + 'phar' => 'src', + ), + 'exceptions' => array( + 'CREDITS' => 'doc', + 'EXPERIMENTAL' => 'doc', + 'LICENSE' => 'doc', + 'Makefile.frag' => 'src', + 'phar_path_check.re' => 'src', + 'TODO' => 'doc', + 'phar.phar' => 'script', + ), +); + +$package = PEAR_PackageFileManager2::importOptions(dirname(__FILE__) . '/package.xml', $options); + +$package->clearDeps(); +$package->setPhpDep('5.2.0'); +$package->setPearInstallerDep('1.4.3'); +$package->addPackageDepWithChannel('optional', 'bz2', 'pecl.php.net', false, false, false, false, 'bz2'); +// all this false business sets the tag that allows us to have hash built +// in statically +$package->addPackageDepWithChannel('optional', 'hash', 'pecl.php.net', false, false, false, false, 'hash'); +$package->addExtensionDep('optional', 'spl'); +$package->addExtensionDep('optional', 'zlib'); +$package->setPackageType('extsrc'); +$package->addRelease(); +$package->setReleaseVersion(phpversion('phar')); +$package->setAPIVersion(Phar::apiVersion()); +$package->setReleaseStability('beta'); +$package->setAPIStability('beta'); +$package->setNotes("\n$notes\n"); +//$package->addGlobalReplacement('package-info', '@package_version@', 'version'); +$package->generateContents(); + +if (isset($_GET['make']) || (isset($_SERVER['argv']) && @$_SERVER['argv'][1] == 'make')) { + $package->writePackageFile(); +} else { + $package->debugPackageFile(); +} + +?> diff --git a/ext/phar/package.xml b/ext/phar/package.xml new file mode 100644 index 0000000000..d2d3dcdfd3 --- /dev/null +++ b/ext/phar/package.xml @@ -0,0 +1,924 @@ + + + phar + pecl.php.net + allows running of complete applications out of .phar files (like Java .jar files) + This is the extension version of PEAR's PHP_Archive package. Support for +zlib, bz2 and crc32 is achieved without any dependency other than the external +zlib or bz2 extension. + +.phar files can be read using the phar stream, or with the Phar class. If the SPL extension +is available, a Phar object can be used as an array to iterate over a phar's contents +or to read files directly from the phar. + +Phar supports tar and zip file formats as well as the native phar file format, and can also be +used to create data-only tar and zip archives with the PharData class, even if +write access is disabled by the phar.readonly ini variable. + +Executable phar archives can be created using the streams API or with the Phar class, if +the phar.readonly ini variable is set to false. + +Full support for MD5 and SHA1 signatures is possible. Signatures can be required +if the ini variable phar.require_hash is set to true. When PECL extension hash is +available then SHA-256 and SHA-512 signatures are supported as well. + +Phar is APC-compatible, the latest APC will cache files within a phar archive, resulting in +a 6x speedup measured running phpMyAdmin as a phar archive. + + Greg Beaver + cellog + cellog@php.net + yes + + + Marcus Boerger + helly + helly@php.net + yes + + + Steph Fox + sfox + sfox@php.net + yes + + 2008-05-12 + + + 2.0.0b1 + 1.1.1 + + + beta + beta + + PHP License + + +BC BREAKING RELEASE + BC breaks: + * Phar object Compression API is rewritten. Use Phar::compress() and decompress(), + Phar::compressFiles()/decompressFiles() and PharFileInfo->compress()/decompress(). + * phar.extract_list and Phar::getExtractList() are removed + +Major feature functionality release + * new default stub allows running of phar-based phars without phar extension [Greg/Steph] + * add support for tar-based and zip-based phar archives [Greg] + * add Phar::isFileFormat() [Greg] + * add Phar::convertToExecutable(), Phar::convertToData() [Greg] + * add Phar::compress() [Greg] + * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to + decompressFiles() [Greg] + * conversion to compressed or to other file formats automatically copies the archive + to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph] + * add Phar::webPhar() for running a web-based application unmodified + directly from a phar archive [Greg] + * file functions (fopen-based and stat-based) can be instructed to only look for + relative paths within a phar via Phar::interceptFileFuncs() + * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph] + non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg] + * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg] + * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg] + * add option to compress the entire phar file for phar/tar file format [Greg] + * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg] + * implement Phar::copy(string $from, string $to) [Greg] + * implement Phar::running(), returns path or URL to currently executed phar + * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg] + * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph] + * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg] + * add Phar::delete() [Greg] + * implement Phar::unlinkArchive() [Greg] + +Security addition + * aliases are validated so that they contain no directory separators as intended + * on conversion to other formats, user-supplied aliases are validated + +Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored, + conversion API refactored + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5.2.0 + + + 1.4.3 + + + + + bz2 + pecl.php.net + bz2 + + + hash + pecl.php.net + hash + + + spl + + + zlib + + + + phar + + + + + 2.0.0b1 + 1.1.1 + + + beta + beta + + 2008-05-12 + PHP License + + +BC BREAKING RELEASE + BC breaks: + * Phar object Compression API is rewritten. Use Phar::compress() and decompress(), + Phar::compressFiles()/decompressFiles() and PharFileInfo->compress()/decompress(). + * phar.extract_list and Phar::getExtractList() are removed + +Major feature functionality release + * new default stub allows running of phar-based phars without phar extension [Greg/Steph] + * add support for tar-based and zip-based phar archives [Greg] + * add Phar::isFileFormat() [Greg] + * add Phar::convertToExecutable(), Phar::convertToData() [Greg] + * add Phar::compress() [Greg] + * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to + decompressFiles() [Greg] + * conversion to compressed or to other file formats automatically copies the archive + to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph] + * add Phar::webPhar() for running a web-based application unmodified + directly from a phar archive [Greg] + * file functions (fopen-based and stat-based) can be instructed to only look for + relative paths within a phar via Phar::interceptFileFuncs() + * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph] + non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg] + * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg] + * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg] + * add option to compress the entire phar file for phar/tar file format [Greg] + * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg] + * implement Phar::copy(string $from, string $to) [Greg] + * implement Phar::running(), returns path or URL to currently executed phar + * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg] + * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph] + * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg] + * add Phar::delete() [Greg] + * implement Phar::unlinkArchive() [Greg] + +Security addition + * aliases are validated so that they contain no directory separators as intended + * on conversion to other formats, user-supplied aliases are validated + +Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored, + conversion API refactored + + + + + + 2.0.0a2 + 1.1.1 + + + alpha + alpha + + 2008-03-27 + PHP License + Major feature functionality release + * new default stub allows running of phar-based phars without phar extension [Greg/Steph] + * add support for tar-based and zip-based phar archives [Greg] + * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg] + * add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() [Greg] + * add Phar::compress() [Greg] + * conversion to compressed or to other file formats automatically copies the archive + to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph] + * add Phar::webPhar() for running a web-based application unmodified + directly from a phar archive [Greg] + * file functions (fopen-based and stat-based) can be instructed to only look for + relative paths within a phar via Phar::interceptFileFuncs() + * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph] + non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg] + * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg] + * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg] + * add option to compress the entire phar file for phar/tar file format [Greg] + * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg] + * implement Phar::copy(string $from, string $to) [Greg] + * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg] + * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg] + * add Phar::delete() [Greg] + +Changes since 2.0.0a1: fix build in PHP 5.2 + + + + 2.0.0a1 + 1.1.1 + + + alpha + alpha + + 2008-03-26 + PHP License + Major feature functionality release + * new default stub allows running of phar-based phars without phar extension [Greg/Steph] + * add support for tar-based and zip-based phar archives [Greg] + * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg] + * add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() [Greg] + * add Phar::compress() [Greg] + * conversion to compressed or to other file formats automatically copies the archive + to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph] + * add Phar::webPhar() for running a web-based application unmodified + directly from a phar archive [Greg] + * file functions (fopen-based and stat-based) can be instructed to only look for + relative paths within a phar via Phar::interceptFileFuncs() + * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph] + non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg] + * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg] + * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg] + * add option to compress the entire phar file for phar/tar file format [Greg] + * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg] + * implement Phar::copy(string $from, string $to) [Greg] + * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg] + * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg] + * add Phar::delete() [Greg] + + + + 1.2.1 + 1.1.0 + + + stable + stable + + 2007-08-24 + PHP License + * add Phar::setAlias() [Greg] +* fix too many open file handles issue [Greg] +* fix rename [Greg] +* add Phar::getAlias() [Marcus] +* Made -a optional in pack subcommand of phar.phar [Marcus] +* Fix issue with apache module and extracted archives [Marcus] +* Send all error messages to stderr in phar.phar [Marcus] +* Added new subcommands add and delete to phar.phar [Marcus] +* Made Phar::loadPhar() and Phar::mapPhar() ignore extracted archives [Marcus] +* Fix issue with compressed entries and uncompressing entries [Marcus] +* Verify stubs before writing [Marcus] +* Always use longest stub end to avoid issues with length field [Marcus] + + + + 1.2.0 + 1.1.0 + + + stable + stable + + 2007-05-18 + PHP License + * add PharFileInfo::hasMetadata(), PharFileInfo::delMetadata() [Marcus] +* add Phar::hasMetadata(), Phar::delMetadata() [Marcus] +* fix Phar::CanWrite() [Marcus] +* add preliminary phar command (phar.php) [Marcus] +* add phar command (phar.phar) [Marcus] +* list all available compression methods using Phar::getSupportedCompression() [Marcus] +* remove RINIT [Marcus] + + + + 1.1.0 + 1.1.0 + + + stable + stable + + 2007-04-12 + PHP License + * implement ability connect a phar file 'phar://whatever' to a directory. That way all + access to that phar archive are directed to the extracted directory. This + allows to have the installed files and the archive keep the same includes. + [Marcus] +* implement SHA-2 (256, 512) support [Marcus] +* implement setSignatureAlgorithm() and Phar::MD5 Phar::SHA1 Phar::SHA256 Phar::SHA512 Phar::PGP to + choose the kind of signature to use (PGP falls back to SHA1) [Greg] + + + + 1.0.1 + 1.0.1 + + + stable + stable + + 2007-03-28 + PHP License + * Fix return value of unlink() and rename() when used for phar archievs. [Marcus] + + + + 1.0.0 + 1.0.0 + + + stable + stable + + 2007-03-26 + PHP License + *BACKWARDS COMPATIBILITY BREAK* +Rename Phar->begin/isFlushingToPhar/commit to startBuffering/isBuffering/stopBuffering +Note that isBuffering() returns the opposite value to isFlushingToPhar() + + + diff --git a/ext/phar/phar.c b/ext/phar/phar.c new file mode 100644 index 0000000000..ab2cb08ac4 --- /dev/null +++ b/ext/phar/phar.c @@ -0,0 +1,3091 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#define PHAR_MAIN 1 +#include "phar_internal.h" +#include "SAPI.h" +#include "func_interceptors.h" + +ZEND_DECLARE_MODULE_GLOBALS(phar) +int phar_has_bz2; +int phar_has_zlib; +#if PHP_VERSION_ID >= 50300 +char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC); +#endif + +/** + * set's phar->is_writeable based on the current INI value + */ +static int phar_set_writeable_bit(void *pDest, void *argument TSRMLS_DC) /* {{{ */ +{ + zend_bool keep = *(zend_bool *)argument; + phar_archive_data *phar = *(phar_archive_data **)pDest; + + if (!phar->is_data) { + phar->is_writeable = !keep; + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/* if the original value is 0 (disabled), then allow setting/unsetting at will + otherwise, only allow 1 (enabled), and error on disabling */ +ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */ +{ + zend_bool old, ini; + + if (entry->name_length == 14) { + old = PHAR_G(readonly_orig); + } else { + old = PHAR_G(require_hash_orig); + } + + if (new_value_length == 2 && !strcasecmp("on", new_value)) { + ini = (zend_bool) 1; + } + else if (new_value_length == 3 && !strcasecmp("yes", new_value)) { + ini = (zend_bool) 1; + } + else if (new_value_length == 4 && !strcasecmp("true", new_value)) { + ini = (zend_bool) 1; + } + else { + ini = (zend_bool) atoi(new_value); + } + + /* do not allow unsetting in runtime */ + if (stage == ZEND_INI_STAGE_STARTUP) { + if (entry->name_length == 14) { + PHAR_G(readonly_orig) = ini; + } else { + PHAR_G(require_hash_orig) = ini; + } + } else if (old && !ini) { + return FAILURE; + } + + if (entry->name_length == 14) { + PHAR_G(readonly) = ini; + if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets) { + zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC); + } + } else { + PHAR_G(require_hash) = ini; + } + return SUCCESS; +} +/* }}}*/ + +PHP_INI_BEGIN() + STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals) + STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals) +PHP_INI_END() + +/** + * When all uses of a phar have been concluded, this frees the manifest + * and the phar slot + */ +static void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */ +{ + if (phar->alias && phar->alias != phar->fname) { + efree(phar->alias); + phar->alias = NULL; + } + if (phar->fname) { + efree(phar->fname); + phar->fname = NULL; + } + if (phar->signature) { + efree(phar->signature); + } + if (phar->manifest.arBuckets) { + zend_hash_destroy(&phar->manifest); + phar->manifest.arBuckets = NULL; + } + if (phar->mounted_dirs.arBuckets) { + zend_hash_destroy(&phar->mounted_dirs); + phar->mounted_dirs.arBuckets = NULL; + } + if (phar->metadata) { + zval_ptr_dtor(&phar->metadata); + phar->metadata = 0; + } + if (phar->fp) { + php_stream_close(phar->fp); + phar->fp = 0; + } + if (phar->ufp) { + php_stream_close(phar->ufp); + phar->fp = 0; + } + efree(phar); +} +/* }}}*/ + +/** + * Delete refcount and destruct if needed. On destruct return 1 else 0. + */ +int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */ +{ + if (--phar->refcount < 0) { + if (PHAR_GLOBALS->request_done + || zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) { + phar_destroy_phar_data(phar TSRMLS_CC); + } + return 1; + } else if (!phar->refcount) { + if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) { + /* close open file handle - allows removal or rename of + the file on windows, which has greedy locking + only close if the archive was not already compressed. If it + was compressed, then the fp does not refer to the original file */ + 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; +} +/* }}}*/ + +/** + * Destroy phar's in shutdown, here we don't care about aliases + */ +static void destroy_phar_data_only(void *pDest) /* {{{ */ +{ + phar_archive_data *phar_data = *(phar_archive_data **) pDest; + TSRMLS_FETCH(); + + if (EG(exception) || --phar_data->refcount < 0) { + phar_destroy_phar_data(phar_data TSRMLS_CC); + } +} +/* }}}*/ + +/** + * Delete aliases to phar's that got kicked out of the global table + */ +static int phar_unalias_apply(void *pDest, void *argument TSRMLS_DC) /* {{{ */ +{ + return *(void**)pDest == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/** + * Delete aliases to phar's that got kicked out of the global table + */ +static int phar_tmpclose_apply(void *pDest TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *) pDest; + + if (entry->fp_type != PHAR_TMP) { + return ZEND_HASH_APPLY_KEEP; + } + if (entry->fp && !entry->fp_refcount) { + php_stream_close(entry->fp); + entry->fp = NULL; + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/** + * Filename map destructor + */ +static void destroy_phar_data(void *pDest) /* {{{ */ +{ + phar_archive_data *phar_data = *(phar_archive_data **) pDest; + TSRMLS_FETCH(); + + if (PHAR_GLOBALS->request_ends) { + /* first, iterate over the manifest and close all PHAR_TMP entry fp handles, + this prevents unnecessary unfreed stream resources */ + zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC); + destroy_phar_data_only(pDest); + return; + } + zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC); + if (--phar_data->refcount < 0) { + phar_destroy_phar_data(phar_data TSRMLS_CC); + } +} +/* }}}*/ + +/** + * destructor for the manifest hash, frees each file's entry + */ +void destroy_phar_manifest_entry(void *pDest) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *)pDest; + TSRMLS_FETCH(); + + if (entry->cfp) { + php_stream_close(entry->cfp); + entry->cfp = 0; + } + if (entry->fp) { + php_stream_close(entry->fp); + entry->fp = 0; + } + if (entry->metadata) { + zval_ptr_dtor(&entry->metadata); + entry->metadata = 0; + } + if (entry->metadata_str.c) { + smart_str_free(&entry->metadata_str); + entry->metadata_str.c = 0; + } + efree(entry->filename); + if (entry->link) { + efree(entry->link); + entry->link = 0; + } + if (entry->tmp) { + efree(entry->tmp); + entry->tmp = 0; + } +} +/* }}} */ + +int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */ +{ + int ret = 0; + + if (idata->internal_file) { + if (--idata->internal_file->fp_refcount < 0) { + idata->internal_file->fp_refcount = 0; + } + if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) { + php_stream_close(idata->fp); + } + } + phar_archive_delref(idata->phar TSRMLS_CC); + efree(idata); + return ret; +} +/* }}} */ + +/** + * Removes an entry, either by actually removing it or by marking it. + */ +void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */ +{ + phar_archive_data *phar; + + phar = idata->phar; + if (idata->internal_file->fp_refcount < 2) { + if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) { + php_stream_close(idata->fp); + } + zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len); + idata->phar->refcount--; + efree(idata); + } else { + idata->internal_file->is_deleted = 1; + phar_entry_delref(idata TSRMLS_CC); + } + if (!phar->donotflush) { + phar_flush(phar, 0, 0, 0, error TSRMLS_CC); + } +} +/* }}} */ + +#define MAPPHAR_ALLOC_FAIL(msg) \ + if (fp) {\ + php_stream_close(fp);\ + }\ + if (error) {\ + spprintf(error, 0, msg, fname);\ + }\ + return FAILURE; + +#define MAPPHAR_FAIL(msg) \ + efree(savebuf);\ + if (mydata) {\ + phar_destroy_phar_data(mydata TSRMLS_CC);\ + }\ + if (signature) {\ + efree(signature);\ + }\ + MAPPHAR_ALLOC_FAIL(msg) + +#ifdef WORDS_BIGENDIAN +# define PHAR_GET_32(buffer, var) \ + var = ((((unsigned char*)(buffer))[3]) << 24) \ + | ((((unsigned char*)(buffer))[2]) << 16) \ + | ((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0]); \ + (buffer) += 4 +# define PHAR_GET_16(buffer, var) \ + var = ((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0]); \ + (buffer) += 2 +# define PHAR_ZIP_32(buffer) ((((unsigned char*)(buffer))[3]) << 24) \ + | ((((unsigned char*)(buffer))[2]) << 16) \ + | ((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0]) +# define PHAR_ZIP_16(buffer) ((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0]) +#else +# define PHAR_GET_32(buffer, var) \ + var = *(php_uint32*)(buffer); \ + buffer += 4 +# define PHAR_GET_16(buffer, var) \ + var = *(php_uint16*)(buffer); \ + buffer += 2 +# define PHAR_ZIP_32(buffer) buffer +# define PHAR_ZIP_16(buffer) buffer +#endif + +/** + * Open an already loaded phar + */ +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 + char *unixfname; +#endif + + if (error) { + *error = NULL; + } +#ifdef PHP_WIN32 + unixfname = estrndup(fname, fname_len); + phar_unixify_path_separators(unixfname, fname_len); + if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC) + && ((alias && fname_len == phar->fname_len + && !strncmp(unixfname, phar->fname, fname_len)) || !alias) + ) { + phar_entry_info *stub; + efree(unixfname); +#else + if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC) + && ((alias && fname_len == phar->fname_len + && !strncmp(fname, phar->fname, fname_len)) || !alias) + ) { + phar_entry_info *stub; +#endif + /* logic above is as follows: + If an explicit alias was requested, ensure the filename passed in + matches the phar's filename. + If no alias was passed in, then it can match either and be valid + */ + + if (!is_data) { + /* prevent any ".phar" without a stub getting through */ + if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) { + if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) { + if (error) { + spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname); + } + return FAILURE; + } + } + } + phar->is_data = is_data && (phar->is_tar || phar->is_zip); + if (pphar) { + *pphar = phar; + } + return SUCCESS; + } else { +#ifdef PHP_WIN32 + efree(unixfname); +#endif + if (pphar) { + *pphar = NULL; + } + if (phar && error && !(options & REPORT_ERRORS)) { + efree(error); + } + return FAILURE; + } +} +/* }}}*/ + +/** + * Parse out metadata from the manifest for a single file + * + * Meta-data is in this format: + * [len32][data...] + * + * data is the serialized zval + */ +int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */ +{ + const unsigned char *p; + php_uint32 buf_len; + php_unserialize_data_t var_hash; + + if (!zip_metadata_len) { + PHAR_GET_32(*buffer, buf_len); + } else { + buf_len = zip_metadata_len; + } + + if (buf_len) { + ALLOC_INIT_ZVAL(*metadata); + p = (const unsigned char*) *buffer; + PHP_VAR_UNSERIALIZE_INIT(var_hash); + if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) { + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + zval_ptr_dtor(metadata); + *metadata = NULL; + return FAILURE; + } + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + } else { + *metadata = NULL; + } + if (!zip_metadata_len) { + *buffer += buf_len; + } + return SUCCESS; +} +/* }}}*/ + +static const char hexChars[] = "0123456789ABCDEF"; + +static int phar_hex_str(const char *digest, size_t digest_len, char ** signature) +{ + int pos = -1; + size_t len; + + *signature = (char*)safe_emalloc(digest_len, 2, 1); + + for(len = 0; len < digest_len; ++len) { + (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4]; + (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F]; + } + (*signature)[++pos] = '\0'; + return pos; +} + +/** + * Does not check for a previously opened phar in the cache. + * + * Parse a new one and add it to the cache, returning either SUCCESS or + * FAILURE, and setting pphar to the pointer to the manifest entry + * + * This is used by phar_open_filename to process the manifest, but can be called + * directly. + */ +int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */ +{ + char b32[4], *buffer, *endbuffer, *savebuf; + phar_archive_data *mydata = NULL; + phar_entry_info entry; + php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags; + php_uint16 manifest_ver; + long offset; + int register_alias, sig_len, temp_alias = 0; + char *signature = NULL; + + if (pphar) { + *pphar = NULL; + } + if (error) { + *error = NULL; + } + + /* check for ?>\n and increment accordingly */ + if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) { + MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"") + } + + buffer = b32; + if (3 != php_stream_read(fp, buffer, 3)) { + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)") + } + if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') { + int nextchar; + halt_offset += 3; + if (EOF == (nextchar = php_stream_getc(fp))) { + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)") + } + if ((char) nextchar == '\r') { + /* if we have an \r we require an \n as well */ + if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') { + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)") + } + ++halt_offset; + } + if ((char) nextchar == '\n') { + ++halt_offset; + } + } + /* make sure we are at the right location to read the manifest */ + if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) { + MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"") + } + + /* read in manifest */ + buffer = b32; + if (4 != php_stream_read(fp, buffer, 4)) { + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)") + } + PHAR_GET_32(buffer, manifest_len); + if (manifest_len > 1048576 * 100) { + /* prevent serious memory issues by limiting manifest to at most 100 MB in length */ + MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"") + } + buffer = (char *)emalloc(manifest_len); + savebuf = buffer; + endbuffer = buffer + manifest_len; + if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) { + MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)") + } + + /* extract the number of entries */ + PHAR_GET_32(buffer, manifest_count); + if (manifest_count == 0) { + MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry"); + } + + /* extract API version, lowest nibble currently unused */ + manifest_ver = (((unsigned char)buffer[0]) << 8) + + ((unsigned char)buffer[1]); + buffer += 2; + if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F); + } + return FAILURE; + } + + PHAR_GET_32(buffer, manifest_flags); + + manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK; + + manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK; + /* remember whether this entire phar was compressed with gz/bzip2 */ + manifest_flags |= compression; + + /* The lowest nibble contains the phar wide flags. The compression flags can */ + /* be ignored on reading because it is being generated anyways. */ + if (manifest_flags & PHAR_HDR_SIGNATURE) { + unsigned char buf[1024]; + int read_size, len; + char sig_buf[8], *sig_ptr = sig_buf; + off_t read_len; + + if (-1 == php_stream_seek(fp, -8, SEEK_END) + || (read_len = php_stream_tell(fp)) < 20 + || 8 != php_stream_read(fp, sig_buf, 8) + || memcmp(sig_buf+4, "GBMB", 4)) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } + return FAILURE; + } + PHAR_GET_32(sig_ptr, sig_flags); + switch(sig_flags) { +#if HAVE_HASH_EXT + case PHAR_SIG_SHA512: { + unsigned char digest[64], saved[64]; + PHP_SHA512_CTX context; + + php_stream_rewind(fp); + PHP_SHA512Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_SHA512Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_SHA512Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } + return FAILURE; + } + + sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature); + break; + } + case PHAR_SIG_SHA256: { + unsigned char digest[32], saved[32]; + PHP_SHA256_CTX context; + + php_stream_rewind(fp); + PHP_SHA256Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_SHA256Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_SHA256Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } + return FAILURE; + } + + sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature); + break; + } +#else + case PHAR_SIG_SHA512: + case PHAR_SIG_SHA256: + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname); + } + return FAILURE; +#endif + case PHAR_SIG_SHA1: { + unsigned char digest[20], saved[20]; + PHP_SHA1_CTX context; + + php_stream_rewind(fp); + PHP_SHA1Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_SHA1Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_SHA1Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } + return FAILURE; + } + + sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature); + break; + } + case PHAR_SIG_MD5: { + unsigned char digest[16], saved[16]; + PHP_MD5_CTX context; + + php_stream_rewind(fp); + PHP_MD5Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_MD5Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_MD5Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } + return FAILURE; + } + + sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature); + break; + } + default: + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname); + } + return FAILURE; + } + } else if (PHAR_G(require_hash)) { + efree(savebuf); + php_stream_close(fp); + if (error) { + spprintf(error, 0, "phar \"%s\" does not have a signature", fname); + } + return FAILURE; + } else { + sig_flags = 0; + sig_len = 0; + } + + /* extract alias */ + PHAR_GET_32(buffer, tmp_len); + if (buffer + tmp_len > endbuffer) { + MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)"); + } + if (manifest_len < 10 + tmp_len) { + MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)") + } + /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */ + if (tmp_len) { + /* if the alias is stored we enforce it (implicit overrides explicit) */ + if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len))) + { + buffer[tmp_len] = '\0'; + 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; + alias = buffer; + buffer += tmp_len; + register_alias = 1; + } else if (!alias_len || !alias) { + /* if we neither have an explicit nor an implicit alias, we use the filename */ + alias = NULL; + alias_len = 0; + register_alias = 0; + } else if (alias_len) { + register_alias = 1; + temp_alias = 1; + } + + /* we have 5 32-bit items plus 1 byte at least */ + if (manifest_count > ((manifest_len - 10 - tmp_len) / (5 * 4 + 1))) { + /* prevent serious memory issues */ + MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)") + } + + mydata = ecalloc(sizeof(phar_archive_data), 1); + + /* check whether we have meta data, zero check works regardless of byte order */ + if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) { + MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\""); + } + + /* set up our manifest */ + zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_hash_init(&mydata->mounted_dirs, sizeof(char *), + zend_get_hash_value, NULL, 0); + offset = halt_offset + manifest_len + 4; + memset(&entry, 0, sizeof(phar_entry_info)); + entry.phar = mydata; + entry.fp_type = PHAR_FP; + + for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) { + if (buffer + 4 > endbuffer) { + MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)") + } + PHAR_GET_32(buffer, entry.filename_len); + if (entry.filename_len == 0) { + MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\""); + } + if (buffer + entry.filename_len + 20 > endbuffer) { + MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)"); + } + if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') { + entry.is_dir = 1; + } else { + entry.is_dir = 0; + } + entry.filename = estrndup(buffer, entry.filename_len); + buffer += entry.filename_len; + PHAR_GET_32(buffer, entry.uncompressed_filesize); + PHAR_GET_32(buffer, entry.timestamp); + if (offset == halt_offset + (int)manifest_len + 4) { + mydata->min_timestamp = entry.timestamp; + mydata->max_timestamp = entry.timestamp; + } else { + if (mydata->min_timestamp > entry.timestamp) { + mydata->min_timestamp = entry.timestamp; + } else if (mydata->max_timestamp < entry.timestamp) { + mydata->max_timestamp = entry.timestamp; + } + } + PHAR_GET_32(buffer, entry.compressed_filesize); + PHAR_GET_32(buffer, entry.crc32); + PHAR_GET_32(buffer, entry.flags); + if (entry.is_dir) { + entry.filename_len--; + entry.flags |= PHAR_ENT_PERM_DEF_DIR; + } + if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) { + efree(entry.filename); + MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\""); + } + entry.offset = entry.offset_abs = offset; + offset += entry.compressed_filesize; + switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) { + case PHAR_ENT_COMPRESSED_GZ: + if (!phar_has_zlib) { + if (entry.metadata) { + zval_ptr_dtor(&entry.metadata); + } + efree(entry.filename); + MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\""); + } + break; + case PHAR_ENT_COMPRESSED_BZ2: + if (!phar_has_bz2) { + if (entry.metadata) { + zval_ptr_dtor(&entry.metadata); + } + efree(entry.filename); + MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\""); + } + break; + default: + if (entry.uncompressed_filesize != entry.compressed_filesize) { + if (entry.metadata) { + zval_ptr_dtor(&entry.metadata); + } + efree(entry.filename); + MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)"); + } + break; + } + manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK); + /* if signature matched, no need to check CRC32 for each file */ + entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0); + zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL); + } + + snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF); + mydata->internal_file_start = halt_offset + manifest_len + 4; + mydata->halt_offset = halt_offset; + mydata->flags = manifest_flags; + mydata->fp = fp; + mydata->fname = estrndup(fname, fname_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(mydata->fname, fname_len); +#endif + mydata->fname_len = fname_len; + endbuffer = strrchr(mydata->fname, '/'); + if (endbuffer) { + mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer); + if (mydata->ext == endbuffer) { + mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext; + } + } + mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len); + mydata->alias_len = alias ? alias_len : fname_len; + mydata->sig_flags = sig_flags; + mydata->sig_len = sig_len; + mydata->signature = signature; + phar_request_initialize(TSRMLS_C); + 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 TSRMLS_CC)) { + 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) { + *pphar = mydata; + } + + return SUCCESS; +} +/* }}} */ + +/** + * Create or open a phar for writing + */ +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; + + test = &unused; + if (error) { + *error = NULL; + } + + /* 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); + } + return FAILURE; + } + +check_file: + if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) { + if (pphar) { + *pphar = *test; + } + if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) { + if (error) { + spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname); + } + return FAILURE; + } + if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) { + phar_entry_info *stub; + if (FAILURE == zend_hash_find(&((*test)->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 (!PHAR_G(readonly) || (*test)->is_data) { + (*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)) { + // 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 > 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); + } + + return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC); + +} + +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; + php_stream *fp; + char *actual = NULL, *p; + + if (!pphar) { + pphar = &mydata; + } +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + return FAILURE; + } +#endif + + if (php_check_open_basedir(fname TSRMLS_CC)) { + return FAILURE; + } + + /* first open readonly so it won't be created if not present */ + fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual); + if (actual) { + fname = actual; + fname_len = strlen(actual); + } + + if (fp) { + if (phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) { + if ((*pphar)->is_data || !PHAR_G(readonly)) { + (*pphar)->is_writeable = 1; + } + if (actual) { + efree(actual); + } + return SUCCESS; + } else { + /* file exists, but is either corrupt or not a phar archive */ + if (actual) { + efree(actual); + } + return FAILURE; + } + } + if (actual) { + efree(actual); + } + + if (PHAR_G(readonly) && !is_data) { + if (options & REPORT_ERRORS) { + if (error) { + spprintf(error, 0, "creating archive \"%s\" disabled by INI setting", fname); + } + } + return FAILURE; + } + + /* set up our manifest */ + mydata = ecalloc(sizeof(phar_archive_data), 1); + + mydata->fname = expand_filepath(fname, NULL TSRMLS_CC); + fname_len = strlen(mydata->fname); +#ifdef PHP_WIN32 + phar_unixify_path_separators(mydata->fname, fname_len); +#endif + p = strrchr(mydata->fname, '/'); + if (p) { + mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p); + if (mydata->ext == p) { + mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + fname_len) - mydata->ext; + } + } + + if (pphar) { + *pphar = mydata; + } + zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_hash_init(&mydata->mounted_dirs, sizeof(char *), + zend_get_hash_value, NULL, 0); + mydata->fname_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; + 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; + } else { + 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; + } + 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; + } + } + return SUCCESS; +} +/* }}}*/ + +/** + * Return an already opened filename. + * + * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify + * that the manifest is proper, then pass it to phar_open_file(). SUCCESS + * or FAILURE is returned and pphar is set to a pointer to the phar's manifest + */ +int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ +{ + php_stream *fp; + char *actual; + int ret, is_data = 0; + + if (error) { + *error = NULL; + } + + if (!strstr(fname, ".phar")) { + is_data = 1; + } + + if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } else if (error && *error) { + return FAILURE; + } + +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + return FAILURE; + } +#endif + + if (php_check_open_basedir(fname TSRMLS_CC)) { + return FAILURE; + } + + fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual); + if (!fp) { + if (options & REPORT_ERRORS) { + if (error) { + spprintf(error, 0, "unable to open phar for reading \"%s\"", fname); + } + } + if (actual) { + efree(actual); + } + return FAILURE; + } + + if (actual) { + fname = actual; + fname_len = strlen(actual); + } + + ret = phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); + if (actual) { + efree(actual); + } + return ret; +} +/* }}}*/ + +static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) +{ + const char *c; + int so_far = 0; + + /* this assumes buf_len > search_len */ + c = buf - 1; + do { + if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) { + return (char *) NULL; + } + so_far = c - buf; + if (so_far >= (buf_len - search_len)) { + return (char *) NULL; + } + if (!memcmp(c, search, search_len)) { + return (char *) c; + } + } while (1); +} + +/** + * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify + * that the manifest is proper, then pass it to phar_open_file(). SUCCESS + * or FAILURE is returned and pphar is set to a pointer to the phar's manifest + */ +static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ +{ + const char token[] = "__HALT_COMPILER();"; + const char zip_magic[] = "PK\x03\x04"; + const char gz_magic[] = "\x1f\x8b\x08"; + const char bz_magic[] = "BZh"; + char *pos, buffer[1024 + sizeof(token)], test = '\0'; + const long readsize = sizeof(buffer) - sizeof(token); + const long tokenlen = sizeof(token) - 1; + long halt_offset; + size_t got; + php_uint32 compression = PHAR_FILE_COMPRESSED_NONE; + + if (error) { + *error = NULL; + } + if (-1 == php_stream_rewind(fp)) { + MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"") + } + + buffer[sizeof(buffer)-1] = '\0'; + memset(buffer, 32, sizeof(token)); + halt_offset = 0; + + /* Maybe it's better to compile the file instead of just searching, */ + /* but we only want the offset. So we want a .re scanner to find it. */ + while(!php_stream_eof(fp)) { + if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) { + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") + } + if (!test) { + test = '\1'; + pos = buffer+tokenlen; + if (!memcmp(pos, gz_magic, 3)) { + char err = 0; + php_stream_filter *filter; + php_stream *temp; + /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */ + zval filterparams; + + if (!phar_has_zlib) { + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini") + } + array_init(&filterparams); + +/* this is defined in zlib's zconf.h */ +#ifndef MAX_WBITS +#define MAX_WBITS 15 +#endif + add_assoc_long(&filterparams, "window", MAX_WBITS + 32); + /* entire file is gzip-compressed, uncompress to temporary file */ + if (!(temp = php_stream_fopen_tmpfile())) { + MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"") + } + php_stream_rewind(fp); + filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + err = 1; + add_assoc_long(&filterparams, "window", MAX_WBITS); + filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC); + zval_dtor(&filterparams); + if (!filter) { + php_stream_close(temp); + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6") + } + } else { + zval_dtor(&filterparams); + } + php_stream_filter_append(&temp->writefilters, filter); + if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) { + if (err) { + php_stream_close(temp); + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6") + } + php_stream_close(temp); + MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file") + } + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(fp); + fp = temp; + php_stream_rewind(fp); + compression = PHAR_FILE_COMPRESSED_GZ; + + /* now, start over */ + test = '\0'; + continue; + } else if (!memcmp(pos, bz_magic, 3)) { + php_stream_filter *filter; + php_stream *temp; + + if (!phar_has_bz2) { + MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini") + } + /* entire file is bzip-compressed, uncompress to temporary file */ + if (!(temp = php_stream_fopen_tmpfile())) { + MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"") + } + php_stream_rewind(fp); + filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + php_stream_close(temp); + MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed") + } + php_stream_filter_append(&temp->writefilters, filter); + if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) { + php_stream_close(temp); + MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file") + } + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(fp); + fp = temp; + php_stream_rewind(fp); + compression = PHAR_FILE_COMPRESSED_BZ2; + + /* now, start over */ + test = '\0'; + continue; + } + if (!memcmp(pos, zip_magic, 4)) { + php_stream_seek(fp, 0, SEEK_END); + return phar_open_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC); + } + if (got > 512) { + if (phar_is_tar(pos, fname)) { + php_stream_rewind(fp); + return phar_open_tarfile(fp, fname, fname_len, alias, alias_len, options, pphar, compression, error TSRMLS_CC); + } + } + } + if ((pos = phar_strnstr(buffer, 1024 + sizeof(token), token, sizeof(token)-1)) != NULL) { + halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */ + return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC); + } + + halt_offset += got; + memmove(buffer, buffer + tokenlen, got + 1); + } + + MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)") +} +/* }}} */ + +/* + * 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) +{ + php_stream_statbuf ssb; + char *realpath, old, *a = (char *)(ext + ext_len); + + old = *a; + *a = '\0'; + if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) { +#ifdef PHP_WIN32 + phar_unixify_path_separators(realpath, strlen(realpath)); +#endif + 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; + } +#ifdef PHP_WIN32 + phar_unixify_path_separators(realpath, strlen(realpath)); +#endif + 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; + + 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) */ + pos = strstr(test, ".phar"); + if (pos && (*(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 (!executable) { + pos = strstr(ext_str, ".phar"); + if (!(pos && (*(pos - 1) != '/') + && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') { + return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC); + } + } else { + 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; + + if (!filename_len || filename_len == 1) { + return FAILURE; + } + phar_request_initialize(TSRMLS_C); + /* first check for alias in first segment */ + pos = strchr(filename, '/'); + if (pos && pos != filename) { + if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) { + *ext_str = pos; + *ext_len = -1; + return FAILURE; + } + } + + if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + phar_archive_data **pphar; + + if (is_complete) { + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) { + *ext_str = filename + (filename_len - (*pphar)->ext_len); +woohoo: + *ext_len = (*pphar)->ext_len; + if (executable == 2) { + return SUCCESS; + } + if (executable == 1 && !(*pphar)->is_data) { + return SUCCESS; + } + if (!executable && (*pphar)->is_data) { + return SUCCESS; + } + return FAILURE; + } + } else { + char *key; + uint keylen; + ulong unused; + + zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map)); + while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) { + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) { + break; + } + + if (keylen > (uint) filename_len) { + zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map)); + continue; + } + if (!memcmp(filename, key, keylen) && (filename_len == keylen + || filename[keylen] == '/' || filename[keylen] == '\0')) { + if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) { + break; + } + *ext_str = filename + (keylen - (*pphar)->ext_len); + goto woohoo; + } + zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map)); + } + } + } + + pos = strchr(filename + 1, '.'); +next_extension: + if (!pos) { + return FAILURE; + } + while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) { + pos = strchr(pos + 1, '.'); + if (!pos) { + 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; + } + } + /* 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 FAILURE; +} +/* }}} */ + +static int php_check_dots(const char *element, int n) +{ + for(n--; n >= 0; --n) { + if (element[n] != '.') { + return 1; + } + } + return 0; +} + +#define IS_DIRECTORY_UP(element, len) \ + (len >= 2 && !php_check_dots(element, len)) + +#define IS_DIRECTORY_CURRENT(element, len) \ + (len == 1 && element[0] == '.') + +#define IS_BACKSLASH(c) ((c) == '/') + +#ifdef COMPILE_DL_PHAR +/* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */ +static inline int in_character_class(char ch, const char *delim) +{ + while (*delim) { + if (*delim == ch) { + return 1; + } + ++delim; + } + return 0; +} + +char *tsrm_strtok_r(char *s, const char *delim, char **last) +{ + char *token; + + if (s == NULL) { + s = *last; + } + + while (*s && in_character_class(*s, delim)) { + ++s; + } + if (!*s) { + return NULL; + } + + token = s; + + while (*s && !in_character_class(*s, delim)) { + ++s; + } + if (!*s) { + *last = s; + } else { + *s = '\0'; + *last = s + 1; + } + return token; +} +#endif + +/** + * Remove .. and . references within a phar filename + */ +char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */ +{ + char *ptr, *free_path, *new_phar; + char *tok; + int ptr_length, new_phar_len = 1, path_length = *new_len; + + if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') { + free_path = path; + new_phar_len = PHAR_G(cwd_len); + new_phar = estrndup(PHAR_G(cwd), new_phar_len); + } else { + free_path = path; + new_phar = estrndup("/\0", 2); + } + tok = NULL; + ptr = tsrm_strtok_r(path, "/", &tok); + while (ptr) { + ptr_length = strlen(ptr); + + if (IS_DIRECTORY_UP(ptr, ptr_length)) { + char save; + + save = '/'; + +#define PREVIOUS new_phar[new_phar_len - 1] + + while (new_phar_len > 1 && + !IS_BACKSLASH(PREVIOUS)) { + save = PREVIOUS; + PREVIOUS = '\0'; + new_phar_len--; + } + + if (new_phar[0] != '/') { + new_phar[new_phar_len++] = save; + new_phar[new_phar_len] = '\0'; + } else if (new_phar_len > 1) { + PREVIOUS = '\0'; + new_phar_len--; + } + } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) { + if (new_phar_len > 1) { + new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1+1); + new_phar[new_phar_len++] = '/'; + memcpy(&new_phar[new_phar_len], ptr, ptr_length+1); + } else { + new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1); + memcpy(&new_phar[new_phar_len], ptr, ptr_length+1); + } + + new_phar_len += ptr_length; + } + ptr = tsrm_strtok_r(NULL, "/", &tok); + } + + 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; + } + + efree(free_path); + + if (new_phar_len == 0) { + new_phar = (char *) erealloc(new_phar, new_phar_len+1+1); + new_phar[new_phar_len] = '/'; + new_phar[++new_phar_len] = '\0'; + } + *new_len = new_phar_len; + return new_phar; +} +/* }}} */ + +/** + * Process a phar stream name, ensuring we can handle any of: + * + * - whatever.phar + * - whatever.phar.gz + * - whatever.phar.bz2 + * - whatever.phar.php + * + * Optionally the name might start with 'phar://' + * + * 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, int executable, int for_create TSRMLS_DC) /* {{{ */ +{ + const char *ext_str; +#ifdef PHP_WIN32 + char *save; +#endif + int ext_len, free_filename = 0; + + if (!strncasecmp(filename, "phar://", 7)) { + filename += 7; + filename_len -= 7; + } + + ext_len = 0; +#ifdef PHP_WIN32 + free_filename = 1; + save = filename; + filename = estrndup(filename, filename_len); + phar_unixify_path_separators(filename, filename_len); +#endif + if (phar_detect_phar_fname_ext(filename, 0, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) { + if (ext_len != -1) { + if (!ext_str) { + /* no / detected, restore arch for error message */ +#ifdef PHP_WIN32 + *arch = save; +#else + *arch = filename; +#endif + } + if (free_filename) { + efree(filename); + } + return FAILURE; + } + ext_len = 0; + /* no extension detected - instead we are dealing with an alias */ + } + + *arch_len = ext_str - filename + ext_len; + *arch = estrndup(filename, *arch_len); + if (ext_str[ext_len]) { + *entry_len = filename_len - *arch_len; + *entry = estrndup(ext_str+ext_len, *entry_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(*entry, *entry_len); +#endif + *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC); + } else { + *entry_len = 1; + *entry = estrndup("/", 1); + } + if (free_filename) { + efree(filename); + } + return SUCCESS; +} +/* }}} */ + +/** + * Invoked when a user calls Phar::mapPhar() from within an executing .phar + * to set up its manifest directly + */ +int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */ +{ + char *fname; + long halt_offset; + zval *halt_constant; + php_stream *fp; + int fname_len; + + if (error) { + *error = NULL; + } + fname = zend_get_executed_filename(TSRMLS_C); + fname_len = strlen(fname); + + if (phar_open_loaded(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + + if (!strcmp(fname, "[no active file]")) { + if (error) { + spprintf(error, 0, "cannot initialize a phar outside of PHP execution"); + } + return FAILURE; + } + + MAKE_STD_ZVAL(halt_constant); + if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) { + FREE_ZVAL(halt_constant); + if (error) { + spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar"); + } + return FAILURE; + } + halt_offset = Z_LVAL(*halt_constant); + FREE_ZVAL(halt_constant); + + fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); + + if (!fp) { + if (error) { + spprintf(error, 0, "unable to open phar for reading \"%s\"", fname); + } + return FAILURE; + } + + return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL, PHAR_FILE_COMPRESSED_NONE, error TSRMLS_CC); +} +/* }}} */ + +/** + * Validate the CRC32 of a file opened from within the phar + */ +int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC) /* {{{ */ +{ + php_uint32 crc = ~0; + int len = idata->internal_file->uncompressed_filesize; + php_stream *fp = idata->fp; + phar_entry_info *entry = idata->internal_file; + + if (error) { + *error = NULL; + } + if (entry->is_zip) { + /* verify local file header */ + phar_zip_file_header local; + + if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) { + spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename); + return FAILURE; + } + php_stream_seek(idata->phar->fp, entry->header_offset, SEEK_SET); + + if (sizeof(local) != php_stream_read(idata->phar->fp, (char *) &local, sizeof(local))) { + + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename); + return FAILURE; + } + /* fix up for big-endian systems */ + /* verify local header if not yet verified */ + if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) { + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local head of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename); + return FAILURE; + } + if (-1 == php_stream_seek(idata->phar->fp, PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len), SEEK_CUR)) { + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot seek to start of file data for file \"%s\")", idata->phar->fname, entry->filename); + return FAILURE; + } + } + php_stream_seek(fp, idata->zero, SEEK_SET); + while (len--) { + CRC32(crc, php_stream_getc(fp)); + } + php_stream_seek(fp, idata->zero, SEEK_SET); + if (~crc == crc32) { + entry->is_crc_checked = 1; + return SUCCESS; + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename); + return FAILURE; + } +} +/* }}} */ + +static inline void phar_set_32(char *buffer, int var) /* {{{ */ +{ +#ifdef WORDS_BIGENDIAN + *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF); + *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF); + *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF); + *((buffer) + 0) = (unsigned char) ((var) & 0xFF); +#else + *(php_uint32 *)(buffer) = (php_uint32)(var); +#endif +} /* }}} */ + +static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *)data; + + if (entry->fp_refcount <= 0 && entry->is_deleted) { + return ZEND_HASH_APPLY_REMOVE; + } else { + return ZEND_HASH_APPLY_KEEP; + } +} +/* }}} */ + +#include "stub.h" + +char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) +{ + char *stub = NULL; + int index_len, web_len; + size_t dummy; + + if (!len) { + len = &dummy; + } + + if (error) { + *error = NULL; + } + + if (!index_php) { + index_php = "index.php"; + } + + if (!web_index) { + web_index = "index.php"; + } + + index_len = strlen(index_php); + web_len = strlen(web_index); + + if (index_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len); + return NULL; + } + } + + if (web_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len); + return NULL; + } + } + + phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC); + return stub; +} + +/** + * Save phar contents to disk + * + * user_stub contains either a string, or a resource pointer, if len is a negative length. + * user_stub and len should be both 0 if the default or existing stub should be used + */ +int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC) /* {{{ */ +{ +/* static const char newstub[] = "\r\n"; */ + char *newstub; + phar_entry_info *entry, *newentry; + int halt_offset, restore_alias_len, global_flags = 0, closeoldfile; + char *pos, has_dirs = 0; + char manifest[18], entry_buffer[24]; + off_t manifest_ftell; + long offset; + size_t wrote; + php_uint32 manifest_len, mytime, loc, new_manifest_count; + php_uint32 newcrc32; + php_stream *file, *oldfile, *newfile, *stubfile; + php_stream_filter *filter; + php_serialize_data_t metadata_hash; + smart_str main_metadata_str = {0}; + int free_user_stub, free_fp = 1, free_ufp = 1; + + if (error) { + *error = NULL; + } + + if (PHAR_G(readonly) && !phar->is_data) { + return EOF; + } + + if (!zend_hash_num_elements(&phar->manifest) && !user_stub) { + return EOF; + } + + if (phar->is_zip) { + return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC); + } + if (phar->is_tar) { + return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC); + } + + if (phar->fp && !phar->is_brandnew) { + oldfile = phar->fp; + closeoldfile = 0; + php_stream_rewind(oldfile); + } else { + oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL); + closeoldfile = oldfile != NULL; + } + newfile = php_stream_fopen_tmpfile(); + if (!newfile) { + if (error) { + spprintf(error, 0, "unable to create temporary file"); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + return EOF; + } + + if (user_stub) { + if (len < 0) { + /* resource passed in */ + if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname); + } + return EOF; + } + if (len == -1) { + len = PHP_STREAM_COPY_ALL; + } else { + len = -len; + } + user_stub = 0; + if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname); + } + return EOF; + } + free_user_stub = 1; + } else { + free_user_stub = 0; + } + if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) + { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + return EOF; + } + len = pos - user_stub + 18; + if ((size_t)len != php_stream_write(newfile, user_stub, len) + || 5 != php_stream_write(newfile, " ?>\r\n", 5)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + return EOF; + } + phar->halt_offset = len + 5; + if (free_user_stub) { + efree(user_stub); + } + } else { + size_t written; + + if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) { + written = php_stream_copy_to_stream(oldfile, newfile, phar->halt_offset); + newstub = NULL; + } else { + /* this is either a brand new phar or a default stub overwrite */ + newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC); + written = php_stream_write(newfile, newstub, phar->halt_offset); + } + if (phar->halt_offset != written) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + if (newstub) { + spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname); + } else { + spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname); + } + } + if (newstub) { + efree(newstub); + } + return EOF; + } + if (newstub) { + efree(newstub); + } + } + manifest_ftell = php_stream_tell(newfile); + halt_offset = manifest_ftell; + + /* Check whether we can get rid of some of the deleted entries which are + * unused. However some might still be in use so even after this clean-up + * we need to skip entries marked is_deleted. */ + zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC); + + /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */ + main_metadata_str.c = 0; + if (phar->metadata) { + PHP_VAR_SERIALIZE_INIT(metadata_hash); + php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(metadata_hash); + } else { + main_metadata_str.len = 0; + } + new_manifest_count = 0; + offset = 0; + for (zend_hash_internal_pointer_reset(&phar->manifest); + zend_hash_has_more_elements(&phar->manifest) == SUCCESS; + zend_hash_move_forward(&phar->manifest)) { + if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) { + continue; + } + if (entry->cfp) { + /* did we forget to get rid of cfp last time? */ + php_stream_close(entry->cfp); + entry->cfp = 0; + } + if (entry->is_deleted || entry->is_mounted) { + /* remove this from the new phar */ + continue; + } + if (!entry->is_modified && entry->fp_refcount) { + /* open file pointers refer to this fp, do not free the stream */ + switch (entry->fp_type) { + case PHAR_FP: + free_fp = 0; + break; + case PHAR_UFP: + free_ufp = 0; + default: + break; + } + } + /* after excluding deleted files, calculate manifest size in bytes and number of entries */ + ++new_manifest_count; + + if (entry->is_dir) { + /* we use this to calculate API version, 1.1.1 is used for phars with directories */ + has_dirs = 1; + } + if (entry->metadata) { + if (entry->metadata_str.c) { + smart_str_free(&entry->metadata_str); + } + entry->metadata_str.c = 0; + entry->metadata_str.len = 0; + PHP_VAR_SERIALIZE_INIT(metadata_hash); + php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(metadata_hash); + } else { + if (entry->metadata_str.c) { + smart_str_free(&entry->metadata_str); + } + entry->metadata_str.c = 0; + entry->metadata_str.len = 0; + } + + /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */ + offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0); + + /* compress and rehash as necessary */ + if ((oldfile && !entry->is_modified) || entry->is_dir) { + if (entry->fp_type == PHAR_UFP) { + /* reset so we can copy the compressed data over */ + entry->fp_type = PHAR_FP; + } + continue; + } + if (!phar_get_efp(entry, 0 TSRMLS_CC)) { + /* re-open internal file pointer just-in-time */ + newentry = phar_open_jit(phar, entry, oldfile, error, 0 TSRMLS_CC); + if (!newentry) { + /* major problem re-opening, so we ignore this file and the error */ + efree(*error); + *error = NULL; + continue; + } + entry = newentry; + } + file = phar_get_efp(entry, 0 TSRMLS_CC); + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + newcrc32 = ~0; + mytime = entry->uncompressed_filesize; + for (loc = 0;loc < mytime; ++loc) { + CRC32(newcrc32, php_stream_getc(file)); + } + entry->crc32 = ~newcrc32; + entry->is_crc_checked = 1; + if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { + /* not compressed */ + entry->compressed_filesize = entry->uncompressed_filesize; + continue; + } + filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC); + if (!filter) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { + if (error) { + spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname); + } + } else { + if (error) { + spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname); + } + } + return EOF; + } + + /* create new file that holds the compressed version */ + /* work around inability to specify freedom in write and strictness + in read count */ + entry->cfp = php_stream_fopen_tmpfile(); + if (!entry->cfp) { + if (error) { + spprintf(error, 0, "unable to create temporary file"); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + return EOF; + } + php_stream_flush(file); + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + php_stream_filter_append((&entry->cfp->writefilters), filter); + if (entry->uncompressed_filesize != php_stream_copy_to_stream(file, entry->cfp, entry->uncompressed_filesize)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + php_stream_filter_flush(filter, 1); + php_stream_flush(entry->cfp); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_seek(entry->cfp, 0, SEEK_END); + entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp); + /* generate crc on compressed file */ + php_stream_rewind(entry->cfp); + entry->old_flags = entry->flags; + entry->is_modified = 1; + global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK); + } + global_flags |= PHAR_HDR_SIGNATURE; + + /* write out manifest pre-header */ + /* 4: manifest length + * 4: manifest entry count + * 2: phar version + * 4: phar global flags + * 4: alias length + * ?: the alias itself + * 4: phar metadata length + * ?: phar metadata + */ + restore_alias_len = phar->alias_len; + if (phar->is_temporary_alias) { + phar->alias_len = 0; + } + + manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len; + phar_set_32(manifest, manifest_len); + phar_set_32(manifest+4, new_manifest_count); + if (has_dirs) { + *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF); + *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0)); + } else { + *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF); + *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0)); + } + phar_set_32(manifest+10, global_flags); + phar_set_32(manifest+14, phar->alias_len); + + /* write the manifest header */ + if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest)) + || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + phar->alias_len = restore_alias_len; + if (error) { + spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname); + } + return EOF; + } + + phar->alias_len = restore_alias_len; + + phar_set_32(manifest, main_metadata_str.len); + if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len + && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) { + smart_str_free(&main_metadata_str); + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + phar->alias_len = restore_alias_len; + if (error) { + spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname); + } + return EOF; + } + smart_str_free(&main_metadata_str); + + /* re-calculate the manifest location to simplify later code */ + manifest_ftell = php_stream_tell(newfile); + + /* now write the manifest */ + for (zend_hash_internal_pointer_reset(&phar->manifest); + zend_hash_has_more_elements(&phar->manifest) == SUCCESS; + zend_hash_move_forward(&phar->manifest)) { + if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) { + continue; + } + if (entry->is_deleted || entry->is_mounted) { + /* remove this from the new phar if deleted, ignore if mounted */ + continue; + } + if (entry->is_dir) { + /* add 1 for trailing slash */ + phar_set_32(entry_buffer, entry->filename_len + 1); + } else { + phar_set_32(entry_buffer, entry->filename_len); + } + if (4 != php_stream_write(newfile, entry_buffer, 4) + || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len) + || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + if (entry->is_dir) { + spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname); + } else { + spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname); + } + } + return EOF; + } + /* set the manifest meta-data: + 4: uncompressed filesize + 4: creation timestamp + 4: compressed filesize + 4: crc32 + 4: flags + 4: metadata-len + +: metadata + */ + mytime = time(NULL); + phar_set_32(entry_buffer, entry->uncompressed_filesize); + phar_set_32(entry_buffer+4, mytime); + phar_set_32(entry_buffer+8, entry->compressed_filesize); + phar_set_32(entry_buffer+12, entry->crc32); + phar_set_32(entry_buffer+16, entry->flags); + phar_set_32(entry_buffer+20, entry->metadata_str.len); + if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer)) + || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + } + + /* now copy the actual file data to the new phar */ + offset = php_stream_tell(newfile); + for (zend_hash_internal_pointer_reset(&phar->manifest); + zend_hash_has_more_elements(&phar->manifest) == SUCCESS; + zend_hash_move_forward(&phar->manifest)) { + if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) { + continue; + } + if (entry->is_deleted || entry->is_dir || entry->is_mounted) { + continue; + } + if (entry->cfp) { + file = entry->cfp; + php_stream_rewind(file); + } else { + file = phar_get_efp(entry, 0 TSRMLS_CC); + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + } + if (!file) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + /* this will have changed for all files that have either + changed compression or been modified */ + entry->offset = entry->offset_abs = offset; + offset += entry->compressed_filesize; + wrote = php_stream_copy_to_stream(file, newfile, entry->compressed_filesize); + if (entry->compressed_filesize != wrote) { + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname); + } + return EOF; + } + entry->is_modified = 0; + if (entry->cfp) { + php_stream_close(entry->cfp); + entry->cfp = NULL; + } + if (entry->fp_type == PHAR_MOD) { + /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed + when the phar_entry_data is phar_entry_delref'ed */ + if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) { + php_stream_close(entry->fp); + } + entry->fp = NULL; + entry->fp_type = PHAR_FP; + } else if (entry->fp_type == PHAR_UFP) { + entry->fp_type = PHAR_FP; + } + } + + /* append signature */ + if (global_flags & PHAR_HDR_SIGNATURE) { + unsigned char buf[1024]; + int sig_flags = 0, sig_len; + char sig_buf[4]; + + php_stream_rewind(newfile); + + if (phar->signature) { + efree(phar->signature); + } + + switch(phar->sig_flags) { +#if HAVE_HASH_EXT + case PHAR_SIG_SHA512: { + unsigned char digest[64]; + PHP_SHA512_CTX context; + + PHP_SHA512Init(&context); + while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_SHA512Update(&context, buf, sig_len); + } + PHP_SHA512Final(digest, &context); + php_stream_write(newfile, (char *) digest, sizeof(digest)); + sig_flags |= PHAR_SIG_SHA512; + phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature); + break; + } + case PHAR_SIG_SHA256: { + unsigned char digest[32]; + PHP_SHA256_CTX context; + + PHP_SHA256Init(&context); + while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_SHA256Update(&context, buf, sig_len); + } + PHP_SHA256Final(digest, &context); + php_stream_write(newfile, (char *) digest, sizeof(digest)); + sig_flags |= PHAR_SIG_SHA256; + phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature); + break; + } +#else + case PHAR_SIG_SHA512: + case PHAR_SIG_SHA256: + if (closeoldfile) { + php_stream_close(oldfile); + } + php_stream_close(newfile); + if (error) { + spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname); + } + return EOF; +#endif + case PHAR_SIG_PGP: + /* TODO: currently fall back to sha1,later do both */ + default: + case PHAR_SIG_SHA1: { + unsigned char digest[20]; + PHP_SHA1_CTX context; + + PHP_SHA1Init(&context); + while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_SHA1Update(&context, buf, sig_len); + } + PHP_SHA1Final(digest, &context); + php_stream_write(newfile, (char *) digest, sizeof(digest)); + sig_flags |= PHAR_SIG_SHA1; + phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature); + break; + } + case PHAR_SIG_MD5: { + unsigned char digest[16]; + PHP_MD5_CTX context; + + PHP_MD5Init(&context); + while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_MD5Update(&context, buf, sig_len); + } + PHP_MD5Final(digest, &context); + php_stream_write(newfile, (char *) digest, sizeof(digest)); + sig_flags |= PHAR_SIG_MD5; + phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature); + break; + } + } + phar_set_32(sig_buf, sig_flags); + php_stream_write(newfile, sig_buf, 4); + php_stream_write(newfile, "GBMB", 4); + phar->sig_flags = sig_flags; + } + + /* finally, close the temp file, rename the original phar, + move the temp to the old phar, unlink the old phar, and reload it into memory + */ + if (phar->fp && free_fp) { + php_stream_close(phar->fp); + } + if (phar->ufp) { + if (free_ufp) { + php_stream_close(phar->ufp); + } + phar->ufp = NULL; + } + if (closeoldfile) { + php_stream_close(oldfile); + } + + phar->internal_file_start = halt_offset + manifest_len + 4; + phar->halt_offset = halt_offset; + phar->is_brandnew = 0; + + php_stream_rewind(newfile); + + if (phar->donotflush) { + /* deferred flush */ + phar->fp = newfile; + } else { + phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); + if (!phar->fp) { + phar->fp = newfile; + if (error) { + spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); + } + return EOF; + } + if (phar->flags & PHAR_FILE_COMPRESSED_GZ) { + php_stream_filter *filter; + /* to properly compress, we have to tell zlib to add a zlib header */ + zval filterparams; + + array_init(&filterparams); + add_assoc_long(&filterparams, "window", MAX_WBITS+16); + filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC); + zval_dtor(&filterparams); + if (!filter) { + if (error) { + spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); + } + return EOF; + } + php_stream_filter_append(&phar->fp->writefilters, filter); + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(phar->fp); + /* use the temp stream as our base */ + phar->fp = newfile; + } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) { + php_stream_filter *filter; + + filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC); + php_stream_filter_append(&phar->fp->writefilters, filter); + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(phar->fp); + /* use the temp stream as our base */ + phar->fp = newfile; + } else { + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + /* we could also reopen the file in "rb" mode but there is no need for that */ + php_stream_close(newfile); + } + } + + if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) { + if (error) { + spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname); + } + return EOF; + } + + return EOF; +} +/* }}} */ + +#ifdef COMPILE_DL_PHAR +ZEND_GET_MODULE(phar) +#endif + +/* {{{ phar_functions[] + * + * Every user visible function must have an entry in phar_functions[]. + */ +function_entry phar_functions[] = { + {NULL, NULL, NULL} /* Must be the last line in phar_functions[] */ +}; +/* }}}*/ + +/* {{{ php_phar_init_globals + */ +static void php_phar_init_globals_module(zend_phar_globals *phar_globals) +{ + memset(phar_globals, 0, sizeof(zend_phar_globals)); + phar_globals->readonly = 1; +} +/* }}} */ + +#if PHP_VERSION_ID >= 50300 +static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */ +{ + return php_stream_read(((phar_archive_data*)handle)->fp, buf, len); +} +/* }}} */ + +static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */ +{ + return ((phar_archive_data*)handle)->halt_offset + 32; +} /* }}} */ + +#else /* PHP_VERSION_ID */ + +static long stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */ +{ + return (long)php_stream_tell((php_stream*)handle); +} +/* }}} */ +#endif + +zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); +#if PHP_VERSION_ID >= 50300 +#define phar_orig_zend_open zend_stream_open_function +char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC) +{ + return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC); +} +#else +int (*phar_orig_zend_open)(const char *filename, zend_file_handle *handle TSRMLS_DC); +#endif + +static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */ +{ + zend_op_array *res; + char *name = NULL; + int failed; + phar_archive_data *phar; + + if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) { + if (SUCCESS == phar_open_filename(file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) { + if (phar->is_zip || phar->is_tar) { + zend_file_handle f = *file_handle; + + /* zip or tar-based phar */ + spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php"); + if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) { + efree(name); + name = NULL; + file_handle->filename = f.filename; + if (file_handle->opened_path) { + efree(file_handle->opened_path); + } + file_handle->opened_path = f.opened_path; + file_handle->free_filename = f.free_filename; + } else { + *file_handle = f; + } + } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) { + /* compressed phar */ +#if PHP_VERSION_ID >= 50300 && PHP_VERSION_ID < 60000 + file_handle->type = ZEND_HANDLE_STREAM; + file_handle->free_filename = 0; + file_handle->handle.stream.handle = phar; + file_handle->handle.stream.reader = phar_zend_stream_reader; + file_handle->handle.stream.closer = NULL; + file_handle->handle.stream.fsizer = phar_zend_stream_fsizer; + file_handle->handle.stream.isatty = 0; + php_stream_rewind(phar->fp); + memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap)); +#else /* PHP_VERSION_ID */ + file_handle->type = ZEND_HANDLE_STREAM; + file_handle->free_filename = 0; + file_handle->handle.stream.handle = phar->fp; + file_handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read; + file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */ + file_handle->handle.stream.fteller = stream_fteller_for_zend; + file_handle->handle.stream.interactive = 0; + php_stream_rewind(phar->fp); +#endif + } + } + } + zend_try { + failed = 0; + res = phar_orig_compile_file(file_handle, type TSRMLS_CC); + } zend_catch { + failed = 1; + } zend_end_try(); + if (name) { + efree(name); + } + if (failed) { + zend_bailout(); + } + return res; +} +/* }}} */ + +#if PHP_VERSION_ID < 50300 +int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */ +{ + char *arch, *entry; + int arch_len, entry_len; + + /* this code is obsoleted in php 5.3 */ + entry = (char *) filename; + if (!IS_ABSOLUTE_PATH(entry, strlen(entry)) && !strstr(entry, "://")) { + phar_archive_data **pphar = NULL; + char *fname; + int fname_len; + + 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, 1, 0 TSRMLS_CC)) { + zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar); + efree(arch); + efree(entry); + } + } + /* retrieving an include within the current directory, so use this if possible */ + if (!(entry = phar_find_in_include_path((char *) filename, strlen(filename), NULL TSRMLS_CC))) { + /* this file is not in the phar, use the original path */ + goto skip_phar; + } + if (SUCCESS == phar_orig_zend_open(entry, handle TSRMLS_CC)) { + if (!handle->opened_path) { + handle->opened_path = entry; + } + if (entry != filename) { + handle->free_filename = 1; + } + return SUCCESS; + } + if (entry != filename) { + efree(entry); + } + return FAILURE; + } +skip_phar: + return phar_orig_zend_open(filename, handle TSRMLS_CC); +} +/* }}} */ +#endif +typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC); +typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr); + +PHP_MINIT_FUNCTION(phar) /* {{{ */ +{ + ZEND_INIT_MODULE_GLOBALS(phar, php_phar_init_globals_module, NULL); + REGISTER_INI_ENTRIES(); + + phar_has_bz2 = zend_hash_exists(&module_registry, "bz2", sizeof("bz2")); + phar_has_zlib = zend_hash_exists(&module_registry, "zlib", sizeof("zlib")); + phar_orig_compile_file = zend_compile_file; + zend_compile_file = phar_compile_file; + +#if PHP_VERSION_ID >= 50300 + phar_save_resolve_path = zend_resolve_path; + zend_resolve_path = phar_resolve_path; +#else + phar_orig_zend_open = zend_stream_open_function; + zend_stream_open_function = phar_zend_open; +#endif + + phar_object_init(TSRMLS_C); + + return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC); +} +/* }}} */ + +PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */ +{ + return php_unregister_url_stream_wrapper("phar" TSRMLS_CC); + if (zend_compile_file == phar_compile_file) { + zend_compile_file = phar_orig_compile_file; + } + +#if PHP_VERSION_ID < 50300 + if (zend_stream_open_function == phar_zend_open) { + zend_stream_open_function = phar_orig_zend_open; + } +#endif +} +/* }}} */ + +void phar_request_initialize(TSRMLS_D) /* {{{ */ +{ + if (!PHAR_GLOBALS->request_init) + { + PHAR_GLOBALS->request_init = 1; + PHAR_GLOBALS->request_ends = 0; + 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_SERVER_mung_list), sizeof(const char *), zend_get_hash_value, NULL, 0); + PHAR_G(cwd) = NULL; + PHAR_G(cwd_len) = 0; + PHAR_G(cwd_init) = 0; + phar_intercept_functions(TSRMLS_C); + } +} +/* }}} */ + +PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */ +{ + PHAR_GLOBALS->request_ends = 1; + if (PHAR_GLOBALS->request_init) + { + phar_release_functions(TSRMLS_C); + zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map)); + PHAR_GLOBALS->phar_alias_map.arBuckets = NULL; + zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map)); + PHAR_GLOBALS->phar_fname_map.arBuckets = NULL; + zend_hash_destroy(&(PHAR_GLOBALS->phar_SERVER_mung_list)); + PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets = NULL; + PHAR_GLOBALS->request_init = 0; + if (PHAR_G(cwd)) { + efree(PHAR_G(cwd)); + } + PHAR_G(cwd) = NULL; + PHAR_G(cwd_len) = 0; + PHAR_G(cwd_init) = 0; + } + PHAR_GLOBALS->request_done = 1; + return SUCCESS; +} +/* }}} */ + +PHP_MINFO_FUNCTION(phar) /* {{{ */ +{ + php_info_print_table_start(); + php_info_print_table_header(2, "Phar: PHP Archive support", "enabled"); + php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION); + php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION); + php_info_print_table_row(2, "CVS revision", "$Revision$"); + php_info_print_table_row(2, "Phar-based phar archives", "enabled"); + php_info_print_table_row(2, "Tar-based phar archives", "enabled"); + php_info_print_table_row(2, "ZIP-based phar archives", "enabled"); + if (phar_has_zlib) { + php_info_print_table_row(2, "gzip compression", "enabled"); + } else { + php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)"); + } + if (phar_has_bz2) { + php_info_print_table_row(2, "bzip2 compression", "enabled"); + } else { + php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)"); + } + php_info_print_table_end(); + + php_info_print_box_start(0); + PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik."); + PUTS(!sapi_module.phpinfo_as_text?"
":"\n"); + PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger."); + PUTS(!sapi_module.phpinfo_as_text?"
":"\n"); + PUTS("Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle."); + php_info_print_box_end(); + + DISPLAY_INI_ENTRIES(); +} +/* }}} */ + +/* {{{ phar_module_entry + */ +static zend_module_dep phar_deps[] = { + ZEND_MOD_OPTIONAL("apc") + ZEND_MOD_OPTIONAL("zlib") + ZEND_MOD_OPTIONAL("bz2") +#if HAVE_SPL + ZEND_MOD_REQUIRED("spl") +#endif + {NULL, NULL, NULL} +}; + +zend_module_entry phar_module_entry = { + STANDARD_MODULE_HEADER_EX, NULL, + phar_deps, + "Phar", + phar_functions, + PHP_MINIT(phar), + PHP_MSHUTDOWN(phar), + NULL, + PHP_RSHUTDOWN(phar), + PHP_MINFO(phar), + PHP_PHAR_VERSION, + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/phar.phar b/ext/phar/phar.phar new file mode 100755 index 0000000000..f26ce2b756 --- /dev/null +++ b/ext/phar/phar.phar @@ -0,0 +1,1229 @@ +#!/usr/bin/php + + * @author Greg Beaver + * @link http://www.synapticmedia.net Synaptic Media + * @version $Id: Archive.php,v 1.52 2007/09/01 20:28:14 cellog Exp $ + * @package PHP_Archive + * @category PHP + */ + +class PHP_Archive +{ + const GZ = 0x00001000; + const BZ2 = 0x00002000; + const SIG = 0x00010000; + const SHA1 = 0x0002; + const MD5 = 0x0001; + /** + * Whether this archive is compressed with zlib + * + * @var bool + */ + private $_compressed; + /** + * @var string Real path to the .phar archive + */ + private $_archiveName = null; + /** + * Current file name in the phar + * @var string + */ + protected $currentFilename = null; + /** + * Length of current file in the phar + * @var string + */ + protected $internalFileLength = null; + /** + * Current file statistics (size, creation date, etc.) + * @var string + */ + protected $currentStat = null; + /** + * @var resource|null Pointer to open .phar + */ + protected $fp = null; + /** + * @var int Current Position of the pointer + */ + protected $position = 0; + + /** + * Map actual realpath of phars to meta-data about the phar + * + * Data is indexed by the alias that is used by internal files. In other + * words, if a file is included via: + * + * require_once 'phar://PEAR.phar/PEAR/Installer.php'; + * + * then the alias is "PEAR.phar" + * + * Information stored is a boolean indicating whether this .phar is compressed + * with zlib, another for bzip2, phar-specific meta-data, and + * the precise offset of internal files + * within the .phar, used with the {@link $_manifest} to load actual file contents + * @var array + */ + private static $_pharMapping = array(); + /** + * Map real file paths to alias used + * + * @var array + */ + private static $_pharFiles = array(); + /** + * File listing for the .phar + * + * The manifest is indexed per phar. + * + * Files within the .phar are indexed by their relative path within the + * .phar. Each file has this information in its internal array + * + * - 0 = uncompressed file size + * - 1 = timestamp of when file was added to phar + * - 2 = offset of file within phar relative to internal file's start + * - 3 = compressed file size (actual size in the phar) + * @var array + */ + private static $_manifest = array(); + /** + * Absolute offset of internal files within the .phar, indexed by absolute + * path to the .phar + * + * @var array + */ + private static $_fileStart = array(); + /** + * file name of the phar + * + * @var string + */ + private $_basename; + + + /** + * Default MIME types used for the web front controller + * + * @var array + */ + public static $defaultmimes = array( + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'arc' => 'application/octet-stream', + 'arj' => 'application/octet-stream', + 'art' => 'image/x-jg', + 'asf' => 'video/x-ms-asf', + 'asx' => 'video/x-ms-asf', + 'avi' => 'video/avi', + 'bin' => 'application/octet-stream', + 'bm' => 'image/bmp', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bzip2', + 'css' => 'text/css', + 'doc' => 'application/msword', + 'dot' => 'application/msword', + 'dv' => 'video/x-dv', + 'dvi' => 'application/x-dvi', + 'eps' => 'application/postscript', + 'exe' => 'application/octet-stream', + 'gif' => 'image/gif', + 'gz' => 'application/x-gzip', + 'gzip' => 'application/x-gzip', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ico' => 'image/x-icon', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'js' => 'application/x-javascript', + 'log' => 'text/plain', + 'mid' => 'audio/x-midi', + 'mov' => 'video/quicktime', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg3', + 'mpg' => 'audio/mpeg', + 'pdf' => 'aplication/pdf', + 'png' => 'image/png', + 'rtf' => 'application/rtf', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'txt' => 'text/plain', + 'xml' => 'text/xml', + ); + + public static $defaultphp = array( + 'php' => true + ); + + public static $defaultphps = array( + 'phps' => true + ); + + public static $deny = array('/.+\.inc$/'); + + public static function viewSource($archive, $file) + { + // security, idea borrowed from PHK + if (!file_exists($archive . '.introspect')) { + header("HTTP/1.0 404 Not Found"); + return false; + } + if (self::_fileExists($archive, $_GET['viewsource'])) { + $source = highlight_file('phar://@ALIAS@/' . + $_GET['viewsource'], true); + header('Content-Type: text/html'); + header('Content-Length: ' . strlen($source)); + echo 'Source of ', + htmlspecialchars($_GET['viewsource']), ''; + echo '

Source of ', + htmlspecialchars($_GET['viewsource']), '

'; + if (isset($_GET['introspect'])) { + echo 'Return to ', htmlspecialchars($_GET['introspect']), '
'; + } + echo $source; + return false; + } else { + header("HTTP/1.0 404 Not Found"); + return false; + } + + } + + public static function introspect($archive, $dir) + { + // security, idea borrowed from PHK + if (!file_exists($archive . '.introspect')) { + header("HTTP/1.0 404 Not Found"); + return false; + } + if (!$dir) { + $dir = '/'; + } + $dir = self::processFile($dir); + if ($dir[0] != '/') { + $dir = '/' . $dir; + } + try { + $self = htmlspecialchars($_SERVER['PHP_SELF']); + $iterate = new DirectoryIterator('phar://@ALIAS@' . $dir); + echo 'Introspect ', htmlspecialchars($dir), + '

Introspect ', htmlspecialchars($dir), + '

    '; + if ($dir != '/') { + echo '
  • ..
  • '; + } + foreach ($iterate as $entry) { + if ($entry->isDot()) continue; + $name = self::processFile($entry->getPathname()); + $name = str_replace('phar://@ALIAS@/', '', $name); + if ($entry->isDir()) { + echo '
  • ', + htmlspecialchars($entry->getFilename()), '/ [directory]
  • '; + } else { + echo '
  • ', + htmlspecialchars($entry->getFilename()), '
  • '; + } + } + return false; + } catch (Exception $e) { + echo 'Directory not found: ', + htmlspecialchars($dir), '', + '

    Directory not found: ', htmlspecialchars($dir), '

    ', + '

    Try ', + 'This link

    '; + return false; + } + } + + public static function webFrontController($initfile) + { + if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) { + $uri = parse_url($_SERVER['REQUEST_URI']); + $archive = realpath($_SERVER['SCRIPT_FILENAME']); + $subpath = str_replace('/' . basename($archive), '', $uri['path']); + if (!$subpath || $subpath == '/') { + if (isset($_GET['viewsource'])) { + return self::viewSource($archive, $_GET['viewsource']); + } + if (isset($_GET['introspect'])) { + return self::introspect($archive, $_GET['introspect']); + } + $subpath = '/' . $initfile; + } + if (!self::_fileExists($archive, substr($subpath, 1))) { + header("HTTP/1.0 404 Not Found"); + return false; + } + foreach (self::$deny as $pattern) { + if (preg_match($pattern, $subpath)) { + header("HTTP/1.0 404 Not Found"); + return false; + } + } + $inf = pathinfo(basename($subpath)); + if (!isset($inf['extension'])) { + header('Content-Type: text/plain'); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://@ALIAS@' . $subpath); + return false; + } + if (isset(self::$defaultphp[$inf['extension']])) { + include 'phar://@ALIAS@' . $subpath; + return false; + } + if (isset(self::$defaultmimes[$inf['extension']])) { + header('Content-Type: ' . self::$defaultmimes[$inf['extension']]); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://@ALIAS@' . $subpath); + return false; + } + if (isset(self::$defaultphps[$inf['extension']])) { + header('Content-Type: text/html'); + $c = highlight_file('phar://@ALIAS@' . $subpath, true); + header('Content-Length: ' . strlen($c)); + echo $c; + return false; + } + header('Content-Type: text/plain'); + header('Content-Length: ' . + self::_filesize($archive, substr($subpath, 1))); + readfile('phar://@ALIAS@' . $subpath); + } + } + + /** + * Detect end of stub + * + * @param string $buffer stub past '__HALT_'.'COMPILER();' + * @return end of stub, prior to length of manifest. + */ + private static final function _endOfStubLength($buffer) + { + $pos = 0; + if (!strlen($buffer)) { + return $pos; + } + if (($buffer[0] == ' ' || $buffer[0] == "\n") && @substr($buffer, 1, 2) == '?>') + { + $pos += 3; + if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") { + $pos += 2; + } + else if ($buffer[$pos] == "\n") { + $pos += 1; + } + } + return $pos; + } + + /** + * Allows loading an external Phar archive without include()ing it + * + * @param string $file phar package to load + * @param string $alias alias to use + * @throws Exception + */ + public static final function loadPhar($file, $alias = NULL) + { + $file = realpath($file); + if ($file) { + $fp = fopen($file, 'rb'); + $buffer = ''; + while (!feof($fp)) { + $buffer .= fread($fp, 8192); + // don't break phars + if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) { + $buffer .= fread($fp, 5); + fclose($fp); + $pos += 18; + $pos += self::_endOfStubLength(substr($buffer, $pos)); + return self::_mapPhar($file, $pos, $alias); + } + } + fclose($fp); + } + } + + /** + * Map a full real file path to an alias used to refer to the .phar + * + * This function can only be called from the initialization of the .phar itself. + * Any attempt to call from outside the .phar or to re-alias the .phar will fail + * as a security measure. + * @param string $alias + * @param int $dataoffset the value of __COMPILER_HALT_OFFSET__ + */ + public static final function mapPhar($alias = NULL, $dataoffset = NULL) + { + try { + $trace = debug_backtrace(); + $file = $trace[0]['file']; + // this ensures that this is safe + if (!in_array($file, get_included_files())) { + die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' . + 'the phar that initiates it'); + } + $file = realpath($file); + if (!isset($dataoffset)) { + $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__'); + $fp = fopen($file, 'rb'); + fseek($fp, $dataoffset, SEEK_SET); + $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5)); + fclose($fp); + } + + self::_mapPhar($file, $dataoffset); + } catch (Exception $e) { + die($e->getMessage()); + } + } + + /** + * Sub-function, allows recovery from errors + * + * @param unknown_type $file + * @param unknown_type $dataoffset + */ + private static function _mapPhar($file, $dataoffset, $alias = NULL) + { + $file = realpath($file); + if (isset(self::$_manifest[$file])) { + return; + } + if (!is_array(self::$_pharMapping)) { + self::$_pharMapping = array(); + } + $fp = fopen($file, 'rb'); + // seek to __HALT_COMPILER_OFFSET__ + fseek($fp, $dataoffset); + $manifest_length = unpack('Vlen', fread($fp, 4)); + $manifest = ''; + $last = '1'; + while (strlen($last) && strlen($manifest) < $manifest_length['len']) { + $read = 8192; + if ($manifest_length['len'] - strlen($manifest) < 8192) { + $read = $manifest_length['len'] - strlen($manifest); + } + $last = fread($fp, $read); + $manifest .= $last; + } + if (strlen($manifest) < $manifest_length['len']) { + throw new Exception('ERROR: manifest length read was "' . + strlen($manifest) .'" should be "' . + $manifest_length['len'] . '"'); + } + $info = self::_unserializeManifest($manifest); + if ($info['alias']) { + $alias = $info['alias']; + $explicit = true; + } else { + if (!isset($alias)) { + $alias = $file; + } + $explicit = false; + } + self::$_manifest[$file] = $info['manifest']; + $compressed = $info['compressed']; + self::$_fileStart[$file] = ftell($fp); + fclose($fp); + if ($compressed & 0x00001000) { + if (!function_exists('gzinflate')) { + throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' . + ' for compressed .phars'); + } + } + if ($compressed & 0x00002000) { + if (!function_exists('bzdecompress')) { + throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' . + ' for compressed .phars'); + } + } + if (isset(self::$_pharMapping[$alias])) { + throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' . + $alias . '" cannot re-alias to "' . $file . '"'); + } + self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit, + $info['metadata']); + self::$_pharFiles[$file] = $alias; + } + + /** + * extract the manifest into an internal array + * + * @param string $manifest + * @return false|array + */ + private static function _unserializeManifest($manifest) + { + // retrieve the number of files in the manifest + $info = unpack('V', substr($manifest, 0, 4)); + $apiver = substr($manifest, 4, 2); + $apiver = bin2hex($apiver); + $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]); + $majorcompat = hexdec($apiver[0]); + $calcapi = explode('.', self::APIVersion()); + if ($calcapi[0] != $majorcompat) { + throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' . + 'PHP_Archive is API version '.self::APIVersion()); + } + if ($calcapi[0] === '0') { + if (self::APIVersion() != $apiver_dots) { + throw new Exception('Phar is API version ' . $apiver_dots . + ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR); + } + } + $flags = unpack('V', substr($manifest, 6, 4)); + $ret = array('compressed' => $flags & 0x00003000); + // signature is not verified by default in PHP_Archive, phar is better + $ret['hassignature'] = $flags & 0x00010000; + $aliaslen = unpack('V', substr($manifest, 10, 4)); + if ($aliaslen) { + $ret['alias'] = substr($manifest, 14, $aliaslen[1]); + } else { + $ret['alias'] = false; + } + $manifest = substr($manifest, 14 + $aliaslen[1]); + $metadatalen = unpack('V', substr($manifest, 0, 4)); + if ($metadatalen[1]) { + $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1])); + $manifest = substr($manifest, 4 + $metadatalen[1]); + } else { + $ret['metadata'] = null; + $manifest = substr($manifest, 4); + } + $offset = 0; + $start = 0; + for ($i = 0; $i < $info[1]; $i++) { + // length of the file name + $len = unpack('V', substr($manifest, $start, 4)); + $start += 4; + // file name + $savepath = substr($manifest, $start, $len[1]); + $start += $len[1]; + // retrieve manifest data: + // 0 = uncompressed file size + // 1 = timestamp of when file was added to phar + // 2 = compressed filesize + // 3 = crc32 + // 4 = flags + // 5 = metadata length + $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24))); + $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3] + & 0xffffffff); + if ($ret['manifest'][$savepath][5]) { + $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24, + $ret['manifest'][$savepath][5])); + } else { + $ret['manifest'][$savepath][6] = null; + } + $ret['manifest'][$savepath][7] = $offset; + $offset += $ret['manifest'][$savepath][2]; + $start += 24 + $ret['manifest'][$savepath][5]; + } + return $ret; + } + + /** + * @param string + */ + private static function processFile($path) + { + if ($path == '.') { + return ''; + } + $std = str_replace("\\", "/", $path); + while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ; + $std = str_replace("/./", "", $std); + if (strlen($std) > 1 && $std[0] == '/') { + $std = substr($std, 1); + } + if (strncmp($std, "./", 2) == 0) { + return substr($std, 2); + } else { + return $std; + } + } + + /** + * Seek in the master archive to a matching file or directory + * @param string + */ + protected function selectFile($path, $allowdirs = true) + { + $std = self::processFile($path); + if (isset(self::$_manifest[$this->_archiveName][$path])) { + $this->_setCurrentFile($path); + return true; + } + if (!$allowdirs) { + return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"'; + } + foreach (self::$_manifest[$this->_archiveName] as $file => $info) { + if (empty($std) || + //$std is a directory + strncmp($std.'/', $path, strlen($std)+1) == 0) { + $this->currentFilename = $this->internalFileLength = $this->currentStat = null; + return true; + } + } + return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"'; + } + + private function _setCurrentFile($path) + { + $this->currentStat = array( + 2 => 0100444, // file mode, readable by all, writeable by none + 4 => 0, // uid + 5 => 0, // gid + 7 => self::$_manifest[$this->_archiveName][$path][0], // size + 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time + ); + $this->currentFilename = $path; + $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2]; + // seek to offset of file header within the .phar + if (is_resource(@$this->fp)) { + fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]); + } + } + + private static function _fileExists($archive, $path) + { + return isset(self::$_manifest[$archive]) && + isset(self::$_manifest[$archive][$path]); + } + + private static function _filesize($archive, $path) + { + return self::$_manifest[$archive][$path][0]; + } + + /** + * Seek to a file within the master archive, and extract its contents + * @param string + * @return array|string an array containing an error message string is returned + * upon error, otherwise the file contents are returned + */ + public function extractFile($path) + { + $this->fp = @fopen($this->_archiveName, "rb"); + if (!$this->fp) { + return array('Error: cannot open phar "' . $this->_archiveName . '"'); + } + if (($e = $this->selectFile($path, false)) === true) { + $data = ''; + $count = $this->internalFileLength; + while ($count) { + if ($count < 8192) { + $data .= @fread($this->fp, $count); + $count = 0; + } else { + $count -= 8192; + $data .= @fread($this->fp, 8192); + } + } + @fclose($this->fp); + if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) { + $data = gzinflate($data); + } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) { + $data = bzdecompress($data); + } + if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) { + if (strlen($data) != $this->currentStat[7]) { + return array("Not valid internal .phar file (size error {$size} != " . + $this->currentStat[7] . ")"); + } + if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data) & 0xffffffff)) { + return array("Not valid internal .phar file (checksum error)"); + } + self::$_manifest[$this->_archiveName][$path]['ok'] = true; + } + return $data; + } else { + @fclose($this->fp); + return array($e); + } + } + + /** + * Parse urls like phar:///fullpath/to/my.phar/file.txt + * + * @param string $file + * @return false|array + */ + static protected function parseUrl($file) + { + if (substr($file, 0, 7) != 'phar://') { + return false; + } + $file = substr($file, 7); + + $ret = array('scheme' => 'phar'); + $pos_p = strpos($file, '.phar.php'); + $pos_z = strpos($file, '.phar.gz'); + $pos_b = strpos($file, '.phar.bz2'); + if ($pos_p) { + if ($pos_z) { + return false; + } + $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php')); + $ret['path'] = substr($file, strlen($ret['host'])); + } elseif ($pos_z) { + $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz')); + $ret['path'] = substr($file, strlen($ret['host'])); + } elseif ($pos_b) { + $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2')); + $ret['path'] = substr($file, strlen($ret['host'])); + } elseif (($pos_p = strpos($file, ".phar")) !== false) { + $ret['host'] = substr($file, 0, $pos_p + strlen('.phar')); + $ret['path'] = substr($file, strlen($ret['host'])); + } else { + return false; + } + if (!$ret['path']) { + $ret['path'] = '/'; + } + return $ret; + } + + /** + * Locate the .phar archive in the include_path and detect the file to open within + * the archive. + * + * Possible parameters are phar://pharname.phar/filename_within_phar.ext + * @param string a file within the archive + * @return string the filename within the .phar to retrieve + */ + public function initializeStream($file) + { + $file = self::processFile($file); + $info = @parse_url($file); + if (!$info) { + $info = self::parseUrl($file); + } + if (!$info) { + return false; + } + if (!isset($info['host'])) { + // malformed internal file + return false; + } + if (!isset(self::$_pharFiles[$info['host']]) && + !isset(self::$_pharMapping[$info['host']])) { + try { + self::loadPhar($info['host']); + // use alias from here out + $info['host'] = self::$_pharFiles[$info['host']]; + } catch (Exception $e) { + return false; + } + } + if (!isset($info['path'])) { + return false; + } elseif (strlen($info['path']) > 1) { + $info['path'] = substr($info['path'], 1); + } + if (isset(self::$_pharMapping[$info['host']])) { + $this->_basename = $info['host']; + $this->_archiveName = self::$_pharMapping[$info['host']][0]; + $this->_compressed = self::$_pharMapping[$info['host']][1]; + } elseif (isset(self::$_pharFiles[$info['host']])) { + $this->_archiveName = $info['host']; + $this->_basename = self::$_pharFiles[$info['host']]; + $this->_compressed = self::$_pharMapping[$this->_basename][1]; + } + $file = $info['path']; + return $file; + } + + /** + * Open the requested file - PHP streams API + * + * @param string $file String provided by the Stream wrapper + * @access private + */ + public function stream_open($file) + { + return $this->_streamOpen($file); + } + + /** + * @param string filename to opne, or directory name + * @param bool if true, a directory will be matched, otherwise only files + * will be matched + * @uses trigger_error() + * @return bool success of opening + * @access private + */ + private function _streamOpen($file, $searchForDir = false) + { + $path = $this->initializeStream($file); + if (!$path) { + trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR); + } + if (is_array($this->file = $this->extractFile($path))) { + trigger_error($this->file[0], E_USER_ERROR); + return false; + } + if ($path != $this->currentFilename) { + if (!$searchForDir) { + trigger_error("Cannot open '$file', is a directory", E_USER_ERROR); + return false; + } else { + $this->file = ''; + return true; + } + } + + if (!is_null($this->file) && $this->file !== false) { + return true; + } else { + return false; + } + } + + /** + * Read the data - PHP streams API + * + * @param int + * @access private + */ + public function stream_read($count) + { + $ret = substr($this->file, $this->position, $count); + $this->position += strlen($ret); + return $ret; + } + + /** + * Whether we've hit the end of the file - PHP streams API + * @access private + */ + function stream_eof() + { + return $this->position >= $this->currentStat[7]; + } + + /** + * For seeking the stream - PHP streams API + * @param int + * @param SEEK_SET|SEEK_CUR|SEEK_END + * @access private + */ + public function stream_seek($pos, $whence) + { + switch ($whence) { + case SEEK_SET: + if ($pos < 0) { + return false; + } + $this->position = $pos; + break; + case SEEK_CUR: + if ($pos + $this->currentStat[7] < 0) { + return false; + } + $this->position += $pos; + break; + case SEEK_END: + if ($pos + $this->currentStat[7] < 0) { + return false; + } + $this->position = $pos + $this->currentStat[7]; + break; + default: + return false; + } + return true; + } + + /** + * The current position in the stream - PHP streams API + * @access private + */ + public function stream_tell() + { + return $this->position; + } + + /** + * The result of an fstat call, returns mod time from creation, and file size - + * PHP streams API + * @uses _stream_stat() + * @access private + */ + public function stream_stat() + { + return $this->_stream_stat(); + } + + /** + * Retrieve statistics on a file or directory within the .phar + * @param string file/directory to stat + * @access private + */ + public function _stream_stat($file = null) + { + $std = $file ? self::processFile($file) : $this->currentFilename; + if ($file) { + if (isset(self::$_manifest[$this->_archiveName][$file])) { + $this->_setCurrentFile($file); + $isdir = false; + } else { + do { + $isdir = false; + if ($file == '/') { + break; + } + foreach (self::$_manifest[$this->_archiveName] as $path => $info) { + if (strpos($path, $file) === 0) { + if (strlen($path) > strlen($file) && + $path[strlen($file)] == '/') { + break 2; + } + } + } + // no files exist and no directories match this string + return false; + } while (false); + $isdir = true; + } + } else { + $isdir = false; // open streams must be files + } + $mode = $isdir ? 0040444 : 0100444; + // 040000 = dir, 010000 = file + // everything is readable, nothing is writeable + return array( + 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices + 'dev' => 0, 'ino' => 0, + 'mode' => $mode, + 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0, + 'size' => $this->currentStat[7], + 'atime' => $this->currentStat[9], + 'mtime' => $this->currentStat[9], + 'ctime' => $this->currentStat[9], + ); + } + + /** + * Stat a closed file or directory - PHP streams API + * @param string + * @param int + * @access private + */ + public function url_stat($url, $flags) + { + $path = $this->initializeStream($url); + return $this->_stream_stat($path); + } + + /** + * Open a directory in the .phar for reading - PHP streams API + * @param string directory name + * @access private + */ + public function dir_opendir($path) + { + $info = @parse_url($path); + if (!$info) { + $info = self::parseUrl($path); + if (!$info) { + trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir', + E_USER_ERROR); + return false; + } + } + $path = !empty($info['path']) ? + $info['host'] . $info['path'] : $info['host'] . '/'; + $path = $this->initializeStream('phar://' . $path); + if (isset(self::$_manifest[$this->_archiveName][$path])) { + trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir', + E_USER_ERROR); + return false; + } + if ($path == false) { + trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR); + return false; + } + $this->fp = @fopen($this->_archiveName, "rb"); + if (!$this->fp) { + trigger_error('Error: cannot open phar "' . $this->_archiveName . '"'); + return false; + } + $this->_dirFiles = array(); + foreach (self::$_manifest[$this->_archiveName] as $file => $info) { + if ($path == '/') { + if (strpos($file, '/')) { + $a = explode('/', $file); + $this->_dirFiles[array_shift($a)] = true; + } else { + $this->_dirFiles[$file] = true; + } + } elseif (strpos($file, $path) === 0) { + $fname = substr($file, strlen($path) + 1); + if (strpos($fname, '/')) { + // this is a directory + $a = explode('/', $fname); + $this->_dirFiles[array_shift($a)] = true; + } elseif ($file[strlen($path)] == '/') { + // this is a file + $this->_dirFiles[$fname] = true; + } + } + } + @fclose($this->fp); + if (!count($this->_dirFiles)) { + return false; + } + @uksort($this->_dirFiles, 'strnatcmp'); + return true; + } + + /** + * Read the next directory entry - PHP streams API + * @access private + */ + public function dir_readdir() + { + $ret = key($this->_dirFiles); + @next($this->_dirFiles); + if (!$ret) { + return false; + } + return $ret; + } + + /** + * Close a directory handle opened with opendir() - PHP streams API + * @access private + */ + public function dir_closedir() + { + $this->_dirFiles = array(); + return true; + } + + /** + * Rewind to the first directory entry - PHP streams API + * @access private + */ + public function dir_rewinddir() + { + @reset($this->_dirFiles); + return true; + } + + /** + * API version of this class + * @return string + */ + public static final function APIVersion() + { + return '1.0.0'; + } + + /** + * Retrieve Phar-specific metadata for a Phar archive + * + * @param string $phar full path to Phar archive, or alias + * @return null|mixed The value that was serialized for the Phar + * archive's metadata + * @throws Exception + */ + public static function getPharMetadata($phar) + { + if (isset(self::$_pharFiles[$phar])) { + $phar = self::$_pharFiles[$phar]; + } + if (!isset(self::$_pharMapping[$phar])) { + throw new Exception('Unknown Phar archive: "' . $phar . '"'); + } + return self::$_pharMapping[$phar][4]; + } + + /** + * Retrieve File-specific metadata for a Phar archive file + * + * @param string $phar full path to Phar archive, or alias + * @param string $file relative path to file within Phar archive + * @return null|mixed The value that was serialized for the Phar + * archive's metadata + * @throws Exception + */ + public static function getFileMetadata($phar, $file) + { + if (!isset(self::$_pharFiles[$phar])) { + if (!isset(self::$_pharMapping[$phar])) { + throw new Exception('Unknown Phar archive: "' . $phar . '"'); + } + $phar = self::$_pharMapping[$phar][0]; + } + if (!isset(self::$_manifest[$phar])) { + throw new Exception('Unknown Phar: "' . $phar . '"'); + } + $file = self::processFile($file); + if (!isset(self::$_manifest[$phar][$file])) { + throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"'); + } + return self::$_manifest[$phar][$file][6]; + } + + /** + * @return list of supported signature algorithmns. + */ + public static function getsupportedsignatures() + { + $ret = array('MD5', 'SHA-1'); + if (extension_loaded('hash')) { + $ret[] = 'SHA-256'; + $ret[] = 'SHA-512'; + } + return $ret; + } +} +?> +N#/usr/src/PHP_5_3/ext/phar/phar.pharclicommand.inc?,ÚeäG¤ +-åzF¶directorygraphiterator.incôÚeäGuôÎr†¶directorytreeiterator.inc%ÚeäG]†p‹¶invertedregexiterator.incÖÚeäGÕICÖC¶pharcommand.incm«ÚeäG!Q•®Ó¶phar.incÚeäG)ìk<¶ÅkoÛFò»ÅZЕT,ɖ] wv¤^.w +$m¤ŸA ©¥Ä EꖤíÀõïÌ>È]{Ɲ[wvÞ;¯Õë»ÃÉÉù«WäïQœP&q˜í÷Aº™ÆixBàyœnYVȇ]Àøƒ[Ó ƒ<'oßýüVÀó¥ ,v#ä}ÀÂ2'ÿÈ(ÛR±k”Àëòââ2áoð—1©±œK~Zèòæ6/Xä6ȁã,Í3ä\ ñþÐ=M‹ ˆ³´«;Êr#³é'(ܖx'Èýe º!ÀmÃÇÃ;ëa¸ßädNƂoþȵ§k¹øv0–ùzT¦!ÊGÖkT@ÁÊ°ð9Kc)Xq`Á:¾†Å.Î' „”šæâ\¼³¥(9M¢ëë--¤vrŸ¯,xÉ|ÿ†m?ã +¼‚#"ø'¯ÉåHc_b;e,cþà—¬²õ6¾£é˜„;~%ÃGäxy±z";š¾¤'B“œ"‘Ó8Ïiákò,¹¨ËÙjµôX™z«Q'ýßÒ¯ivŸVLx’ðlõä=ƒ—‰¡B'5è´¦žÈÝ lvHPÛÍI².sÊÖèG¾p-2&ÝhoL¬1 ›5ží=8»° §¹z¿Ã(㟝ÁÖ×›¬êÞp·Æ+P#™Ï‰7ñ\  +Î@BÓz×÷\’ï¾#†ºPË5Ýҕ! @V&nZ‘ .ÙbÞ.šþ2üê½Ôl,1~‘"#‡€{ZP^† Y¤ùütœ×5_N/´Äo( á.H¼ªDú R§šë(‰D êàÁ¹òDúXsžG]WÊ^OªQ©LiìÙ +³íTß-£ÁW“‰Åüfk®sÏq”ô~֊ýO3 +øñˆt-iå¾eÞ˂8Ñý9ÿXÂL¹¯‘m›/¥üîÕMa¹Ò¢ÆÙYKÐpcºˆMZ»ƒ™Æ Q<(c¼Œ LæŒ/Q.ît?#A.ÃçbBµù±¸¹/ª [¤2GZçO¥wn”÷Z[œA¥¦éœÊaµ¸1AöY:zþ1WKnF#¢Û¸Õ¦6Ëh¥ÂŸÈò¢üëN-)I¼9–Õa]~¦|…„>ÜçÛf±Xœ‘ÿéó?ÿõñ# E˜Nl\F ÀéC\@u»¡XdŒH»ÐŠ ïk¨ñ…;ýz¿I´¢vDê²Êço‡:õéY¼ÕMG™†…ð÷+`+®3Z”,=Æj6®q]¡ŒmöÄj_*éWˆôò³ÃfPÔ*o‚¯¹_·K¼éá=?0ÅUc’—·¹¥ÙÀ“‡ ž¦ôž|¤QB9½·ˆÓ¯°ëÀ 6òl ’zƒQE(6YÏï)ô„зŒx˜Ú×gðÑ>¯%6…àc“E +‘bL.@¦„×—ŠNÏ ®h#*N>Œ,°–¨u¿ +­ÉÆ09Sâ"º³YK6¢­HÅ,™ròðæ­=ü‚ø[v*Ò[3zH8j°iŒµøX¬¶Ðä) 4½ r¡iŸs1²…n\áQ !XrŠ«$݈¸8 +C_þǗ»65Ð,QˆìüZEŒ @­×× ×WçBñ2óŸØŸªÚCõ¦Üu›'Ob­:ôê0k'Ø “x _ÑôBq¼{xá?fQwd×Zÿe +ØИÂ`ØÈÚ ëÛ,KTä#üÿ•~kaÅGàè{i@´I4sz¹?9•cçâÖ$N'ٗyAn) R˜è–²icìpbɤH*‘Ž’ˆî‡^µ5+»Î«W€ 2ã5|‘?ÿ¨ÃLf+G‡,÷½ó±'3¨NNú"²–ìºj\L“ÇaòÎy,EûMñK{}æÄíLÅ¿üöîݑYX78 + ^ç°Ðiœ®e…Á¡ùç5ãI‹¶KOàÂj¥Ó?T54ì%UÓ +¨ÎH–RœZxÐË¿³8õ˜?´tàYîÛj»#t²‰Y¯B†„rHÔÉ!(v¾,™ u £ù|Îý‹üþ;9ʼnùªÌ¼ ¿Ágq.hEÝ +ûÍ +ͱECbJ_›Œæ\ii¯¢£Åx?‹¹dÆ +ëÓ!ù €~N£ÌoT‹fñ²é#¨çªG[ï×LÛá§á.#š.øD«.Ì#ÅküÙ ê´Ðï"8ŸûbæTSí>m©¡*j*Lu*ð ({ÔÒ­à?^–4Ù>R3aæJbî<É-Ž‚×N|!“Ó |m]lD|Ÿ>\úÃd&"ýç -5ƒ¨UiPøÁĐÌȹ„¿ïáﯽT®$•äò¿%%?&üÔ¯r,°€Ø ~ ÉÁgèíø聀cðwô€ˆà gH]ß zЊßáœAð>c›{@÷‹å,òùÁrzìy÷ÁƒÿÃßȄ}1ºáKççd§ñ¾Ü8@[é¯8QÙÞ]âVk`1ÑDÝ +xƒ+ݪæÕ£m i¤+—‘®„‘§ÃR‚ò•i­+Ћ‹Ûí—h`pqxËå,uð—Éð1ɟrx<æDGj„ƒò]qϸr{†­2W[¢ŸGTUWì8:¨Hʽš|¸«¾–¸þ’»( |™†LÒúõ€aRJƒV7)£×²’4V]IZN#<ôm21_xAúÍóKù»;1A…ŠMuñ}=`c1½£UšŸ6‡g¬Lݜñ©.1f×ú;îwq¸kL¶ëË,³Ô—Á…oéôk æYïÕÕ{8`¤Ø)oŸyLŸuUKÄ?,/Vv”<­:ЪUáÀÆíˆóúµë÷ c)è†ùœÜ7҅~„ÎéÂø‘pa^å𧫾Q¿è»¾¤Cy™E^Kæd™qOÌWü”43š¾æ3~‹Òàºq1ÈeÀp‰­ç}8w)™S© Î¸­™ +yZVMjzm ‘ªJnÛhà÷•gÍ߶)L6-0êCπ7w†<4–3C“SDƓÚfl÷#ðt$smLéNš,®FÃèÜÑéh-¡™^<º¬% §Uuq—ɵ8ÄÑË⨿éH¸o&­ÔnK´6‡òTÏ, ÜØ[d1 §‚ ­ý(XI[®Aþg<ˆYÈñÕ +¾D CέMXqDtñ¼Æ{@&hí¾ßaš Á]'Ámý£Ó¼Ñm·æe7ö®*Õç9ÎÚ³BªŠ:ê¨Á9vê ÕªŽ!-ШOf¦£?€ ?.Nþ…RÑNÂ0}fÉþá>ø 5¾L#☰8°½ø´Ôîš`·´BÔ·ÝØDc°»Ý=瞞Óôz§¹mÙVïän—l0Teb»$O™BAô_—qj[ IŒ¯DVäàmÈK¾FYuŸÃ%Ð5‘FµÂØ(ø;…ŠG +•f`J-$Üe(V¸Ã¢ô:ï÷/àԔK”`8t+T„'D$0ŸÌ!`ςˆ­{M„C"Ô¡@¥DAÆ×[iö&›ì e÷¿¯($Ë8œuÏv&åÜ(äÉi/ß·ón[­eÁ©2’qL3.•(¨:>ʉJÛ5ŒÖi¡}m&ëê8ûC†Úâø ß%4Õ·SÓ+FI™\ý~7žVéªs€á8ÞS< ã{?ðfé·ÓmWµÝjó˗ã¸Ã ˆ£Ç0Zø³ñÇpäNâ±ÅîÄF¥H-–—I'ô‚{}î"ŒL»}¥¿Ÿ¶õi^Éàæ SÛnÚ@}‰˜$ìiÕ'!¡@T'b^*U²3Ø+ۚ]' &ÿÞYÛ\r­%Öx.gΟ_fQÖ¨7ê'GGpµ1Â\:¥µ&D©‘?te4êÀ52 )Í3¯Ä2‹Q•ÑI\@ ¥`´˜2À¤(ËD®£”ï)RˆUn.4__z½¯Ð1·o&Q$½—CžÉ\ÐnÀ•3´6é“í‡ÈÁŽØ†èBLÌÂÀN&’È"ìT#ƒú7ý'$%ÓN»§§j®4&säÜ÷´ÍìôúÓ¨×ÌRÃ4Qšò@ÂÒ%ȄŽºœ4S3Ab MÚ§œBùâ°(c.µEžÚðóý`h}6gͬca¢g¿ÂÄk >ïˆE±ÌžeÅے:—ƒÚ*çÇø—?ðüë‰;¾܍KX» åŸwSg8p]úӛ>Nîo^>IO‡·þÍxêo'î¨Ù€möôÆî5Ï{ô¦&lŸñùjœT¨~E¨sJ@GLÚtƸ4÷Œp!W8‡gɲ¿ñ*¯í+^µ[[¡›ÆRp­–™Y[°¬f|Ñ;ƒf çÐԑT~ˆz„™Ž,Ûďm(š«îîÅ^—ÏvRÇv§ uϳl¸„Ö ´Àá”ã^ÍQmWañøÿÅêX¿;-»Ê«{ˆŒïëÔÓÄïÇz'ò C¶©*t– Š ·_À%ٙ"Ž­¦ ´ëÙüj+kµ“)ñs…ä›2_‰µUžŸ“d_ˆö²¢Y0½ìÿ…PÍj1>o ï0ÞªPÝzVÑқ¡ô bvv7 É2™A|w“u[ZÅu.óý&«MÛ´RH1›Là½2c¿‘K†‘;š«¥€È1¶&Zøl]/{2X>(ïaۋ¿’xۋ¯4¸q°S¤ƒ‡‡Tc•ŠâÌó|¯ÝJ@þXçì·ø£R0 nUÞ8 oÓ¼x à‘Ñ–þ6ä$EÖõ#ä@Fÿð¢PZcË/ãH‹Y\U°šSî(¹dO–‘s–âœ~d³¾í=ýwÛ6’?_þ +$ë.åF–íìõî]R»uR'Í{Iš§×·u²^J‚$ž)RKR‰Ýnþ÷›|’²œìî½ó{m$ ó…™øíw«ÅêΝý¯¿¾Ã¾fßϒ”³Õ".&ùrgÓQ’MèA’Í‹|½b¯áý0.>c“4.KöäÅó'¢==Š×Õ"/{ `Ö%{œóbÎE¯i\qþ“íÑ?ð;>BÀ¬†²gŸýþûïr|*2~Uñlj*Ñ7[Q?üÿ{»HJ iS^²jÁÅg˜Ëgô}%'''_ŽØóŠ}LҔ9[—|ÊfE¾Ttåû“<+ó”c·$cy1å«rVð +ô31Ÿ¬+ŸÍÖÙ¤J ×Ha".D‘#èa“å*åKžU1‚é¢ø^”ÐŒŽˆ¬½èùû\$¹«õ8M&o cr1çÕÅÙëÔ¬åù`'=²¸˜_$Ùl—š Øø4Z+«â¢à+WƒˆEÐ<=d÷Ùøïßá¿ÿÚ}D>)”>}úÔ»?‰fÈø÷5{’&쯘zÄô“ïWq/äD€þNSXÁ,Ôèhôö#O?ð@#9s¦×sÆçÀ˜œ‰¹s‰G²í>ý뛗¤jú`[ÒÊÏ8øÔAèùÍ 42ó _ºd&¦…käÑRýªþ%Q¬g•'YÉb2%‚Zþü«¤‰ûq‘Løèú †d(닼äÙ(ÔG©®WœèO@àCV®ø$™áDQ‚$̋K–gî +®³Ë,ÿ˜Y‹$Ñ@à:¬GvlG·eG0“"¾ègøÅ;:ö=¡§’žGqšÄe4l¶ø§ÔâÕÏ/^x ß„cÐ=Eþ!™¢côËâ%g3P3zD£È¶kÎÆ=Ñή·BzgsÀ™ý—‹=üBÊ—Ö¤¨eЍ‹4ò€æ#ö‡»ûë²Ø'Ù>XÀݱº³¨1þEúã2¶Hª’§3ö.úÃÝw©z(ãiô Ð(žT¥8l…<§›ô#ˆÈ*Nç[®ô-Qè@\3ž ¡žOsUw[ׁ÷[Ð7Åv¬K`^¡x¢ï†âaƒåº¥–MÒ5ˆãëOÞÀà*à%6M +˜qH:“0áõn‹ÍzMM«ªm&‡YìLhUéwiåaL³çE¿å º ÊK¾Ôô˜(å(‚^Ь”õ“h9ýFÀ|ùÃ7Ñ0*ñ¡ø~öãÉaÔÎ~I¿ù|ί¶š.A86W(ïa¾Na‰ø•–#ÔûI¶ZW´neÇj]~­ŸdSûz\NŠ„,£-ƶâšöÃD® ׃VDяLQÆ×Ë1˜t6@n9Ÿ¢7R®ÇJŒI@rrSVb¯AR‚*uLdùeˆò£H¿„ìçbq&î#H‡Ô_ƒ’ ø ¿_ ö•vé¥U¿ ¤y ›¬­æ @³ù„6Q¸"¯|}q"]±I"ÚÀ{.À›(«=â|³;!ëoý9_³ ¸O°sá<¢wÑ!|’¥86¨ìŠÅ–[—ȨuЙ䀂­Ã‚j¿¾0Ï$ 1&BR[ÇiÈòŠñ¢\rçØÛ´Žaf„`G,f0 Ÿ¾„ÕG/<-sOa?YæK]HØÝJߨu”²Z¡4Œ+µñ7V¶?%ê&X ^UÀ'EKò6( 1üE¼Z€µŽF2á+˸¸±@l–dDúʘmûa„µ‹`u!?þíÁF¸cû÷÷Ç0샛!?äNûôÂ.âq’B/”œ‡A%œ­W«¼=t–̳öæ¼ì>²æœdÒ%ÏkïÁ7ÿ¡Zëä6ÚàÄa€áç ©ía¿9|ö£½!&Ra‚Ÿýd³‚ +&/ƒ0ðx²±P©;é%¿¦ Àd6oà³Æ‡‚sAçVùõí€úì:k_ð¿­ÔÓÔt•Q„²Ëî±Ø îtT;eOÇÔíhõD¢×Ãþýï5(wš0版Ó}ÔÚèIU&z×`?³ùPZ­€Øà:ÃóÀ%3³5ų XÕÀê3è<Ðsª…«4¼Ù~¾§<¨~» XU~Ùlá1ދÁ]°‹BSîúŸ¨x'06ÁµxðóiB«/¢(C)!÷ÜU´ŒM 7ÌOxù§Ã· gÍÁ@£B†§l–Ìׅð½Á¯°7ücìŒõ'õƒÌ…\βæù–B~‚Díkß$õA Û!é2jj„ë‹ñ.T6ê+ìíÙÿÈîâ<.ø¸«%µmj÷ùÅGäÒØZDéær•&ÕàÞ»ìސýµe+ò×]ÒÝ0W¯ªƒíÅdÁKïPj>`}çÔppoøØ´³wÕûûƒó¿à¿£¯qôówð·ÿ–Ÿäð#Œ¡î IDa¨lL¹1uÕòüð}-ü!.›>Ý ÃÙÜMʒW1Že ëÅî½Fª*gÝÜo€8Ó37…¸"À#X?5 æÑcǬdˆͮgšŒ£žl@{¹`ÿ2 åR˜¾ƒú¤ÄŠ†1¥‰ XúæJ öv­†ê@deéiH+hWíɛ„­s-úÿ`M„Ðt‚Š6K½U’$T§N’Ëé_-/ÛK¾+|Ó¤üï8M¦øå©´~íerß½×*¤[2 +W/ârÛ¬7,áTÐäЪú î*PâäWØ ¡lí¶°%"µûéå òio\I=?×Ëz#‘F“ñCðv¿€‡å˜e&…h–duœ˜1_µä2‰Uï‰ÅÏ°%΋¥,hábÕ¿}ž›™>%<‰³eÞ[ʚX5Ðr¢9=S5¢ýF’ UO›(`Ò³‘"œC⏦U2‚x㧁ëµ0–„üœÅc‘ñÀåkᘑÍ炡­¯ŠáÕ`†P° ìÓ« áïÞ*§uCØR¥œpÁ55Ðyø°Ú;†}êK ”Íù`~ºç“È› +ߺHÛe8Zí¥ÉeCìž,8ìI*ÃÇCÿGñVŽA±7I½¤’)lðsf´Q°h£ #‰î8§WÕÇo1–y¬ýa©n#ª–’NB\ìÛ£f{¤[zf.4ª†¼o‚nS(AŠ$bÍTVÛ¨9 +Éí[3õ¶§°ÞHúêmÂ'$E#`œ¦Ä…Ey;•î²ÖüÄ[mâN¸^—MâæãÿÁH(xâXUKŽƨ7ށ¬H¯l¬à$6 +Á&$ßý¬ +å×Ð(”uj×'§”˜BÐSÐ4ß pAi„Ý€hé>"û%êBú¯9õê\t C–€‚öïҀqµ²e|=æòŒpC«ä.Æ,Í<Ép=n×y’Õ'íôö–al$y"ØÙ⽐ïSû=²Æ&è*Y.{GG£#0Ayv&Ò½¶’V7wßÅØmÞ»þ rW¸8B;‰a)b>½Ö¾Y _Le„¶­ä\¨ØhÃÝ°êzàëØøÅ +ÜÒîb²œb9æÅJÅH éx^3[Õ1Ô)¯‹â1æj±>û¬$£}êkÃFukÁAÀrß{ñ^{¬:RƒmÎ\’Þ3RÏ{%©B +âfvžžcŽÍNŠÌÇÉZkÚUÀ^ +ͪ‘¸ÛŸ&E9òu›³Iõ´T¸¨L7%”U°òõ)LƉXâvÕŽ°_å@¶·2<‰»îá¡:´)¿ œûø…V!®C¨°%±rÉ(¹£r=–ñ*É"ĵ²«(ܬ¢²JB]Յ®Q<ž<G`U^áÞ^Æ."Ÿ²©•ˆr)¾ŠWÊ㟮Z±ûS#J +«V”fžV:oƒ­‡ÎSÊë‘ôï'x º`ÇÌS)E]²3bÏgl/A¶NDµqÍO¯^üÙè@qNYÚ1‡È|eVX(*D©Žµú +A‹>YÆYj€ÀÝ`¯~zkt2ëú‹o…ú§­ì’ç’W(íä~¸|}Æ뺋 ÝR~¬±ðŽ(ÕÞÁß1)H1{ۖ™]ª¿øb÷28ŒšQù t¤Ø=ÖÛ£Ö@1’=1•š ÙÁ= ”Oô‡»Þ°/µ—9MhOîoÎ E3ž­&´ 4ƒ6zÁï³COظ^ëè‰ ³'ÀV˽Õüv&£ïρ¸¡òÆB÷ÁÐdÕPñÅÝ0_¸“Âv¸cR?õñhüCïÒÀbmº‰†´ñ-濙øßs`„©)„ן Asï[<¡&X„l¶Ê¨EFª†üÉwÙwÇÔÊÈ+ÏräP1°—²Á§¶‡‚§uˆŒ|‹:5BD֪ɪ6Pï*ÙMv¹P5p¬M‹GÛ!íP™F8èÆQ¨ë¸Ïèââéó§£h_ÕÎE7Æ-úîØã׋g¨šp̽c`²3P܃ɡ—o i§6 “FÐÖüfÄcÎV)fRÐÿ×V¤ÙIv¨uӆ¶–gSŸ¥%¯[=ëgi¡u·í²ª˜oqC_)NAuõ0 Î!T¯Ö4ÏéTFñÎÒù¤¾Ã¦Šõä‰þ£‚Hé35æ®´kd‡;:AyëÅ:ëÚI¼®£Ÿ#y”›‘GPVvGwïP§=KÎÙé•(p]ƗàÜa+9¦99¢Ó꣱õÒÞ$¸Šëš¬3ѼãõÎs½êçdå‰KR1û“”\–òÙ¯ƒì)ÉÀ1jëT{÷õñ¯Ï_?è9ð”ÏâuZaƒuq ÷ìr“xK³…k¨*¸OTr@öð+h%­ùÊVõïjpp£Ãøӆx2Ö'b+ŸéV¥ø¼´ä±qȔ®Ÿ€†W«E‘¯çºêÏ1ÁÓ¹ îèA“¬äE%âȕªÿú"aCmLr‰:/$R®nšGÝ©@½´Â¥^⛞G[GmŠäÝ ø CzI†çIøÕsš~^tŒ.myž}àXéoõ7u.(c¿ 5÷™Ël3c.ÍDUµ_±|àl7ÖY¡s@Œó<åq&@d¹2¿,D!9úƒ^ˆQá¹(uHͪ;n»aêl*ºí@“:ħ'¨ÑøªXšÇy”\A;é· ÛEåºðpHȜYµ^ç¿1#õ¯BÖëDîÀ˜LYû7|².JŒ«*vQh=êè¨Ú×ý ™k»¥é"27í6ÂUP †%HjüªÍ€­V± ¼W.Ô0€w¤fýƒ¶üí>Ue"t|¹ª®ÕFK·©"‹Þð8}W‹Eͨ…ó{{5o;gníl=F`xä°;ÃŒb°ó%½FéƊ÷)ݨ+Òpà”WT½!ks‘f`!}ž +‹Z>ÛפVsENc}§@»¥s¬LØÂT|½¡â›,û±«~¢8Dõß(·ê@óÑôìðTjnÞiê_ÛQ$Qۂr²àÆu.>´•9ø¦@ˆ‡×YZe"¤â%}ÔµGi<áƒhã?ø?ñÜ`VªXˆ‘÷öØ1;@CRkœ<“è€Ý–LM=´ À«Y¬î65Ù"=Ru?2ÂGæÂø(—°v'‹œÝ)tj;™çâÉ{:‹ôcšÚbhcu[› +…¹ÊÊáÓ/±³ }+Û oýHßKÊH À\à +ºzïWÕõUý¾³ޚë ÊË©.¨kgf‰d+.Àûʞ+Z’ÓfEAèÚ²¸ÓÕ®Nm|—†‘¢˜zT{Ð’^“píCmº·¯álÙS5e´§xY.Ê^Ä~ɜ•(k6|©¸BÔ¥íñÓ&©ít +̇ç pC»ªQŸòÞZbcÿÇ<ҝ8»fóÌ ¯VÏHˆîU±æ®úKÓ Ø€¸V¹bRLÅ€þ….ÞÈ®‘í*^Ãz+WJ±ŽZ]I²ªQ°‚íŒþãå‡x·Õ+p¦á L™0t¹œÊ´-*°º&­k[[&^×\¥u£î«¶)7꫞&º°j]¤QGœ¨-ÇÒ5ã7ëÌ;YÌõ˜¡Ì¦vï“áñN:Ö. CQÕfãmÁµzkÞ+HTìå‹RïQI`mÝ˺nÀf‚¨Äâ`Ü!_ì­j/2bf(‰Cm$qYûw³Q”D¼G54Ú-Id™´DvÓêD f’±Ÿß¼`¢· d->£ˆv‘EԘ½ö—T‰]Sä õÊ͋xµHÜ ¦%ìZԞa[%kéƒÞjÁKèØÉ]õÕ Â_V9àåÉvb×Ö gúï{ßynD¥­ê—ö …)§üªÂkF»4Ê©Ñ,((bÞFC‰‹F»¿B‘ˆuŠÄP©u$ßn ÒƒRµ¦°éeK¸µÕt8H¢®†mìKì:íV F÷nÅ¢i°>ÛPN7­Ê–wµÂ’`I¶ýX]ҍd¹¶ùg7ÕvéŸê­ ÝË%H +rN ¥wÑè]´kÖ1oWºÜ¦ ƒj7ÀøÈ^Ka—)ªxˆGގGd±¿ Õ4H'öL*¹é_åÖ$_g•xŒ‘òÃÎóÏ?e)ìÜñRf@WfV1Mó|:òœƒÖåÉ9Á?çÎÅ!¾ ˜jbÐBô)`c|éH¥kcŒØS9—™„ó̼à +;©+ ¢îv•ÄG»ÍU$Q4= òêqÊ3—®ÂÆVáG£Ù’BÂî®Q DÁ„Q 9¢+ò µÑÜÐ?r‡r…ó´Öq3å[«ñF¶[+qž÷˜r‹iÔÌÙP)å-©ûBÇCT×)_ÁÒë&äõ¼X&Ž/ÅO1Þ*“Nyèƈ:êx0£Ÿu®À8ëjä9!aî­ÉI…‰³îøgë@톃úL§L^¤ªÒoSßMæ7ëËòÓÕ $Z+eHr/D“ï'ù +$×Pôú¯l4Ñ´l·Õ§±ëùåNn›/9åH0Wö _éJ¨Ð¸>>çœ÷mq‚›W§tû·§{Iä,Ì̽rtsÇÖO Êùo«¼÷úþ!p8©‹ñº¿§jjyµ²|WûR„nµFMoõÔuVoâƵ0 ÝH¯çilVÁ’ˆ×öT´)’ŠÊ:Z-¹'È,•Ï×ÅÈͤYý°­bí&²ë©Sƒ-2&rªL*«‹\1l‘YÏÆuÆ©0¯·c•Rh{Šõò&vVŠ–»Ôm¶¥º=YÎ;oÒé–1ß$Âçu'O“Ô»%ì·Ä¿ÿ? ûyè‹qÓý¬¥pZ͑/µ‘56±¢ÒCWÙ¨–þb›nõçeSU~à贉Oû©º>šr“ä¥*ïés¾ G¢Óh+jRûžh-éÿÌ5øNå?¶î>ŒL-ö§[)²1/ +ªÝ›éʓq¸}eD~Ìúª &^€€Á‘Ú”õ(§ 3OÞÙSBýó敠ܲÜP­¨çäÒÄ é¼²õP_큯Kì2Š¡É ë"°vfk”u¯Â œ{QÕD¤¿I?]•-µ>M$®[=Üß'âEÛ«{[Æhh¼¡f;—Œ—lœÝíE9sø&å6:v¦Ë3ûèùŽpõ9V·ÞêìT+”¶3@7Y{­ æ͵Æ++¥C£«e:ôSìó¯ M⪹žújÞ¢¯žu髐‚}j?…ÚÛUY-$Ìøœ%’ +ÊÂ_яÒ&f¤‰þ‰4˜‡¤nü¬¦(3É^“OðzN§’ùRÝke’Q/…Š”ª®4W)Öúb3}ˆ«àŽöÎL؇9›úM·¤ð&‚s‰ÍÐHj•¾…žQNYÛ +aúù‰ÙμÈÕh§ËÕ=è€V:iIW÷×Djà &RØãÉ©úD!½µVìõ„c¡n ¤Ê6ªdÒMԓbîÕ¯LšÉæ‰Ý­[tѧ©>žðÛÜõa.ÿŒÄêF’œïçˆÍ}Ó½F¬8¼ +hãŠýö+79UÜyGc=ÍMOÜÊüƒÇnB‚0°>TžJØb¢?kµÆ§7e¿ÃÖ=/㼑כÌ ¥Ëú¼ö LK©úö­Êw±kݜ×Ðí7Înå•vD—Qž©†!Crb—Š=¼Ð–é7-ȏ·a@º&O¾cˆÈz4Oùû¯îÂ"`Jz_¥ÒrŠ ²Ï•7-|ïkW0=z/ìY3˜Ð&\½%H!Ñ*EKýfÚzÏ(¬q]Ÿ¬Š ÅuµÆËj)Öu£h +E=t8&惬^KoO ¯1vU2¡´x­±¼]÷r¤–·ÚÆ"ACÓÈ0œÿ^ݕpNaã3–·ã¢T«·Ö3­õ‹T7õœ¨ëå…Ò!hÛ  ¥V$|ÏÂNžNU]fÝu^/ææΫ€¨_Úèlý¥'tƒ‰|Ñ 4ïb5‰ª³Ž-zi(dK ‹w€ÄÊtÇNb¼à®\c‚»ýeGˆÁ¹`,zË*r®ÝA0óµìÈKª¦Xß"µõ€~ë¾Ð¯•›Û'½x ð^¼*¨­›Ôßt8Q]1UåÈÍ7óã¤÷°=¥+þ]WJ€ÖÔöpó’Ìôñ°nkäu:Ò~¯™D·¥ü«yyúŠI1¾ªÚlŒ¡]¡8sýgéÆÑÁ_„ŠGɤ"[&ÞMSS00 å㵸tÛz\üíßÈׂ~ý³3]Lïs¶nÉ×ê$„r¶<„ðW ê|çÊ5ê>G˲|›9ZޔÖ?ÄÑêo:Ä¡À !‹¯r¦šyoʦª÷ö}Ûø öxQ]6¬žÈ—œ€6þ­nSè +ˆoÕßÀi„(%èÜÑ|­¦ÍÙêlêðõ£¦†ï}!C?§ÖåÇI±!݋—2‡©ŽxÙÜk–XŽžÁÇïˬnÇPû™â 3² ’)T‰ÿ<èÒ⦞†º…>«¡îe¨hJ‡cP»Aö5èi}ÄùW0ȽôÿÆVÿz*`š”iڂ¡F7` ï«|*î¤ :06]ÐÈ@yC¦Ý?©ô ßøI"±ìc³ã[g'h™3˜Å¹ì;PHo#2/Ì x5pÃö\ÐÎ,ÿ‰»üÿŒ + ¾ñBßØ/A{Þк/lŸä¹j³Ñ»+yÈP+mFÆn­Ó £õs<_×Ia¿WyY&ò’XeL6Ie(aûî%®Sáô¼ó¥‡M³n’µÿ.¼ªMÃ~+v½‹hÓ}Ü¥ íÚÄníãö¹¿Õ•ïÿ0µ˜ÎI[(Pé±¼¶ wÝûßzÑT°¢ÿyD©µÑ%¸+¼ë¿×_BüžíÑ7ªr}õÓ«S£¼ÕÕõv¥QÎ#üÿ…øñQ°—ÛÁlk^68)a7Ɛ¾-×Þ_馎æ¯òg‚÷×¥÷Wùbc½vѳ_££c|Òã_à's1Õ¡>7MÐñ!æ拍û÷mò›@ë½ã¤|bT0yM¼ ’Þ?bØÜ,ý:ý¯Ç¤ùÇÆò¶`ÒGRí©õއHýêä&dY5Ö WÀ½Ÿ­•ŒÐ“P>ò´\\ ù´ B`•;ý-É®.îþW²HÙ;çzAüŒ¿#Éq®¶:ÌZ¹=*‚»´Òl-Àw·Ÿÿ¦:r˜§µVH¾ot#¶è˜® v=’ëÔ:Œj,†ioÆh²z¹ߨš ¢¯Fšõބ#øâ;XiÁc_³Ãƒƒ]¶¯ž<¤ïÍ?ìÍÓ|Lǘaz,†A˜-êÕ!ËÀú`Õ¼1wµ>êžfu½o7ŽFÞÕ-p´¶P£u»Èþ·5/18#"2vòÅw½’íʋ˜¥5¨Ý¾¬ô]°”ÚfÂ8Š†UûÇE2YÐ5¸€gCÉcÿe|5PĤÖø’„´}àM³MF,zˆwÅȋãy\ "†™â}KlÙÈà{¤|ý‹–å +~º#?|w|獒AOƒ@…Ï쯘£6±T/4Öڋš4ö˜) °qYÈì.jˆÿ݁jj i˅ÌûÞ¼}K¸Ÿ×E­T<™(˜Àc¦ A] OµMzEۜ«PÃZÄ^ز¦ ƒÎíE ¾¨`…œOqN;”¢'çf6»…«þ%z‡ºmXVe‰6•9Vq mÛþËúôdSž×o N +ÝÐ_מ÷Ön:Öv^]ֆJ²½®ì©Ú ±\Og}·ã¥öá^) ²ÛЋ'F_±jU”›tÇBN~£s‹>0]\ªHXÄ$“… £;}«CÿÂhtçx™>´M¤A£Ós"¤:Ë-Æ2ÞékL¶ò9ÆôݲÐ&•¸3ï9°ÓVäQ~&ò}o|؎!7@ç?_9X-˪á~L†W^¡„d*ÿtGBMB \ No newline at end of file diff --git a/ext/phar/phar/clicommand.inc b/ext/phar/phar/clicommand.inc new file mode 100755 index 0000000000..067456d691 --- /dev/null +++ b/ext/phar/phar/clicommand.inc @@ -0,0 +1,377 @@ +argc = $argc; + $this->argv = $argv; + $this->cmds = self::getCommands($this); + $this->typs = self::getArgTyps($this); + + if ($argc < 2) { + self::error("No command given, check ${argv[0]} help\n"); + } elseif (!isset($this->cmds[$argv[1]]['run'])) { + self::error("Unknown command '${argv[1]}', check ${argv[0]} help\n"); + } else { + $command = $argv[1]; + } + + if (isset($this->cmds[$command]['arg'])) { + $this->args = call_user_func(array($this, $this->cmds[$command]['arg'])); + $i = 1; + $missing = false; + while (++$i < $argc) { + if ($argv[$i][0] == '-') { + if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]])) { + $arg = $argv[$i][1]; + if (++$i >= $argc) { + self::error("Missing argument to parameter '$arg' of command '$command', check ${argv[0]} help\n"); + } else { + $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv); + } + } else { + self::error("Unknown parameter '${argv[$i]}' to command $command, check ${argv[0]} help\n"); + } + } else { + break; + } + } + if (isset($this->args[''])) { + if ($i >= $argc) { + if (isset($this->args['']['require']) && $this->args['']['require']) { + self::error("Missing default trailing arguments to command $command, check ${argv[0]} help\n"); + } + } else { + $this->args['']['val'] = array(); + while($i < $argc) { + $this->args['']['val'][] = $argv[$i++]; + } + } + } else if ($i < $argc) { + self::error("Unexpected default arguments to command $command, check ${argv[0]} help\n"); + } + + foreach($this->args as $arg => $inf) { + if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required']) { + $missing .= "Missing parameter '-$arg' to command $command, check ${argv[0]} help\n"; + } + } + if (strlen($missing)) + { + self::error($missing); + } + } + + call_user_func(array($this, $this->cmds[$command]['run']), $this->args); + } + + static function notice ($msg) + { + fprintf(STDERR, $msg); + } + + static function error ($msg, $exit_code = 1) + { + self::notice($msg); + exit($exit_code); + } + + function checkArgTyp($arg, $i, $argc, $argv) + { + $typ = $this->args[$arg]['typ']; + + if (isset($this->typs[$typ]['typ'])) { + return call_user_func(array($this, $this->typs[$typ]['typ']), $argv[$i], $this->args[$arg], $arg); + } else { + return $argv[$i]; + } + } + + static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs) + { + $a = array(); + $r = new ReflectionClass($cmdclass); + $l = strlen($prefix); + + foreach($r->getMethods() as $m) + { + if (substr($m->name, 0, $l) == $prefix) + { + foreach($subs as $sub) + { + $what = substr($m->name, $l+strlen($sub)+1); + $func = $prefix . $sub . '_' . $what; + $what = str_replace('_', '-', $what); + if ($r->hasMethod($func)) + { + if (!isset($a[$what])) + { + $a[$what] = array(); + } + $a[$what][$sub] = /*$m->class . '::' .*/ $func; + } + } + } + } + return $a; + } + + static function getCommands(CLICommand $cmdclass) + { + return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run')); + } + + static function getArgTyps(CLICommand $cmdclass) + { + return self::getSubFuncs($cmdclass, 'cli_arg_', array('typ')); + } + + static function cli_arg_typ_bool($arg, $cfg, $key) + { + return (bool)$arg; + } + + + static function cli_arg_typ_int($arg, $cfg, $key) + { + if ((int)$arg != $arg) { + self::error("Argument to -$key must be an integer.\n"); + } + + return (int)$arg; + } + + static function cli_arg_typ_regex($arg, $cfg, $key) + { + if (strlen($arg)) + { + if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false) + { + return $arg; + } + else + { + return '/' . $arg . '/'; + } + } + else + { + return NULL; + } + } + + static function cli_arg_typ_select($arg, $cfg, $key) + { + if (!in_array($arg, array_keys($cfg['select']))) { + self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n"); + } + return $arg; + } + + static function cli_arg_typ_dir($arg, $cfg, $key) + { + $f = realpath($arg); + + if ($f===false || !file_exists($f) || !is_dir($f)) { + self::error("Requested path '$arg' does not exist.\n"); + } + return $f; + } + + static function cli_arg_typ_file($arg) + { + $f = new SplFileInfo($arg); + $f = $f->getRealPath(); + if ($f===false || !file_exists($f)) + { + echo "Requested file '$arg' does not exist.\n"; + exit(1); + } + return $f; + } + + static function cli_arg_typ_filenew($arg, $cfg, $key) + { + $d = dirname($arg); + $f = realpath($d); + + if ($f === false) { + self::error("Path for file '$arg' does not exist.\n"); + } + return $f . '/' . basename($arg); + } + + static function cli_arg_typ_filecont($arg, $cfg, $key) + { + return file_get_contents(self::cli_arg_typ_file($arg, $cfg, $key)); + } + + function cli_get_SP2($l1, $arg_inf) + { + return str_repeat(' ', $l1 + 2 + 4 + 8); + } + + function cli_get_SP3($l1, $l2, $arg_inf) + { + return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2); + } + + static function cli_cmd_inf_help() + { + return "This help or help for a selected command."; + } + + private function cli_wordwrap($what, $l, $sp) + { + $p = max(79 - $l, 40); // minimum length for paragraph + $b = substr($what, 0, $l); // strip out initial $l + $r = substr($what, $l); // remainder + $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's + return $b . wordwrap($r, $p, "\n".$sp); + } + + private function cli_help_get_args($func, $l, $sp, $required) + { + $inf = ""; + foreach(call_user_func($func, $l, $sp) as $arg => $conf) + { + if ((isset($conf['required']) && $conf['required']) != $required) + { + continue; + } + if (strlen($arg)) + { + $arg = "-$arg "; + } + else + { + $arg = "... "; + } + $sp2 = $this->cli_get_SP2($l, $inf); + $l2 = strlen($sp2); + $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n"; + if (isset($conf['select']) && count($conf['select'])) + { + $ls = 0; + foreach($conf['select'] as $opt => $what) + { + $ls = max($ls, strlen($opt)); + } + $sp3 = $this->cli_get_SP3($l, $ls, $inf); + $l3 = strlen($sp3); + foreach($conf['select'] as $opt => $what) + { + $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-${ls}s ", $opt) . $what, $l3, $sp3) . "\n"; + } + } + } + if (strlen($inf)) + { + if ($required) + { + return $sp . "Required arguments:\n\n" . $inf; + } + else + { + return $sp . "Optional arguments:\n\n". $inf; + } + } + } + + function cli_cmd_arg_help() + { + return array('' => array('typ'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.')); + } + + function cli_cmd_run_help() + { + $argv = $this->argv; + $which = $this->args['']['val']; + if (isset($which)) + { + if (count($which) != 1) { + self::error("More than one command given.\n"); + } + + $which = $which[0]; + if (!array_key_exists($which, $this->cmds)) { + self::error("Unknown command, cannot retrieve help.\n"); + } + + $l = strlen($which); + $cmds = array($which => $this->cmds[$which]); + } else { + echo "\n$argv[0] [options]\n\n"; + $l = 0; + ksort($this->cmds); + foreach($this->cmds as $name => $funcs) { + $l = max($l, strlen($name)); + } + $inf = "Commands:"; + $lst = ""; + $ind = strlen($inf) + 1; + foreach($this->cmds as $name => $funcs) + { + $lst .= ' ' . $name; + } + echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n"; + $cmds = $this->cmds; + } + $sp = str_repeat(' ', $l + 2); + foreach($cmds as $name => $funcs) + { + $inf = $name . substr($sp, strlen($name)); + if (isset($funcs['inf'])) + { + $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n"; + if (isset($funcs['arg'])) + { + $inf .= "\n"; + $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true); + $inf .= "\n"; + $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false); + } + } + echo "$inf\n\n"; + } + exit(0); + } + + static function cli_cmd_inf_help_list() + { + return "Lists available commands."; + } + + function cli_cmd_run_help_list() + { + ksort($this->cmds); + $lst = ''; + foreach($this->cmds as $name => $funcs) { + $lst .= $name . ' '; + } + echo substr($lst, 0, -1) . "\n"; + } +} + +?> diff --git a/ext/phar/phar/phar.php b/ext/phar/phar/phar.php new file mode 100755 index 0000000000..68a437b206 --- /dev/null +++ b/ext/phar/phar/phar.php @@ -0,0 +1,57 @@ +#!/usr/local/bin/php + \ No newline at end of file diff --git a/ext/phar/phar/pharcommand.inc b/ext/phar/phar/pharcommand.inc new file mode 100755 index 0000000000..e95f138d86 --- /dev/null +++ b/ext/phar/phar/pharcommand.inc @@ -0,0 +1,1442 @@ + array( + 'typ' => 'alias', + 'val' => NULL, + 'inf' => ' Provide an alias name for the phar file.' + ), + 'b' => array( + 'typ' => 'any', + 'val' => NULL, + 'inf' => ' Hash-bang line to start the archive (e.g. #!/usr/bin/php). The hash ' + .' mark itself \'#!\' and the newline character are optional.' + ), + 'c' => array( + 'typ' => 'compalg', + 'val' => NULL, + 'inf' => ' Compression algorithm.', + 'select' => array( + '0' => 'No compression', + 'none' => 'No compression', + 'auto' => 'Automatically select compression algorithm' + ) + ), + 'e' => array( + 'typ' => 'entry', + 'val' => NULL, + 'inf' => ' Name of entry to work on (must include PHAR internal directory name if any).' + ), + 'f' => array( + 'typ' => $phartype, + 'val' => NULL, + 'inf' => ' Specifies the phar file to work on.' + ), + 'h' => array( + 'typ' => 'select', + 'val' => NULL, + 'inf' => ' Selects the hash algorithmn.', + 'select' => array('md5' => 'MD5','sha1' => 'SHA1') + ), + 'i' => array( + 'typ' => 'regex', + 'val' => NULL, + 'inf' => ' Specifies a regular expression for input files.' + ), + 'k' => array( + 'typ' => 'any', + 'val' => NULL, + 'inf' => ' Subscription index to work on.', + ), + 'l' => array( + 'typ' => 'int', + 'val' => 0, + 'inf' => ' Number of preceeding subdirectories to strip from file entries', + ), + 'm' => array( + 'typ' => 'any', + 'val' => NULL, + 'inf' => ' Meta data to store with entry (serialized php data).' + ), + 'p' => array( + 'typ' => 'loader', + 'val' => NULL, + 'inf' => ' Location of PHP_Archive class file (pear list-files PHP_Archive).' + .'You can use \'0\' or \'1\' to locate it automatically using the mentioned ' + .'pear command. When using \'0\' the command does not error out when the ' + .'class file cannot be located. This switch also adds some code around the ' + .'stub so that class PHP_Archive gets registered as phar:// stream wrapper ' + .'if necessary. And finally this switch will add the file phar.inc from ' + .'this package and load it to ensure class Phar is present.' + , + ), + 's' => array( + 'typ' => 'file', + 'val' => NULL, + 'inf' => ' Select the stub file.' + ), + 'x' => array( + 'typ' => 'regex', + 'val' => NULL, + 'inf' => ' Regular expression for input files to exclude.' + ), + + ); + + if (extension_loaded('zlib')) { + $phar_args['c']['select']['gz'] = 'GZip compression'; + $phar_args['c']['select']['gzip'] = 'GZip compression'; + } + + if (extension_loaded('bz2')) { + $phar_args['c']['select']['bz2'] = 'BZip2 compression'; + $phar_args['c']['select']['bzip2'] = 'BZip2 compression'; + } + + $hash_avail = Phar::getSupportedSignatures(); + if (in_array('SHA-256', $hash_avail)) { + $phar_args['h']['select']['sha256'] = 'SHA256'; + } + + if (in_array('SHA-512', Phar::getSupportedSignatures())) { + $phar_args['h']['select']['sha512'] = 'SHA512'; + } + + $args = array(); + + foreach($phar_args as $lkey => $cfg) { + $ukey = strtoupper($lkey); + $required = strpos($which, $ukey) !== false; + $optional = strpos($which, $lkey) !== false; + + if ($required || $optional) { + $args[$lkey] = $cfg; + $args[$lkey]['required'] = $required; + } + } + return $args; + } + // }}} + // {{{ static function strEndsWith + /** + * String Ends With + * + * Wether a string end with another needle. + * + * @param string $haystack The haystack + * @param string $needle The needle. + * @return mixed false if doesn't end with anything, the string + * substr'ed if the string ends with the needle. + */ + static function strEndsWith($haystack, $needle) + { + return substr($haystack, -strlen($needle)) == $needle; + } + // }}} + // {{{ static function cli_arg_typ_loader + /** + * Argument type loader + * + * @param string $arg Either 'auto', 'optional' or an filename that + * contains class PHP_Archive + * @param string $cfg Configuration to pass to a new file + * @param string $key The key + * @return string $arg The argument. + */ + static function cli_arg_typ_loader($arg, $cfg, $key) + { + if (($arg == '0' || $arg == '1') && !file_exists($arg)) { + $found = NULL; + foreach(split("\n", `pear list-files PHP_Archive`) as $ent) { + $matches = NULL; + if (preg_match(",^php[ \t]+([^ \t].*pear[\\\\/]PHP[\\\\/]Archive.php)$,", $ent, $matches)) { + $found = $matches[1]; + break; + } + } + if (!isset($found)) { + $msg = "Pear package PHP_Archive or Archive.php class file not found.\n"; + if ($arg == '0') { + self::notice($msg); + } else { + self::error($msg); + } + } + $arg = $found; + } + return self::cli_arg_typ_file($arg); + } + // }}} + // {{{ static function cli_arg_typ_pharnew + /** + * Argument type new phar + * + * @param string $arg The new phar component. + * @param string $cfg Configuration to pass to a new file + * @param string $key The key + * @return string $arg The new argument file. + */ + static function cli_arg_typ_pharnew($arg, $cfg, $key) + { + $arg = self::cli_arg_typ_filenew($arg, $cfg, $key); + if (!Phar::isValidPharFilename($arg)) { + self::error("Phar files must have file extension '.phar', '.phar.php', '.phar.bz2' or '.phar.gz'.\n"); + } + return $arg; + } + // }}} + // {{{ static function cli_arg_typ_pharfile + /** + * Argument type existing Phar file + * + * Return filenam eof an existing Phar. + * + * @param string $arg The file in the phar to open. + * @param string $cfg The configuration information + * @param string $key The key information. + * @return string $pharfile The name of the loaded Phar file. + * @note The Phar will be loaded + */ + static function cli_arg_typ_pharfile($arg, $cfg, $key) + { + try { + $pharfile = self::cli_arg_typ_file($arg, $cfg, $key); + + if (!Phar::loadPhar($pharfile)) { + self::error("Unable to open phar '$arg'\n"); + } + + return $pharfile; + } catch(Exception $e) { + self::error("Exception while opening phar '$arg':\n" . $e->getMessage() . "\n"); + } + } + // }}} + // {{{ static function cli_arg_typ_pharurl + /** + * Argument type Phar url-like + * + * Check the argument as cli_arg_Typ_phar and return its name prefixed + * with phar:// + * + * Ex: + * + * $arg = 'pharchive.phar/file.php'; + * cli_arg_typ_pharurl($arg) + * + * + * @param string $arg The url-like phar archive to retrieve. + * @return string The phar file-archive. + */ + static function cli_arg_typ_pharurl($arg, $cfg, $key) + { + return 'phar://' . self::cli_arg_typ_pharfile($arg, $cfg, $key); + } + // }}} + // {{{ static function cli_arg_typ_phar + /** + * Cli argument type phar + * + * @param string $arg The phar archive to use. + * @return object new Phar of the passed argument. + */ + static function cli_arg_typ_phar($arg, $cfg, $key) + { + try { + return new Phar(self::cli_arg_typ_pharfile($arg, $cfg, $key)); + } catch(Exception $e) { + self::error("Exception while opening phar '$argv':\n" . $e->getMessage() . "\n"); + } + } + // }}} + // {{{ static function cli_arg_typ_entry + /** + * Argument type Entry name + * + * @param string $arg The argument (the entry) + * @return string $arg The entry itself. + */ + static function cli_arg_typ_entry($arg, $cfg, $key) + { + // no further check atm, maybe check for no '/' at beginning + return $arg; + } + // }}} + // {{{ static function cli_arg_typ_compalg + /** + * Argument type compression algorithm + * + * @param string $arg The phar selection + * @param string $cfg The config option. + * @param string $key The key information. + * @return string $arg The selected algorithm + */ + static function cli_arg_typ_compalg($arg, $cfg, $key) + { + $arg = self::cli_arg_typ_select($arg, $cfg, $key); + + switch($arg) { + case 'auto': + if (extension_loaded('zlib')) { + $arg = 'gz'; + } elseif (extension_loaded('bz2')) { + $arg = 'bz2'; + } else { + $arg = '0'; + } + break; + } + return $arg; + } + // }}} + // {{{ static function cli_cmd_inf_pack + /** + * Information pack + * + * @return string A description about packing files into a Phar archive. + */ + static function cli_cmd_inf_pack() + { + return "Pack files into a PHAR archive.\n" . + "When using -s , then the stub file is being " . + "excluded from the list of input files/dirs." . + "To create an archive that contains PEAR class PHP_Archiave " . + "then point -p argument to PHP/Archive.php.\n"; + } + // }}} + // {{{ static function cli_cmd_arg_pack + /** + * Pack a new phar infos + * + * @return array $args The arguments for a new Phar archive. + */ + static function cli_cmd_arg_pack() + { + $args = self::phar_args('abcFhilpsx', 'pharnew'); + + $args[''] = array( + 'typ' => 'any', + 'val' => NULL, + 'required' => 1, + 'inf' => ' Any number of input files and directories. If -i is in use then ONLY files and matching thegiven regular expression are being packed. If -x is given then files matching that regular expression are NOT being packed.', + + ); + + return $args; + } + // }}} + // {{{ function phar_set_stub_begin + /** + * Set the stub + */ + public function phar_set_stub_begin(Phar $phar, $stub, $loader = NULL, $hashbang = NULL) + { + if (isset($stub)) { + $c = file_get_contents($stub); + + if (substr($c, 0, 2) == '#!') { + if (strpos($c, "\n") !== false) { + if (!isset($hashbang)) { + $hashbang = substr($c, 0, strpos($c, "\n") + 1); + } + $c = substr($c, strpos($c, "\n") + 1); + } else { + if (!isset($hashbang)) { + $hashbang = $c; + } + $c = NULL; + } + } + + if (isset($hashbang)) { + if (substr($hashbang, 0, 2) != '#!') { + $hashbang = '#!' . $hashbang; + } + if (substr($hashbang, -1) != "\n") { + $hashbang .= "\n"; + } + } else { + $hashbang = ""; + } + + if (isset($loader)) { + $s = ""; + $s .= file_get_contents($loader); + $s .= "'; + $s .= $c; + + $phar->setStub($hashbang . $s); + } else { + $phar->setStub($hashbang . $c); + } + return new SplFileInfo($stub); + } + return NULL; + } + // }}} + // {{{ function phar_set_stub_end + /** + * Set stub end + */ + public function phar_set_stub_end(Phar $phar, $stub, $loader = NULL) + { + if (isset($stub) && isset($loader)) { + if (substr(__FILE__, -15) == 'pharcommand.inc') { + self::phar_add_file($phar, 0, 'phar.inc', 'phar://'.__FILE__.'/phar.inc', NULL); + } else { + self::phar_add_file($phar, 0, 'phar.inc', dirname(__FILE__).'/phar/phar.inc', NULL); + } + } + } + // }}} + // {{{ function cli_cmd_run_pack + /** + * Pack a new Phar + * + * This function will try to pack a new Phar archive. + * + * @see Exit to make sure that we are done. + */ + public function cli_cmd_run_pack() + { + if (ini_get('phar.readonly')) { + self::error("Creating phar files is disabled by ini setting 'phar.readonly'.\n"); + } + + if (!Phar::canWrite()) { + self::error("Creating phar files is disabled, Phar::canWrite() returned false.\n"); + } + + $alias = $this->args['a']['val']; + $hashbang = $this->args['b']['val']; + $archive = $this->args['f']['val']; + $hash = $this->args['h']['val']; + $regex = $this->args['i']['val']; + $level = $this->args['l']['val']; + $loader = $this->args['p']['val']; + $stub = $this->args['s']['val']; + $invregex = $this->args['x']['val']; + $input = $this->args['']['val']; + + $phar = new Phar($archive, 0, $alias); + + $phar->startBuffering(); + + $stub = $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang); + + if (!is_array($input)) { + $this->phar_add($phar, $level, $input, $regex, $invregex, $stub, NULL, isset($loader)); + } else { + foreach($input as $i) { + $this->phar_add($phar, $level, $i, $regex, $invregex, $stub, NULL, isset($loader)); + } + } + + $this->phar_set_stub_end($phar, $stub, $loader); + + switch($this->args['c']['val']) { + case 'gz': + case 'gzip': + $phar->compressAllFilesGZ(); + break; + case 'bz2': + case 'bzip2': + $phar->compressAllFilesBZIP2(); + break; + default: + $phar->uncompressAllFiles(); + break; + } + + if ($hash) { + $phar->setSignatureAlgorithm($hash); + } + + $phar->stopBuffering(); + exit(0); + } + // }}} + // {{{ static function phar_add + /** + * Add files to a phar archive. + * + * This function will take a directory and iterate through + * it and get the files to insert into the Phar archive. + * + * @param Phar $phar The phar object. + * @param string $input The input directory + * @param string $regex The regex use in RegexIterator. + * @param string $invregex The InvertedRegexIterator expression. + * @param SplFileInfo $stub Stub file object + * @param mixed $compress Compression algorithm or NULL + * @param boolean $noloader Whether to prevent adding the loader + */ + static function phar_add(Phar $phar, $level, $input, $regex, $invregex, SplFileInfo $stub = NULL, $compress = NULL, $noloader = false) + { + if ($input && is_file($input) && !is_dir($input)) { + return self::phar_add_file($phar, $level, $input, $input, $compress); + } + $dir = new RecursiveDirectoryIterator($input); + $dir = new RecursiveIteratorIterator($dir); + + if (isset($regex)) { + $dir = new RegexIterator($dir, $regex); + } + + if (isset($invregex)) { + $dir = new InvertedRegexIterator($dir, $invregex); + } + + try { + foreach($dir as $file) { + if (empty($stub) || $file->getRealPath() != $stub->getRealPath()) { + self::phar_add_file($phar, $level, $dir->getSubPathName(), $file, $compress, $noloader); + } + } + } catch(Excpetion $e) { + self::error("Unable to complete operation on file '$file'\n" . $e->getMessage() . "\n"); + } + } + // }}} + // {{{ static function phar_add_file + /** + * Add a phar file + * + * This function adds a file to a phar archive. + * + * @param Phar $phar The phar object + * @param string $level The level of the file. + * @param string $entry The entry point + * @param string $file The file to add to the archive + * @param string $compress The compression scheme for the file. + * @param boolean $noloader Whether to prevent adding the loader + */ + static function phar_add_file(Phar $phar, $level, $entry, $file, $compress, $noloader = false) + { + $entry = str_replace('//', '/', $entry); + while($level-- > 0 && ($p = strpos($entry, '/')) !== false) { + $entry = substr($entry, $p+1); + } + + if ($noloader && $entry == 'phar.inc') { + return; + } + + echo "$entry\n"; + + $phar[$entry] = file_get_contents($file); + switch($compress) { + case 'gz': + case 'gzip': + $phar[$entry]->setCompressedGZ(); + break; + case 'bz2': + case 'bzip2': + $phar[$entry]->setCompressedBZIP2(); + break; + default: + break; + } + } + // }}} + // {{{ public function phar_dir_echo + /** + * Echo directory + * + * @param string $pn + * @param unknown_type $f + */ + public function phar_dir_echo($pn, $f) + { + echo "$f\n"; + } + // }}} + // {{{ public function phar_dir_operation + /** + * Directory operations + * + * Phar directory operations. + * + * @param RecursiveIteratorIterator $dir The recursiveIteratorIterator object. + * @param string $func Function to call on the iterations + * @param array $args Function arguments. + */ + public function phar_dir_operation(RecursiveIteratorIterator $dir, $func, array $args = array()) + { + $regex = $this->args['i']['val']; + $invregex= $this->args['x']['val']; + + if (isset($regex)) { + $dir = new RegexIterator($dir, $regex); + } + + if (isset($invregex)) { + $dir = new InvertedRegexIterator($dir, $invregex); + } + + $any = false; + foreach($dir as $pn => $f) { + $any = true; + call_user_func($func, $pn, $f, $args); + } + return $any; + } + // {{{ static function cli_cmd_inf_list + /** + * Cli Command Info List + * + * @return string What inf does + */ + static function cli_cmd_inf_list() + { + return "List contents of a PHAR archive."; + } + // }}} + // {{{ static function cli_cmd_arg_list + /** + * Cli Command Argument List + * + * @return arguments list + */ + static function cli_cmd_arg_list() + { + return self::phar_args('Fix', 'pharurl'); + } + // }}} + // {{{ public function cli_cmd_run_list + /** + * Cli Command Run List + * + * @see $this->phar_dir_operation + */ + public function cli_cmd_run_list() + { + $this->phar_dir_operation( + new DirectoryTreeIterator( + $this->args['f']['val']), + array($this, 'phar_dir_echo') + ); + } + // }}} + // {{{ static function cli_command_inf_tree + /** + * Cli Command Inf Tree + * + * @return string The description of a directory tree for a Phar archive. + */ + static function cli_cmd_inf_tree() + { + return "Get a directory tree for a PHAR archive."; + } + // }}} + // {{{ static function cli_cmd_arg_tree + /** + * Cli Command Argument Tree + * + * @return string Arguments in URL format. + */ + static function cli_cmd_arg_tree() + { + return self::phar_args('Fix', 'pharurl'); + } + // }}} + // {{{ public function cli_cmd_run_tree + /** + * Cli Command Run Tree + * + * Set the phar_dir_operation with a directorygraphiterator. + * + * @see DirectoryGraphIterator + * @see $this->phar_dir_operation + * + */ + public function cli_cmd_run_tree() + { + $a = $this->phar_dir_operation( + new DirectoryGraphIterator( + $this->args['f']['val']), + array($this, 'phar_dir_echo') + ); + if (!$a) { + echo "|-\n"; + } + } + // }}} + // {{{ cli_cmd_inf_extract + /** + * Cli Command Inf Extract + * + * @return string The description of the command extra to a directory. + */ + static function cli_cmd_inf_extract() + { + return "Extract a PHAR package to a directory."; + } + // }}} + // {{{ static function cli_cmd_arg_extract + /** + * Cli Command Arguments Extract + * + * The arguments for the extract function. + * + * @return array The arguments for the extraction. + */ + static function cli_cmd_arg_extract() + { + $args = self::phar_args('Fix', 'phar'); + + $args[''] = array( + 'type' => 'dir', + 'val' => '.', + 'inf' => ' Directory to extract to (defaults to \'.\').', + ); + + return $args; + } + // }}} + // {{{ public function cli_cmd_run_extract + /** + * Run Extract + * + * Run the extraction of a phar Archive. + * + * @see $this->phar_dir_operation + */ + public function cli_cmd_run_extract() + { + $dir = $this->args['']['val']; + + if (is_array($dir)) { + if (count($dir) != 1) { + self::error("Only one target directory allowed.\n"); + } else { + $dir = $dir[0]; + } + } + + $phar = $this->args['f']['val']; + $base = $phar->getPathname(); + $bend = strpos($base, '.phar'); + $bend = strpos($base, '/', $bend); + $base = substr($base, 0, $bend + 1); + $blen = strlen($base); + + $this->phar_dir_operation( + new RecursiveIteratorIterator($phar), + array($this, 'phar_dir_extract'), + array($blen, $dir) + ); + } + // }}} + // {{{ public function phar_dir_extract + /** + * Extract to a directory + * + * This function will extract the content of a Phar + * to a directory and create new files and directories + * depending on the permissions on that folder. + * + * @param string $pn + * @param string $f The file name + * @param array $args The directory and Blen informations + */ + public function phar_dir_extract($pn, $f, $args) + { + $blen = $args[0]; + $dir = $args[1]; + $sub = substr($pn, $blen); + $target = $dir . '/' . $sub; + + if (!file_exists(dirname($target))) { + if (!is_writable(dirname($target))) { + self::error("Operation could not be completed\n"); + } + + mkdir(dirname($target)); + } + + echo "$sub"; + + if (!@copy($f, $target)) { + echo " ...error\n"; + } else { + echo " ...ok\n"; + } + } + // }}} + // {{{ static function cli_cmd_inf_delete + /** + * Delete an entry from a phar information. + * + * @return string The information + */ + static function cli_cmd_inf_delete() + { + return 'Delete entry from a PHAR archive'; + } + // }}} + // {{{ static function cli_cmd_arg_delete + /** + * The cli command argument for deleting. + * + * @return array informations about the arguments to use. + */ + static function cli_cmd_arg_delete() + { + return self::phar_args('FE', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_delete + /** + * Deleting execution + * + * Execute the deleting of the file from the phar archive. + */ + public function cli_cmd_run_delete() + { + $phar = $this->args['f']['val']; + $entry = $this->args['e']['val']; + + $phar->startBuffering(); + unset($phar[$entry]); + $phar->stopBuffering(); + } + // }}} + // {{{ static function cli_cmd_inf_add + /** + * Client comment add file information + * + * @return string The description of the feature + */ + static function cli_cmd_inf_add() + { + return "Add entries to a PHAR package."; + } + // }}} + // {{{ static function cli_cmd_arg_add + /** + * Add a file arguments + */ + static function cli_cmd_arg_add() + { + $args = self::phar_args('acFilx', 'phar'); + $args[''] = array( + 'type' => 'any', + 'val' => NULL, + 'required' => 1, + 'inf' => ' Any number of input files and directories. If -i is in use then ONLY files and matching thegiven regular expression are being packed. If -x is given then files matching that regular expression are NOT being packed.', + ); + return $args; + } + // }}} + // {{{ public functio cli_cmd_run_add + /** + * Add a file + * + * Run the action of adding a file to + * a phar archive. + */ + public function cli_cmd_run_add() + { + $compress= $this->args['c']['val']; + $phar = $this->args['f']['val']; + $regex = $this->args['i']['val']; + $level = $this->args['l']['val']; + $invregex= $this->args['x']['val']; + $input = $this->args['']['val']; + + $phar->startBuffering(); + + if (!is_array($input)) { + $this->phar_add($phar, $level, $input, $regex, $invregex, NULL, $compress); + } else { + foreach($input as $i) { + $this->phar_add($phar, $level, $i, $regex, $invregex, NULL, $compress); + } + } + $phar->stopBuffering(); + exit(0); + } + // }}} + // {{{ public function cli_cmd_inf_stub_set + /** + * Set the stup of a phar file. + * + * @return string The stub set description. + */ + public function cli_cmd_inf_stub_set() + { + return "Set the stub of a PHAR file. " . + "If no input file is specified as stub then stdin is being used."; + } + // }}} + // {{{ public function cli_cmd_arg_stub_set + /** + * Set the argument stub + * + * @return string arguments for a stub + */ + public function cli_cmd_arg_stub_set() + { + $args = self::phar_args('bFps', 'phar'); + $args['s']['val'] = 'php://stdin'; + return $args; + } + // }}} + // {{{ public function cli_cmd_run_stub_set + /** + * Cli Command run stub set + * + * @see $phar->setStub() + */ + public function cli_cmd_run_stub_set() + { + $hashbang = $this->args['b']['val']; + $phar = $this->args['f']['val']; + $stub = $this->args['s']['val']; + $loader = $this->args['p']['val']; + + $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang); + $this->phar_set_stub_end($phar, $stub, $loader); + } + // }}} + // {{{ public function cli_cmd_inf_stub_get + /** + * Get the command stub infos. + * + * @return string a description of the stub of a Phar file. + */ + public function cli_cmd_inf_stub_get() + { + return "Get the stub of a PHAR file. " . + "If no output file is specified as stub then stdout is being used."; + } + // }}} + // {{{ public function cli_cmd_arg_stub_get + /** + * Get the argument stub + * + * @return array $args The arguments passed to the stub. + */ + public function cli_cmd_arg_stub_get() + { + $args = self::phar_args('Fs', 'phar'); + $args['s']['val'] = 'php://stdin'; + return $args; + } + // }}} + // {{{ public function cli_cmd_run_stub_get + /** + * Cli Command Run Stub + * + * Get arguments and store them into a stub. + * + * @param arguments $args + * @see $this->args + */ + public function cli_cmd_run_stub_get($args) + { + $phar = $this->args['f']['val']; + $stub = $this->args['s']['val']; + + file_put_contents($stub, $phar->getStub()); + } + // }}} + // {{{ public function cli_cmd_inf_compress + /** + * Cli Command Inf Compress + * + * Cli Command compress informations + * + * @return string A description of the command. + */ + public function cli_cmd_inf_compress() + { + return "Compress or uncompress all files or a selected entry."; + } + // }}} + // {{{ public function cli_cmd_arg_cmpress + /** + * Cli Command Arg Compress + * + * @return array The arguments for compress + */ + public function cli_cmd_arg_compress() + { + return self::phar_args('FCe', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_compress + /** + * Cli Command Run Compress + * + * @see $this->args + */ + public function cli_cmd_run_compress() + { + $phar = $this->args['f']['val']; + $entry = $this->args['e']['val']; + + switch($this->args['c']['val']) { + case 'gz': + case 'gzip': + if (isset($entry)) { + $phar[$entry]->setCompressedGZ(); + } else { + $phar->compressAllFilesGZ(); + } + break; + case 'bz2': + case 'bzip2': + if (isset($entry)) { + $phar[$entry]->setCompressedBZIP2(); + } else { + $phar->compressAllFilesBZIP2(); + } + break; + default: + if (isset($entry)) { + $phar[$entry]->setUncompressed(); + } else { + $phar->uncompressAllFiles(); + } + break; + } + } + // }}} + // {{{ public function cli_cmd_inf_sign + /** + * Cli Command Info Signature + * + * @return string A description of the signature arguments. + */ + public function cli_cmd_inf_sign() + { + return "Set signature hash algorithm."; + } + // }}} + // {{{ public function cli_cmd_arg_sign + /** + * Cli Command Argument Sign + * + * @return array Arguments for Signature + */ + public function cli_cmd_arg_sign() + { + return self::phar_args('FH', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_sign + /** + * Cli Command Run Signature + * + * @see $phar->setSignaturealgorithm + */ + public function cli_cmd_run_sign() + { + $phar = $this->args['f']['val']; + $hash = $this->args['h']['val']; + + $phar->setSignatureAlgorithm($hash); + } + // }}} + // {{{ public function cli_cmd_inf_meta_set + /** + * Cli Command Inf Meta Set + * + * @return string A description + */ + public function cli_cmd_inf_meta_set() + { + return "Set meta data of a PHAR entry or a PHAR package using serialized input. " . + "If no input file is specified for meta data then stdin is being used." . + "You can also specify a particular index using -k. In that case the metadata is " . + "expected to be an array and the value of the given index is being set. If " . + "the metadata is not present or empty a new array will be created. If the " . + "metadata is present and a flat value then the return value is 1. Also using -k " . + "the input is been taken directly rather then being serialized."; + } + // }}} + // {{{ public function cli_cmd_arg_meta_set + /** + * Cli Command Argument Meta Set + * + * @return array The arguments for meta set + */ + public function cli_cmd_arg_meta_set() + { + return self::phar_args('FekM', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_met_set + /** + * Cli Command Run Metaset + * + * @see $phar->startBuffering + * @see $phar->setMetadata + * @see $phar->stopBuffering + */ + public function cli_cmd_run_meta_set() + { + $phar = $this->args['f']['val']; + $entry = $this->args['e']['val']; + $index = $this->args['k']['val']; + $meta = $this->args['m']['val']; + + $phar->startBuffering(); + + if (isset($index)) { + if (isset($entry)) { + if ($phar[$entry]->hasMetadata()) { + $old = $phar[$entry]->getMetadata(); + } else { + $old = array(); + } + } else { + if ($phar->hasMetadata()) { + $old = $phar->getMetadata(); + } else { + $old = array(); + } + } + + if (!is_array($old)) { + self::error('Metadata is a flat value while an index operation was issued.'); + } + + $old[$index] = $meta; + $meta = $old; + } else { + $meta = unserialize($meta); + } + + if (isset($entry)) { + $phar[$entry]->setMetadata($meta); + } else { + $phar->setMetadata($meta); + } + $phar->stopBuffering(); + } + // }}} + // {{{ public function cli_cmd_inf_met_get + /** + * Cli Command Inf Metaget + * + * @return string A description of the metaget arguments + */ + public function cli_cmd_inf_meta_get() + { + return "Get meta information of a PHAR entry or a PHAR package in serialized from. " . + "If no output file is specified for meta data then stdout is being used.\n" . + "You can also specify a particular index using -k. In that case the metadata is " . + "expected to be an array and the value of the given index is returned using echo " . + "rather than using serialize. If that index does not exist or no meta data is " . + "present then the return value is 1."; + } + // }}} + // {{{ public function cli_cmd_arg_meta_get + /** + * Cli Command arg metaget + * + * @return array The arguments for meta get. + */ + public function cli_cmd_arg_meta_get() + { + return self::phar_args('Fek', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_meta_get + /** + * Cli Command Run Metaget + * + * @see $this->args + * @see $phar[$x]->hasMetadata() + * @see $phar->getMetadata() + */ + public function cli_cmd_run_meta_get() + { + $phar = $this->args['f']['val']; + $entry = $this->args['e']['val']; + $index = $this->args['k']['val']; + + if (isset($entry)) { + if (!$phar[$entry]->hasMetadata()) { + echo "No Metadata\n"; + exit(1); + } + echo serialize($phar[$entry]->getMetadata()); + } else { + if (!$phar->hasMetadata()) { + echo "No Metadata\n"; + exit(1); + } + $meta = $phar->getMetadata(); + } + + if (isset($index)) { + if (isset($index)) { + if (isset($meta[$index])) { + echo $meta[$index]; + exit(0); + } else { + echo "No Metadata\n"; + exit(1); + } + } else { + echo serialize($meta); + } + } + } + // }}} + // {{{ public function cli_cmd_inf_meta_del + /** + * Cli Command Inf Metadel + * + * @return string A description of the metadel function + */ + public function cli_cmd_inf_meta_del() + { + return "Delete meta information of a PHAR entry or a PHAR package.\n" . + "If -k is given then the metadata is expected to be an array " . + "and the given index is being deleted.\n" . + "If something was deleted the return value is 0 otherwise it is 1."; + } + // }}} + // {{{ public function cli_cmd_arg_meta_del + /** + * CliC ommand Arg Metadelete + * + * @return array The arguments for metadel + */ + public function cli_cmd_arg_meta_del() + { + return self::phar_args('Fek', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_meta_del + /** + * Cli Command Run MetaDel + * + * @see $phar[$x]->delMetadata() + * @see $phar->delMetadata() + */ + public function cli_cmd_run_meta_del() + { + $phar = $this->args['f']['val']; + $entry = $this->args['e']['val']; + $index = $this->args['k']['val']; + + if (isset($entry)) { + if (isset($index)) { + if (!$phar[$entry]->hasMetadata()) { + exit(1); + } + $meta = $phar[$entry]->getMetadata(); + + // @todo add error message here. + if (!is_array($meta)) { + exit(1); + } + + unset($meta[$index]); + $phar[$entry]->setMetadata($meta); + } else { + exit($phar[$entry]->delMetadata() ? 0 : 1); + } + } else { + if (isset($index)) { + if (!$phar->hasMetadata()) { + exit(1); + } + + $meta = $phar->getMetadata(); + + // @todo Add error message + if (!is_array($meta)) { + exit(1); + } + + unset($meta[$index]); + $phar->setMetadata($meta); + } else { + exit($phar->delMetadata() ? 0 : 1); + } + } + } + // }}} + // {{{ public function cli_cmd_inf_info + /** + * CLi Command Inf Info + * + * @return string A description about the info commands. + */ + public function cli_cmd_inf_info() + { + return "Get information about a PHAR package.\n" . + "By using -k it is possible to return a single value."; + } + // }}} + // {{{ public function cli_cmd_arg_info + /** + * Cli Command Arg Infos + * + * @return array The arguments for info command. + */ + public function cli_cmd_arg_info() + { + return self::phar_args('Fk', 'phar'); + } + // }}} + // {{{ public function cli_cmd_run_info + /** + * Cli Command Run Info + * + * @param args $args + */ + public function cli_cmd_run_info() + { + $phar = $this->args['f']['val']; + $index = $this->args['k']['val']; + + $hash = $phar->getSignature(); + $infos = array(); + + if ($phar->getAlias()) { + $infos['Alias'] = $phar->getAlias(); + } + + if (!$hash) { + $infos['Hash-type'] = 'NONE'; + } else { + $infos['Hash-type'] = $hash['hash_type']; + $infos['Hash'] = $hash['hash']; + } + + $csize = 0; + $usize = 0; + $count = 0; + $ccount = 0; + $ucount = 0; + $mcount = 0; + $compalg = array('GZ'=>0, 'BZ2'=>0); + + foreach(new RecursiveIteratorIterator($phar) as $ent) { + $count++; + if ($ent->isCompressed()) { + $ccount++; + $csize += $ent->getCompressedSize(); + if ($ent->isCompressedGZ()) { + $compalg['GZ']++; + } elseif ($ent->isCompressedBZIP2()) { + $compalg['BZ2']++; + } + } else { + $ucount++; + $csize += $ent->getSize(); + } + + $usize += $ent->getSize(); + + if ($ent->hasMetadata()) { + $mcount++; + } + } + + $infos['Entries'] = $count; + $infos['Uncompressed-files'] = $ucount; + $infos['Compressed-files'] = $ccount; + $infos['Compressed-gz'] = $compalg['GZ']; + $infos['Compressed-bz2'] = $compalg['BZ2']; + $infos['Uncompressed-size'] = $usize; + $infos['Compressed-size'] = $csize; + $infos['Compression-ratio'] = sprintf('%.3g%%', $usize ? ($csize * 100) / $usize : 100); + $infos['Metadata-global'] = $phar->hasMetadata() * 1; + $infos['Metadata-files'] = $mcount; + $infos['Stub-size'] = strlen($phar->getStub()); + + if (isset($index)) { + if (!isset($infos[$index])) { + self::error("Requested value does not exist.\n"); + } + + echo $infos[$index]; + exit(0); + } + + $l = 0; + foreach($infos as $which => $val) { + $l = max(strlen($which), $l); + } + + foreach($infos as $which => $val) { + echo $which . ':' . str_repeat(' ', $l + 1 - strlen($which)) . $val . "\n"; + } + } + // }}} +} +// }}} +?> diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h new file mode 100755 index 0000000000..1aa5425125 --- /dev/null +++ b/ext/phar/phar_internal.h @@ -0,0 +1,470 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "php.h" +#include "tar.h" +#include "php_ini.h" +#include "zend_constants.h" +#include "zend_execute.h" +#include "zend_exceptions.h" +#include "zend_hash.h" +#include "zend_interfaces.h" +#include "zend_operators.h" +#include "zend_qsort.h" +#include "zend_vm.h" +#include "main/php_streams.h" +#include "main/streams/php_stream_plain_wrapper.h" +#include "main/SAPI.h" +#include "main/php_main.h" +#include "main/php_open_temporary_file.h" +#include "ext/standard/info.h" +#include "ext/standard/basic_functions.h" +#include "ext/standard/file.h" +#include "ext/standard/php_string.h" +#include "ext/standard/url.h" +#include "ext/standard/crc32.h" +#include "ext/standard/md5.h" +#include "ext/standard/sha1.h" +#include "ext/standard/php_var.h" +#include "ext/standard/php_smart_str.h" +#include "ext/standard/php_versioning.h" +#ifndef PHP_WIN32 +#include "TSRM/tsrm_strtok_r.h" +#endif +#include "TSRM/tsrm_virtual_cwd.h" +#if HAVE_SPL +#include "ext/spl/spl_array.h" +#include "ext/spl/spl_directory.h" +#include "ext/spl/spl_engine.h" +#include "ext/spl/spl_exceptions.h" +#include "ext/spl/spl_iterators.h" +#endif +#include "php_phar.h" +#ifdef HAVE_STDINT_H +#include +#endif +#if HAVE_HASH_EXT +#include "ext/hash/php_hash.h" +#include "ext/hash/php_hash_sha.h" +#endif + +#ifndef E_RECOVERABLE_ERROR +#define E_RECOVERABLE_ERROR E_ERROR +#endif + +/* PHP_ because this is public information via MINFO */ +#define PHP_PHAR_API_VERSION "1.1.1" +/* x.y.z maps to 0xyz0 */ +#define PHAR_API_VERSION 0x1110 +/* if we bump PHAR_API_VERSION, change this from 0x1100 to PHAR_API_VERSION */ +#define PHAR_API_VERSION_NODIR 0x1100 +#define PHAR_API_MIN_DIR 0x1110 +#define PHAR_API_MIN_READ 0x1000 +#define PHAR_API_MAJORVERSION 0x1000 +#define PHAR_API_MAJORVER_MASK 0xF000 +#define PHAR_API_VER_MASK 0xFFF0 + +#define PHAR_HDR_COMPRESSION_MASK 0x0000F000 +#define PHAR_HDR_COMPRESSED_NONE 0x00000000 +#define PHAR_HDR_COMPRESSED_GZ 0x00001000 +#define PHAR_HDR_COMPRESSED_BZ2 0x00002000 +#define PHAR_HDR_SIGNATURE 0x00010000 + +/* flags for defining that the entire file should be compressed */ +#define PHAR_FILE_COMPRESSION_MASK 0x00F00000 +#define PHAR_FILE_COMPRESSED_NONE 0x00000000 +#define PHAR_FILE_COMPRESSED_GZ 0x00100000 +#define PHAR_FILE_COMPRESSED_BZ2 0x00200000 + +#define PHAR_SIG_MD5 0x0001 +#define PHAR_SIG_SHA1 0x0002 +#define PHAR_SIG_SHA256 0x0003 +#define PHAR_SIG_SHA512 0x0004 +#define PHAR_SIG_PGP 0x0010 + +/* flags byte for each file adheres to these bitmasks. + All unused values are reserved */ +#define PHAR_ENT_COMPRESSION_MASK 0x0000F000 +#define PHAR_ENT_COMPRESSED_NONE 0x00000000 +#define PHAR_ENT_COMPRESSED_GZ 0x00001000 +#define PHAR_ENT_COMPRESSED_BZ2 0x00002000 + +#define PHAR_ENT_PERM_MASK 0x000001FF +#define PHAR_ENT_PERM_MASK_USR 0x000001C0 +#define PHAR_ENT_PERM_SHIFT_USR 6 +#define PHAR_ENT_PERM_MASK_GRP 0x00000038 +#define PHAR_ENT_PERM_SHIFT_GRP 3 +#define PHAR_ENT_PERM_MASK_OTH 0x00000007 +#define PHAR_ENT_PERM_DEF_FILE 0x000001B6 +#define PHAR_ENT_PERM_DEF_DIR 0x000001FF + +#define PHAR_FORMAT_SAME 0 +#define PHAR_FORMAT_PHAR 1 +#define PHAR_FORMAT_TAR 2 +#define PHAR_FORMAT_ZIP 3 + +#define TAR_FILE '0' +#define TAR_LINK '1' +#define TAR_SYMLINK '2' +#define TAR_DIR '5' +#define TAR_NEW '8' + +ZEND_BEGIN_MODULE_GLOBALS(phar) + HashTable phar_fname_map; + HashTable phar_alias_map; + HashTable phar_SERVER_mung_list; + int readonly; + zend_bool readonly_orig; + zend_bool require_hash_orig; + int request_init; + int require_hash; + int request_done; + int request_ends; + void (*orig_fopen)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_file_get_contents)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_link)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_dir)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_opendir)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_fileperms)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_fileinode)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_filesize)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_fileowner)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_filegroup)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_fileatime)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_filemtime)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_filectime)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_filetype)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_writable)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_is_executable)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_lstat)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_readfile)(INTERNAL_FUNCTION_PARAMETERS); + void (*orig_stat)(INTERNAL_FUNCTION_PARAMETERS); + /* used for includes with . in them inside front controller */ + char* cwd; + int cwd_len; + int cwd_init; +ZEND_END_MODULE_GLOBALS(phar) + +ZEND_EXTERN_MODULE_GLOBALS(phar) + +#ifdef ZTS +# include "TSRM.h" +# define PHAR_G(v) TSRMG(phar_globals_id, zend_phar_globals *, v) +# define PHAR_GLOBALS ((zend_phar_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phar_globals_id)]) +#else +# define PHAR_G(v) (phar_globals.v) +# define PHAR_GLOBALS (&phar_globals) +#endif + +#ifndef php_uint16 +# if SIZEOF_SHORT == 2 +# define php_uint16 unsigned short +# else +# define php_uint16 uint16_t +# endif +#endif +#include "pharzip.h" + +#if HAVE_SPL +typedef union _phar_archive_object phar_archive_object; +typedef union _phar_entry_object phar_entry_object; +#endif + +/* + * used in phar_entry_info->fp_type to + */ +enum phar_fp_type { + /* regular file pointer phar_archive_data->fp */ + PHAR_FP, + /* uncompressed file pointer phar_archive_data->uncompressed_fp */ + PHAR_UFP, + /* modified file pointer phar_entry_info->fp */ + PHAR_MOD, + /* temporary manifest entry (file outside of the phar mapped to a location inside the phar) + this entry stores the stream to open in link (normally used for tars, but we steal it here) */ + PHAR_TMP +}; + +typedef struct _phar_archive_data phar_archive_data; +/* entry for one file in a phar file */ +typedef struct _phar_entry_info { + /* first bytes are exactly as in file */ + php_uint32 uncompressed_filesize; + php_uint32 timestamp; + php_uint32 compressed_filesize; + php_uint32 crc32; + php_uint32 flags; + /* remainder */ + /* when changing compression, save old flags in case fp is NULL */ + php_uint32 old_flags; + zval *metadata; + php_uint32 filename_len; + char *filename; + enum phar_fp_type fp_type; + /* offset within original phar file of the file contents */ + long offset_abs; + /* offset within fp of the file contents */ + long offset; + /* offset within original phar file of the file header (for zip-based/tar-based) */ + long header_offset; + php_stream *fp; + php_stream *cfp; + int fp_refcount; + int is_crc_checked:1; + int is_modified:1; + int is_deleted:1; + int is_dir:1; + /* this flag is used for mounted entries (external files mapped to location + inside a phar */ + int is_mounted:1; + char *tmp; + /* used when iterating */ + int is_temp_dir:1; + phar_archive_data *phar; + smart_str metadata_str; + /* tar-based phar file stuff */ + int is_tar:1; + char *link; /* symbolic link to another file */ + char tar_type; + /* zip-based phar file stuff */ + int is_zip:1; +} phar_entry_info; + +/* information about a phar file (the archive itself) */ +struct _phar_archive_data { + char *fname; + int fname_len; + /* for phar_detect_fname_ext, this stores the location of the file extension within fname */ + char *ext; + int ext_len; + char *alias; + int alias_len; + char version[12]; + size_t internal_file_start; + size_t halt_offset; + HashTable manifest; + /* hash of mounted directory paths */ + HashTable mounted_dirs; + php_uint32 flags; + php_uint32 min_timestamp; + php_uint32 max_timestamp; + php_stream *fp; + /* decompressed file contents are stored here */ + php_stream *ufp; + int refcount; + php_uint32 sig_flags; + int sig_len; + char *signature; + zval *metadata; + /* if 1, then this alias was manually specified by the user and is not a permanent alias */ + int is_temporary_alias:1; + int is_modified:1; + int is_writeable:1; + int is_brandnew:1; + /* defer phar creation */ + int donotflush:1; + /* zip-based phar variables */ + int is_zip:1; + /* tar-based phar variables */ + int is_tar:1; + /* PharData variables */ + int is_data:1; +}; + +#define PHAR_MIME_PHP '\0' +#define PHAR_MIME_PHPS '\1' +#define PHAR_MIME_OTHER '\2' + +typedef struct _phar_mime_type { + char *mime; + int len; + /* one of PHAR_MIME_* */ + char type; +} phar_mime_type; + +/* stream access data for one file entry in a phar file */ +typedef struct _phar_entry_data { + phar_archive_data *phar; + php_stream *fp; + /* stream position proxy, allows multiple open streams referring to the same fp */ + off_t position; + /* for copies of the phar fp, defines where 0 is */ + off_t zero; + int for_write:1; + int is_zip:1; + int is_tar:1; + phar_entry_info *internal_file; +} phar_entry_data; + +#if HAVE_SPL +/* archive php object */ +union _phar_archive_object { + zend_object std; + spl_filesystem_object spl; + struct { + zend_object std; + phar_archive_data *archive; + } arc; +}; +#endif + +#if HAVE_SPL +/* entry php object */ +union _phar_entry_object { + zend_object std; + spl_filesystem_object spl; + struct { + zend_object std; + phar_entry_info *entry; + } ent; +}; +#endif + +#ifndef PHAR_MAIN +extern int phar_has_bz2; +extern int phar_has_zlib; +# if PHP_VERSION_ID >= 50300 +extern char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC); +# endif +#endif + +BEGIN_EXTERN_C() + + +#ifdef PHP_WIN32 +char *tsrm_strtok_r(char *s, const char *delim, char **last); + +static inline void phar_unixify_path_separators(char *path, int path_len) +{ + char *s; + + /* unixify win paths */ + for (s = path; s - path < path_len; ++s) { + if (*s == '\\') { + *s = '/'; + } + } +} +#endif +/** + * validate an alias, returns 1 for success, 0 for failure + */ +static inline int phar_validate_alias(const char *alias, int alias_len) /* {{{ */ +{ + return !(memchr(alias, '/', alias_len) || memchr(alias, '\\', alias_len) || memchr(alias, ':', alias_len) || + memchr(alias, ';', alias_len)); +} +/* }}} */ + + +void phar_request_initialize(TSRMLS_D); + +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, 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); + +/* utility functions */ +char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC); +char *phar_decompress_filter(phar_entry_info * entry, int return_unknown); +char *phar_compress_filter(phar_entry_info * entry, int return_unknown); + +int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC); +char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC); +char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC); +phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp, + char **error, int for_write TSRMLS_DC); +int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC); +void destroy_phar_manifest_entry(void *pDest); +int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC); +php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC); +int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC); +int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC); +phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC); +int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC); +int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC); +int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC); + +/* tar functions in tar.c */ +int phar_is_tar(char *buf, char *fname); +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 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 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 +static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +extern php_stream_wrapper php_stream_phar_wrapper; +#endif + +int phar_archive_delref(phar_archive_data *phar TSRMLS_DC); +int phar_entry_delref(phar_entry_data *idata TSRMLS_DC); + +phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC); +phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC); +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 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, + pcr_is_ok, + pcr_err_double_slash, + pcr_err_up_dir, + pcr_err_curr_dir, + pcr_err_back_slash, + pcr_err_star, + pcr_err_illegal_char, + pcr_err_empty_entry +} phar_path_check_result; + +phar_path_check_result phar_path_check(char **p, int *len, const char **error); + +END_EXTERN_C() + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c new file mode 100755 index 0000000000..98b602adbc --- /dev/null +++ b/ext/phar/phar_object.c @@ -0,0 +1,4650 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" +#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 +static zend_class_entry *phar_ce_entry; +#endif + +static int phar_file_type(HashTable *mimes, char *file, char **mime_type TSRMLS_DC) /* {{{ */ +{ + char *ext; + phar_mime_type *mime; + 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(mimes, ext, strlen(ext), (void **) &mime)) { + *mime_type = "application/octet-stream"; + return PHAR_MIME_OTHER; + } + *mime_type = mime->mime; + return mime->type; +} +/* }}} */ + +static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int basename_len, char *request_uri, int request_uri_len TSRMLS_DC) /* {{{ */ +{ + zval **_SERVER, **stuff; + char *path_info; + + /* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */ + if (SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &_SERVER)) { + return; + } + + /* PATH_INFO and PATH_TRANSLATED should always be munged */ + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_PATH_INFO"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) { + ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + } + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_PATH_TRANSLATED"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + if (!PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_SERVER_mung_list))) { + return; + } + if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_REQUEST_URI"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) { + ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + } + } + if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_PHP_SELF"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) { + ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + } + } + + if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_SCRIPT_NAME"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + ZVAL_STRINGL(*stuff, entry, entry_len, 1); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + } + + if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) { + int code; + zval *temp; + char newname[] = "PHAR_SCRIPT_FILENAME"; + + path_info = Z_STRVAL_PP(stuff); + code = Z_STRLEN_PP(stuff); + Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry); + + MAKE_STD_ZVAL(temp); + ZVAL_STRINGL(temp, path_info, code, 0); + zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL); + } + } +} +/* }}} */ + +static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, int basename_len, char *ru, int ru_len TSRMLS_DC) /* {{{ */ +{ + char *name = NULL, buf[8192], *cwd; + zend_syntax_highlighter_ini syntax_highlighter_ini; + sapi_header_line ctr = {0}; + size_t got; + int dummy = 1, name_len, ret; + zend_file_handle file_handle; + zend_op_array *new_op_array; + zval *result = NULL; + + switch (code) { + case PHAR_MIME_PHPS: + efree(basename); + /* highlight source */ + if (entry[0] == '/') { + name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + php_get_highlight_struct(&syntax_highlighter_ini); + + highlight_file(name, &syntax_highlighter_ini TSRMLS_CC); + + phar_entry_delref(phar TSRMLS_CC); + efree(name); +#ifdef PHP_WIN32 + efree(arch); +#endif + zend_bailout(); + case PHAR_MIME_OTHER: + /* send headers, output file contents */ + efree(basename); + 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_get_efp(phar->internal_file, 1 TSRMLS_CC)) { + char *error; + if (!phar_open_jit(phar->phar, phar->internal_file, phar->phar->fp, &error, 0 TSRMLS_CC)) { + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + return -1; + } + phar->fp = phar_get_efp(phar->internal_file, 1 TSRMLS_CC); + phar->zero = phar->internal_file->offset; + } + phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC); + do { + 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); + zend_bailout(); + case PHAR_MIME_PHP: + if (basename) { + phar_mung_server_vars(arch, entry, entry_len, basename, basename_len, ru, ru_len TSRMLS_CC); + efree(basename); + } + phar_entry_delref(phar TSRMLS_CC); + if (entry[0] == '/') { + name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry); + } else { + name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry); + } + + ret = php_stream_open_for_zend_ex(name, &file_handle, ENFORCE_SAFE_MODE|USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); + + if (ret != SUCCESS) { + efree(name); + return -1; + } + PHAR_G(cwd) = NULL; + PHAR_G(cwd_len) = 0; + if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) { + if ((cwd = strrchr(entry, '/'))) { + PHAR_G(cwd_init) = 1; + if (entry == cwd) { + /* root directory */ + PHAR_G(cwd_len) = 0; + PHAR_G(cwd) = NULL; + } else if (entry[0] == '/') { + PHAR_G(cwd_len) = cwd - (entry + 1); + PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len)); + } else { + PHAR_G(cwd_len) = cwd - entry; + PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len)); + } + } + new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); + zend_destroy_file_handle(&file_handle TSRMLS_CC); + } else { + new_op_array = NULL; +#if PHP_VERSION_ID >= 50300 + zend_file_handle_dtor(&file_handle TSRMLS_CC); +#else + zend_file_handle_dtor(&file_handle); +#endif + } +#ifdef PHP_WIN32 + efree(arch); +#endif + if (new_op_array) { + EG(return_value_ptr_ptr) = &result; + EG(active_op_array) = new_op_array; + + zend_try { + zend_execute(new_op_array TSRMLS_CC); + } zend_catch { + } zend_end_try(); + destroy_op_array(new_op_array TSRMLS_CC); + efree(new_op_array); + if (PHAR_G(cwd)) { + efree(PHAR_G(cwd)); + PHAR_G(cwd) = NULL; + PHAR_G(cwd_len) = 0; + } + PHAR_G(cwd_init) = 0; + efree(name); + if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { + zval_ptr_dtor(EG(return_value_ptr_ptr)); + } + zend_bailout(); + } + return PHAR_MIME_PHP; + } + return -1; +} +/* }}} */ + +static void phar_do_403(char *entry, int entry_len TSRMLS_DC) /* {{{ */ +{ + sapi_header_line ctr = {0}; + + ctr.response_code = 403; + ctr.line_len = sizeof("HTTP/1.0 403 Access Denied"); + ctr.line = "HTTP/1.0 403 Access Denied"; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + sapi_send_headers(TSRMLS_C); + PHPWRITE("\n \n Access Denied\n \n \n

    403 - File ", sizeof("\n \n Access Denied\n \n \n

    403 - File ") - 1); + PHPWRITE(entry, entry_len); + PHPWRITE(" Access Denied

    \n \n", sizeof(" Access Denied\n \n") - 1); +} +/* }}} */ + +static void phar_do_404(char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */ +{ + int hi; + phar_entry_data *phar; + char *error; + if (f404_len) { + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, f404, f404_len, "r", 0, &error TSRMLS_CC)) { + if (error) { + efree(error); + } + goto nofile; + } + hi = phar_file_action(phar, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, fname_len, NULL, 0, NULL, 0 TSRMLS_CC); + } else { + sapi_header_line ctr = {0}; +nofile: + ctr.response_code = 404; + ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1; + ctr.line = "HTTP/1.0 404 Not Found"; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + sapi_send_headers(TSRMLS_C); + PHPWRITE("\n \n File Not Found\n \n \n

    404 - File ", sizeof("\n \n File Not Found\n \n \n

    404 - File ") - 1); + PHPWRITE(entry, entry_len); + PHPWRITE(" Not Found

    \n \n", sizeof(" Not Found\n \n") - 1); + } +} +/* }}} */ + +/* post-process REQUEST_URI and retrieve the actual request URI. This is for + cases like http://localhost/blah.phar/path/to/file.php/extra/stuff + which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */ +static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len TSRMLS_DC) /* {{{ */ +{ + char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL; + int e_len = *entry_len - 1, u_len = 0; + phar_archive_data **pphar; + + /* we already know we can retrieve the phar if we reach here */ + zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar); + + do { + if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) { + if (u) { + u[0] = '/'; + *ru = estrndup(u, u_len+1); + ++u_len; + u[0] = '\0'; + } else { + *ru = NULL; + } + *ru_len = u_len; + *entry_len = e_len + 1; + return; + } + if (u) { + u1 = strrchr(e, '/'); + u[0] = '/'; + saveu = u; + e_len += u_len + 1; + u = u1; + if (!u) { + return; + } + } else { + u = strrchr(e, '/'); + if (!u) { + if (saveu) { + saveu[0] = '/'; + } + return; + } + } + u[0] = '\0'; + u_len = strlen(u + 1); + e_len -= u_len + 1; + if (e_len < 0) { + if (saveu) { + saveu[0] = '/'; + } + return; + } + } while (1); +} +/* }}} */ + +/* {{{ proto void Phar::running([bool retphar = true]) + * return the name of the currently running phar archive. If the optional parameter + * is set to true, return the phar:// URL to the currently running phar + */ +PHP_METHOD(Phar, running) +{ + char *fname, *arch, *entry; + int fname_len, arch_len, entry_len; + zend_bool retphar = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &retphar) == FAILURE) { + return; + } + + fname = zend_get_executed_filename(TSRMLS_C); + fname_len = strlen(fname); + + if (fname_len > 7 && !memcmp(fname, "phar://", 7) && 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); + efree(arch); + return; + } else { + RETURN_STRINGL(arch, arch_len, 0); + } + } + RETURN_STRINGL("", 0, 1); +} +/* }}} */ + +/* {{{ proto void Phar::mount(string pharpath, string externalfile) + * mount an external file or path to a location within the phar. This maps + * an external file or directory to a location within the phar archive, allowing + * reference to an external location as if it were within the phar archive. This + * is useful for writable temp files like databases + */ +PHP_METHOD(Phar, mount) +{ + char *fname, *arch, *entry, *path, *actual; + int fname_len, arch_len, entry_len, path_len, actual_len; + phar_archive_data **pphar; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) { + return; + } + + fname = zend_get_executed_filename(TSRMLS_C); + fname_len = strlen(fname); + + if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) { + efree(entry); + entry = NULL; + if (path_len > 7 && !memcmp(path, "phar://", 7)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path); + efree(arch); + return; + } +carry_on2: + 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); + efree(arch); + return; + } +carry_on: + if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch); + if (path && path == entry) { + efree(entry); + } + efree(arch); + return; + } + if (path && path == entry) { + efree(entry); + } + efree(arch); + return; + } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) { + goto carry_on; + } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) { + path = entry; + path_len = entry_len; + goto carry_on2; + } + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual); +} +/* }}} */ + +/* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]]) + * mapPhar for web-based phars. Reads the currently executed file (a phar) + * and registers its manifest. When executed in the CLI or CGI command-line sapi, + * this works exactly like mapPhar(). When executed by a web-based sapi, this + * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the + * intended internal file. + */ +PHP_METHOD(Phar, webPhar) +{ + HashTable mimetypes; + phar_mime_type mime; + zval *mimeoverride = NULL, *rewrite = NULL; + char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL; + int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0; + char *fname, *basename, *path_info, *mime_type, *entry, *pt; + int fname_len, entry_len, code, index_php_len = 0, not_cgi; + phar_entry_data *phar; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) { + return; + } + + phar_request_initialize(TSRMLS_C); + fname = zend_get_executed_filename(TSRMLS_C); + fname_len = strlen(fname); + if (phar_open_compiled_file(alias, alias_len, &error TSRMLS_CC) != SUCCESS) { + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + return; + } + + /* retrieve requested file within phar */ + if (!(SG(request_info).request_method && SG(request_info).request_uri && (!strcmp(SG(request_info).request_method, "GET") || !strcmp(SG(request_info).request_method, "POST")))) { + return; + } +#ifdef PHP_WIN32 + fname = estrndup(fname, fname_len); + phar_unixify_path_separators(fname, fname_len); +#endif + basename = strrchr(fname, '/'); + if (!basename) { + basename = fname; + } else { + ++basename; + } + + if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1)) + || (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) { + char *testit; + + testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC); + if (!(pt = strstr(testit, basename))) { + return; + } + path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC); + if (path_info) { + entry = estrdup(path_info); + entry_len = strlen(entry); + spprintf(&path_info, 0, "%s%s", testit, path_info); + free_pathinfo = 1; + } else { + path_info = testit; + entry = estrndup("", 0); + entry_len = 0; + } + pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname))); + not_cgi = 0; + } else { + path_info = SG(request_info).request_uri; + + if (!(pt = strstr(path_info, basename))) { + /* this can happen with rewrite rules - and we have no idea what to do then, so return */ + return; + } + entry_len = strlen(path_info); + + entry_len -= (pt - path_info) + (fname_len - (basename - fname)); + entry = estrndup(pt + (fname_len - (basename - fname)), entry_len); + + pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname))); + not_cgi = 1; + } + + if (rewrite) { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + zval *params, *retval_ptr, **zp[1]; + + MAKE_STD_ZVAL(params); + ZVAL_STRINGL(params, entry, entry_len, 1); + zp[0] = ¶ms; + +#if PHP_VERSION_ID < 50300 + if (FAILURE == zend_fcall_info_init(rewrite, &fci, &fcc TSRMLS_CC)) { +#else + if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) { +#endif + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback"); + if (free_pathinfo) { + efree(path_info); + } + return; + } + + fci.param_count = 1; + fci.params = zp; +#if PHP_VERSION_ID < 50300 + ++(params->refcount); +#else + Z_ADDREF_P(params); +#endif + fci.retval_ptr_ptr = &retval_ptr; + + if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) { + if (!EG(exception)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback"); + } + if (free_pathinfo) { + efree(path_info); + } + return; + } + if (!fci.retval_ptr_ptr || !retval_ptr) { + if (free_pathinfo) { + efree(path_info); + } + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false"); + return; + } + switch (Z_TYPE_P(retval_ptr)) { + case IS_STRING : + efree(entry); + if (fci.retval_ptr_ptr != &retval_ptr) { + entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr)); + entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr); + } else { + entry = Z_STRVAL_P(retval_ptr); + entry_len = Z_STRLEN_P(retval_ptr); + } + break; + case IS_BOOL : + phar_do_403(entry, entry_len TSRMLS_CC); + if (free_pathinfo) { + efree(path_info); + } + zend_bailout(); + return; + default: + efree(retval_ptr); + if (free_pathinfo) { + efree(path_info); + } + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false"); + return; + } + } + + if (entry_len) { + phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC); + } + if (!entry_len || (entry_len == 1 && entry[0] == '/')) { + efree(entry); + /* direct request */ + if (index_php_len) { + entry = index_php; + entry_len = index_php_len; + if (entry[0] != '/') { + spprintf(&entry, 0, "/%s", index_php); + ++entry_len; + } + } else { + /* assume "index.php" is starting point */ + entry = estrndup("/index.php", sizeof("/index.php")); + entry_len = sizeof("/index.php")-1; + } + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, NULL TSRMLS_CC)) { + phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC); + if (free_pathinfo) { + efree(path_info); + } + zend_bailout(); + } else { + char *tmp, sa; + sapi_header_line ctr = {0}; + ctr.response_code = 301; + ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")+1; + ctr.line = "HTTP/1.1 301 Moved Permanently"; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + + if (not_cgi) { + tmp = strstr(path_info, basename) + fname_len; + sa = *tmp; + *tmp = '\0'; + } + ctr.response_code = 0; + if (path_info[strlen(path_info)-1] == '/') { + ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1); + } else { + ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry); + } + if (not_cgi) { + *tmp = sa; + } + if (free_pathinfo) { + efree(path_info); + } + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + sapi_send_headers(TSRMLS_C); + phar_entry_delref(phar TSRMLS_CC); + efree(ctr.line); + zend_bailout(); + } + } + + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, &error TSRMLS_CC)) { + phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC); +#ifdef PHP_WIN32 + efree(fname); +#endif + zend_bailout(); + } + + /* set up mime types */ + zend_hash_init(&mimetypes, sizeof(phar_mime_type *), zend_get_hash_value, NULL, 0); +#define PHAR_SET_MIME(mimetype, ret, fileext) \ + mime.mime = mimetype; \ + mime.len = sizeof((mimetype))+1; \ + mime.type = ret; \ + zend_hash_add(&mimetypes, fileext, sizeof(fileext)-1, (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") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt") + PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd") + PHAR_SET_MIME("", PHAR_MIME_PHP, "php") + PHAR_SET_MIME("", PHAR_MIME_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") + PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html") + PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls") + PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico") + PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe") + PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg") + PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg") + PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js") + PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi") + PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid") + 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") + PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "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") + PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "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") + + /* set up user overrides */ +#define PHAR_SET_USER_MIME(ret) \ + if (Z_TYPE_PP(val) == IS_LONG) { \ + mime.mime = ""; \ + mime.len = 0; \ + } else { \ + mime.mime = Z_STRVAL_PP(val); \ + mime.len = Z_STRLEN_PP(val); \ + } \ + mime.type = ret; \ + zend_hash_update(&mimetypes, key, keylen-1, (void *)&mime, sizeof(phar_mime_type), NULL); + + if (mimeoverride) { + if (!zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) { + goto no_mimes; + } + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mimeoverride)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mimeoverride)); zend_hash_move_forward(Z_ARRVAL_P(mimeoverride))) { + zval **val; + char *key; + uint keylen; + ulong intkey; + if (HASH_KEY_IS_LONG == zend_hash_get_current_key_ex(Z_ARRVAL_P(mimeoverride), &key, &keylen, &intkey, 0, NULL)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Key of MIME type overrides array must be a file extension, was \"%d\"", intkey); + phar_entry_delref(phar TSRMLS_CC); +#ifdef PHP_WIN32 + efree(fname); +#endif + RETURN_FALSE; + } + if (FAILURE == zend_hash_get_current_data(Z_ARRVAL_P(mimeoverride), (void **) &val)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Failed to retrieve Mime type for extension \"%s\"", key); + phar_entry_delref(phar TSRMLS_CC); +#ifdef PHP_WIN32 + efree(fname); +#endif + RETURN_FALSE; + } + switch (Z_TYPE_PP(val)) { + case IS_LONG : + if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) { + PHAR_SET_USER_MIME((char) Z_LVAL_PP(val)) + } else { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed"); + phar_entry_delref(phar TSRMLS_CC); +#ifdef PHP_WIN32 + efree(fname); +#endif + RETURN_FALSE; + } + break; + case IS_STRING : + PHAR_SET_USER_MIME(PHAR_MIME_OTHER) + break; + default : + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed"); + phar_entry_delref(phar TSRMLS_CC); +#ifdef PHP_WIN32 + efree(fname); +#endif + RETURN_FALSE; + } + } + } + +no_mimes: + code = phar_file_type(&mimetypes, entry, &mime_type TSRMLS_CC); + zend_hash_destroy(&mimetypes); + ret = phar_file_action(phar, mime_type, code, entry, entry_len, fname, fname_len, pt, strlen(pt), ru, ru_len TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void Phar::mungServer(array munglist) + * Defines a list of up to 4 $_SERVER variables that should be modified for execution + * to mask the presence of the phar archive. This should be used in conjunction with + * Phar::webPhar(), and has no effect otherwise + * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME + */ +PHP_METHOD(Phar, mungServer) +{ + zval *mungvalues; + int php_self = 0, request_uri = 0, script_name = 0, script_filename = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) { + return; + } + + if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME"); + return; + } + if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME"); + return; + } + + phar_request_initialize(TSRMLS_C); + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mungvalues)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mungvalues)); zend_hash_move_forward(Z_ARRVAL_P(mungvalues))) { + zval **data = NULL; + + if (SUCCESS != zend_hash_get_current_data(Z_ARRVAL_P(mungvalues), (void **) &data)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "unable to retrieve array value in Phar::mungServer()"); + return; + } + if (Z_TYPE_PP(data) != IS_STRING) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME"); + return; + } + if (!php_self && Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) { + if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add PHP_SELF to Phar::mungServer() list of values to mung"); + return; + } + php_self = 1; + } + if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) { + if (!request_uri && !strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) { + if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add REQUEST_URI to Phar::mungServer() list of values to mung"); + return; + } + request_uri = 1; + } + if (!script_name && !strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) { + if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_NAME to Phar::mungServer() list of values to mung"); + return; + } + script_name = 1; + } + } + if (!script_filename && Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) { + if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_FILENAME to Phar::mungServer() list of values to mung"); + return; + } + script_filename = 1; + } + } +} +/* }}} */ + +/* {{{ proto void Phar::interceptFileFuncs() + * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions + * and return stat on files within the phar for relative paths + * + * Once called, this cannot be reversed, and continue until the end of the request. + * + * This allows legacy scripts to be pharred unmodified + */ +PHP_METHOD(Phar, interceptFileFuncs) +{ + phar_intercept_functions(TSRMLS_C); +} +/* }}} */ + +/* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]]) + * Return a stub that can be used to run a phar-based archive without the phar extension + * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile + * is the web startup filename, and also defaults to "index.php" + */ +PHP_METHOD(Phar, createDefaultStub) +{ + char *index = NULL, *webindex = NULL, *stub, *error; + int index_len = 0, webindex_len = 0; + size_t stub_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) { + return; + } + + stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC); + + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + return; + } + RETURN_STRINGL(stub, stub_len, 0); +} +/* }}} */ + +/* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]]) + * Reads the currently executed file (a phar) and registers its manifest */ +PHP_METHOD(Phar, mapPhar) +{ + char *alias = NULL, *error; + int alias_len = 0; + long dataoffset = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) { + return; + } + + phar_request_initialize(TSRMLS_C); + + RETVAL_BOOL(phar_open_compiled_file(alias, alias_len, &error TSRMLS_CC) == SUCCESS); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} /* }}} */ + +/* {{{ proto mixed Phar::loadPhar(string filename [, string alias]) + * Loads any phar archive with an alias */ +PHP_METHOD(Phar, loadPhar) +{ + char *fname, *alias = NULL, *error; + int fname_len, alias_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) { + return; + } + + phar_request_initialize(TSRMLS_C); + + RETVAL_BOOL(phar_open_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} /* }}} */ + +/* {{{ proto string Phar::apiVersion() + * Returns the api version */ +PHP_METHOD(Phar, apiVersion) +{ + RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1, 1); +} +/* }}}*/ + +/* {{{ proto bool Phar::canCompress([int method]) + * Returns whether phar extension supports compression using zlib/bzip2 */ +PHP_METHOD(Phar, canCompress) +{ + long method = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) { + return; + } + + switch (method) { + case PHAR_ENT_COMPRESSED_GZ: + if (phar_has_zlib) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + + case PHAR_ENT_COMPRESSED_BZ2: + if (phar_has_bz2) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + + default: + if (phar_has_zlib || phar_has_bz2) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } + } +} +/* }}} */ + +/* {{{ proto bool Phar::canWrite() + * Returns whether phar extension supports writing and creating phars */ +PHP_METHOD(Phar, canWrite) +{ + RETURN_BOOL(!PHAR_G(readonly)); +} +/* }}} */ + +/* {{{ 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|b", &fname, &fname_len, &executable) == FAILURE) { + return; + } + + fname_len = executable; + RETVAL_BOOL(phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, fname_len, 2, 1 TSRMLS_CC) == SUCCESS); +} +/* }}} */ + +#if HAVE_SPL +/** + * from spl_directory + */ +static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */ +{ + phar_archive_delref((phar_archive_data *) object->oth TSRMLS_CC); + object->oth = NULL; +} +/* }}} */ + +/** + * from spl_directory + */ +static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC) /* {{{ */ +{ + phar_archive_data *phar_data = (phar_archive_data *) dst->oth; + + ++(phar_data->refcount); +} +/* }}} */ + +static spl_other_handler phar_spl_foreign_handler = { + phar_spl_foreign_dtor, + phar_spl_foreign_clone +}; +#endif /* 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) +{ +#if !HAVE_SPL + 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 = NULL, *entry = NULL, *save_fname, *objname; + 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; + zval *zobj = getThis(), arg1, arg2; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) { + return; + } + + phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (phar_obj->arc.archive) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice"); + return; + } + +#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; +#ifdef PHP_WIN32 + phar_unixify_path_separators(arch, arch_len); +#endif + fname = arch; + fname_len = arch_len; +#ifdef PHP_WIN32 + } else { + arch = estrndup(fname, fname_len); + arch_len = fname_len; + save_fname = fname; + fname = arch; + phar_unixify_path_separators(arch, arch_len); +#endif + } + + 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); + fname = save_fname; + } + if (entry) { + efree(entry); + } + if (error) { + 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; + } + + if (fname == arch) { + 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; + + if (entry) { + fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry); + efree(entry); + } else { + fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname); + } + + INIT_PZVAL(&arg1); + ZVAL_STRINGL(&arg1, fname, fname_len, 0); + + if (ZEND_NUM_ARGS() > 1) { + INIT_PZVAL(&arg2); + ZVAL_LONG(&arg2, flags); + zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj), + &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2); + } else { + zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), + &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); +#endif /* HAVE_SPL */ +} +/* }}} */ + +/* {{{ proto array Phar::getSupportedSignatures() + * Return array of supported signature types + */ +PHP_METHOD(Phar, getSupportedSignatures) +{ + array_init(return_value); + + add_next_index_stringl(return_value, "MD5", 3, 1); + add_next_index_stringl(return_value, "SHA-1", 5, 1); +#if HAVE_HASH_EXT + add_next_index_stringl(return_value, "SHA-256", 7, 1); + add_next_index_stringl(return_value, "SHA-512", 7, 1); +#endif +} +/* }}} */ + +/* {{{ proto array Phar::getSupportedCompression() + * Return array of supported comparession algorithms + */ +PHP_METHOD(Phar, getSupportedCompression) +{ + array_init(return_value); + + if (phar_has_zlib) { + add_next_index_stringl(return_value, "GZ", 2, 1); + } + if (phar_has_bz2) { + add_next_index_stringl(return_value, "BZIP2", 5, 1); + } +} +/* }}} */ + +/* {{{ proto array Phar::unlinkArchive(string archive) + * Completely remove a phar archive from memory and disk + */ +PHP_METHOD(Phar, unlinkArchive) +{ + char *fname, *error, *zname, *arch, *entry; + int fname_len, zname_len, arch_len, entry_len; + phar_archive_data *phar; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + RETURN_FALSE; + } + + if (!fname_len) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"\""); + return; + } + + if (FAILURE == phar_open_filename(fname, fname_len, NULL, 0, REPORT_ERRORS, &phar, &error TSRMLS_CC)) { + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\": %s", fname, error); + efree(error); + } else { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\"", fname); + } + return; + } + + zname = zend_get_executed_filename(TSRMLS_C); + zname_len = strlen(zname); + + if (zname_len > 7 && !memcmp(zname, "phar://", 7) && SUCCESS == phar_split_fname(zname, zname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) { + if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" cannot be unlinked from within itself", fname); + efree(arch); + efree(entry); + return; + } + efree(arch); + efree(entry); + } + + if (phar->refcount) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname); + return; + } + fname = estrndup(phar->fname, phar->fname_len); + phar_archive_delref(phar TSRMLS_CC); + unlink(fname); + efree(fname); + RETURN_TRUE; +} +/* }}} */ + +#if HAVE_SPL + +#define PHAR_ARCHIVE_OBJECT() \ + phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \ + if (!phar_obj->arc.archive) { \ + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Cannot call method on an uninitialized Phar object"); \ + return; \ + } + +static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ +{ + zval **value; + zend_uchar key_type; + zend_bool is_splfileinfo = 0, close_fp = 1; + ulong int_key; + struct _t { + phar_archive_object *p; + zend_class_entry *c; + char *b; + uint l; + zval *ret; + } *p_obj = (struct _t*) puser; + uint str_key_len, base_len = p_obj->l, fname_len; + phar_entry_data *data; + php_stream *fp; + long contents_len; + char *fname, *error, *str_key, *base = p_obj->b, *opened, *save = NULL, *temp = NULL; + zend_class_entry *ce = p_obj->c; + phar_archive_object *phar_obj = p_obj->p; + char *str = "[stream]"; + + iter->funcs->get_current_data(iter, &value TSRMLS_CC); + if (EG(exception)) { + return ZEND_HASH_APPLY_STOP; + } + if (!value) { + /* failure in get_current_data */ + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned no value", ce->name); + return ZEND_HASH_APPLY_STOP; + } + switch (Z_TYPE_PP(value)) { + case IS_STRING : + break; + case IS_RESOURCE : + php_stream_from_zval_no_verify(fp, value); + if (!fp) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %s returned an invalid stream handle", ce->name); + return ZEND_HASH_APPLY_STOP; + } + if (iter->funcs->get_current_key) { + key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + if (EG(exception)) { + return ZEND_HASH_APPLY_STOP; + } + if (key_type == HASH_KEY_IS_LONG) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name); + return ZEND_HASH_APPLY_STOP; + } + save = str_key; + if (str_key[str_key_len - 1] == '\0') str_key_len--; + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name); + return ZEND_HASH_APPLY_STOP; + } + close_fp = 0; + opened = (char *) estrndup(str, sizeof("[stream]") + 1); + goto after_open_fp; + case IS_OBJECT : + if (instanceof_function(Z_OBJCE_PP(value), spl_ce_SplFileInfo TSRMLS_CC)) { + char *test = NULL; + zval dummy; + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(*value TSRMLS_CC); + + if (!base_len) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %s returns an SplFileInfo object, so base directory must be specified", ce->name); + return ZEND_HASH_APPLY_STOP; + } + switch (intern->type) { + case SPL_FS_DIR: +#if PHP_VERSION_ID >= 60000 + test = spl_filesystem_object_get_path(intern, NULL, NULL TSRMLS_CC).s; +#elif PHP_VERSION_ID >= 50300 + test = spl_filesystem_object_get_path(intern, NULL TSRMLS_CC); +#else + test = intern->path; +#endif + fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name); + php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC); + if (Z_BVAL(dummy)) { + /* ignore directories */ + efree(fname); + return ZEND_HASH_APPLY_KEEP; + } + test = expand_filepath(fname, NULL TSRMLS_CC); + if (test) { + efree(fname); + fname = test; + fname_len = strlen(fname); + } + save = fname; + is_splfileinfo = 1; + goto phar_spl_fileinfo; + case SPL_FS_INFO: + case SPL_FS_FILE: + fname = expand_filepath(intern->file_name, NULL TSRMLS_CC); + fname_len = strlen(fname); + save = fname; + is_splfileinfo = 1; + goto phar_spl_fileinfo; + } + } + /* fall-through */ + default : + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid value (must return a string)", ce->name); + return ZEND_HASH_APPLY_STOP; + } + + fname = Z_STRVAL_PP(value); + fname_len = Z_STRLEN_PP(value); + +phar_spl_fileinfo: + if (base_len) { + temp = expand_filepath(base, NULL TSRMLS_CC); + base = temp; + base_len = strlen(base); + if (strstr(fname, base)) { + str_key_len = fname_len - base_len; + if (str_key_len <= 0) { + if (save) { + efree(save); + efree(temp); + } + return ZEND_HASH_APPLY_KEEP; + } + str_key = fname + base_len; + if (*str_key == '/' || *str_key == '\\') { + str_key++; + str_key_len--; + } + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that is not in the base directory \"%s\"", ce->name, fname, base); + if (save) { + efree(save); + efree(temp); + } + return ZEND_HASH_APPLY_STOP; + } + } else { + if (iter->funcs->get_current_key) { + key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + if (EG(exception)) { + return ZEND_HASH_APPLY_STOP; + } + if (key_type == HASH_KEY_IS_LONG) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name); + return ZEND_HASH_APPLY_STOP; + } + save = str_key; + if (str_key[str_key_len - 1] == '\0') str_key_len--; + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name); + return ZEND_HASH_APPLY_STOP; + } + } +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that safe mode prevents opening", ce->name, fname); + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + return ZEND_HASH_APPLY_STOP; + } +#endif + + if (php_check_open_basedir(fname TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that open_basedir prevents opening", ce->name, fname); + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + return ZEND_HASH_APPLY_STOP; + } + + /* try to open source file, then create internal phar file and copy contents */ + fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened); + if (!fp) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a file that could not be opened \"%s\"", ce->name, fname); + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + return ZEND_HASH_APPLY_STOP; + } + +after_open_fp: + if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error TSRMLS_CC))) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error); + efree(error); + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + if (close_fp) { + php_stream_close(fp); + } + return ZEND_HASH_APPLY_STOP; + } else { + if (error) { + efree(error); + } + contents_len = php_stream_copy_to_stream(fp, data->fp, PHP_STREAM_COPY_ALL); + } + if (close_fp) { + php_stream_close(fp); + } + + add_assoc_string(p_obj->ret, str_key, opened, 0); + + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + + data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len; + phar_entry_delref(data TSRMLS_CC); + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex]) + * Construct a phar archive from an existing directory, recursively. + * Optional second parameter is a regular expression for filtering directory contents. + * + * Return value is an array mapping phar index to actual files added. + */ +PHP_METHOD(Phar, buildFromDirectory) +{ + char *dir, *error, *regex = NULL; + int dir_len, regex_len = 0; + zend_bool apply_reg = 0; + zval arg, arg2, *iter, *iteriter, *regexiter = NULL; + struct { + phar_archive_object *p; + zend_class_entry *c; + char *b; + uint l; + zval *ret; + } pass; + + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write to archive - write operations restricted by INI setting"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &dir, &dir_len, ®ex, ®ex_len) == FAILURE) { + RETURN_FALSE; + } + + MAKE_STD_ZVAL(iter); + + if (SUCCESS != object_init_ex(iter, spl_ce_RecursiveDirectoryIterator)) { + zval_ptr_dtor(&iter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + INIT_PZVAL(&arg); + ZVAL_STRINGL(&arg, dir, dir_len, 0); + + zend_call_method_with_1_params(&iter, spl_ce_RecursiveDirectoryIterator, + &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg); + + if (EG(exception)) { + zval_ptr_dtor(&iter); + RETURN_FALSE; + } + + MAKE_STD_ZVAL(iteriter); + + if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) { + zval_ptr_dtor(&iter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator, + &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter); + + if (EG(exception)) { + zval_ptr_dtor(&iter); + zval_ptr_dtor(&iteriter); + RETURN_FALSE; + } + + zval_ptr_dtor(&iter); + + if (regex_len > 0) { + apply_reg = 1; + MAKE_STD_ZVAL(regexiter); + + if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) { + zval_dtor(regexiter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + INIT_PZVAL(&arg2); + ZVAL_STRINGL(&arg2, regex, regex_len, 0); + + zend_call_method_with_2_params(®exiter, spl_ce_RegexIterator, + &spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2); + } + + array_init(return_value); + + pass.c = apply_reg ? Z_OBJCE_P(regexiter) : Z_OBJCE_P(iteriter); + pass.p = phar_obj; + pass.b = dir; + pass.l = dir_len; + pass.ret = return_value; + + if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) { + zval_ptr_dtor(&iteriter); + if (apply_reg) { + zval_ptr_dtor(®exiter); + } + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + } +} + +/* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory]) + * Construct a phar archive from an iterator. The iterator must return a series of strings + * that are full paths to files that should be added to the phar. The iterator key should + * be the path that the file will have within the phar archive. + * + * If base directory is specified, then the key will be ignored, and instead the portion of + * the current value minus the base directory will be used + * + * Returned is an array mapping phar index to actual file added + */ +PHP_METHOD(Phar, buildFromIterator) +{ + zval *obj; + char *error; + uint base_len = 0; + char *base = NULL; + struct { + phar_archive_object *p; + zend_class_entry *c; + char *b; + uint l; + zval *ret; + } pass; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &obj, zend_ce_traversable, &base, &base_len) == FAILURE) { + RETURN_FALSE; + } + + array_init(return_value); + + pass.c = Z_OBJCE_P(obj); + pass.p = phar_obj; + pass.b = base; + pass.l = base_len; + pass.ret = return_value; + + if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) { + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + } + +} +/* }}} */ + +/* {{{ proto int Phar::count() + * Returns the number of entries in the Phar archive + */ +PHP_METHOD(Phar, count) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_LONG(zend_hash_num_elements(&phar_obj->arc.archive->manifest)); +} +/* }}} */ + +/* {{{ proto bool Phar::isFileFormat(int format) + * Returns true if the phar archive is based on the tar/zip/phar file format depending + * on whether Phar::TAR, Phar::ZIP or Phar::PHAR was passed in + */ +PHP_METHOD(Phar, isFileFormat) +{ + long type; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) { + RETURN_FALSE; + } + switch (type) { + case PHAR_FORMAT_TAR: + RETURN_BOOL(phar_obj->arc.archive->is_tar); + case PHAR_FORMAT_ZIP: + RETURN_BOOL(phar_obj->arc.archive->is_zip); + case PHAR_FORMAT_PHAR: + RETURN_BOOL(!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip); + default: + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown file format specified"); + } +} +/* }}} */ + +static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */ +{ + char *error; + off_t offset; + phar_entry_info *link; + + if (FAILURE == phar_open_entry_fp(entry, &error, 1 TSRMLS_CC)) { + if (error) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename); + } + return FAILURE; + } + /* copy old contents in entirety */ + phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC); + offset = php_stream_tell(fp); + link = phar_get_link_source(entry TSRMLS_CC); + if (!link) { + link = entry; + } + if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename); + return FAILURE; + } + if (entry->fp_type == PHAR_MOD) { + /* save for potential restore on error */ + entry->cfp = entry->fp; + entry->fp = NULL; + } + /* set new location of file contents */ + entry->fp_type = PHAR_FP; + entry->offset = offset; + return SUCCESS; +} +/* }}} */ + +static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC) +{ + char *oldname = NULL, *oldpath = NULL; + char *basename = NULL, *basepath = NULL; + char *newname = NULL, *newpath = NULL; + zval *ret, arg1; + zend_class_entry *ce; + char *error; + const char *pcr_error; + int ext_len = ext ? strlen(ext) : 0; + + if (!ext) { + if (phar->is_zip) { + if (phar->is_data) { + ext = "zip"; + } else { + ext = "phar.zip"; + } + } else if (phar->is_tar) { + switch (phar->flags) { + case PHAR_FILE_COMPRESSED_GZ: + if (phar->is_data) { + ext = "tar.gz"; + } else { + ext = "phar.tar.gz"; + } + break; + case PHAR_FILE_COMPRESSED_BZ2: + if (phar->is_data) { + ext = "tar.bz2"; + } else { + ext = "phar.tar.bz2"; + } + break; + default: + if (phar->is_data) { + ext = "tar"; + } else { + ext = "phar.tar"; + } + } + } else { + switch (phar->flags) { + case PHAR_FILE_COMPRESSED_GZ: + ext = "phar.gz"; + break; + case PHAR_FILE_COMPRESSED_BZ2: + ext = "phar.bz2"; + break; + default: + ext = "phar"; + } + } + } else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) { + if (phar->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar converted from \"%s\" has invalid extension %s", phar->fname, ext); + } + return NULL; + } + + if (ext[0] == '.') { + ++ext; + } + + oldpath = estrndup(phar->fname, phar->fname_len); + oldname = strrchr(phar->fname, '/'); + ++oldname; + + basename = estrndup(oldname, strlen(oldname)); + spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext); + efree(basename); + + basepath = estrndup(oldpath, strlen(oldpath) - strlen(oldname)); + phar->fname_len = spprintf(&newpath, 0, "%s%s", basepath, newname); + phar->fname = newpath; + efree(basepath); + efree(newname); + + if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len)) { + efree(oldpath); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname); + return NULL; + } + + if (!phar->is_data) { + if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) { + efree(oldpath); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext); + return NULL; + } + if (phar->alias) { + if (phar->is_temporary_alias) { + phar->alias = NULL; + phar->alias_len = 0; + } else { + phar->alias = estrndup(newpath, strlen(newpath)); + phar->alias_len = strlen(newpath); + phar->is_temporary_alias = 1; + zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL); + } + } + } else { + if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) { + efree(oldpath); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext); + return NULL; + } + phar->alias = NULL; + phar->alias_len = 0; + } + + if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL)) { + efree(oldpath); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname); + return NULL; + } + + phar_flush(phar, 0, 0, 1, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error); + efree(error); + efree(oldpath); + return NULL; + } + + efree(oldpath); + + if (phar->is_data) { + ce = phar_ce_data; + } else { + ce = phar_ce_archive; + } + + MAKE_STD_ZVAL(ret); + if (SUCCESS != object_init_ex(ret, ce)) { + zval_dtor(ret); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname); + return NULL; + } + INIT_PZVAL(&arg1); + ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len, 0); + + zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1); + + return ret; +} + +static zval *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, php_uint32 flags TSRMLS_DC) /* {{{ */ +{ + phar_archive_data *phar; + phar_entry_info *entry, newentry; + zval *ret; + + phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data)); + /* set whole-archive compression and type from parameter */ + phar->flags = flags; + + phar->is_data = source->is_data; + switch (convert) { + case PHAR_FORMAT_TAR : + phar->is_tar = 1; + break; + case PHAR_FORMAT_ZIP : + phar->is_zip = 1; + break; + default : + phar->is_data = 0; + break; + } + + zend_hash_init(&(phar->manifest), sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + + phar->fp = php_stream_fopen_tmpfile(); + phar->fname = source->fname; + phar->fname_len = source->fname_len; + phar->is_temporary_alias = source->is_temporary_alias; + phar->alias = source->alias; + /* first copy each file's uncompressed contents to a temporary file and set per-file flags */ + for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) { + + if (FAILURE == zend_hash_get_current_data(&source->manifest, (void **) &entry)) { + zend_hash_destroy(&(phar->manifest)); + php_stream_close(phar->fp); + efree(phar); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\"", source->fname); + return NULL; + } + newentry = *entry; + if (newentry.link) { + newentry.link = estrdup(newentry.link); + goto no_copy; + } + if (newentry.tmp) { + newentry.tmp = estrdup(newentry.tmp); + goto no_copy; + } + if (FAILURE == phar_copy_file_contents(&newentry, phar->fp TSRMLS_CC)) { + zend_hash_destroy(&(phar->manifest)); + php_stream_close(phar->fp); + efree(phar); + /* exception already thrown */ + return NULL; + } +no_copy: + newentry.filename = estrndup(newentry.filename, newentry.filename_len); + if (newentry.metadata) { + zval *t; + + t = newentry.metadata; + ALLOC_ZVAL(newentry.metadata); + *newentry.metadata = *t; + zval_copy_ctor(newentry.metadata); +#if PHP_VERSION_ID < 50300 + newentry.metadata->refcount = 1; +#else + Z_SET_REFCOUNT_P(newentry.metadata, 1); +#endif + + newentry.metadata_str.c = NULL; + newentry.metadata_str.len = 0; + } + newentry.is_zip = phar->is_zip; + newentry.is_tar = phar->is_tar; + if (newentry.is_tar) { + newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE); + } + newentry.is_modified = 1; + newentry.phar = phar; + newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */ + zend_hash_add(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL); + } + + if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) { + return ret; + } else { + zend_hash_destroy(&(phar->manifest)); + php_stream_close(phar->fp); + efree(phar->fname); + efree(phar); + return NULL; + } +} +/* }}} */ + +/* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]]) + * Convert a phar.tar or phar.zip archive to the phar file format. The + * optional parameter allows the user to determine the new + * filename extension (default is phar). + */ +PHP_METHOD(Phar, convertToExecutable) +{ + char *ext = NULL; + int is_data, ext_len = 0; + php_uint32 flags; + zval *ret; + /* a number that is not 0, 1 or 2 (Which is also Greg's birthday, so there) */ + long format = 9021976, method = 9021976; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) { + return; + } + + if (PHAR_G(readonly)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out executable phar archive, phar is read-only"); + return; + } + + switch (format) { + case 9021976: + case PHAR_FORMAT_SAME: /* null is converted to 0 */ + /* by default, use the existing format */ + if (phar_obj->arc.archive->is_tar) { + format = PHAR_FORMAT_TAR; + } else if (phar_obj->arc.archive->is_zip) { + format = PHAR_FORMAT_ZIP; + } else { + format = PHAR_FORMAT_PHAR; + } + break; + case PHAR_FORMAT_PHAR: + case PHAR_FORMAT_TAR: + case PHAR_FORMAT_ZIP: + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP"); + return; + } + + switch (method) { + case 9021976: + flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK; + break; + case 0: + flags = PHAR_FILE_COMPRESSED_NONE; + break; + case PHAR_ENT_COMPRESSED_GZ: + if (format == PHAR_FORMAT_ZIP) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression"); + return; + } + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with gzip, enable ext/zlib in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_GZ; + break; + + case PHAR_ENT_COMPRESSED_BZ2: + if (format == PHAR_FORMAT_ZIP) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression"); + return; + } + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_BZ2; + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2"); + return; + } + + is_data = phar_obj->arc.archive->is_data; + phar_obj->arc.archive->is_data = 0; + ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC); + phar_obj->arc.archive->is_data = is_data; + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto object Phar::convertToData([int format[, int compression [, string file_ext]]]) + * Convert an archive to a non-executable .tar or .zip. + * The optional parameter allows the user to determine the new + * filename extension (default is .zip or .tar). + */ +PHP_METHOD(Phar, convertToData) +{ + char *ext = NULL; + int is_data, ext_len = 0; + php_uint32 flags; + zval *ret; + /* a number that is not 0, 1 or 2 (Which is also Greg's birthday so there) */ + long format = 9021976, method = 9021976; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) { + return; + } + + switch (format) { + case 9021976: + case PHAR_FORMAT_SAME: /* null is converted to 0 */ + /* by default, use the existing format */ + if (phar_obj->arc.archive->is_tar) { + format = PHAR_FORMAT_TAR; + } else if (phar_obj->arc.archive->is_zip) { + format = PHAR_FORMAT_ZIP; + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP"); + return; + } + break; + case PHAR_FORMAT_PHAR: + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP"); + return; + case PHAR_FORMAT_TAR: + case PHAR_FORMAT_ZIP: + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP"); + return; + } + + switch (method) { + case 9021976: + flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK; + break; + case 0: + flags = PHAR_FILE_COMPRESSED_NONE; + break; + case PHAR_ENT_COMPRESSED_GZ: + if (format == PHAR_FORMAT_ZIP) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression"); + return; + } + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with gzip, enable ext/zlib in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_GZ; + break; + + case PHAR_ENT_COMPRESSED_BZ2: + if (format == PHAR_FORMAT_ZIP) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression"); + return; + } + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_BZ2; + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2"); + return; + } + + is_data = phar_obj->arc.archive->is_data; + phar_obj->arc.archive->is_data = 1; + ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC); + phar_obj->arc.archive->is_data = is_data; + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto int|false Phar::isCompressed() + * Returns Phar::GZ or PHAR::BZ2 if the entire archive is compressed + * (.tar.gz/tar.bz2 and so on), or FALSE otherwise. + */ +PHP_METHOD(Phar, isCompressed) +{ + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_GZ) { + RETURN_LONG(PHAR_ENT_COMPRESSED_GZ); + } + if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_BZ2) { + RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2); + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool Phar::isWritable() + * Returns true if phar.readonly=0 or phar is a PharData AND the actual file is writable. + */ +PHP_METHOD(Phar, isWritable) +{ + php_stream_statbuf ssb; + PHAR_ARCHIVE_OBJECT(); + + if (!phar_obj->arc.archive->is_writeable) { + RETURN_FALSE; + } + if (SUCCESS != php_stream_stat_path(phar_obj->arc.archive->fname, &ssb)) { + if (phar_obj->arc.archive->is_brandnew) { + /* assume it works if the file doesn't exist yet */ + RETURN_TRUE; + } + RETURN_FALSE; + } + RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0); +} +/* }}} */ + +/* {{{ proto bool Phar::delete(string entry) + * Deletes a named file within the archive. + */ +PHP_METHOD(Phar, delete) +{ + char *fname; + int fname_len; + char *error; + phar_entry_info *entry; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + RETURN_FALSE; + } + + if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) { + if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ + RETURN_TRUE; + } else { + entry->is_deleted = 1; + entry->is_modified = 1; + phar_obj->arc.archive->is_modified = 1; + } + } + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be deleted", fname); + RETURN_FALSE; + } + + phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int Phar::getAlias() + * Returns the alias for the Phar or NULL. + */ +PHP_METHOD(Phar, getAlias) +{ + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->alias && phar_obj->arc.archive->alias != phar_obj->arc.archive->fname) { + RETURN_STRINGL(phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, 1); + } +} +/* }}} */ + +/* {{{ proto int Phar::getPath() + * Returns the real path to the phar archive on disk + */ +PHP_METHOD(Phar, getPath) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_STRINGL(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, 1); +} +/* }}} */ + +/* {{{ proto bool Phar::setAlias(string alias) + * Sets the alias for a Phar archive. The default value is the full path + * to the archive. + */ +PHP_METHOD(Phar, setAlias) +{ + char *alias, *error, *oldalias; + phar_archive_data **fd_ptr; + int alias_len, oldalias_len, old_temp, readd = 0; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + RETURN_FALSE; + } + + 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_FALSE; + } + + 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; + } + 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; + } + if (!phar_validate_alias(alias, alias_len)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "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; + } + + oldalias = phar_obj->arc.archive->alias; + oldalias_len = phar_obj->arc.archive->alias_len; + old_temp = phar_obj->arc.archive->is_temporary_alias; + if (alias_len) { + phar_obj->arc.archive->alias = estrndup(alias, alias_len); + } else { + phar_obj->arc.archive->alias = NULL; + } + phar_obj->arc.archive->alias_len = alias_len; + phar_obj->arc.archive->is_temporary_alias = 0; + + phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC); + if (error) { + phar_obj->arc.archive->alias = oldalias; + phar_obj->arc.archive->alias_len = oldalias_len; + phar_obj->arc.archive->is_temporary_alias = old_temp; + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + if (readd) { + zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), oldalias, oldalias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL); + } + efree(error); + RETURN_FALSE; + } + zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL); + if (oldalias) { + efree(oldalias); + } + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto string Phar::getVersion() + * Return version info of Phar archive + */ +PHP_METHOD(Phar, getVersion) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_STRING(phar_obj->arc.archive->version, 1); +} +/* }}} */ + +/* {{{ proto void Phar::startBuffering() + * Do not flush a writeable phar (save its contents) until explicitly requested + */ +PHP_METHOD(Phar, startBuffering) +{ + PHAR_ARCHIVE_OBJECT(); + + phar_obj->arc.archive->donotflush = 1; +} +/* }}} */ + +/* {{{ proto bool Phar::isBuffering() + * Returns whether write operations are flushing to disk immediately. + */ +PHP_METHOD(Phar, isBuffering) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_BOOL(!phar_obj->arc.archive->donotflush); +} +/* }}} */ + +/* {{{ proto bool Phar::stopBuffering() + * Saves the contents of a modified archive to disk. + */ +PHP_METHOD(Phar, stopBuffering) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + + phar_obj->arc.archive->donotflush = 0; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} +/* }}} */ + +/* {{{ proto bool Phar::setStub(string|stream stub [, int len]) + * Change the stub in a phar, phar.tar or phar.zip archive to something other + * than the default. The stub *must* end with a call to __HALT_COMPILER(). + */ +PHP_METHOD(Phar, setStub) +{ + zval *zstub; + char *stub, *error; + int stub_len; + long len = -1; + php_stream *stream; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot change stub, phar is read-only"); + 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) { + len = -len; + } else { + len = -1; + } + phar_flush(phar_obj->arc.archive, (char *) &zstub, len, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot change stub, unable to read from input stream"); + } + } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) { + phar_flush(phar_obj->arc.archive, stub, stub_len, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool Phar::setDefaultStub([string index[, string webindex]]) + * In a pure phar archive, sets a stub that can be used to run the archive + * regardless of whether the phar extension is available. The first parameter + * is the CLI startup filename, which defaults to "index.php". The second + * parameter is the web startup filename and also defaults to "index.php" + * (falling back to CLI behaviour). + * Both parameters are optional. + * In a phar.zip or phar.tar archive, the default stub is used only to + * identify the archive to the extension as a Phar object. This allows the + * extension to treat phar.zip and phar.tar types as honorary phars. Since + * files cannot be loaded via this kind of stub, no parameters are accepted + * when the Phar object is zip- or tar-based. + */ + PHP_METHOD(Phar, setDefaultStub) +{ + char *index = NULL, *webindex = NULL, *error = NULL, *stub = NULL; + int index_len = 0, webindex_len = 0, created_stub = 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; + } + + if (ZEND_NUM_ARGS() > 0 && (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "method accepts no arguments for a tar- or zip-based phar stub, %d given", ZEND_NUM_ARGS()); + RETURN_FALSE; + } + + if (PHAR_G(readonly)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot change stub: phar.readonly=1"); + RETURN_FALSE; + } + + if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) { + + stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC); + + if (error) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, error); + efree(error); + if (stub) { + efree(stub); + } + RETURN_FALSE; + } + created_stub = 1; + } + + phar_flush(phar_obj->arc.archive, stub, stub_len, 1, &error TSRMLS_CC); + + if (created_stub) { + efree(stub); + } + + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto array Phar::setSignatureAlgorithm(int sigtype) + * Sets the signature algorithm for a phar and applies it. The signature + * algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, + * Phar::SHA512, or Phar::PGP (PGP is not yet supported and falls back to + * SHA-1). Note that zip- and tar- based phar archives cannot support + * signatures. + */ +PHP_METHOD(Phar, setSignatureAlgorithm) +{ + long algo; + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot set signature algorithm, phar is read-only"); + return; + } + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot set signature algorithm, not possible with tar-based phar archives"); + return; + } + if (phar_obj->arc.archive->is_zip) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot set signature algorithm, not possible with zip-based phar archives"); + return; + } + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &algo) != SUCCESS) { + return; + } + + switch (algo) { + case PHAR_SIG_SHA256 : + case PHAR_SIG_SHA512 : +#if !HAVE_HASH_EXT + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled"); + return; +#endif + case PHAR_SIG_MD5 : + case PHAR_SIG_SHA1 : + case PHAR_SIG_PGP : + phar_obj->arc.archive->sig_flags = algo; + phar_obj->arc.archive->is_modified = 1; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + break; + default : + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Unknown signature algorithm specified"); + } +} +/* }}} */ + +/* {{{ proto array|false Phar::getSignature() + * Returns a hash signature, or FALSE if the archive is unsigned. + */ +PHP_METHOD(Phar, getSignature) +{ + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->signature) { + array_init(return_value); + add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1); + switch(phar_obj->arc.archive->sig_flags) { + case PHAR_SIG_MD5: + add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1); + break; + case PHAR_SIG_SHA1: + add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1); + break; + case PHAR_SIG_SHA256: + add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1); + break; + case PHAR_SIG_SHA512: + add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1); + break; + } + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto bool Phar::getModified() + * Return whether phar was modified + */ +PHP_METHOD(Phar, getModified) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_BOOL(phar_obj->arc.archive->is_modified); +} +/* }}} */ + +static int phar_set_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *)pDest; + php_uint32 compress = *(php_uint32 *)argument; + + if (entry->is_deleted) { + return ZEND_HASH_APPLY_KEEP; + } + entry->old_flags = entry->flags; + entry->flags &= ~PHAR_ENT_COMPRESSION_MASK; + entry->flags |= compress; + entry->is_modified = 1; + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +static int phar_test_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *)pDest; + + if (entry->is_deleted) { + return ZEND_HASH_APPLY_KEEP; + } + if (!phar_has_bz2) { + if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) { + *(int *) argument = 0; + } + } + if (!phar_has_zlib) { + if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { + *(int *) argument = 0; + } + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +static void pharobj_set_compression(HashTable *manifest, php_uint32 compress TSRMLS_DC) /* {{{ */ +{ + zend_hash_apply_with_argument(manifest, phar_set_compression, &compress TSRMLS_CC); +} +/* }}} */ + +static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */ +{ + int test; + test = 1; + zend_hash_apply_with_argument(manifest, phar_test_compression, &test TSRMLS_CC); + return test; +} +/* }}} */ + +/* {{{ proto object Phar::compress(int method[, string extension]) + * Compress a .tar, or .phar.tar with whole-file compression + * The parameter can be one of Phar::GZ or Phar::BZ2 to specify + * the kind of compression desired + */ +PHP_METHOD(Phar, compress) +{ + long method; + char *ext = NULL; + int ext_len = 0; + php_uint32 flags; + zval *ret; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &method, &ext, &ext_len) == FAILURE) { + return; + } + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot compress phar archive, phar is read-only"); + return; + } + + if (phar_obj->arc.archive->is_zip) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot compress zip-based archives with whole-archive compression"); + return; + } + + switch (method) { + case 0: + flags = PHAR_FILE_COMPRESSED_NONE; + break; + case PHAR_ENT_COMPRESSED_GZ: + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with gzip, enable ext/zlib in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_GZ; + break; + + case PHAR_ENT_COMPRESSED_BZ2: + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini"); + return; + } + flags = PHAR_FILE_COMPRESSED_BZ2; + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2"); + return; + } + + if (phar_obj->arc.archive->is_tar) { + ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, flags TSRMLS_CC); + } else { + ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, flags TSRMLS_CC); + } + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto object Phar::decompress([string extension]) + * Decompress a .tar, or .phar.tar with whole-file compression + */ +PHP_METHOD(Phar, decompress) +{ + char *ext = NULL; + int ext_len = 0; + zval *ret; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ext, &ext_len) == FAILURE) { + return; + } + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot decompress phar archive, phar is read-only"); + return; + } + + if (phar_obj->arc.archive->is_zip) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot decompress zip-based archives with whole-archive compression"); + return; + } + + if (phar_obj->arc.archive->is_tar) { + ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC); + } else { + ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC); + } + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto object Phar::compressFiles(int method) + * Compress all files within a phar or zip archive using the specified compression + * The parameter can be one of Phar::GZ or Phar::BZ2 to specify + * the kind of compression desired + */ +PHP_METHOD(Phar, compressFiles) +{ + char *error; + php_uint32 flags; + long method; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) { + return; + } + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar is readonly, cannot change compression"); + return; + } + + switch (method) { + case PHAR_ENT_COMPRESSED_GZ: + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress files within archive with gzip, enable ext/zlib in php.ini"); + return; + } + flags = PHAR_ENT_COMPRESSED_GZ; + break; + + case PHAR_ENT_COMPRESSED_BZ2: + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress files within archive with bz2, enable ext/bz2 in php.ini"); + return; + } + flags = PHAR_ENT_COMPRESSED_BZ2; + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2"); + return; + } + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive"); + return; + } + if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) { + if (flags == PHAR_FILE_COMPRESSED_GZ) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed"); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress all files as Bzip2, some are compressed as gzip and cannot be decompressed"); + } + return; + } + pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC); + + phar_obj->arc.archive->is_modified = 1; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error); + efree(error); + } +} +/* }}} */ + +/* {{{ proto bool Phar::decompressFiles() + * decompress every file + */ +PHP_METHOD(Phar, decompressFiles) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar is readonly, cannot change compression"); + return; + } + if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed"); + return; + } + if (phar_obj->arc.archive->is_tar) { + RETURN_TRUE; + } else { + pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_NONE TSRMLS_CC); + } + + phar_obj->arc.archive->is_modified = 1; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool Phar::copy(string oldfile, string newfile) + * copy a file internal to the phar archive to another new file within the phar + */ +PHP_METHOD(Phar, copy) +{ + char *oldfile, *newfile, *error; + const char *pcr_error; + int oldfile_len, newfile_len; + phar_entry_info *oldentry, newentry = {0}, *temp; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) { + return; + } + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot copy \"%s\" to \"%s\", phar is read-only", oldfile, newfile); + RETURN_FALSE; + } + + if (!zend_hash_exists(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len) || SUCCESS != zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry) || oldentry->is_deleted) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + if (zend_hash_exists(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len)) { + if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len, (void**)&temp) || !temp->is_deleted) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->arc.archive->fname); + RETURN_FALSE; + } + } + + if (phar_path_check(&newfile, &newfile_len, &pcr_error) > pcr_is_ok) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "file \"%s\" contains invalid characters %s, cannot be copied from \"%s\" in phar %s", newfile, pcr_error, oldfile, phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info)); + if (newentry.metadata) { + zval *t; + + t = newentry.metadata; + ALLOC_ZVAL(newentry.metadata); + *newentry.metadata = *t; + zval_copy_ctor(newentry.metadata); +#if PHP_VERSION_ID < 50300 + newentry.metadata->refcount = 1; +#else + Z_SET_REFCOUNT_P(newentry.metadata, 1); +#endif + + newentry.metadata_str.c = NULL; + newentry.metadata_str.len = 0; + } + newentry.filename = estrndup(newfile, newfile_len); + newentry.filename_len = newfile_len; + newentry.fp_refcount = 0; + + if (oldentry->fp_type != PHAR_FP) { + if (FAILURE == phar_copy_entry_fp(oldentry, &newentry, &error TSRMLS_CC)) { + efree(newentry.filename); + php_stream_close(newentry.fp); + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + return; + } + } + + zend_hash_add(&oldentry->phar->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL); + phar_obj->arc.archive->is_modified = 1; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int Phar::offsetExists(string entry) + * determines whether a file exists in the phar + */ +PHP_METHOD(Phar, offsetExists) +{ + char *fname; + int fname_len; + phar_entry_info *entry; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + return; + } + + if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) { + if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ + RETURN_FALSE; + } + } + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto int Phar::offsetGet(string entry) + * get a PharFileInfo object for a specific file + */ +PHP_METHOD(Phar, offsetGet) +{ + char *fname, *error; + int fname_len; + zval *zfname; + phar_entry_info *entry; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + return; + } + + if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error TSRMLS_CC))) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:""); + } else { + if (entry->is_temp_dir) { + efree(entry->filename); + efree(entry); + } + fname_len = spprintf(&fname, 0, "phar://%s/%s", phar_obj->arc.archive->fname, fname); + MAKE_STD_ZVAL(zfname); + ZVAL_STRINGL(zfname, fname, fname_len, 0); + spl_instantiate_arg_ex1(phar_obj->spl.info_class, &return_value, 0, zfname TSRMLS_CC); + zval_ptr_dtor(&zfname); + } + +} +/* }}} */ + +/* {{{ add a file within the phar archive from a string or resource + */ +static void phar_add_file(phar_archive_data *phar, char *filename, int filename_len, char *cont_str, int cont_len, zval *zresource TSRMLS_DC) +{ + char *error; + long contents_len; + phar_entry_data *data; + php_stream *contents_file; + + if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, filename, filename_len, "w+b", 0, &error TSRMLS_CC))) { + if (error) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created: %s", filename, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created", filename); + } + return; + } else { + if (error) { + efree(error); + } + if (!data->internal_file->is_dir) { + if (cont_str) { + contents_len = php_stream_write(data->fp, cont_str, cont_len); + if (contents_len != cont_len) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename); + return; + } + } else { + if (!(php_stream_from_zval_no_verify(contents_file, &zresource))) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename); + return; + } + contents_len = php_stream_copy_to_stream(contents_file, data->fp, PHP_STREAM_COPY_ALL); + } + data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len; + } + phar_entry_delref(data TSRMLS_CC); + phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + } +} +/* }}} */ + +/* {{{ create a directory within the phar archive + */ +static void phar_mkdir(phar_archive_data *phar, char *dirname, int dirname_len TSRMLS_DC) +{ + char *error; + phar_entry_data *data; + + if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, dirname, dirname_len, "w+b", 2, &error TSRMLS_CC))) { + if (error) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created: %s", dirname, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created", dirname); + } + return; + } else { + if (error) { + efree(error); + } + phar_entry_delref(data TSRMLS_CC); + phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + } +} +/* }}} */ + + +/* {{{ proto int Phar::offsetSet(string entry, string value) + * set the contents of an internal file to those of an external file + */ +PHP_METHOD(Phar, offsetSet) +{ + char *fname, *cont_str = NULL; + int fname_len, cont_len; + zval *zresource; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting"); + return; + } + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sr", &fname, &fname_len, &zresource) == FAILURE + && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) { + return; + } + + if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set stub \".phar/stub.php\" directly in phar \"%s\", use setStub", phar_obj->arc.archive->fname); + return; + } + + if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set alias \".phar/alias.txt\" directly in phar \"%s\", use setAlias", phar_obj->arc.archive->fname); + return; + } + phar_add_file(phar_obj->arc.archive, fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int Phar::offsetUnset(string entry) + * remove a file from a phar + */ +PHP_METHOD(Phar, offsetUnset) +{ + char *fname, *error; + int fname_len; + phar_entry_info *entry; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + return; + } + + if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) { + if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ + return; + } + entry->is_modified = 0; + entry->is_deleted = 1; + /* we need to "flush" the stream to save the newly deleted file on disk */ + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; + } + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto string Phar::addEmptyDir(string dirname) + * Adds an empty directory to the phar archive + */ +PHP_METHOD(Phar, addEmptyDir) +{ + char *dirname; + int dirname_len; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dirname, &dirname_len) == FAILURE) { + return; + } + + phar_mkdir(phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto string Phar::addFile(string filename[, string localname]) + * Adds a file to the archive using the filename, or the second parameter as the name within the archive + */ +PHP_METHOD(Phar, addFile) +{ + char *fname, *localname = NULL; + int fname_len, localname_len = 0; + php_stream *resource; + zval *zresource; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) { + return; + } + +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, safe_mode restrictions prevent this", fname); + return; + } +#endif + + if (!strstr(fname, "://") && php_check_open_basedir(fname TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, open_basedir restrictions prevent this", fname); + return; + } + + if (!(resource = php_stream_open_wrapper(fname, "rb", 0, NULL))) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive", fname); + return; + } + if (localname) { + fname = localname; + fname_len = localname_len; + } + + MAKE_STD_ZVAL(zresource); + php_stream_to_zval(resource, zresource); + phar_add_file(phar_obj->arc.archive, fname, fname_len, NULL, 0, zresource TSRMLS_CC); + efree(zresource); + php_stream_close(resource); +} +/* }}} */ + +/* {{{ proto string Phar::addFromString(string localname, string contents) + * Adds a file to the archive using its contents as a string + */ +PHP_METHOD(Phar, addFromString) +{ + char *localname, *cont_str; + int localname_len, cont_len; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) { + return; + } + + phar_add_file(phar_obj->arc.archive, localname, localname_len, cont_str, cont_len, NULL TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto string Phar::getStub() + * Returns the stub at the head of a phar archive as a string. + */ +PHP_METHOD(Phar, getStub) +{ + size_t len; + char *buf; + php_stream *fp; + php_stream_filter *filter = NULL; + phar_entry_info *stub; + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) { + + if (SUCCESS == zend_hash_find(&(phar_obj->arc.archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) { + if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew && !(stub->flags & PHAR_ENT_COMPRESSION_MASK)) { + fp = phar_obj->arc.archive->fp; + } else { + fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL); + if (stub->flags & PHAR_ENT_COMPRESSION_MASK) { + char *filter_name; + + if ((filter_name = phar_decompress_filter(stub, 0)) != NULL) { + filter = php_stream_filter_create(phar_decompress_filter(stub, 0), NULL, php_stream_is_persistent(fp) TSRMLS_CC); + } else { + filter = NULL; + } + if (!filter) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", phar_obj->arc.archive->fname, phar_decompress_filter(stub, 1)); + return; + } + php_stream_filter_append(&fp->readfilters, filter); + } + } + + if (!fp) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to read stub"); + return; + } + + php_stream_seek(fp, stub->offset_abs, SEEK_SET); + len = stub->uncompressed_filesize; + goto carry_on; + } else { + RETURN_STRINGL("", 0, 1); + } + } + len = phar_obj->arc.archive->halt_offset; + + if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) { + fp = phar_obj->arc.archive->fp; + } else { + fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL); + } + + if (!fp) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to read stub"); + return; + } + + php_stream_rewind(fp); +carry_on: + buf = safe_emalloc(len, 1, 1); + if (len != php_stream_read(fp, buf, len)) { + if (fp != phar_obj->arc.archive->fp) { + php_stream_close(fp); + } + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to read stub"); + efree(buf); + return; + } + if (filter) { + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + } + if (fp != phar_obj->arc.archive->fp) { + php_stream_close(fp); + } + buf[len] = '\0'; + + RETURN_STRINGL(buf, len, 0); +} +/* }}}*/ + +/* {{{ proto int Phar::hasMetaData() + * Returns TRUE if the phar has global metadata, FALSE otherwise. + */ +PHP_METHOD(Phar, hasMetadata) +{ + PHAR_ARCHIVE_OBJECT(); + + RETURN_BOOL(phar_obj->arc.archive->metadata != NULL); +} +/* }}} */ + +/* {{{ proto int Phar::getMetaData() + * Returns the global metadata of the phar + */ +PHP_METHOD(Phar, getMetadata) +{ + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->metadata) { + RETURN_ZVAL(phar_obj->arc.archive->metadata, 1, 0); + } +} +/* }}} */ + +/* {{{ proto int Phar::setMetaData(mixed $metadata) + * Sets the global metadata of the phar + */ +PHP_METHOD(Phar, setMetadata) +{ + char *error; + zval *metadata; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting"); + return; + } + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot set metadata, not possible with tar-based phar archives"); + return; + } + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) { + return; + } + + if (phar_obj->arc.archive->metadata) { + zval_ptr_dtor(&phar_obj->arc.archive->metadata); + phar_obj->arc.archive->metadata = NULL; + } + + MAKE_STD_ZVAL(phar_obj->arc.archive->metadata); + ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0); + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} +/* }}} */ + +/* {{{ proto int Phar::delMetadata() + * Deletes the global metadata of the phar + */ +PHP_METHOD(Phar, delMetadata) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting"); + return; + } + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot delete metadata, not possible with tar-based phar archives"); + return; + } + if (phar_obj->arc.archive->metadata) { + zval_ptr_dtor(&phar_obj->arc.archive->metadata); + phar_obj->arc.archive->metadata = NULL; + + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + RETURN_FALSE; + } else { + RETURN_TRUE; + } + } else { + RETURN_TRUE; + } +} +/* }}} */ +#if (PHP_MAJOR_VERSION < 6) +#define OPENBASEDIR_CHECKPATH(filename) \ + (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC) +#else +#define OPENBASEDIR_CHECKPATH(filename) \ + php_check_open_basedir(filename TSRMLS_CC) +#endif + +static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC) +{ + php_stream_statbuf ssb; + int len; + php_stream *fp; + char *fullpath, *slash; + mode_t mode; + + if (entry->is_mounted) { + /* silently ignore mounted entries */ + return SUCCESS; + } + len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename); + if (len >= MAXPATHLEN) { + char *tmp; + /* truncate for error message */ + fullpath[50] = '\0'; + if (entry->filename_len > 50) { + tmp = estrndup(entry->filename, 50); + spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, fullpath); + efree(tmp); + } else { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath); + } + efree(fullpath); + return FAILURE; + } + if (!len) { + spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename); + efree(fullpath); + return FAILURE; + } + + if (OPENBASEDIR_CHECKPATH(fullpath)) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + + /* let see if the path already exists */ + if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + /* perform dirname */ + slash = strrchr(entry->filename, '/'); + if (slash) { + fullpath[dest_len + (slash - entry->filename) + 1] = '\0'; + } else { + fullpath[dest_len] = '\0'; + } + if (FAILURE == php_stream_stat_path(fullpath, &ssb)) { + if (entry->is_dir) { + if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { + spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + } else { + if (!php_stream_mkdir(fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { + spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + } + } + if (slash) { + fullpath[dest_len + (slash - entry->filename) + 1] = '/'; + } else { + fullpath[dest_len] = '/'; + } + + /* it is a standalone directory, job done */ + if (entry->is_dir) { + efree(fullpath); + return SUCCESS; + } + + fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); + + if (!fp) { + spprintf(error, 4096, "Cannot extract \"%s\", could not open for writing \"%s\"", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + + if (!phar_get_efp(entry, 0 TSRMLS_CC)) { + if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { + if (error) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error); + } else { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", entry->filename, fullpath); + } + efree(fullpath); + php_stream_close(fp); + return FAILURE; + } + } + + if (FAILURE == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to seek internal file pointer", entry->filename, fullpath); + efree(fullpath); + php_stream_close(fp); + return FAILURE; + } + + if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp, entry->uncompressed_filesize)) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", copying contents failed", entry->filename, fullpath); + efree(fullpath); + php_stream_close(fp); + return FAILURE; + } + + php_stream_close(fp); + mode = (mode_t) entry->flags & PHAR_ENT_PERM_MASK; + + if (FAILURE == VCWD_CHMOD(fullpath, mode)) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", setting file permissions failed", entry->filename, fullpath); + efree(fullpath); + return FAILURE; + } + + efree(fullpath); + return SUCCESS; +} + +/* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite]) + * Extract one or more file from a phar archive, optionally overwriting existing files + */ +PHP_METHOD(Phar, extractTo) +{ + char *error = NULL; + php_stream_statbuf ssb; + phar_entry_info *entry; + char *pathto, *filename; + int pathto_len, filename_len; + int ret, i; + int nelems; + zval *zval_files = NULL; + zend_bool overwrite = 0; + PHAR_ARCHIVE_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) { + return; + } + + if (pathto_len < 1) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, + "Invalid argument, extraction path must be non-zero length"); + return; + } + if (pathto_len >= MAXPATHLEN) { + char *tmp = estrndup(pathto, 50); + /* truncate for error message */ + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Cannot extract to \"%s...\", destination directory is too long for filesystem", tmp); + efree(tmp); + return; + } + + if (php_stream_stat_path(pathto, &ssb) < 0) { + ret = php_stream_mkdir(pathto, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL); + if (!ret) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to create path \"%s\" for extraction", pathto); + return; + } + } else if (!(ssb.sb.st_mode & S_IFDIR)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to use path \"%s\" for extraction, it is a file, must be a directory", pathto); + return; + } + + if (zval_files) { + switch (Z_TYPE_P(zval_files)) { + case IS_NULL: + goto all_files; + case IS_STRING: + filename = Z_STRVAL_P(zval_files); + filename_len = Z_STRLEN_P(zval_files); + break; + case IS_ARRAY: + nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files)); + if (nelems == 0 ) { + RETURN_FALSE; + } + for (i = 0; i < nelems; i++) { + zval **zval_file; + if (zend_hash_index_find(Z_ARRVAL_P(zval_files), i, (void **) &zval_file) == SUCCESS) { + switch (Z_TYPE_PP(zval_file)) { + case IS_STRING: + break; + default: + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, + "Invalid argument, array of filenames to extract contains non-string value"); + return; + } + if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, Z_STRVAL_PP(zval_file), Z_STRLEN_PP(zval_file), (void **)&entry)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, + "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_PP(zval_file), phar_obj->arc.archive->fname); + } + if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, + "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error); + efree(error); + return; + } + } + } + RETURN_TRUE; + default: + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, + "Invalid argument, expected a filename (string) or array of filenames"); + return; + } + if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, filename, filename_len, (void **)&entry)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, + "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->arc.archive->fname); + return; + } + if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, + "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error); + efree(error); + return; + } + } else { + phar_archive_data *phar = phar_obj->arc.archive; + +all_files: + /* Extract all files */ + if (!zend_hash_num_elements(&(phar->manifest))) { + RETURN_TRUE; + } + + for (zend_hash_internal_pointer_reset(&phar->manifest); + zend_hash_has_more_elements(&phar->manifest) == SUCCESS; + zend_hash_move_forward(&phar->manifest)) { + phar_entry_info *entry; + if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) { + continue; + } + if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, + "Extraction from phar \"%s\" failed: %s", phar->fname, error); + efree(error); + return; + } + } + } + RETURN_TRUE; +} +/* }}} */ + + +/* {{{ proto void PharFileInfo::__construct(string entry) + * Construct a Phar entry object + */ +PHP_METHOD(PharFileInfo, __construct) +{ + char *fname, *arch, *entry, *error; + int fname_len, arch_len, entry_len; + phar_entry_object *entry_obj; + phar_entry_info *entry_info; + phar_archive_data *phar_data; + zval *zobj = getThis(), arg1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { + return; + } + + entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (entry_obj->ent.entry) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice"); + return; + } + + if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC) == FAILURE) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname); + return; + } + + if (phar_open_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) { + efree(arch); + efree(entry); + if (error) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Cannot open phar file '%s': %s", fname, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Cannot open phar file '%s'", fname); + } + return; + } + + if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error TSRMLS_CC)) == NULL) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error?", ":"", error?error:""); + efree(arch); + efree(entry); + return; + } + + efree(arch); + efree(entry); + + entry_obj->ent.entry = entry_info; + + INIT_PZVAL(&arg1); + ZVAL_STRINGL(&arg1, fname, fname_len, 0); + + zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), + &spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1); +} +/* }}} */ + +#define PHAR_ENTRY_OBJECT() \ + phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \ + if (!entry_obj->ent.entry) { \ + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Cannot call method on an uninitialized PharFileInfo object"); \ + return; \ + } + +/* {{{ proto void PharFileInfo::__destruct() + * clean up directory-based entry objects + */ +PHP_METHOD(PharFileInfo, __destruct) +{ + phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \ + + if (entry_obj->ent.entry && entry_obj->ent.entry->is_temp_dir) { + if (entry_obj->ent.entry->filename) { + efree(entry_obj->ent.entry->filename); + entry_obj->ent.entry->filename = NULL; + } + efree(entry_obj->ent.entry); + entry_obj->ent.entry = NULL; + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::getCompressedSize() + * Returns the compressed size + */ +PHP_METHOD(PharFileInfo, getCompressedSize) +{ + PHAR_ENTRY_OBJECT(); + + RETURN_LONG(entry_obj->ent.entry->compressed_filesize); +} +/* }}} */ + +/* {{{ proto bool PharFileInfo::isCompressed([int compression_type]) + * Returns whether the entry is compressed, and whether it is compressed with Phar::GZ or Phar::BZ2 if specified + */ +PHP_METHOD(PharFileInfo, isCompressed) +{ + /* a number that is not Phar::GZ or Phar::BZ2 */ + long method = 9021976; + PHAR_ENTRY_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) { + return; + } + + switch (method) { + case 9021976: + RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK); + case PHAR_ENT_COMPRESSED_GZ: + RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ); + case PHAR_ENT_COMPRESSED_BZ2: + RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2); + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Unknown compression type specified"); \ + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::getCRC32() + * Returns CRC32 code or throws an exception if not CRC checked + */ +PHP_METHOD(PharFileInfo, getCRC32) +{ + PHAR_ENTRY_OBJECT(); + + if (entry_obj->ent.entry->is_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry is a directory, does not have a CRC"); \ + return; + } + if (entry_obj->ent.entry->is_crc_checked) { + RETURN_LONG(entry_obj->ent.entry->crc32); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry was not CRC checked"); \ + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::isCRCChecked() + * Returns whether file entry is CRC checked + */ +PHP_METHOD(PharFileInfo, isCRCChecked) +{ + PHAR_ENTRY_OBJECT(); + + RETURN_BOOL(entry_obj->ent.entry->is_crc_checked); +} +/* }}} */ + +/* {{{ proto int PharFileInfo::getPharFlags() + * Returns the Phar file entry flags + */ +PHP_METHOD(PharFileInfo, getPharFlags) +{ + PHAR_ENTRY_OBJECT(); + + RETURN_LONG(entry_obj->ent.entry->flags & ~(PHAR_ENT_PERM_MASK|PHAR_ENT_COMPRESSION_MASK)); +} +/* }}} */ + +/* {{{ proto int PharFileInfo::chmod() + * set the file permissions for the Phar. This only allows setting execution bit, read/write + */ +PHP_METHOD(PharFileInfo, chmod) +{ + char *error; + long perms; + PHAR_ENTRY_OBJECT(); + + if (entry_obj->ent.entry->is_temp_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry \"%s\" is a temporary directory (not an actual entry in the archive), cannot chmod", entry_obj->ent.entry->filename); \ + return; + } + if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot modify permissions for file \"%s\" in phar \"%s\", write operations are prohibited", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname); + return; + } + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perms) == FAILURE) { + return; + } + /* clear permissions */ + entry_obj->ent.entry->flags &= ~PHAR_ENT_PERM_MASK; + perms &= 0777; + entry_obj->ent.entry->flags |= perms; + entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags; + entry_obj->ent.entry->phar->is_modified = 1; + entry_obj->ent.entry->is_modified = 1; + /* hackish cache in php_stat needs to be cleared */ + /* if this code fails to work, check main/streams/streams.c, _php_stream_stat_path */ + if (BG(CurrentLStatFile)) { + efree(BG(CurrentLStatFile)); + } + if (BG(CurrentStatFile)) { + efree(BG(CurrentStatFile)); + } + BG(CurrentLStatFile) = NULL; + BG(CurrentStatFile) = NULL; + + phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::hasMetaData() + * Returns the metadata of the entry + */ +PHP_METHOD(PharFileInfo, hasMetadata) +{ + PHAR_ENTRY_OBJECT(); + + RETURN_BOOL(entry_obj->ent.entry->metadata != NULL); +} +/* }}} */ + +/* {{{ proto int PharFileInfo::getMetaData() + * Returns the metadata of the entry + */ +PHP_METHOD(PharFileInfo, getMetadata) +{ + PHAR_ENTRY_OBJECT(); + + if (entry_obj->ent.entry->metadata) { + RETURN_ZVAL(entry_obj->ent.entry->metadata, 1, 0); + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::setMetaData(mixed $metadata) + * Sets the metadata of the entry + */ +PHP_METHOD(PharFileInfo, setMetadata) +{ + char *error; + zval *metadata; + PHAR_ENTRY_OBJECT(); + + if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting"); + return; + } + if (entry_obj->ent.entry->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot set metadata, not possible with tar-based phar archives"); + return; + } + if (entry_obj->ent.entry->is_temp_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata"); \ + return; + } + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) { + return; + } + + if (entry_obj->ent.entry->metadata) { + zval_ptr_dtor(&entry_obj->ent.entry->metadata); + entry_obj->ent.entry->metadata = NULL; + } + + MAKE_STD_ZVAL(entry_obj->ent.entry->metadata); + ZVAL_ZVAL(entry_obj->ent.entry->metadata, metadata, 1, 0); + + phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } +} +/* }}} */ + +/* {{{ proto bool PharFileInfo::delMetaData() + * Deletes the metadata of the entry + */ +PHP_METHOD(PharFileInfo, delMetadata) +{ + char *error; + PHAR_ENTRY_OBJECT(); + + if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting"); + return; + } + if (entry_obj->ent.entry->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot delete metadata, not possible with tar-based phar archives"); + return; + } + if (entry_obj->ent.entry->is_temp_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata"); \ + return; + } + if (entry_obj->ent.entry->metadata) { + zval_ptr_dtor(&entry_obj->ent.entry->metadata); + entry_obj->ent.entry->metadata = NULL; + + phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + RETURN_FALSE; + } else { + RETURN_TRUE; + } + } else { + RETURN_TRUE; + } +} +/* }}} */ + +/* {{{ proto string PharFileInfo::getContent() + * return the complete file contents of the entry (like file_get_contents) + */ +PHP_METHOD(PharFileInfo, getContent) +{ + char *error; + php_stream *fp; + phar_entry_info *link; + PHAR_ENTRY_OBJECT(); + + if (entry_obj->ent.entry->is_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname); + return; + } + link = phar_get_link_source(entry_obj->ent.entry TSRMLS_CC); + if (!link) { + link = entry_obj->ent.entry; + } + if (SUCCESS != phar_open_entry_fp(link, &error, 0 TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error); + efree(error); + return; + } + if (!(fp = phar_get_efp(link, 0 TSRMLS_CC))) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname); + return; + } + phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC); + Z_TYPE_P(return_value) = IS_STRING; + Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0); + if (!Z_STRVAL_P(return_value)) { + Z_STRVAL_P(return_value) = estrndup("", 0); + } +} +/* }}} */ + +/* {{{ proto int PharFileInfo::compress(int compression_type) + * Instructs the Phar class to compress the current file using zlib or bzip2 compression + */ +PHP_METHOD(PharFileInfo, compress) +{ + long method; + char *error; + PHAR_ENTRY_OBJECT(); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) { + return; + } + + if (entry_obj->ent.entry->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with Gzip compression, not possible with tar-based phar archives"); + return; + } + if (entry_obj->ent.entry->is_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry is a directory, cannot set compression"); \ + return; + } + if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar is readonly, cannot change compression"); + return; + } + if (entry_obj->ent.entry->is_deleted) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress deleted file"); + return; + } + + switch (method) { + case PHAR_ENT_COMPRESSED_GZ: + if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) { + RETURN_TRUE; + return; + } + if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0) { + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with gzip compression, file is already compressed with bzip2 compression and bz2 extension is not enabled, cannot decompress"); + return; + } + /* decompress this file indirectly */ + if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar error: Cannot decompress bzip2-compressed file \"%s\" in phar \"%s\" in order to compress with gzip: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error); + efree(error); + return; + } + } + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with gzip compression, zlib extension is not enabled"); + return; + } + entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags; + entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK; + entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_GZ; + break; + case PHAR_ENT_COMPRESSED_BZ2: + if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) { + RETURN_TRUE; + return; + } + if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0) { + if (!phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with bzip2 compression, file is already compressed with gzip compression and zlib extension is not enabled, cannot decompress"); + return; + } + /* decompress this file indirectly */ + if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar error: Cannot decompress gzip-compressed file \"%s\" in phar \"%s\" in order to compress with bzip2: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error); + efree(error); + return; + } + } + if (!phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with bzip2 compression, bz2 extension is not enabled"); + return; + } + entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags; + entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK; + entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_BZ2; + break; + default: + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Unknown compression type specified"); \ + } + + entry_obj->ent.entry->phar->is_modified = 1; + entry_obj->ent.entry->is_modified = 1; + + phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int PharFileInfo::decompress() + * Instructs the Phar class to decompress the current file + */ +PHP_METHOD(PharFileInfo, decompress) +{ + char *error; + PHAR_ENTRY_OBJECT(); + + if (entry_obj->ent.entry->is_dir) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ + "Phar entry is a directory, cannot set compression"); \ + return; + } + if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK) == 0) { + RETURN_TRUE; + return; + } + if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Phar is readonly, cannot decompress"); + return; + } + if (entry_obj->ent.entry->is_deleted) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress deleted file"); + return; + } + if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0 && !phar_has_zlib) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot decompress Gzip-compressed file, zlib extension is not enabled"); + return; + } + if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0 && !phar_has_bz2) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot decompress Bzip2-compressed file, bz2 extension is not enabled"); + return; + } + if (!entry_obj->ent.entry->fp) { + if (FAILURE == phar_open_archive_fp(entry_obj->ent.entry->phar TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot decompress entry \"%s\", phar error: Cannot open phar archive \"%s\" for reading", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname); + return; + } + entry_obj->ent.entry->fp_type = PHAR_FP; + } + entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags; + entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK; + entry_obj->ent.entry->phar->is_modified = 1; + entry_obj->ent.entry->is_modified = 1; + + phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + RETURN_TRUE; +} +/* }}} */ + +#endif /* HAVE_SPL */ + +/* {{{ phar methods */ + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar___construct, 0, 0, 1) + ZEND_ARG_INFO(0, filename) + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, alias) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_createDS, 0, 0, 0) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, webindex) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_loadPhar, 0, 0, 1) + ZEND_ARG_INFO(0, filename) + ZEND_ARG_INFO(0, alias) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mapPhar, 0, 0, 0) + ZEND_ARG_INFO(0, alias) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mount, 0, 0, 2) + ZEND_ARG_INFO(0, inphar) + ZEND_ARG_INFO(0, externalfile) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mungServer, 0, 0, 1) + ZEND_ARG_INFO(0, munglist) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_webPhar, 0, 0, 0) + ZEND_ARG_INFO(0, alias) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, f404) + ZEND_ARG_INFO(0, mimetypes) + ZEND_ARG_INFO(0, rewrites) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_running, 0, 0, 1) + ZEND_ARG_INFO(0, retphar) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_ua, 0, 0, 1) + ZEND_ARG_INFO(0, archive) +ZEND_END_ARG_INFO(); + +#if HAVE_SPL + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_build, 0, 0, 1) + ZEND_ARG_INFO(0, iterator) + ZEND_ARG_INFO(0, base_directory) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_conv, 0, 0, 0) + ZEND_ARG_INFO(0, format) + ZEND_ARG_INFO(0, compression_type) + ZEND_ARG_INFO(0, file_ext) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comps, 0, 0, 1) + ZEND_ARG_INFO(0, compression_type) + ZEND_ARG_INFO(0, file_ext) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_decomp, 0, 0, 0) + ZEND_ARG_INFO(0, file_ext) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comp, 0, 0, 1) + ZEND_ARG_INFO(0, compression_type) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_compo, 0, 0, 0) + ZEND_ARG_INFO(0, compression_type) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_copy, 0, 0, 2) + ZEND_ARG_INFO(0, newfile) + ZEND_ARG_INFO(0, oldfile) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_delete, 0, 0, 1) + ZEND_ARG_INFO(0, entry) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromdir, 0, 0, 1) + ZEND_ARG_INFO(0, base_dir) + ZEND_ARG_INFO(0, regex) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetExists, 0, 0, 1) + ZEND_ARG_INFO(0, entry) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, entry) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setAlias, 0, 0, 1) + ZEND_ARG_INFO(0, alias) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setMetadata, 0, 0, 1) + ZEND_ARG_INFO(0, metadata) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setSigAlgo, 0, 0, 1) + ZEND_ARG_INFO(0, algorithm) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setStub, 0, 0, 1) + ZEND_ARG_INFO(0, newstub) + ZEND_ARG_INFO(0, maxlen) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_emptydir, 0, 0, 0) + ZEND_ARG_INFO(0, dirname) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_extract, 0, 0, 1) + ZEND_ARG_INFO(0, pathto) + ZEND_ARG_INFO(0, files) + ZEND_ARG_INFO(0, overwrite) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_addfile, 0, 0, 1) + ZEND_ARG_INFO(0, filename) + ZEND_ARG_INFO(0, localname) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromstring, 0, 0, 1) + ZEND_ARG_INFO(0, localname) + ZEND_ARG_INFO(0, contents) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isff, 0, 0, 1) + ZEND_ARG_INFO(0, fileformat) +ZEND_END_ARG_INFO(); + +#endif /* HAVE_SPL */ + +zend_function_entry php_archive_methods[] = { +#if !HAVE_SPL + PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PRIVATE) +#else + PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PUBLIC) + PHP_ME(Phar, addEmptyDir, arginfo_phar_emptydir, ZEND_ACC_PUBLIC) + PHP_ME(Phar, addFile, arginfo_phar_addfile, ZEND_ACC_PUBLIC) + PHP_ME(Phar, addFromString, arginfo_phar_fromstring, ZEND_ACC_PUBLIC) + PHP_ME(Phar, buildFromDirectory, arginfo_phar_fromdir, ZEND_ACC_PUBLIC) + PHP_ME(Phar, buildFromIterator, arginfo_phar_build, ZEND_ACC_PUBLIC) + PHP_ME(Phar, compressFiles, arginfo_phar_comp, ZEND_ACC_PUBLIC) + PHP_ME(Phar, decompressFiles, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, compress, arginfo_phar_comps, ZEND_ACC_PUBLIC) + PHP_ME(Phar, decompress, arginfo_phar_decomp, ZEND_ACC_PUBLIC) + PHP_ME(Phar, convertToExecutable, arginfo_phar_conv, ZEND_ACC_PUBLIC) + PHP_ME(Phar, convertToData, arginfo_phar_conv, ZEND_ACC_PUBLIC) + PHP_ME(Phar, copy, arginfo_phar_copy, ZEND_ACC_PUBLIC) + PHP_ME(Phar, count, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, delete, arginfo_phar_delete, ZEND_ACC_PUBLIC) + PHP_ME(Phar, delMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, extractTo, arginfo_phar_extract, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getAlias, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getPath, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getModified, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getSignature, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getStub, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, getVersion, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, hasMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, isBuffering, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, isCompressed, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, isFileFormat, arginfo_phar_isff, ZEND_ACC_PUBLIC) + PHP_ME(Phar, isWritable, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, offsetExists, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(Phar, offsetGet, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(Phar, offsetSet, arginfo_phar_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(Phar, offsetUnset, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(Phar, setAlias, arginfo_phar_setAlias, ZEND_ACC_PUBLIC) + PHP_ME(Phar, setDefaultStub, arginfo_phar_createDS, ZEND_ACC_PUBLIC) + PHP_ME(Phar, setMetadata, arginfo_phar_setMetadata, ZEND_ACC_PUBLIC) + PHP_ME(Phar, setSignatureAlgorithm, arginfo_phar_setSigAlgo, ZEND_ACC_PUBLIC) + PHP_ME(Phar, setStub, arginfo_phar_setStub, ZEND_ACC_PUBLIC) + PHP_ME(Phar, startBuffering, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, stopBuffering, NULL, ZEND_ACC_PUBLIC) +#endif + /* static member functions */ + PHP_ME(Phar, apiVersion, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, canCompress, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, canWrite, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, createDefaultStub, arginfo_phar_createDS, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, getSupportedCompression,NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, getSupportedSignatures,NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, interceptFileFuncs, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, isValidPharFilename, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, loadPhar, arginfo_phar_loadPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, mapPhar, arginfo_phar_mapPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, running, arginfo_phar_running, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, mount, arginfo_phar_mount, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, mungServer, arginfo_phar_mungServer, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, unlinkArchive, arginfo_phar_ua, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + PHP_ME(Phar, webPhar, arginfo_phar_webPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) + {NULL, NULL, NULL} +}; + +#if HAVE_SPL +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_entry___construct, 0, 0, 1) + ZEND_ARG_INFO(0, filename) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_chmod, 0, 0, 1) + ZEND_ARG_INFO(0, perms) +ZEND_END_ARG_INFO(); + +zend_function_entry php_entry_methods[] = { + PHP_ME(PharFileInfo, __construct, arginfo_entry___construct, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, __destruct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, chmod, arginfo_entry_chmod, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, compress, arginfo_phar_comp, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, decompress, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, delMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, getCompressedSize, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, getCRC32, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, getContent, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, getMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, getPharFlags, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, hasMetadata, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, isCompressed, arginfo_phar_compo, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, isCRCChecked, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PharFileInfo, setMetadata, arginfo_phar_setMetadata, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; +#endif /* HAVE_SPL */ + +zend_function_entry phar_exception_methods[] = { + {NULL, NULL, NULL} +}; +/* }}} */ + +#define REGISTER_PHAR_CLASS_CONST_LONG(class_name, const_name, value) \ + zend_declare_class_constant_long(class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC); + +#if PHP_VERSION_ID < 50200 +# define phar_exception_get_default() zend_exception_get_default() +#else +# define phar_exception_get_default() zend_exception_get_default(TSRMLS_C) +#endif + +void phar_object_init(TSRMLS_D) /* {{{ */ +{ + zend_class_entry ce; + + INIT_CLASS_ENTRY(ce, "PharException", phar_exception_methods); + phar_ce_PharException = zend_register_internal_class_ex(&ce, phar_exception_get_default(), NULL TSRMLS_CC); + +#if HAVE_SPL + INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods); + phar_ce_archive = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL TSRMLS_CC); + + 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) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "GZ", PHAR_ENT_COMPRESSED_GZ) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "NONE", PHAR_ENT_COMPRESSED_NONE) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHAR", PHAR_FORMAT_PHAR) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "TAR", PHAR_FORMAT_TAR) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "ZIP", PHAR_FORMAT_ZIP) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "COMPRESSED", PHAR_ENT_COMPRESSION_MASK) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHP", PHAR_MIME_PHP) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHPS", PHAR_MIME_PHPS) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "MD5", PHAR_SIG_MD5) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PGP", PHAR_SIG_PGP) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA1", PHAR_SIG_SHA1) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA256", PHAR_SIG_SHA256) + REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA512", PHAR_SIG_SHA512) +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/phar_path_check.c b/ext/phar/phar_path_check.c new file mode 100755 index 0000000000..c1a273281b --- /dev/null +++ b/ext/phar/phar_path_check.c @@ -0,0 +1,187 @@ +/* Generated by re2c 0.12.3 on Tue Jan 8 18:41:21 2008 */ +#line 1 "ext/phar/phar_path_check.re" +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" + +phar_path_check_result phar_path_check(char **s, int *len, const char **error) +{ + const unsigned char *p = (const unsigned char*)*s; + const unsigned char *m; + + if (*len == 1 && *p == '.') { + *error = "current directory reference"; + return pcr_err_curr_dir; + } else if (*len == 2 && p[0] == '.' && p[1] == '.') { + *error = "upper directory reference"; + return pcr_err_up_dir; + } + +#define YYCTYPE unsigned char +#define YYCURSOR p +#define YYLIMIT p+*len +#define YYMARKER m +#define YYFILL(n) + +loop: +{ + +#line 48 "ext/phar/phar_path_check.c" + { + YYCTYPE yych; + + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + if(yych <= '.') { + if(yych <= 0x0A) { + if(yych <= 0x00) goto yy13; + if(yych <= 0x09) goto yy10; + goto yy12; + } else { + if(yych <= 0x19) goto yy10; + if(yych == '*') goto yy6; + goto yy15; + } + } else { + if(yych <= '?') { + if(yych <= '/') goto yy2; + if(yych <= '>') goto yy15; + goto yy8; + } else { + if(yych == '\\') goto yy4; + if(yych <= 0x7F) goto yy15; + goto yy10; + } + } +yy2: + yych = *(YYMARKER = ++YYCURSOR); + if(yych <= '-') goto yy3; + if(yych <= '.') goto yy16; + if(yych <= '/') goto yy18; +yy3: +#line 93 "ext/phar/phar_path_check.re" + { + goto loop; + } +#line 85 "ext/phar/phar_path_check.c" +yy4: + ++YYCURSOR; +#line 60 "ext/phar/phar_path_check.re" + { + *error = "back-slash"; + return pcr_err_back_slash; + } +#line 93 "ext/phar/phar_path_check.c" +yy6: + ++YYCURSOR; +#line 64 "ext/phar/phar_path_check.re" + { + *error = "star"; + return pcr_err_star; + } +#line 101 "ext/phar/phar_path_check.c" +yy8: + ++YYCURSOR; +#line 68 "ext/phar/phar_path_check.re" + { + if (**s == '/') { + (*s)++; + } + *len = (p - (const unsigned char*)*s) -1; + *error = NULL; + return pcr_use_query; + } +#line 113 "ext/phar/phar_path_check.c" +yy10: + ++YYCURSOR; +yy11: +#line 76 "ext/phar/phar_path_check.re" + { + *error ="illegal character"; + return pcr_err_illegal_char; + } +#line 122 "ext/phar/phar_path_check.c" +yy12: + yych = *++YYCURSOR; + goto yy11; +yy13: + ++YYCURSOR; +#line 80 "ext/phar/phar_path_check.re" + { + if (**s == '/') { + (*s)++; + (*len)--; + } + if ((p - (const unsigned char*)*s) - 1 != *len) + { + *error ="illegal character"; + return pcr_err_illegal_char; + } + *error = NULL; + return pcr_is_ok; + } +#line 142 "ext/phar/phar_path_check.c" +yy15: + yych = *++YYCURSOR; + goto yy3; +yy16: + yych = *++YYCURSOR; + if(yych <= 0x00) goto yy21; + if(yych <= '-') goto yy17; + if(yych <= '.') goto yy20; + if(yych <= '/') goto yy21; +yy17: + YYCURSOR = YYMARKER; + goto yy3; +yy18: + ++YYCURSOR; +#line 48 "ext/phar/phar_path_check.re" + { + *error = "double slash"; + return pcr_err_double_slash; + } +#line 162 "ext/phar/phar_path_check.c" +yy20: + yych = *++YYCURSOR; + if(yych <= 0x00) goto yy23; + if(yych == '/') goto yy23; + goto yy17; +yy21: + ++YYCURSOR; +#line 56 "ext/phar/phar_path_check.re" + { + *error = "current directory reference"; + return pcr_err_curr_dir; + } +#line 175 "ext/phar/phar_path_check.c" +yy23: + ++YYCURSOR; +#line 52 "ext/phar/phar_path_check.re" + { + *error = "upper directory reference"; + return pcr_err_up_dir; + } +#line 183 "ext/phar/phar_path_check.c" + } +} +#line 96 "ext/phar/phar_path_check.re" + +} diff --git a/ext/phar/phar_path_check.re b/ext/phar/phar_path_check.re new file mode 100755 index 0000000000..97a6b5d565 --- /dev/null +++ b/ext/phar/phar_path_check.re @@ -0,0 +1,97 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" + +phar_path_check_result phar_path_check(char **s, int *len, const char **error) +{ + const unsigned char *p = (const unsigned char*)*s; + const unsigned char *m; + + if (*len == 1 && *p == '.') { + *error = "current directory reference"; + return pcr_err_curr_dir; + } else if (*len == 2 && p[0] == '.' && p[1] == '.') { + *error = "upper directory reference"; + return pcr_err_up_dir; + } + +#define YYCTYPE unsigned char +#define YYCURSOR p +#define YYLIMIT p+*len +#define YYMARKER m +#define YYFILL(n) + +loop: +/*!re2c +END = "\x00"; +ILL = [\x01-\x19\x80-\xFF]; +EOS = "/" | END; +ANY = .; +"//" { + *error = "double slash"; + return pcr_err_double_slash; + } +"/.." EOS { + *error = "upper directory reference"; + return pcr_err_up_dir; + } +"/." EOS { + *error = "current directory reference"; + return pcr_err_curr_dir; + } +"\\" { + *error = "back-slash"; + return pcr_err_back_slash; + } +"*" { + *error = "star"; + return pcr_err_star; + } +"?" { + if (**s == '/') { + (*s)++; + } + *len = (p - (const unsigned char*)*s) -1; + *error = NULL; + return pcr_use_query; + } +ILL { + *error ="illegal character"; + return pcr_err_illegal_char; + } +END { + if (**s == '/') { + (*s)++; + (*len)--; + } + if ((p - (const unsigned char*)*s) - 1 != *len) + { + *error ="illegal character"; + return pcr_err_illegal_char; + } + *error = NULL; + return pcr_is_ok; + } +ANY { + goto loop; + } +*/ +} diff --git a/ext/phar/pharzip.h b/ext/phar/pharzip.h new file mode 100644 index 0000000000..e74b5ba47f --- /dev/null +++ b/ext/phar/pharzip.h @@ -0,0 +1,247 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef PHP_WIN32 +#pragma pack(1) +# define PHAR_ZIP_PACK +#else +# define PHAR_ZIP_PACK __attribute__((__packed__)) +#endif +typedef struct _phar_zip_file_header { + char signature[4]; /* local file header signature 4 bytes (0x04034b50) */ + char zipversion[2]; /* version needed to extract 2 bytes */ + php_uint16 flags; /* general purpose bit flag 2 bytes */ + php_uint16 compressed; /* compression method 2 bytes */ + php_uint16 timestamp; /* last mod file time 2 bytes */ + php_uint16 datestamp; /* last mod file date 2 bytes */ + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ + php_uint16 filename_len; /* file name length 2 bytes */ + php_uint16 extra_len; /* extra field length 2 bytes */ +/* file name (variable size) */ +/* extra field (variable size) */ +} PHAR_ZIP_PACK phar_zip_file_header; + +typedef struct _phar_zip_file_datadesc { + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ +} PHAR_ZIP_PACK phar_zip_data_desc; + +typedef struct _phar_zip_file_datadesc_zip64 { + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 8 bytes */ + php_uint32 compsize2; + php_uint32 uncompsize; /* uncompressed size 8 bytes */ + php_uint32 uncompsize2; +} PHAR_ZIP_PACK phar_zip_data_desc_zip64; + +typedef struct _phar_zip_archive_extra_data_record { + char signature[4]; /* archive extra data signature 4 bytes (0x08064b50) */ + php_uint32 len; /* extra field length 4 bytes */ +/* extra field data (variable size) */ +} PHAR_ZIP_PACK phar_zip_archive_extra_data_record; + +/* madeby/extractneeded value if bzip2 compression is used */ +#define PHAR_ZIP_BZIP2 "46" +/* madeby/extractneeded value for other cases */ +#define PHAR_ZIP_NORM "20" + +#define PHAR_ZIP_FLAG_ENCRYPTED 0x0001 +/* data descriptor present for this file */ +#define PHAR_ZIP_FLAG_DATADESC 0x0008 +#define PHAR_ZIP_FLAG_UTF8 0x0400 + +/* +0 - The file is stored (no compression) +1 - The file is Shrunk +2 - The file is Reduced with compression factor 1 +3 - The file is Reduced with compression factor 2 +4 - The file is Reduced with compression factor 3 +5 - The file is Reduced with compression factor 4 +6 - The file is Imploded +7 - Reserved for Tokenizing compression algorithm +8 - The file is Deflated +9 - Enhanced Deflating using Deflate64(tm) +10 - PKWARE Data Compression Library Imploding (old IBM TERSE) +11 - Reserved by PKWARE +12 - File is compressed using BZIP2 algorithm +13 - Reserved by PKWARE +14 - LZMA (EFS) +15 - Reserved by PKWARE +16 - Reserved by PKWARE +17 - Reserved by PKWARE +18 - File is compressed using IBM TERSE (new) +19 - IBM LZ77 z Architecture (PFS) +97 - WavPack compressed data +98 - PPMd version I, Rev 1 +*/ +#define PHAR_ZIP_COMP_NONE 0 +#define PHAR_ZIP_COMP_DEFLATE 8 +#define PHAR_ZIP_COMP_BZIP2 12 + +/* + -ASi Unix Extra Field: + ==================== + + The following is the layout of the ASi extra block for Unix. The + local-header and central-header versions are identical. + (Last Revision 19960916) + + Value Size Description + ----- ---- ----------- + (Unix3) 0x756e Short tag for this extra block type ("nu") + TSize Short total data size for this block + CRC Long CRC-32 of the remaining data + Mode Short file permissions + SizDev Long symlink'd size OR major/minor dev num + UID Short user ID + GID Short group ID + (var.) variable symbolic link filename + + Mode is the standard Unix st_mode field from struct stat, containing + user/group/other permissions, setuid/setgid and symlink info, etc. + + If Mode indicates that this file is a symbolic link, SizDev is the + size of the file to which the link points. Otherwise, if the file + is a device, SizDev contains the standard Unix st_rdev field from + struct stat (includes the major and minor numbers of the device). + SizDev is undefined in other cases. + + If Mode indicates that the file is a symbolic link, the final field + will be the name of the file to which the link points. The file- + name length can be inferred from TSize. + + [Note that TSize may incorrectly refer to the data size not counting + the CRC; i.e., it may be four bytes too small.] +*/ + +typedef struct _phar_zip_extra_field_header { + char tag[2]; + php_uint16 size; +} PHAR_ZIP_PACK phar_zip_extra_field_header; + +typedef struct _phar_zip_unix3 { + char tag[2]; /* 0x756e Short tag for this extra block type ("nu") */ + php_uint16 size; /* TSize Short total data size for this block */ + php_uint32 crc32; /* CRC Long CRC-32 of the remaining data */ + php_uint16 perms; /* Mode Short file permissions */ + php_uint32 symlinksize; /* SizDev Long symlink'd size OR major/minor dev num */ + php_uint16 uid; /* UID Short user ID */ + php_uint16 gid; /* GID Short group ID */ +/* (var.) variable symbolic link filename */ +} PHAR_ZIP_PACK phar_zip_unix3; + +typedef struct _phar_zip_central_dir_file { + char signature[4]; /* central file header signature 4 bytes (0x02014b50) */ + char madeby[2]; /* version made by 2 bytes */ + char zipversion[2]; /* version needed to extract 2 bytes */ + php_uint16 flags; /* general purpose bit flag 2 bytes */ + php_uint16 compressed; /* compression method 2 bytes */ + php_uint16 timestamp; /* last mod file time 2 bytes */ + php_uint16 datestamp; /* last mod file date 2 bytes */ + php_uint32 crc32; /* crc-32 4 bytes */ + php_uint32 compsize; /* compressed size 4 bytes */ + php_uint32 uncompsize; /* uncompressed size 4 bytes */ + php_uint16 filename_len; /* file name length 2 bytes */ + php_uint16 extra_len; /* extra field length 2 bytes */ + php_uint16 comment_len; /* file comment length 2 bytes */ + php_uint16 disknumber; /* disk number start 2 bytes */ + php_uint16 internal_atts; /* internal file attributes 2 bytes */ + php_uint32 external_atts; /* external file attributes 4 bytes */ + php_uint32 offset; /* relative offset of local header 4 bytes */ + +/* file name (variable size) */ +/* extra field (variable size) */ +/* file comment (variable size) */ +} PHAR_ZIP_PACK phar_zip_central_dir_file; + +typedef struct _phar_zip_dir_signature { + char signature[4]; /* header signature 4 bytes (0x05054b50) */ + php_uint16 size; /* size of data 2 bytes */ +} PHAR_ZIP_PACK phar_zip_dir_signature; + +typedef struct _phar_zip64_dir_end { + char signature[4]; /* zip64 end of central dir + signature 4 bytes (0x06064b50) */ + php_uint32 size1; /* size of zip64 end of central + directory record 8 bytes */ + php_uint32 size2; + char madeby[2]; /* version made by 2 bytes */ + php_uint16 extractneeded; /* version needed to extract 2 bytes */ + php_uint32 disknum; /* number of this disk 4 bytes */ + php_uint32 cdir_num; /* number of the disk with the + start of the central directory 4 bytes */ + php_uint32 entries1; /* total number of entries in the + central directory on this disk 8 bytes */ + php_uint32 entries2; + php_uint32 entriestotal1; /* total number of entries in the + central directory 8 bytes */ + php_uint32 entriestotal2; + php_uint32 cdirsize1; /* size of the central directory 8 bytes */ + php_uint32 cdirsize2; + php_uint32 offset1; /* offset of start of central + directory with respect to + the starting disk number 8 bytes */ + php_uint32 offset2; +/* zip64 extensible data sector (variable size) */ +} PHAR_ZIP_PACK phar_zip64_dir_end; + +typedef struct _phar_zip64_dir_locator { + char signature[4]; /* zip64 end of central dir locator + signature 4 bytes (0x07064b50) */ + php_uint32 disknum; /* number of the disk with the + start of the zip64 end of + central directory 4 bytes */ + php_uint32 diroffset1; /* relative offset of the zip64 + end of central directory record 8 bytes */ + php_uint32 diroffset2; + php_uint32 totaldisks; /* total number of disks 4 bytes */ +} PHAR_ZIP_PACK phar_zip64_dir_locator; + +typedef struct _phar_zip_dir_end { + char signature[4]; /* end of central dir signature 4 bytes (0x06054b50) */ + php_uint16 disknumber; /* number of this disk 2 bytes */ + php_uint16 centraldisk; /* number of the disk with the + start of the central directory 2 bytes */ + php_uint16 counthere; /* total number of entries in the + central directory on this disk 2 bytes */ + php_uint16 count; /* total number of entries in + the central directory 2 bytes */ + php_uint32 cdir_size; /* size of the central directory 4 bytes */ + php_uint32 cdir_offset; /* offset of start of central + directory with respect to + the starting disk number 4 bytes */ + php_uint16 comment_len; /* .ZIP file comment length 2 bytes */ +/* .ZIP file comment (variable size) */ +} PHAR_ZIP_PACK phar_zip_dir_end; +#ifdef PHP_WIN32 +#pragma pack() +#endif +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/php_phar.h b/ext/phar/php_phar.h new file mode 100644 index 0000000000..89023972f6 --- /dev/null +++ b/ext/phar/php_phar.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2005 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_PHAR_H +#define PHP_PHAR_H + +#define PHP_PHAR_VERSION "2.0.0b2-dev" + +#include "ext/standard/basic_functions.h" +extern zend_module_entry phar_module_entry; +#define phpext_phar_ptr &phar_module_entry + +#ifdef PHP_WIN32 +#define PHP_PHAR_API __declspec(dllexport) +#else +#define PHP_PHAR_API +#endif + +#endif /* PHP_PHAR_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/shortarc.php b/ext/phar/shortarc.php new file mode 100644 index 0000000000..fa52636646 --- /dev/null +++ b/ext/phar/shortarc.php @@ -0,0 +1,295 @@ + 2, + 'c' => 'text/plain', + 'cc' => 'text/plain', + 'cpp' => 'text/plain', + 'c++' => 'text/plain', + 'dtd' => 'text/plain', + 'h' => 'text/plain', + 'log' => 'text/plain', + 'rng' => 'text/plain', + 'txt' => 'text/plain', + 'xsd' => 'text/plain', + 'php' => 1, + 'inc' => 1, + 'avi' => 'video/avi', + 'bmp' => 'image/bmp', + 'css' => 'text/css', + 'gif' => 'image/gif', + 'htm' => 'text/html', + 'html' => 'text/html', + 'htmls' => 'text/html', + 'ico' => 'image/x-ico', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'js' => 'application/x-javascript', + 'midi' => 'audio/midi', + 'mid' => 'audio/midi', + 'mod' => 'audio/mod', + 'mov' => 'movie/quicktime', + 'mp3' => 'audio/mp3', + 'mpg' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'pdf' => 'application/pdf', + 'png' => 'image/png', + 'swf' => 'application/shockwave-flash', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'wav' => 'audio/wav', + 'xbm' => 'image/xbm', + 'xml' => 'text/xml', + ); + + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + + $basename = basename(__FILE__); + if (!strpos($_SERVER['REQUEST_URI'], $basename)) { + chdir(Extract_Phar::$temp); + include $web; + return; + } + $pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); + if (!$pt || $pt == '/') { + $pt = $web; + header('HTTP/1.1 301 Moved Permanently'); + header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); + exit; + } + $a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); + if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { + header('HTTP/1.0 404 Not Found'); + echo "\n \n File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; + exit; + } + $b = pathinfo($a); + if (!isset($b['extension'])) { + header('Content-Type: text/plain'); + header('Content-Length: ' . filesize($a)); + readfile($a); + exit; + } + if (isset($mimes[$b['extension']])) { + if ($mimes[$b['extension']] === 1) { + include $a; + exit; + } + if ($mimes[$b['extension']] === 2) { + highlight_file($a); + exit; + } + header('Content-Type: ' .$mimes[$b['extension']]); + header('Content-Length: ' . filesize($a)); + readfile($a); + exit; + } +} + +class Extract_Phar +{ + static $temp; + static $origdir; + const GZ = 0x1000; + const BZ2 = 0x2000; + const MASK = 0x3000; + const START = 'index.php'; + const LEN = XXXX; + + static function go($return = false) + { + $fp = fopen(__FILE__, 'rb'); + fseek($fp, self::LEN); + $L = unpack('V', $a = fread($fp, 4)); + $m = ''; + + do { + $read = 8192; + if ($L[1] - strlen($m) < 8192) { + $read = $L[1] - strlen($m); + } + $last = fread($fp, $read); + $m .= $last; + } while (strlen($last) && strlen($m) < $L[1]); + + if (strlen($m) < $L[1]) { + die('ERROR: manifest length read was "' . + strlen($m) .'" should be "' . + $L[1] . '"'); + } + + $info = self::_unpack($m); + $f = $info['c']; + + if ($f & self::GZ) { + if (!function_exists('gzinflate')) { + die('Error: zlib extension is not enabled -' . + ' gzinflate() function needed for zlib-compressed .phars'); + } + } + + if ($f & self::BZ2) { + if (!function_exists('bzdecompress')) { + die('Error: bzip2 extension is not enabled -' . + ' bzdecompress() function needed for bz2-compressed .phars'); + } + } + + $temp = self::tmpdir(); + + if (!$temp || !is_writable($temp)) { + $sessionpath = session_save_path(); + if (strpos ($sessionpath, ";") !== false) + $sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); + if (!file_exists($sessionpath) || !is_dir($sessionpath)) { + die('Could not locate temporary directory to extract phar'); + } + $temp = $sessionpath; + } + + $temp .= '/pharextract/'.basename(__FILE__, '.phar'); + self::$temp = $temp; + self::$origdir = getcwd(); + @mkdir($temp, 0777, true); + $temp = realpath($temp); + + if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { + self::_removeTmpFiles($temp, getcwd()); + @mkdir($temp, 0777, true); + @file_put_contents($temp . '/' . md5_file(__FILE__), ''); + + foreach ($info['m'] as $path => $file) { + $a = !file_exists(dirname($temp . '/' . $path)); + @mkdir(dirname($temp . '/' . $path), 0777, true); + clearstatcache(); + + if ($path[strlen($path) - 1] == '/') { + @mkdir($temp . '/' . $path, 0777); + } else { + file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); + @chmod($temp . '/' . $path, 0666); + } + } + } + + chdir($temp); + + if (!$return) { + include self::START; + } + } + + static function tmpdir() + { + if (strpos(PHP_OS, 'WIN') !== false) { + if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { + return $var; + } + if (is_dir('/temp') || mkdir('/temp')) { + return realpath('/temp'); + } + return false; + } + if ($var = getenv('TMPDIR')) { + return $var; + } + return realpath('/tmp'); + } + + static function _unpack($m) + { + $info = unpack('V', substr($m, 0, 4)); + // skip API version, phar flags, alias, metadata + $l = unpack('V', substr($m, 10, 4)); + $m = substr($m, 14 + $l[1]); + $s = unpack('V', substr($m, 0, 4)); + $o = 0; + $start = 4 + $s[1]; + $ret['c'] = 0; + + for ($i = 0; $i < $info[1]; $i++) { + // length of the file name + $len = unpack('V', substr($m, $start, 4)); + $start += 4; + // file name + $savepath = substr($m, $start, $len[1]); + $start += $len[1]; + // retrieve manifest data: + // 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags + // 5 = metadata length + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); + $ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] + & 0xffffffff); + $ret['m'][$savepath][7] = $o; + $o += $ret['m'][$savepath][2]; + $start += 24 + $ret['m'][$savepath][5]; + $ret['c'] |= $ret['m'][$savepath][4] & self::MASK; + } + return $ret; + } + + static function extractFile($path, $entry, $fp) + { + $data = ''; + $c = $entry[2]; + + while ($c) { + if ($c < 8192) { + $data .= @fread($fp, $c); + $c = 0; + } else { + $c -= 8192; + $data .= @fread($fp, 8192); + } + } + + if ($entry[4] & self::GZ) { + $data = gzinflate($data); + } elseif ($entry[4] & self::BZ2) { + $data = bzdecompress($data); + } + + if (strlen($data) != $entry[0]) { + die("Invalid internal .phar file (size error " . strlen($data) . " != " . + $stat[7] . ")"); + } + + if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { + die("Invalid internal .phar file (checksum error)"); + } + + return $data; + } + + static function _removeTmpFiles($temp, $origdir) + { + chdir($temp); + + foreach (glob('*') as $f) { + if (file_exists($f)) { + is_dir($f) ? @rmdir($f) : @unlink($f); + if (file_exists($f) && is_dir($f)) { + self::_removeTmpFiles($f, getcwd()); + } + } + } + + @rmdir($temp); + clearstatcache(); + chdir($origdir); + } +} diff --git a/ext/phar/stream.c b/ext/phar/stream.c new file mode 100644 index 0000000000..3d9f14e4d4 --- /dev/null +++ b/ext/phar/stream.c @@ -0,0 +1,845 @@ +/* + +----------------------------------------------------------------------+ + | phar:// stream wrapper support | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver <cellog@php.net> | + | Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ +*/ + +#define PHAR_STREAM 1 +#include "phar_internal.h" +#include "stream.h" +#include "dirstream.h" + +php_stream_ops phar_ops = { + phar_stream_write, /* write */ + phar_stream_read, /* read */ + phar_stream_close, /* close */ + phar_stream_flush, /* flush */ + "phar stream", + phar_stream_seek, /* seek */ + NULL, /* cast */ + phar_stream_stat, /* stat */ + NULL, /* set option */ +}; + +php_stream_wrapper_ops phar_stream_wops = { + phar_wrapper_open_url, + NULL, /* phar_wrapper_close */ + NULL, /* phar_wrapper_stat, */ + phar_wrapper_stat, /* stat_url */ + phar_wrapper_open_dir, /* opendir */ + "phar", + phar_wrapper_unlink, /* unlink */ + phar_wrapper_rename, /* rename */ + phar_wrapper_mkdir, /* create directory */ + phar_wrapper_rmdir, /* remove directory */ +}; + +php_stream_wrapper php_stream_phar_wrapper = { + &phar_stream_wops, + NULL, + 0 /* is_url */ +}; + +/** + * Open a phar file for streams API + */ +php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */ +{ + php_url *resource; + char *arch = NULL, *entry = NULL, *error; + int arch_len, entry_len; + + if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) { + return NULL; + } + if (mode[0] == 'a') { + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported"); + } + return NULL; + } + 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 or non-existent phar \"%s\"", filename); + } + } + return NULL; + } + resource = ecalloc(1, sizeof(php_url)); + resource->scheme = estrndup("phar", 4); + resource->host = arch; + + resource->path = entry; +#if MBO_0 + if (resource) { + fprintf(stderr, "Alias: %s\n", alias); + fprintf(stderr, "Scheme: %s\n", resource->scheme); +/* fprintf(stderr, "User: %s\n", resource->user);*/ +/* fprintf(stderr, "Pass: %s\n", resource->pass ? "***" : NULL);*/ + fprintf(stderr, "Host: %s\n", resource->host); +/* fprintf(stderr, "Port: %d\n", resource->port);*/ + fprintf(stderr, "Path: %s\n", resource->path); +/* fprintf(stderr, "Query: %s\n", resource->query);*/ +/* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/ + } +#endif + if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { + phar_archive_data **pphar = NULL; + + if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) { + pphar = NULL; + } + if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) { + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); + } + php_url_free(resource); + return NULL; + } + 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)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + } + efree(error); + } + php_url_free(resource); + return NULL; + } + } else { + if (phar_open_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) + { + if (error) { + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + } + efree(error); + } + php_url_free(resource); + return NULL; + } + } + return resource; +} +/* }}} */ + +/** + * used for fopen('phar://...') and company + */ +static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */ +{ + phar_entry_data *idata; + char *internal_file; + char *error; + HashTable *pharcontext; + php_url *resource = NULL; + php_stream *fpf; + zval **pzoption, *metadata; + uint host_len; + + if ((resource = phar_open_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) { + return NULL; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", path); + return NULL; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", path); + return NULL; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + /* strip leading "/" */ + internal_file = estrdup(resource->path + 1); + if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { + if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error TSRMLS_CC))) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host); + } + efree(internal_file); + php_url_free(resource); + return NULL; + } + if (error) { + efree(error); + } + fpf = php_stream_alloc(&phar_ops, idata, NULL, mode); + php_url_free(resource); + efree(internal_file); + if (context && context->options && zend_hash_find(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption) == SUCCESS) { + pharcontext = HASH_OF(*pzoption); + if (idata->internal_file->uncompressed_filesize == 0 + && idata->internal_file->compressed_filesize == 0 + && zend_hash_find(pharcontext, "compress", sizeof("compress"), (void**)&pzoption) == SUCCESS + && Z_TYPE_PP(pzoption) == IS_LONG + && (Z_LVAL_PP(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0 + ) { + idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK; + idata->internal_file->flags |= Z_LVAL_PP(pzoption); + } + if (zend_hash_find(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption) == SUCCESS) { + if (idata->internal_file->metadata) { + zval_ptr_dtor(&idata->internal_file->metadata); + idata->internal_file->metadata = NULL; + } + + MAKE_STD_ZVAL(idata->internal_file->metadata); + metadata = *pzoption; + ZVAL_ZVAL(idata->internal_file->metadata, metadata, 1, 0); + idata->phar->is_modified = 1; + } + } + if (opened_path) { + spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename); + } + return fpf; + } else { + if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) || !idata) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host); + } + efree(internal_file); + php_url_free(resource); + return NULL; + } + } + php_url_free(resource); + +#if MBO_0 + fprintf(stderr, "Pharname: %s\n", idata->phar->filename); + fprintf(stderr, "Filename: %s\n", internal_file); + fprintf(stderr, "Entry: %s\n", idata->internal_file->filename); + fprintf(stderr, "Size: %u\n", idata->internal_file->uncompressed_filesize); + fprintf(stderr, "Compressed: %u\n", idata->internal_file->flags); + fprintf(stderr, "Offset: %u\n", idata->internal_file->offset_within_phar); + fprintf(stderr, "Cached: %s\n", idata->internal_file->filedata ? "yes" : "no"); +#endif + + /* check length, crc32 */ + if (!idata->internal_file->is_crc_checked && phar_postprocess_file(wrapper, options, idata, idata->internal_file->crc32, &error TSRMLS_CC) != SUCCESS) { + /* already issued the error */ + phar_entry_delref(idata TSRMLS_CC); + efree(internal_file); + return NULL; + } + + if (!PHAR_G(cwd_init) && options & STREAM_OPEN_FOR_INCLUDE) { + char *entry = idata->internal_file->filename, *cwd; + + PHAR_G(cwd_init) = 1; + if ((idata->phar->is_tar || idata->phar->is_zip) && idata->internal_file->filename_len == sizeof(".phar/stub.php")-1 && !strncmp(idata->internal_file->filename, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + /* we're executing the stub, which doesn't count as a file */ + PHAR_G(cwd_init) = 0; + } else if ((cwd = strrchr(entry, '/'))) { + PHAR_G(cwd_len) = cwd - entry; + PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len)); + } else { + /* root directory */ + PHAR_G(cwd_len) = 0; + PHAR_G(cwd) = NULL; + } + } + fpf = php_stream_alloc(&phar_ops, idata, NULL, mode); + if (opened_path) { + spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename); + } + efree(internal_file); + return fpf; +} +/* }}} */ + +/** + * Used for fclose($fp) where $fp is a phar archive + */ +static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ +{ + phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC); + + return 0; +} +/* }}} */ + +/** + * used for fread($fp) and company on a fopen()ed phar file handle + */ +static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + phar_entry_data *data = (phar_entry_data *)stream->abstract; + size_t got; + + if (data->internal_file->is_deleted) { + stream->eof = 1; + return 0; + } + + /* use our proxy position */ + php_stream_seek(data->fp, data->position + data->zero, SEEK_SET); + + got = php_stream_read(data->fp, buf, MIN(count, data->internal_file->uncompressed_filesize - data->position)); + data->position = php_stream_tell(data->fp) - data->zero; + stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize); + + + return got; +} +/* }}} */ + +/** + * Used for fseek($fp) on a phar file handle + */ +static int phar_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */ +{ + phar_entry_data *data = (phar_entry_data *)stream->abstract; + + int res; + off_t temp; + switch (whence) { + case SEEK_END : + temp = data->zero + data->internal_file->uncompressed_filesize + offset; + break; + case SEEK_CUR : + temp = data->zero + data->position + offset; + break; + case SEEK_SET : + temp = data->zero + offset; + break; + } + if (temp > data->zero + (off_t) data->internal_file->uncompressed_filesize) { + *newoffset = -1; + return -1; + } + if (temp < data->zero) { + *newoffset = -1; + return -1; + } + res = php_stream_seek(data->fp, temp, SEEK_SET); + *newoffset = php_stream_tell(data->fp) - data->zero; + data->position = *newoffset; + return res; +} +/* }}} */ + +/** + * Used for writing to a phar file + */ +static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + phar_entry_data *data = (phar_entry_data *) stream->abstract; + + php_stream_seek(data->fp, data->position, SEEK_SET); + if (count != php_stream_write(data->fp, buf, count)) { + php_stream_wrapper_log_error(stream->wrapper, stream->flags TSRMLS_CC, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname); + return -1; + } + data->position = php_stream_tell(data->fp); + if (data->position > (off_t)data->internal_file->uncompressed_filesize) { + data->internal_file->uncompressed_filesize = data->position; + } + data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize; + data->internal_file->old_flags = data->internal_file->flags; + data->internal_file->is_modified = 1; + return count; +} +/* }}} */ + +/** + * Used to save work done on a writeable phar + */ +static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */ +{ + char *error; + int ret; + if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) { + ret = phar_flush(((phar_entry_data *)stream->abstract)->phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, error); + efree(error); + } + return ret; + } else { + return EOF; + } +} +/* }}} */ + + /* {{{ phar_dostat */ +/** + * stat an opened phar file handle stream, used by phar_stat() + */ +void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, + zend_bool is_temp_dir, char *alias, int alias_len TSRMLS_DC) +{ + char *tmp; + int tmp_len; + memset(ssb, 0, sizeof(php_stream_statbuf)); + + if (!is_temp_dir && !data->is_dir) { + ssb->sb.st_size = data->uncompressed_filesize; + ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; + ssb->sb.st_mode |= S_IFREG; /* regular file */ + /* timestamp is just the timestamp when this was added to the phar */ +#ifdef NETWARE + ssb->sb.st_mtime.tv_sec = data->timestamp; + ssb->sb.st_atime.tv_sec = data->timestamp; + ssb->sb.st_ctime.tv_sec = data->timestamp; +#else + ssb->sb.st_mtime = data->timestamp; + ssb->sb.st_atime = data->timestamp; + ssb->sb.st_ctime = data->timestamp; +#endif + } else if (!is_temp_dir && data->is_dir) { + ssb->sb.st_size = 0; + ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; + ssb->sb.st_mode |= S_IFDIR; /* regular directory */ + /* timestamp is just the timestamp when this was added to the phar */ +#ifdef NETWARE + ssb->sb.st_mtime.tv_sec = data->timestamp; + ssb->sb.st_atime.tv_sec = data->timestamp; + ssb->sb.st_ctime.tv_sec = data->timestamp; +#else + ssb->sb.st_mtime = data->timestamp; + ssb->sb.st_atime = data->timestamp; + ssb->sb.st_ctime = data->timestamp; +#endif + } else { + ssb->sb.st_size = 0; + ssb->sb.st_mode = 0777; + ssb->sb.st_mode |= S_IFDIR; /* regular directory */ +#ifdef NETWARE + ssb->sb.st_mtime.tv_sec = phar->max_timestamp; + ssb->sb.st_atime.tv_sec = phar->max_timestamp; + ssb->sb.st_ctime.tv_sec = phar->max_timestamp; +#else + ssb->sb.st_mtime = phar->max_timestamp; + ssb->sb.st_atime = phar->max_timestamp; + ssb->sb.st_ctime = phar->max_timestamp; +#endif + } + if (!phar->is_writeable) { + ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777); + } + + ssb->sb.st_nlink = 1; + ssb->sb.st_rdev = -1; + if (data) { + tmp_len = data->filename_len + alias_len; + } else { + tmp_len = alias_len + 1; + } + tmp = (char *) emalloc(tmp_len); + memcpy(tmp, alias, alias_len); + if (data) { + memcpy(tmp + alias_len, data->filename, data->filename_len); + } else { + *(tmp+alias_len) = '/'; + } + /* this is only for APC, so use /dev/null device - no chance of conflict there! */ + ssb->sb.st_dev = 0xc; + /* generate unique inode number for alias/filename, so no phars will conflict */ + ssb->sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len); + efree(tmp); +#ifndef PHP_WIN32 + ssb->sb.st_blksize = -1; + ssb->sb.st_blocks = -1; +#endif +} +/* }}}*/ + +/** + * Stat an opened phar file handle + */ +static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ +{ + phar_entry_data *data = (phar_entry_data *)stream->abstract; + + /* If ssb is NULL then someone is misbehaving */ + if (!ssb) { + return -1; + } + + phar_dostat(data->phar, data->internal_file, ssb, 0, data->phar->alias, data->phar->alias_len TSRMLS_CC); + return 0; +} +/* }}} */ + +/** + * Stream wrapper stat implementation of stat() + */ +static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, + php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + php_url *resource = NULL; + char *internal_file, *key, *error; + uint keylen; + ulong unused; + phar_archive_data *phar; + phar_entry_info *entry; + uint host_len; + int internal_file_len; + + if ((resource = phar_open_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) { + return FAILURE; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + return FAILURE; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + return FAILURE; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + internal_file = resource->path + 1; /* strip leading "/" */ + /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */ + if (FAILURE == phar_get_archive(&phar, resource->host, strlen(resource->host), NULL, 0, &error TSRMLS_CC)) { + php_url_free(resource); + if (error) { + efree(error); + } + return FAILURE; + } + if (error) { + efree(error); + } + if (*internal_file == '\0') { + /* root directory requested */ + phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); + php_url_free(resource); + return SUCCESS; + } + if (!phar->manifest.arBuckets) { + php_url_free(resource); + return FAILURE; + } + internal_file_len = strlen(internal_file); + /* search through the manifest of files, and if we have an exact match, it's a file */ + if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) { + phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC); + php_url_free(resource); + return SUCCESS; + } else { + /* search for directory (partial match of a file) */ + zend_hash_internal_pointer_reset(&phar->manifest); + while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { + if (HASH_KEY_NON_EXISTANT != + zend_hash_get_current_key_ex( + &phar->manifest, &key, &keylen, &unused, 0, NULL)) { + if (keylen >= (uint)internal_file_len && 0 == memcmp(internal_file, key, internal_file_len)) { + /* directory found, all dirs have the same stat */ + if (key[internal_file_len] == '/') { + phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); + php_url_free(resource); + return SUCCESS; + } + } + } + if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { + break; + } + } + /* check for mounted directories */ + if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) { + char *key; + ulong unused; + uint keylen; + + zend_hash_internal_pointer_reset(&phar->mounted_dirs); + while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) { + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) { + break; + } + if ((int)keylen >= internal_file_len || strncmp(key, internal_file, keylen)) { + continue; + } else { + char *test; + int test_len; + phar_entry_info *entry; + php_stream_statbuf ssbi; + + if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) { + goto free_resource; + } + if (!entry->tmp || !entry->is_mounted) { + goto free_resource; + } + test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen); + if (SUCCESS != php_stream_stat_path(test, &ssbi)) { + efree(test); + continue; + } + /* mount the file/directory just in time */ + if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) { + efree(test); + goto free_resource; + } + efree(test); + if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) { + goto free_resource; + } + phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC); + php_url_free(resource); + return SUCCESS; + } + } + } + } + +free_resource: + php_url_free(resource); + return FAILURE; +} +/* }}} */ + +/** + * Unlink a file within a phar archive + */ +static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + php_url *resource; + char *internal_file, *error; + phar_entry_data *idata; + phar_archive_data **pphar; + uint host_len; + + if ((resource = phar_open_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed"); + return 0; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource->scheme || !resource->host || !resource->path) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url); + return 0; + } + + if (strcasecmp("phar", resource->scheme)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url); + return 0; + } + + host_len = strlen(resource->host); + phar_request_initialize(TSRMLS_C); + + if (FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), resource->host, strlen(resource->host), (void **) &pphar)) { + pphar = NULL; + } + if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) { + php_url_free(resource); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); + return 0; + } + + /* need to copy to strip leading "/", will get touched again */ + internal_file = estrdup(resource->path + 1); + if (FAILURE == phar_get_entry_data(&idata, resource->host, strlen(resource->host), internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) { + /* constraints of fp refcount were not met */ + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error); + efree(error); + } else { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url); + } + efree(internal_file); + php_url_free(resource); + return 0; + } + if (error) { + efree(error); + } + if (idata->internal_file->fp_refcount > 1) { + /* more than just our fp resource is open for this file */ + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host); + efree(internal_file); + php_url_free(resource); + phar_entry_delref(idata TSRMLS_CC); + return 0; + } + php_url_free(resource); + efree(internal_file); + phar_entry_remove(idata, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } + return 1; +} +/* }}} */ + +static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + php_url *resource_from, *resource_to; + char *error; + phar_archive_data *phar, *pfrom, *pto; + phar_entry_info *entry; + uint host_len; + + error = NULL; + + 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) { + efree(error); + } + } + if (PHAR_G(readonly) && (!pfrom || !pfrom->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; + } + + 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 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; + } + + if (strcmp(resource_from->host, resource_to->host)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to); + return 0; + } + + /* 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); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from); + return 0; + } + + if (!resource_to->scheme || !resource_to->host || !resource_to->path) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to); + return 0; + } + + if (strcasecmp("phar", resource_from->scheme)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from); + return 0; + } + + if (strcasecmp("phar", resource_to->scheme)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to); + return 0; + } + + host_len = strlen(resource_from->host); + phar_request_initialize(TSRMLS_C); + + if (SUCCESS != phar_get_archive(&phar, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + efree(error); + return 0; + } + + if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) { + phar_entry_info new, *source; + + /* perform rename magic */ + if (entry->is_deleted) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to); + return 0; + } + /* transfer all data over to the new entry */ + memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info)); + /* mark the old one for deletion */ + entry->is_deleted = 1; + entry->fp = NULL; + entry->metadata = 0; + entry->link = entry->tmp = NULL; + source = entry; + + /* add to the manifest, and then store the pointer to the new guy in entry */ + zend_hash_add(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info), (void **) &entry); + + entry->filename = estrdup(resource_to->path+1); + if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + efree(error); + zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename)); + return 0; + } + entry->is_modified = 1; + entry->filename_len = strlen(entry->filename); + phar_flush(phar, 0, 0, 0, &error TSRMLS_CC); + if (error) { + php_url_free(resource_from); + php_url_free(resource_to); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); + efree(error); + zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename)); + return 0; + } + } + php_url_free(resource_from); + php_url_free(resource_to); + return 1; +} +/* }}} */ diff --git a/ext/phar/stream.h b/ext/phar/stream.h new file mode 100644 index 0000000000..f273acb0aa --- /dev/null +++ b/ext/phar/stream.h @@ -0,0 +1,49 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver <cellog@php.net> | + | Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +BEGIN_EXTERN_C() +int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC); + +php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC); +void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC); + +static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); +static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC); +static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); +static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC); + +/* file/stream handlers */ +static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC); +static size_t phar_stream_read( php_stream *stream, char *buf, size_t count TSRMLS_DC); +static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC); +static int phar_stream_flush(php_stream *stream TSRMLS_DC); +static int phar_stream_seek( php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC); +static int phar_stream_stat( php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); +END_EXTERN_C() + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/phar/stub.h b/ext/phar/stub.h new file mode 100644 index 0000000000..f5858e2f07 --- /dev/null +++ b/ext/phar/stub.h @@ -0,0 +1,33 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension generated stub | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver <cellog@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC) +{ + static const char newstub0[] = "<?php\n\n$web = '"; + static const char newstub1_0[] = "';\n\nif (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\nset_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());\nPhar::webPhar(null, $web);\ninclude 'phar://' . __FILE__ . '/' . Extract_Phar::START;\nreturn;\n}\n\nif (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {\nExtract_Phar::go(true);\n$mimes = array(\n'phps' => 2,\n'c' => 'text/plain',\n'cc' => 'text/plain',\n'cpp' => 'text/plain',\n'c++' => 'text/plain',\n'dtd' => 'text/plain',\n'h' => 'text/plain',\n'log' => 'text/plain',\n'rng' => 'text/plain',\n'txt' => 'text/plain',\n'xsd' => 'text/plain',\n'php' => 1,\n'inc' => 1,\n'avi' => 'video/avi',\n'bmp' => 'image/bmp',\n'css' => 'text/css',\n'gif' => 'image/gif',\n'htm' => 'text/html',\n'html' => 'text/html',\n'htmls' => 'text/html',\n'ico' => 'image/x-ico',\n'jpe' => 'image/jpeg',\n'jpg' => 'image/jpeg',\n'jpeg' => 'image/jpeg',\n'js' => 'application/x-javascript',\n'midi' => 'audio/midi',\n'mid' => 'audio/midi',\n'mod' => 'audio/mod',\n'mov' => 'movie/quicktime',\n'mp3' => 'audio/mp3',\n'mpg' => 'video/mpeg',\n'mpeg' => 'video/mpeg',\n'pdf' => 'application/pdf',\n'png' => 'image/png',\n'swf' => 'application/shockwave-flash',\n'tif' => 'image/tiff',\n'tiff' => 'image/tiff',\n'wav' => 'audio/wav',\n'xbm' => 'image/xbm',\n'xml' => 'text/xml',\n);\n\nheader(\"Cache-Control: no-cache, must-revalidate\");\nheader(\"Pragma: no-cache\");\n\n$basename = basename(__FILE__);\nif (!strpos($_SERVER['REQUEST_URI'], $basename)) {\nchdir(Extract_Phar::$temp);\ninclude $web;\nreturn;\n}\n$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));\nif (!$pt || $pt == '/') {\n$pt = $web;\nheader('HTTP/1.1 301 Moved Permanently');\nheader('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);\nexit;\n}\n$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);\nif (!$a || strlen(dirname($a)) < strlen("; + static const char newstub1_1[] = "Extract_Phar::$temp)) {\nheader('HTTP/1.0 404 Not Found');\necho \"<html>\\n <head>\\n <title>File Not Found<title>\\n </head>\\n <body>\\n <h1>404 - File \", $pt, \" Not Found</h1>\\n </body>\\n</html>\";\nexit;\n}\n$b = pathinfo($a);\nif (!isset($b['extension'])) {\nheader('Content-Type: text/plain');\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\nif (isset($mimes[$b['extension']])) {\nif ($mimes[$b['extension']] === 1) {\ninclude $a;\nexit;\n}\nif ($mimes[$b['extension']] === 2) {\nhighlight_file($a);\nexit;\n}\nheader('Content-Type: ' .$mimes[$b['extension']]);\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\n}\n\nclass Extract_Phar\n{\nstatic $temp;\nstatic $origdir;\nconst GZ = 0x1000;\nconst BZ2 = 0x2000;\nconst MASK = 0x3000;\nconst START = '"; + static const char newstub2[] = "';\nconst LEN = "; + static const char newstub3_0[] = ";\n\nstatic function go($return = false)\n{\n$fp = fopen(__FILE__, 'rb');\nfseek($fp, self::LEN);\n$L = unpack('V', $a = fread($fp, 4));\n$m = '';\n\ndo {\n$read = 8192;\nif ($L[1] - strlen($m) < 8192) {\n$read = $L[1] - strlen($m);\n}\n$last = fread($fp, $read);\n$m .= $last;\n} while (strlen($last) && strlen($m) < $L[1]);\n\nif (strlen($m) < $L[1]) {\ndie('ERROR: manifest length read was \"' .\nstrlen($m) .'\" should be \"' .\n$L[1] . '\"');\n}\n\n$info = self::_unpack($m);\n$f = $info['c'];\n\nif ($f & self::GZ) {\nif (!function_exists('gzinflate')) {\ndie('Error: zlib extension is not enabled -' .\n' gzinflate() function needed for zlib-compressed .phars');\n}\n}\n\nif ($f & self::BZ2) {\nif (!function_exists('bzdecompress')) {\ndie('Error: bzip2 extension is not enabled -' .\n' bzdecompress() function needed for bz2-compressed .phars');\n}\n}\n\n$temp = self::tmpdir();\n\nif (!$temp || !is_writable($temp)) {\n$sessionpath = session_save_path();\nif (strpos ($sessionpath, \";\") !== false)\n$sessionpath = substr ($sessionpath, strpos ($sessionpath, \";\")+1);\nif (!file_exists($sessionpath) || !is_dir($sessionpath)) {\ndie('Could not locate temporary directory to extract phar');\n}\n$temp = $sessionpath;\n}\n\n$temp .= '/pharextract/'.basename(__FILE__, '.phar');\nself::$temp = $temp;\nself::$origdir = getcwd();\n@mkdir($temp, 0777, true);\n$temp = realpath($temp);\n\nif (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {\nself::_removeTmpFiles($temp, getcwd());\n@mkdir($temp, 0777, true);\n@file_put_contents($temp . '/' . md5_file(__FILE__), '');\n\nforeach ($info['m'] as $path => $file) {\n$a = !file_exists(dirname($temp . '/' . $path));\n@mkdir(dirname($temp . '/' . $path), 0777, true);\nclearstatcache();\n\nif ($path[strlen($path) - 1] == '/') {\n@mkdir($temp . '/' . $path, 0777);\n} else {\nfile_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));\n@chmod($temp . '/' . $path, 0666);\n}\n}\n}\n\nchdir($temp);\n\nif (!$return) {\ninclude self::START;\n}\n}\n\nstatic fun"; + static const char newstub3_1[] = "ction tmpdir()\n{\nif (strpos(PHP_OS, 'WIN') !== false) {\nif ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {\nreturn $var;\n}\nif (is_dir('/temp') || mkdir('/temp')) {\nreturn realpath('/temp');\n}\nreturn false;\n}\nif ($var = getenv('TMPDIR')) {\nreturn $var;\n}\nreturn realpath('/tmp');\n}\n\nstatic function _unpack($m)\n{\n$info = unpack('V', substr($m, 0, 4));\n $l = unpack('V', substr($m, 10, 4));\n$m = substr($m, 14 + $l[1]);\n$s = unpack('V', substr($m, 0, 4));\n$o = 0;\n$start = 4 + $s[1];\n$ret['c'] = 0;\n\nfor ($i = 0; $i < $info[1]; $i++) {\n $len = unpack('V', substr($m, $start, 4));\n$start += 4;\n $savepath = substr($m, $start, $len[1]);\n$start += $len[1];\n $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));\n$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]\n& 0xffffffff);\n$ret['m'][$savepath][7] = $o;\n$o += $ret['m'][$savepath][2];\n$start += 24 + $ret['m'][$savepath][5];\n$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;\n}\nreturn $ret;\n}\n\nstatic function extractFile($path, $entry, $fp)\n{\n$data = '';\n$c = $entry[2];\n\nwhile ($c) {\nif ($c < 8192) {\n$data .= @fread($fp, $c);\n$c = 0;\n} else {\n$c -= 8192;\n$data .= @fread($fp, 8192);\n}\n}\n\nif ($entry[4] & self::GZ) {\n$data = gzinflate($data);\n} elseif ($entry[4] & self::BZ2) {\n$data = bzdecompress($data);\n}\n\nif (strlen($data) != $entry[0]) {\ndie(\"Invalid internal .phar file (size error \" . strlen($data) . \" != \" .\n$stat[7] . \")\");\n}\n\nif ($entry[3] != sprintf(\"%u\", crc32($data) & 0xffffffff)) {\ndie(\"Invalid internal .phar file (checksum error)\");\n}\n\nreturn $data;\n}\n\nstatic function _removeTmpFiles($temp, $origdir)\n{\nchdir($temp);\n\nforeach (glob('*') as $f) {\nif (file_exists($f)) {\nis_dir($f) ? @rmdir($f) : @unlink($f);\nif (file_exists($f) && is_dir($f)) {\nself::_removeTmpFiles($f, getcwd());\n}\n}\n}\n\n@rmdir($temp);\nclearstatcache();\nchdir($origdir);\n}\n}\n\nExtract_Phar::go();\n__HALT_COMPILER(); ?>"; + + static const int newstub_len = 6633; + + *len = spprintf(stub, name_len + web_len + newstub_len, "%s%s%s%s%s%s%d%s%s", newstub0, web, newstub1_0, newstub1_1, index_php, newstub2, name_len + web_len + newstub_len, newstub3_0, newstub3_1); +} diff --git a/ext/phar/tar.c b/ext/phar/tar.c new file mode 100644 index 0000000000..ac19ef3f68 --- /dev/null +++ b/ext/phar/tar.c @@ -0,0 +1,831 @@ +/* + +----------------------------------------------------------------------+ + | TAR archive support for Phar | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov <dmitry@zend.com> | + | Gregory Beaver <cellog@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "phar_internal.h" + +static php_uint32 phar_tar_number(char *buf, int len) /* {{{ */ +{ + php_uint32 num = 0; + int i = 0; + + while (i < len && buf[i] == ' ') { + ++i; + } + while (i < len && + buf[i] >= '0' && + buf[i] <= '7') { + num = num * 8 + (buf[i] - '0'); + ++i; + } + return num; +} +/* }}} */ + +/* adapted from format_octal() in libarchive + * + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +static int phar_tar_octal(char *buf, php_uint32 val, int len) /* {{{ */ +{ + char *p = buf; + int s = len; + + p += len; /* Start at the end and work backwards. */ + while (s-- > 0) { + *--p = (char)('0' + (val & 7)); + val >>= 3; + } + + if (val == 0) + return SUCCESS; + + /* If it overflowed, fill field with max value. */ + while (len-- > 0) + *p++ = '7'; + + return FAILURE; +} +/* }}} */ + +static php_uint32 phar_tar_checksum(char *buf, int len) /* {{{ */ +{ + php_uint32 sum = 0; + char *end = buf + len; + + while (buf != end) { + sum += (unsigned char)*buf; + ++buf; + } + return sum; +} +/* }}} */ + +int phar_is_tar(char *buf, char *fname) +{ + tar_header *header = (tar_header *) buf; + php_uint32 checksum = phar_tar_number(header->checksum, sizeof(header->checksum)); + php_uint32 ret; + char save[sizeof(header->checksum)]; + + /* assume that the first filename in a tar won't begin with <?php */ + if (!strncmp(buf, "<?php", sizeof("<?php")-1)) { + return 0; + } + + memcpy(save, header->checksum, sizeof(header->checksum)); + memset(header->checksum, ' ', sizeof(header->checksum)); + ret = (checksum == phar_tar_checksum(buf, 512)); + memcpy(header->checksum, save, sizeof(header->checksum)); + if (!ret && strstr(fname, ".tar")) { + /* probably a corrupted tar - so we will pretend it is one */ + return 1; + } + return ret; +} + +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, is_data, options, &phar, error TSRMLS_CC); + + if (FAILURE == ret) { + return FAILURE; + } + + if (pphar) { + *pphar = phar; + } + + phar->is_data = is_data; + + if (phar->is_tar) { + return ret; + } + + if (phar->is_brandnew) { + phar->is_tar = 1; + phar->internal_file_start = 0; + return SUCCESS; + } + + /* we've reached here - the phar exists and is a regular phar */ + if (error) { + spprintf(error, 4096, "phar tar error: \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar", fname); + } + return FAILURE; +} + +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) /* {{{ */ +{ + char buf[512], *actual_alias = NULL, *p; + phar_entry_info entry = {0}; + size_t pos = 0, read, totalsize; + tar_header *hdr; + php_uint32 sum1, sum2, size, old; + phar_archive_data *myphar, **actual; + + if (error) { + *error = NULL; + } + + php_stream_seek(fp, 0, SEEK_END); + totalsize = php_stream_tell(fp); + php_stream_seek(fp, 0, SEEK_SET); + read = php_stream_read(fp, buf, sizeof(buf)); + if (read != sizeof(buf)) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname); + } + php_stream_close(fp); + return FAILURE; + } + hdr = (tar_header*)buf; + old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0); + + myphar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data)); + zend_hash_init(&myphar->manifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_hash_init(&myphar->mounted_dirs, sizeof(char *), + zend_get_hash_value, NULL, 0); + myphar->is_tar = 1; + /* remember whether this entire phar was compressed with gz/bzip2 */ + myphar->flags = compression; + + entry.is_tar = 1; + entry.is_crc_checked = 1; + entry.phar = myphar; + do { + pos += sizeof(buf); + hdr = (tar_header*) buf; + sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum)); + if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) { + break; + } + memset(hdr->checksum, ' ', sizeof(hdr->checksum)); + sum2 = phar_tar_checksum(buf, old?sizeof(old_tar_header):sizeof(tar_header)); + + size = entry.uncompressed_filesize = entry.compressed_filesize = + phar_tar_number(hdr->size, sizeof(hdr->size)); + + if (!old && hdr->prefix[0] != 0) { + char name[256]; + + strcpy(name, hdr->prefix); + /* remove potential buffer overflow */ + if (hdr->name[99]) { + strncat(name, hdr->name, 100); + } else { + strcat(name, hdr->name); + } + entry.filename_len = strlen(hdr->prefix) + 100; + if (name[entry.filename_len - 1] == '/') { + /* some tar programs store directories with trailing slash */ + entry.filename_len--; + } + entry.filename = estrndup(name, entry.filename_len); + } else { + entry.filename = estrdup(hdr->name); + entry.filename_len = strlen(entry.filename); + if (entry.filename[entry.filename_len - 1] == '/') { + /* some tar programs store directories with trailing slash */ + entry.filename[entry.filename_len - 1] = '\0'; + entry.filename_len--; + } + } + if (sum1 != sum2) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename); + } + efree(entry.filename); + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + + entry.tar_type = ((old & (hdr->typeflag == 0))?'0':hdr->typeflag); + entry.offset = entry.offset_abs = pos; /* header_offset unused in tar */ + entry.fp_type = PHAR_FP; + entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK; + entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime)); + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) { + entry.tar_type = TAR_DIR; + } + if (entry.tar_type == TAR_DIR) { + entry.is_dir = 1; + } else { + entry.is_dir = 0; + } + + entry.link = NULL; + if (entry.tar_type == TAR_LINK) { + if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname); + } + efree(entry.filename); + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + entry.link = estrdup(hdr->linkname); + } else if (entry.tar_type == TAR_SYMLINK) { + entry.link = estrdup(hdr->linkname); + } + zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL); + if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + size_t read; + /* found explicit alias */ + if (size > 511) { + if (error) { + spprintf(error, 4096, "phar error: tar-based phar \"%s\" has alias that is larger than 511 bytes, cannot process", fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + read = php_stream_read(fp, buf, size); + if (read == size) { + buf[size] = '\0'; + if (!phar_validate_alias(buf, size)) { + if (size > 50) { + buf[50] = '.'; + buf[51] = '.'; + buf[52] = '.'; + buf[53] = '\0'; + } + if (error) { + spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + actual_alias = estrndup(buf, size); + myphar->alias = actual_alias; + myphar->alias_len = size; + php_stream_seek(fp, pos, SEEK_SET); + } else { + if (error) { + spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + } + size = (size+511)&~511; + pos += size; + if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) { + /* this is not good enough - seek succeeds even on truncated tars */ + php_stream_seek(fp, size, SEEK_CUR); + if ((uint)php_stream_tell(fp) > totalsize) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + } + read = php_stream_read(fp, buf, sizeof(buf)); + if (read != sizeof(buf)) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + } while (read != 0); + myphar->fname = estrndup(fname, fname_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(myphar->fname, fname_len); +#endif + myphar->fname_len = fname_len; + p = strrchr(myphar->fname, '/'); + if (p) { + myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p); + if (myphar->ext == p) { + myphar->ext = memchr(p + 1, '.', (myphar->fname + fname_len) - p - 1); + } + if (myphar->ext) { + myphar->ext_len = (myphar->fname + fname_len) - myphar->ext; + } + } + myphar->fp = fp; + phar_request_initialize(TSRMLS_C); + if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) { + if (error) { + spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname); + } + php_stream_close(fp); + zend_hash_destroy(&myphar->manifest); + myphar->manifest.arBuckets = 0; + zend_hash_destroy(&myphar->mounted_dirs); + myphar->mounted_dirs.arBuckets = 0; + efree(myphar); + return FAILURE; + } + 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), 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_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 { + 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) { + *pphar = myphar; + } + return SUCCESS; +} +/* }}} */ + +struct _phar_pass_tar_info { + php_stream *old; + php_stream *new; + int free_fp; + int free_ufp; + char **error; +}; + +int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) +{ + tar_header header; + size_t pos; + phar_entry_info *entry = (phar_entry_info *) pDest; + struct _phar_pass_tar_info *fp = (struct _phar_pass_tar_info *)argument; + char padding[512]; + + if (entry->is_mounted) { + return ZEND_HASH_APPLY_KEEP; + } + if (entry->is_deleted) { + if (entry->fp_refcount <= 0) { + return ZEND_HASH_APPLY_REMOVE; + } else { + /* we can't delete this in-memory until it is closed */ + return ZEND_HASH_APPLY_KEEP; + } + } + + memset((char *) &header, 0, sizeof(header)); + if (entry->filename_len > 100) { + if (entry->filename_len > 255) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too long for tar file format", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + memcpy(header.prefix, entry->filename+100, entry->filename_len - 100); + memcpy(header.name, entry->filename, 100); + } else { + memcpy(header.name, entry->filename, entry->filename_len); + } + phar_tar_octal(header.mode, entry->flags & PHAR_ENT_PERM_MASK, sizeof(header.mode)-1); + if (FAILURE == phar_tar_octal(header.size, entry->uncompressed_filesize, sizeof(header.size)-1)) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too large for tar file format", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, file modification time of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + /* calc checksum */ + header.typeflag = entry->tar_type; + if (entry->link) { + strncpy(header.linkname, entry->link, strlen(entry->link)); + } + strncpy(header.magic, "ustar", sizeof("ustar")-1); + strncpy(header.version, "00", sizeof("00")-1); + strncpy(header.checksum, " ", sizeof(" ")-1); + entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header)); + if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, checksum of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + + /* write header */ + entry->header_offset = php_stream_tell(fp->new); + if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for file \"%s\" could not be written", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + pos = php_stream_tell(fp->new); /* save start of file within tar */ + + /* write contents */ + if (entry->uncompressed_filesize) { + if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) { + return ZEND_HASH_APPLY_STOP; + } + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written, seek failed", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize)) { + if (fp->error) { + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename); + } + return ZEND_HASH_APPLY_STOP; + } + + memset(padding, 0, 512); + php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize); + } + if (!entry->is_modified && entry->fp_refcount) { + /* open file pointers refer to this fp, do not free the stream */ + switch (entry->fp_type) { + case PHAR_FP: + fp->free_fp = 0; + break; + case PHAR_UFP: + fp->free_ufp = 0; + default: + break; + } + } + + entry->is_modified = 0; + if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) { + if (!entry->fp_refcount) { + php_stream_close(entry->fp); + } + entry->fp = NULL; + } + entry->fp_type = PHAR_FP; + + /* note new location within tar */ + entry->offset = entry->offset_abs = pos; + return ZEND_HASH_APPLY_KEEP; +} + +int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */ +{ + phar_entry_info entry = {0}; + static const char newstub[] = "<?php // tar-based phar archive stub file\n__HALT_COMPILER();"; + php_stream *oldfile, *newfile, *stubfile; + int closeoldfile, free_user_stub; + struct _phar_pass_tar_info pass; + char *buf; + + entry.flags = PHAR_ENT_PERM_DEF_FILE; + entry.timestamp = time(NULL); + entry.is_modified = 1; + entry.is_crc_checked = 1; + entry.is_tar = 1; + entry.tar_type = '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); + entry.filename_len = sizeof(".phar/alias.txt")-1; + entry.fp = php_stream_fopen_tmpfile(); + entry.crc32 = phar_tar_checksum(phar->alias, phar->alias_len); + if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) { + if (error) { + spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + entry.uncompressed_filesize = phar->alias_len; + if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + if (error) { + spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + } else { + zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1); + } + + /* set stub */ + if (user_stub && !defaultstub) { + char *pos; + if (len < 0) { + /* resource passed in */ + if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) { + if (error) { + spprintf(error, 0, "unable to access resource to copy stub to new tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + if (len == -1) { + len = PHP_STREAM_COPY_ALL; + } else { + len = -len; + } + user_stub = 0; + if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) { + if (error) { + spprintf(error, 0, "unable to read resource to copy stub to new tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + free_user_stub = 1; + } else { + free_user_stub = 0; + } + if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) + { + if (error) { + spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + return EOF; + } + len = pos - user_stub + 18; + entry.fp = php_stream_fopen_tmpfile(); + entry.uncompressed_filesize = len + 5; + + if ((size_t)len != php_stream_write(entry.fp, user_stub, len) + || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) { + if (error) { + spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + php_stream_close(entry.fp); + return EOF; + } + entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); + entry.filename_len = sizeof(".phar/stub.php")-1; + zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL); + if (free_user_stub) { + efree(user_stub); + } + } else { + /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */ + entry.fp = php_stream_fopen_tmpfile(); + + if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { + php_stream_close(entry.fp); + if (error) { + spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); + } + return EOF; + } + + entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1; + entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); + entry.filename_len = sizeof(".phar/stub.php")-1; + + if (!defaultstub) { + if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_close(entry.fp); + efree(entry.filename); + if (error) { + spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + } else { + php_stream_close(entry.fp); + efree(entry.filename); + } + } else { + if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_close(entry.fp); + efree(entry.filename); + if (error) { + spprintf(error, 0, "unable to overwrite stub in tar-based phar \"%s\"", phar->fname); + } + return EOF; + } + } + } + +nostub: + + if (phar->fp && !phar->is_brandnew) { + oldfile = phar->fp; + closeoldfile = 0; + php_stream_rewind(oldfile); + } else { + oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL); + closeoldfile = oldfile != NULL; + } + newfile = php_stream_fopen_tmpfile(); + if (!newfile) { + if (error) { + spprintf(error, 0, "unable to create temporary file"); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + return EOF; + } + + pass.old = oldfile; + pass.new = newfile; + pass.error = error; + pass.free_fp = 1; + pass.free_ufp = 1; + + zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC); + + /* add final zero blocks */ + buf = (char *) ecalloc(1024, 1); + php_stream_write(newfile, buf, 1024); + efree(buf); + + if (closeoldfile) { + php_stream_close(oldfile); + } + /* on error in the hash iterator above, error is set */ + if (error && *error) { + php_stream_close(newfile); + return EOF; + } + if (phar->fp && pass.free_fp) { + php_stream_close(phar->fp); + } + if (phar->ufp) { + if (pass.free_ufp) { + php_stream_close(phar->ufp); + } + phar->ufp = NULL; + } + + phar->is_brandnew = 0; + + php_stream_rewind(newfile); + + if (phar->donotflush) { + /* deferred flush */ + phar->fp = newfile; + } else { + phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); + if (!phar->fp) { + phar->fp = newfile; + if (error) { + spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname); + } + return EOF; + } + if (phar->flags & PHAR_FILE_COMPRESSED_GZ) { + php_stream_filter *filter; + /* to properly compress, we have to tell zlib to add a zlib header */ + zval filterparams; + + array_init(&filterparams); +/* this is defined in zlib's zconf.h */ +#ifndef MAX_WBITS +#define MAX_WBITS 15 +#endif + add_assoc_long(&filterparams, "window", MAX_WBITS + 16); + filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC); + zval_dtor(&filterparams); + if (!filter) { + /* copy contents uncompressed rather than lose them */ + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + php_stream_close(newfile); + if (error) { + spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); + } + return EOF; + } + php_stream_filter_append(&phar->fp->writefilters, filter); + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(phar->fp); + /* use the temp stream as our base */ + phar->fp = newfile; + } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) { + php_stream_filter *filter; + + filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC); + php_stream_filter_append(&phar->fp->writefilters, filter); + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + php_stream_filter_flush(filter, 1); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_close(phar->fp); + /* use the temp stream as our base */ + phar->fp = newfile; + } else { + php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL); + /* we could also reopen the file in "rb" mode but there is no need for that */ + php_stream_close(newfile); + } + } + return EOF; +} +/* }}} */ diff --git a/ext/phar/tar.h b/ext/phar/tar.h new file mode 100644 index 0000000000..6dc1fd3127 --- /dev/null +++ b/ext/phar/tar.h @@ -0,0 +1,90 @@ +#ifndef __PHAR_TAR_H +#define __PHAR_TAR_H +/* + +----------------------------------------------------------------------+ + | TAR archive support for Phar | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov <dmitry@zend.com> | + | Gregory Beaver <cellog@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef PHP_WIN32 +#pragma pack(1) +# define PHAR_TAR_PACK +#else +# define PHAR_TAR_PACK __attribute__((__packed__)) +#endif +/** + * the format of the header block for a file, in the older UNIX-compatible + * TAR format + */ +typedef struct _old_tar_header { /* {{{ */ + char name[100]; /* name of file; + directory is indicated by a trailing slash (/) */ + char mode[8]; /* file mode */ + char uid[8]; /* owner user ID */ + char gid[8]; /* owner group ID */ + char size[12]; /* length of file in bytes */ + char mtime[12]; /* modify time of file */ + char checksum[8]; /* checksum for header */ + char link; /* indicator for links; + 1 for a linked file, + 2 for a symbolic link, + 0 otherwise */ + char linkname[100]; /* name of linked file */ +} PHAR_TAR_PACK old_tar_header; +/* }}} */ + +/** + * the new USTAR header format. + * Note that tar can determine that the USTAR format is being used by the + * presence of the null-terminated string "ustar" in the magic field. + */ +typedef struct _tar_header { /* {{{ */ + char name[100]; /* name of file */ + char mode[8]; /* file mode */ + char uid[8]; /* owner user ID */ + char gid[8]; /* owner group ID */ + char size[12]; /* length of file in bytes */ + char mtime[12]; /* modify time of file */ + char checksum[8]; /* checksum for header */ + char typeflag; /* type of file + 0 Regular file + 1 Link to another file already archived + 2 Symbolic link + 3 Character special device + 4 Block special device + 5 Directory + 6 FIFO special file + 7 Reserved */ + char linkname[100]; /* name of linked file */ + char magic[6]; /* USTAR indicator */ + char version[2]; /* USTAR version */ + char uname[32]; /* owner user name */ + char gname[32]; /* owner group name */ + char devmajor[8]; /* device major number */ + char devminor[8]; /* device minor number */ + char prefix[155]; /* prefix for file name; + the value of the prefix field, if non-null, + is prefixed to the name field to allow names + longer then 100 characters */ + char padding[12]; /* unused zeroed bytes */ +} PHAR_TAR_PACK tar_header; +/* }}} */ + +#ifdef PHP_WIN32 +#pragma pack() +#endif + +#endif /* __PHAR_TAR_H */ diff --git a/ext/phar/tests/001.phpt b/ext/phar/tests/001.phpt new file mode 100644 index 0000000000..1205e4e1aa --- /dev/null +++ b/ext/phar/tests/001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Phar::apiVersion +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +var_dump(Phar::apiVersion()); +?> +===DONE=== +--EXPECT-- +string(5) "1.1.1" +===DONE=== diff --git a/ext/phar/tests/002.phpt b/ext/phar/tests/002.phpt new file mode 100644 index 0000000000..a7cf0cb2d2 --- /dev/null +++ b/ext/phar/tests/002.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar::mapPhar truncated manifest/improper params +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +try { +Phar::mapPhar(5, 'hio', 'hi'); + +Phar::mapPhar(); +} catch (Exception $e) { + echo $e->getMessage(); +} +__HALT_COMPILER(); ?> +--EXPECTF-- +Warning: Phar::mapPhar() expects at most 2 parameters, 3 given in %s002.php on line %d +internal corruption of phar "%s002.php" (truncated manifest at manifest length) \ No newline at end of file diff --git a/ext/phar/tests/003.phpt b/ext/phar/tests/003.phpt new file mode 100644 index 0000000000..fcc95a8481 --- /dev/null +++ b/ext/phar/tests/003.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar::canCompress +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +/* check this works and actually returns the boolean value */ +var_dump(Phar::canCompress() == ( + extension_loaded("zlib") || extension_loaded("bz2") + )); +?> +--EXPECT-- +bool(true) diff --git a/ext/phar/tests/003a.phpt b/ext/phar/tests/003a.phpt new file mode 100755 index 0000000000..37e31072d4 --- /dev/null +++ b/ext/phar/tests/003a.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar::canCompress, specific +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +var_dump(Phar::canCompress(Phar::GZ) == extension_loaded("zlib")); +var_dump(Phar::canCompress(Phar::BZ2) == extension_loaded("bz2")); +?> +===DONE=== +--EXPECT-- +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/tests/004.phpt b/ext/phar/tests/004.phpt new file mode 100644 index 0000000000..963a9b45a0 --- /dev/null +++ b/ext/phar/tests/004.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar::mapPhar no __HALT_COMPILER(); +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--FILE-- +<?php +try { +Phar::mapPhar('hio'); +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +--EXPECTF-- +__HALT_COMPILER(); must be declared in a phar diff --git a/ext/phar/tests/005.phpt b/ext/phar/tests/005.phpt new file mode 100644 index 0000000000..a6e3449016 --- /dev/null +++ b/ext/phar/tests/005.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar::mapPhar truncated manifest (none) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--FILE-- +<?php +try { +Phar::mapPhar('hio'); +} catch (Exception $e) { +echo $e->getMessage(); +} +__HALT_COMPILER(); ?>() +--EXPECTF-- +internal corruption of phar "%s" (truncated manifest at manifest length) diff --git a/ext/phar/tests/006.phpt b/ext/phar/tests/006.phpt new file mode 100644 index 0000000000..b2e8b29ef9 --- /dev/null +++ b/ext/phar/tests/006.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar::mapPhar truncated manifest (manifest length truncated) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--FILE-- +<?php +try { +Phar::mapPhar('hio'); +} catch (Exception $e) { +echo $e->getMessage(); +} +__HALT_COMPILER(); ?> +--EXPECTF-- +internal corruption of phar "%s" (truncated manifest at manifest length) diff --git a/ext/phar/tests/007.phpt b/ext/phar/tests/007.phpt new file mode 100644 index 0000000000..a13c2a452a --- /dev/null +++ b/ext/phar/tests/007.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar::mapPhar manifest too big +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--FILE-- +<?php +try { +Phar::mapPhar('hio'); +} catch (Exception $e) { +echo $e->getMessage(); +} +__HALT_COMPILER(); ?>~~~~ +--EXPECTF-- +manifest cannot be larger than 100 MB in phar "%s" diff --git a/ext/phar/tests/008.phpt b/ext/phar/tests/008.phpt new file mode 100644 index 0000000000..664ffea5cb --- /dev/null +++ b/ext/phar/tests/008.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar::mapPhar truncated manifest (not enough for manifest length) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--FILE-- +<?php +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; +$file .= pack('V', 500) . 'notenough'; +file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { +include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +internal corruption of phar "%s" (truncated manifest header) diff --git a/ext/phar/tests/009.phpt b/ext/phar/tests/009.phpt new file mode 100644 index 0000000000..c80445d61b --- /dev/null +++ b/ext/phar/tests/009.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar::mapPhar too many manifest entries +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; +$file .= pack('VVnVVV', 500, 500, 0x1000, 0x00000000, 0, 0) . str_repeat('A', 500); +file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { +include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +internal corruption of phar "%s009.phar.php" (too many manifest entries for size of manifest) diff --git a/ext/phar/tests/010.phpt b/ext/phar/tests/010.phpt new file mode 100644 index 0000000000..3dce5f8f4c --- /dev/null +++ b/ext/phar/tests/010.phpt @@ -0,0 +1,29 @@ +--TEST-- +Phar::mapPhar buffer overrun +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +// this fails because the manifest length does not include the other 10 byte manifest data + +$manifest = pack('V', 1) . 'a' . pack('VVVVVV', 0, time(), 0, crc32(''), 0x00000000, 0); +$file .= pack('VVnVV', strlen($manifest), 1, 0x1000, 0x00000000, 3) . 'hio' . pack('V', 0) . $manifest; + +file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { +include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +echo file_get_contents('phar://hio/a'); +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +internal corruption of phar "%s" (too many manifest entries for size of manifest) diff --git a/ext/phar/tests/011.phpt b/ext/phar/tests/011.phpt new file mode 100644 index 0000000000..4a1f0dd42c --- /dev/null +++ b/ext/phar/tests/011.phpt @@ -0,0 +1,30 @@ +--TEST-- +Phar::mapPhar filesize too small in manifest +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +// compressed file length does not match incompressed lentgh for an uncompressed file + +$files = array(); +$files['a'] = array('cont'=>'a','ulen'=>1,'clen'=>2);; +include 'files/phar_test.inc'; +try { +include $fname; +echo file_get_contents('phar://hio/a'); +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +internal corruption of phar "%s" (compressed and uncompressed size does not match for uncompressed entry) diff --git a/ext/phar/tests/012.phpt b/ext/phar/tests/012.phpt new file mode 100644 index 0000000000..3246eff468 --- /dev/null +++ b/ext/phar/tests/012.phpt @@ -0,0 +1,28 @@ +--TEST-- +Phar::mapPhar valid file +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; + +include 'files/phar_test.inc'; +include $fname; + +echo file_get_contents('phar://hio/a'); + +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +a diff --git a/ext/phar/tests/013.phpt b/ext/phar/tests/013.phpt new file mode 100644 index 0000000000..ae3ae72936 --- /dev/null +++ b/ext/phar/tests/013.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar::mapPhar filesize mismatch +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; +// filesize should be 1, and is 2 + +$files = array(); +$files['a'] = array('cont'=>'a', 'ulen'=>2, 'clen'=>2); +include 'files/phar_test.inc'; + +echo file_get_contents($pname.'/a'); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (%s file "a") in %s on line %d diff --git a/ext/phar/tests/014.phpt b/ext/phar/tests/014.phpt new file mode 100644 index 0000000000..d08e6550b6 --- /dev/null +++ b/ext/phar/tests/014.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar::mapPhar filesize mismatch +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; +// wrong crc32 + +$files = array(); +$files['a'] = array('cont'=>'a', 'crc32'=>crc32('aX')); +include 'files/phar_test.inc'; + +echo file_get_contents($pname.'/a'); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (crc32 mismatch on file "a") in %s on line %d diff --git a/ext/phar/tests/015.phpt b/ext/phar/tests/015.phpt new file mode 100644 index 0000000000..b93b77e9fb --- /dev/null +++ b/ext/phar/tests/015.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar::mapPhar valid file (gzipped) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = array('cont'=>'a','comp'=>chr(75) . chr(4) . chr(0) /* 'a' gzdeflated */, 'flags'=>0x00001000); +include 'files/phar_test.inc'; + +echo file_get_contents($pname .'/a'); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +a diff --git a/ext/phar/tests/015b.phpt b/ext/phar/tests/015b.phpt new file mode 100755 index 0000000000..08ead2d9c0 --- /dev/null +++ b/ext/phar/tests/015b.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar::mapPhar valid file (bzip2) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = array('cont'=>'Hello World', 'comp'=>pack('H*', '425a6834314159265359065c89da0000009780400000400080060490002000310c082031a916c41d41e2ee48a70a1200cb913b40'),'flags'=>0x00002000); +include 'files/phar_test.inc'; + +var_dump(file_get_contents($pname . '/a')); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(11) "Hello World" diff --git a/ext/phar/tests/016.phpt b/ext/phar/tests/016.phpt new file mode 100644 index 0000000000..302d06d3cb --- /dev/null +++ b/ext/phar/tests/016.phpt @@ -0,0 +1,39 @@ +--TEST-- +Phar::mapPhar invalid file (gzipped file length is too short) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; +// file length is too short + +$files = array(); +// "hi" gzdeflated +$files['a'] = array('cont'=>'a','comp'=> pack('H*', 'cbc80400'),'flags'=>0x00001000, 'ulen' => 1, 'clen' => 4); +$files['b'] = $files['a']; +$files['c'] = array('cont'=>'*'); +$files['d'] = $files['a']; +include 'files/phar_test.inc'; + +var_dump(file_get_contents($pname . '/a')); +var_dump(file_get_contents($pname . '/b')); +var_dump(file_get_contents($pname . '/c')); +var_dump(file_get_contents($pname . '/d')); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "a") in %s on line %d +bool(false) + +Warning: file_get_contents(phar://%s/b): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "b") in %s on line %d +bool(false) +string(1) "*" + +Warning: file_get_contents(phar://%s/d): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "d") in %s on line %d +bool(false) diff --git a/ext/phar/tests/016b.phpt b/ext/phar/tests/016b.phpt new file mode 100755 index 0000000000..8fe66826d6 --- /dev/null +++ b/ext/phar/tests/016b.phpt @@ -0,0 +1,24 @@ +--TEST-- +Phar::mapPhar invalid file (gzipped file length is too short) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; +// file length is too short + +$files = array(); +$files['a'] = array('cont'=>'a','flags'=>0x00001000, 'clen' => 1); +include 'files/phar_test.inc'; + +echo file_get_contents($pname . '/a'); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "a") in %s on line %d diff --git a/ext/phar/tests/017.phpt b/ext/phar/tests/017.phpt new file mode 100644 index 0000000000..ec012eaa11 --- /dev/null +++ b/ext/phar/tests/017.phpt @@ -0,0 +1,26 @@ +--TEST-- +Phar: opendir test - no dir specified at all +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'abc'; +include 'files/phar_test.inc'; + +include $fname; +$dir = opendir('phar://hio'); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: opendir(phar://hio): failed to open dir: phar error: no directory in "phar://hio", must have at least phar://hio/ for root directory (always use full path to a new phar) +phar url "phar://hio" is unknown in %s017.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/018.phpt b/ext/phar/tests/018.phpt new file mode 100644 index 0000000000..97cd323779 --- /dev/null +++ b/ext/phar/tests/018.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: opendir test, root directory +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +include 'files/phar_test.inc'; + +include $fname; +$dir = opendir('phar://hio/'); +while (false !== ($a = readdir($dir))) { + var_dump($a); + var_dump(is_dir('phar://hio/' . $a)); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(1) "a" +bool(false) +string(1) "b" +bool(true) \ No newline at end of file diff --git a/ext/phar/tests/019.phpt b/ext/phar/tests/019.phpt new file mode 100644 index 0000000000..3d00b5f8e9 --- /dev/null +++ b/ext/phar/tests/019.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: opendir test, subdirectory +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +$files['b/c/d'] = 'c'; +$files['bad/c'] = 'd'; +include 'files/phar_test.inc'; +include $fname; +$dir = opendir('phar://hio/b'); +while (false !== ($a = readdir($dir))) { + var_dump($a); + var_dump(is_dir('phar://hio/b/' . $a)); +} +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(1) "a" +bool(false) +string(1) "c" +bool(true) \ No newline at end of file diff --git a/ext/phar/tests/019b.phpt b/ext/phar/tests/019b.phpt new file mode 100755 index 0000000000..574919b793 --- /dev/null +++ b/ext/phar/tests/019b.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar: opendir test, recurse into +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +$files['b/c/d'] = 'c'; +$files['bad/c'] = 'd'; +include 'files/phar_test.inc'; +include $fname; + +function dump($phar, $base) +{ + var_dump($phar . $base); + $dir = opendir($phar . $base); + if ($base == '/') + { + $base = ''; + } + while (false !== ($entry = readdir($dir))) { + $entry = $base . '/' . $entry; + var_dump($entry); + var_dump(is_dir($phar . $entry)); + if (is_dir($phar . $entry)) + { + dump($phar, $entry); + } + } +} + +dump('phar://hio', '/'); + +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(11) "phar://hio/" +string(2) "/a" +bool(false) +string(2) "/b" +bool(true) +string(12) "phar://hio/b" +string(4) "/b/a" +bool(false) +string(4) "/b/c" +bool(true) +string(14) "phar://hio/b/c" +string(6) "/b/c/d" +bool(false) +string(4) "/bad" +bool(true) +string(14) "phar://hio/bad" +string(6) "/bad/c" +bool(false) diff --git a/ext/phar/tests/019c.phpt b/ext/phar/tests/019c.phpt new file mode 100755 index 0000000000..242b666871 --- /dev/null +++ b/ext/phar/tests/019c.phpt @@ -0,0 +1,73 @@ +--TEST-- +Phar: opendir test, recurse into +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +$files['b/c/d'] = 'c'; +$files['bad/c'] = 'd'; +include 'files/phar_test.inc'; +include $fname; + +function dump($phar, $base) +{ + var_dump($phar . $base); + $dir = opendir($phar . $base); + if ($base == '/') + { + $base = ''; + } + while (false !== ($entry = readdir($dir))) { + $entry = $base . '/' . $entry; + var_dump($entry); + var_dump(is_dir($phar . $entry)); + if (is_dir($phar . $entry)) + { + dump($phar, $entry); + } + else + { + var_dump(file_get_contents($phar . $entry)); + } + } +} + +dump('phar://hio', '/'); + +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(11) "phar://hio/" +string(2) "/a" +bool(false) +string(1) "a" +string(2) "/b" +bool(true) +string(12) "phar://hio/b" +string(4) "/b/a" +bool(false) +string(1) "b" +string(4) "/b/c" +bool(true) +string(14) "phar://hio/b/c" +string(6) "/b/c/d" +bool(false) +string(1) "c" +string(4) "/bad" +bool(true) +string(14) "phar://hio/bad" +string(6) "/bad/c" +bool(false) +string(1) "d" diff --git a/ext/phar/tests/020.phpt b/ext/phar/tests/020.phpt new file mode 100644 index 0000000000..b06cdbf731 --- /dev/null +++ b/ext/phar/tests/020.phpt @@ -0,0 +1,136 @@ +--TEST-- +Phar: url stat +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$pfile = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +$files['b/c/d'] = 'c'; +$files['bad/c'] = 'd'; +include 'files/phar_test.inc'; +include $fname; + +var_dump(stat('phar://hio/a'), stat('phar://hio/b')); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +array(26) { + [0]=> + int(12) + [1]=> + int(%d) + [2]=> + int(33060) + [3]=> + int(1) + [4]=> + int(0) + [5]=> + int(0) + [6]=> + int(-1) + [7]=> + int(1) + [8]=> + int(%d) + [9]=> + int(%d) + [10]=> + int(%d) + [11]=> + int(-1) + [12]=> + int(-1) + ["dev"]=> + int(12) + ["ino"]=> + int(%d) + ["mode"]=> + int(33060) + ["nlink"]=> + int(1) + ["uid"]=> + int(0) + ["gid"]=> + int(0) + ["rdev"]=> + int(-1) + ["size"]=> + int(1) + ["atime"]=> + int(%d) + ["mtime"]=> + int(%d) + ["ctime"]=> + int(%d) + ["blksize"]=> + int(-1) + ["blocks"]=> + int(-1) +} +array(26) { + [0]=> + int(12) + [1]=> + int(%d) + [2]=> + int(16749) + [3]=> + int(1) + [4]=> + int(0) + [5]=> + int(0) + [6]=> + int(-1) + [7]=> + int(0) + [8]=> + int(%d) + [9]=> + int(%d) + [10]=> + int(%d) + [11]=> + int(-1) + [12]=> + int(-1) + ["dev"]=> + int(12) + ["ino"]=> + int(%d) + ["mode"]=> + int(16749) + ["nlink"]=> + int(1) + ["uid"]=> + int(0) + ["gid"]=> + int(0) + ["rdev"]=> + int(-1) + ["size"]=> + int(0) + ["atime"]=> + int(%d) + ["mtime"]=> + int(%d) + ["ctime"]=> + int(%d) + ["blksize"]=> + int(-1) + ["blocks"]=> + int(-1) +} \ No newline at end of file diff --git a/ext/phar/tests/021.phpt b/ext/phar/tests/021.phpt new file mode 100644 index 0000000000..9c9cd97568 --- /dev/null +++ b/ext/phar/tests/021.phpt @@ -0,0 +1,85 @@ +--TEST-- +Phar: stream stat +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +$files['b/a'] = 'b'; +$files['b/c/d'] = 'c'; +$files['bad/c'] = 'd'; + +include 'files/phar_test.inc'; + +include $fname; + +$fp = fopen('phar://hio/a', 'r'); +var_dump(fstat($fp)); +fclose($fp); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +array(26) { + [0]=> + int(12) + [1]=> + int(%d) + [2]=> + int(33060) + [3]=> + int(1) + [4]=> + int(0) + [5]=> + int(0) + [6]=> + int(-1) + [7]=> + int(1) + [8]=> + int(%d) + [9]=> + int(%d) + [10]=> + int(%d) + [11]=> + int(-1) + [12]=> + int(-1) + ["dev"]=> + int(12) + ["ino"]=> + int(%d) + ["mode"]=> + int(33060) + ["nlink"]=> + int(1) + ["uid"]=> + int(0) + ["gid"]=> + int(0) + ["rdev"]=> + int(-1) + ["size"]=> + int(1) + ["atime"]=> + int(%d) + ["mtime"]=> + int(%d) + ["ctime"]=> + int(%d) + ["blksize"]=> + int(-1) + ["blocks"]=> + int(-1) +} \ No newline at end of file diff --git a/ext/phar/tests/022.phpt b/ext/phar/tests/022.phpt new file mode 100644 index 0000000000..20c24a0214 --- /dev/null +++ b/ext/phar/tests/022.phpt @@ -0,0 +1,110 @@ +--TEST-- +Phar: stream stat +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'abcdefg'; + +include 'files/phar_test.inc'; + +include $fname; + +$fp = fopen('phar://hio/a', 'r'); +var_dump(ftell($fp)); +echo 'fseek($fp, 1)';var_dump(fseek($fp, 1)); +var_dump(ftell($fp)); +echo 'fseek($fp, 1, SEEK_CUR)';var_dump(fseek($fp, 1, SEEK_CUR)); +var_dump(ftell($fp)); +echo 'fseek($fp, -1, SEEK_CUR)';var_dump(fseek($fp, -1, SEEK_CUR)); +var_dump(ftell($fp)); +echo 'fseek($fp, -1, SEEK_END)';var_dump(fseek($fp, -1, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, -8, SEEK_END)';var_dump(fseek($fp, -8, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, -7, SEEK_END)';var_dump(fseek($fp, -7, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, 0, SEEK_END)';var_dump(fseek($fp, 0, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, 1, SEEK_END)';var_dump(fseek($fp, 1, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, -8, SEEK_END)';var_dump(fseek($fp, -8, SEEK_END)); +var_dump(ftell($fp)); +echo 'fseek($fp, 6)';var_dump(fseek($fp, 6)); +var_dump(ftell($fp)); +echo 'fseek($fp, 8)';var_dump(fseek($fp, 8)); +var_dump(ftell($fp)); +echo 'fseek($fp, -1)';var_dump(fseek($fp, -1)); +var_dump(ftell($fp)); +echo "next\n"; +fseek($fp, 4); +var_dump(ftell($fp)); +echo 'fseek($fp, -5, SEEK_CUR)';var_dump(fseek($fp, -5, SEEK_CUR)); +var_dump(ftell($fp)); +fseek($fp, 4); +var_dump(ftell($fp)); +echo 'fseek($fp, 5, SEEK_CUR)';var_dump(fseek($fp, 5, SEEK_CUR)); +var_dump(ftell($fp)); +fseek($fp, 4); +var_dump(ftell($fp)); +echo 'fseek($fp, -4, SEEK_CUR)';var_dump(fseek($fp, -4, SEEK_CUR)); +var_dump(ftell($fp)); +fseek($fp, 4); +var_dump(ftell($fp)); +echo 'fseek($fp, 3, SEEK_CUR)';var_dump(fseek($fp, 3, SEEK_CUR)); +var_dump(ftell($fp)); +fclose($fp); +?> +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +exit(0); + ?> +--EXPECT-- +int(0) +fseek($fp, 1)int(0) +int(1) +fseek($fp, 1, SEEK_CUR)int(0) +int(2) +fseek($fp, -1, SEEK_CUR)int(0) +int(1) +fseek($fp, -1, SEEK_END)int(0) +int(6) +fseek($fp, -8, SEEK_END)int(-1) +bool(false) +fseek($fp, -7, SEEK_END)int(0) +int(0) +fseek($fp, 0, SEEK_END)int(0) +int(7) +fseek($fp, 1, SEEK_END)int(-1) +bool(false) +fseek($fp, -8, SEEK_END)int(-1) +bool(false) +fseek($fp, 6)int(0) +int(6) +fseek($fp, 8)int(-1) +bool(false) +fseek($fp, -1)int(-1) +bool(false) +next +int(4) +fseek($fp, -5, SEEK_CUR)int(-1) +bool(false) +int(4) +fseek($fp, 5, SEEK_CUR)int(-1) +bool(false) +int(4) +fseek($fp, -4, SEEK_CUR)int(0) +int(0) +int(4) +fseek($fp, 3, SEEK_CUR)int(0) +int(7) diff --git a/ext/phar/tests/023.phpt b/ext/phar/tests/023.phpt new file mode 100755 index 0000000000..808f91deae --- /dev/null +++ b/ext/phar/tests/023.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: phar:// file_get_contents +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; + +include 'files/phar_test.inc'; + +var_dump(file_get_contents($pname . '/a.php')); +var_dump(file_get_contents($pname . '/b.php')); +var_dump(file_get_contents($pname . '/b/c.php')); + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(28) "<?php echo "This is a\n"; ?>" +string(28) "<?php echo "This is b\n"; ?>" +string(30) "<?php echo "This is b/c\n"; ?>" +===DONE=== diff --git a/ext/phar/tests/024.phpt b/ext/phar/tests/024.phpt new file mode 100755 index 0000000000..ad30d2644d --- /dev/null +++ b/ext/phar/tests/024.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: phar:// include +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; + +include 'files/phar_test.inc'; + +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +This is a +This is b +This is b/c +===DONE=== diff --git a/ext/phar/tests/025.phpt b/ext/phar/tests/025.phpt new file mode 100755 index 0000000000..bbb5bc4e83 --- /dev/null +++ b/ext/phar/tests/025.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: phar:// include (repeated names) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = '<?php echo "This is a\n"; ?>'; +$files['b'] = '<?php echo "This is b\n"; ?>'; +$files['b/b'] = '<?php echo "This is b/b\n"; ?>'; + +include 'files/phar_test.inc'; + +include $pname . '/a'; +include $pname . '/b'; +include $pname . '/b/b'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +This is a +This is b +This is b/b +===DONE=== diff --git a/ext/phar/tests/026.phpt b/ext/phar/tests/026.phpt new file mode 100755 index 0000000000..696fbcf415 --- /dev/null +++ b/ext/phar/tests/026.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: phar:// require from within +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; require \''.$pname.'/b.php\'; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; require \''.$pname.'/b/c.php\'; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; require \''.$pname.'/b/d.php\'; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; require \''.$pname.'/e.php\'; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; + +include 'files/phar_test.inc'; + +require $pname . '/a.php'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +This is a +This is b +This is b/c +This is b/d +This is e +===DONE=== diff --git a/ext/phar/tests/027.phpt b/ext/phar/tests/027.phpt new file mode 100755 index 0000000000..679fefc2cd --- /dev/null +++ b/ext/phar/tests/027.phpt @@ -0,0 +1,94 @@ +--TEST-- +Phar: phar:// opendir +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; require \''.$pname.'/b.php\'; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; require \''.$pname.'/b/c.php\'; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; require \''.$pname.'/b/d.php\'; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; require \''.$pname.'/e.php\'; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; + +include 'files/phar_test.inc'; + +function dump($phar, $base) +{ + var_dump(str_replace(dirname(__FILE__), '*', $phar) . $base); + $dir = opendir($phar . $base); + if ($base == '/') + { + $base = ''; + } + while (false !== ($entry = readdir($dir))) { + $entry = $base . '/' . $entry; + var_dump($entry); + var_dump(is_dir($phar . $entry)); + if (is_dir($phar . $entry)) + { + dump($phar, $entry); + } + } +} + +dump($pname, '/'); + +$a = opendir($pname); +// this may stop working in future versions, but is here for code coverage purposes +echo "fseek on dir handle\n"; +var_dump(fseek($a, 0, SEEK_END), ftell($a)); +var_dump(fseek($a, -1), ftell($a)); +var_dump(fseek($a, 1), ftell($a)); +echo "fwrite on dir handle\n"; +var_dump(fwrite($a, 'hi')); +var_dump(fstat($a)); +closedir($a); +echo "opendir edge cases\n"; +var_dump(opendir("phar://")); +var_dump(opendir("phar://foo.phar/hi")); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +string(%d) "phar://*/027.phar.php/" +string(6) "/a.php" +bool(false) +string(2) "/b" +bool(true) +string(%d) "phar://*/027.phar.php/b" +string(8) "/b/c.php" +bool(false) +string(8) "/b/d.php" +bool(false) +string(6) "/b.php" +bool(false) +string(6) "/e.php" +bool(false) +fseek on dir handle +int(0) +int(4) +int(-1) +int(4) +int(0) +int(1) +fwrite on dir handle +int(0) +bool(false) +opendir edge cases + +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 %s027.php on line %d +bool(false) + +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) +===DONE=== diff --git a/ext/phar/tests/028.phpt b/ext/phar/tests/028.phpt new file mode 100755 index 0000000000..087f822777 --- /dev/null +++ b/ext/phar/tests/028.phpt @@ -0,0 +1,47 @@ +--TEST-- +Phar::loadPhar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$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"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; include "'.$pname.'/b/c.php"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; include "'.$pname.'/b/d.php"; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; include "'.$pname.'/e.php"; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; + +include 'files/phar_test.inc'; + +Phar::loadPhar($fname, 'hio'); + +include $fname; + +echo "======\n"; + +include $pname . '/a.php'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +This is a +This is b +This is b/c +This is b/d +This is e +====== +This is a +This is b +This is b/c +This is b/d +This is e +===DONE=== diff --git a/ext/phar/tests/029.phpt b/ext/phar/tests/029.phpt new file mode 100755 index 0000000000..41fcec03e7 --- /dev/null +++ b/ext/phar/tests/029.phpt @@ -0,0 +1,50 @@ +--TEST-- +Phar::loadPhar overloading alias names +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?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(); ?>'; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; include "'.$pname.'/b/c.php"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; include "'.$pname.'/b/d.php"; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; include "'.$pname.'/e.php"; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; + +include 'files/phar_test.inc'; + +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')); +} +catch (Exception $e) +{ + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); +?> +--EXPECTF-- +bool(true) +bool(true) +alias "copy" is already used for archive "%s029.1.phar.php" cannot be overloaded with "%s029.2.phar.php" +===DONE=== diff --git a/ext/phar/tests/030.phpt b/ext/phar/tests/030.phpt new file mode 100755 index 0000000000..afaeb1a802 --- /dev/null +++ b/ext/phar/tests/030.phpt @@ -0,0 +1,38 @@ +--TEST-- +Phar::loadPhar ignoring alias +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; include \''.$pname.'/b.php\'; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; include \''.$pname.'/b/c.php\'; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; include \''.$pname.'/b/d.php\'; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; include \''.$pname.'/e.php\'; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; + +include 'files/phar_test.inc'; + +Phar::loadPhar($fname); + +require $pname . '/a.php'; + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +This is a +This is b +This is b/c +This is b/d +This is e +===DONE=== diff --git a/ext/phar/tests/031.phpt b/ext/phar/tests/031.phpt new file mode 100755 index 0000000000..4d5988621d --- /dev/null +++ b/ext/phar/tests/031.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: include and parser error +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 3; + +require_once 'files/phar_oo_test.inc'; + +Phar::loadPhar($fname); + +$pname = 'phar://' . $fname . '/a.php'; + +var_dump(file_get_contents($pname)); +require $pname; + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +string(25) "<?php echo new new class;" + +Parse error: %s in phar://%sphar_oo_test.phar.php/a.php on line %d diff --git a/ext/phar/tests/032.phpt b/ext/phar/tests/032.phpt new file mode 100755 index 0000000000..faf3dcbf58 --- /dev/null +++ b/ext/phar/tests/032.phpt @@ -0,0 +1,29 @@ +--TEST-- +Phar: require hash +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=1 +--FILE-- +<?php + +$pharconfig = 0; + +require_once 'files/phar_oo_test.inc'; + +try { +Phar::loadPhar($fname); +} catch (Exception $e) { +echo $e->getMessage(); +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- + +phar "%sphar_oo_test.phar.php" does not have a signature===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/033.phpt b/ext/phar/tests/033.phpt new file mode 100644 index 0000000000..d53c7f52fa --- /dev/null +++ b/ext/phar/tests/033.phpt @@ -0,0 +1,47 @@ +--TEST-- +Phar::chmod +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php'; +$pname = 'phar://hio'; +$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>'; +$files['dir/'] = ''; +$hasdir = 1; +include 'files/phar_test.inc'; +$a = new Phar($fname); +var_dump($a['a.php']->isExecutable()); +$a['a.php']->chmod(0777); +var_dump($a['a.php']->isExecutable()); +$a['a.php']->chmod(0666); +var_dump($a['a.php']->isExecutable()); +echo "test dir\n"; +var_dump($a['dir']->isDir()); +var_dump($a['dir']->isReadable()); +$a['dir']->chmod(000); +var_dump($a['dir']->isReadable()); +$a['dir']->chmod(0666); +var_dump($a['dir']->isReadable()); +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); +?> +--EXPECT-- +bool(false) +bool(true) +bool(false) +test dir +bool(true) +bool(true) +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/033a.phpt b/ext/phar/tests/033a.phpt new file mode 100644 index 0000000000..e8725bdda6 --- /dev/null +++ b/ext/phar/tests/033a.phpt @@ -0,0 +1,36 @@ +--TEST-- +Phar::chmod +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php'; +$pname = 'phar://hio'; +$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>'; +include 'files/phar_test.inc'; +try { + $a = new Phar($fname); + var_dump($a['a.php']->isExecutable()); + $a['a.php']->chmod(0777); + var_dump($a['a.php']->isExecutable()); + $a['a.php']->chmod(0666); + var_dump($a['a.php']->isExecutable()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); +?> +--EXPECTF-- +bool(false) +Cannot modify permissions for file "a.php" in phar "%s033a.1.phar.php", write operations are prohibited +===DONE=== diff --git a/ext/phar/tests/addfuncs.phpt b/ext/phar/tests/addfuncs.phpt new file mode 100644 index 0000000000..d9a183fd68 --- /dev/null +++ b/ext/phar/tests/addfuncs.phpt @@ -0,0 +1,41 @@ +--TEST-- +Phar: addFile/addFromString +--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; +$phar = new Phar($fname); +$phar->addFromString('a', 'hi'); +echo file_get_contents($pname . '/a') . "\n"; +$phar->addFile($pname . '/a', 'b'); +echo file_get_contents($pname . '/b') . "\n"; +try { +$phar->addFile($pname . '/a'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$phar->addFile($pname . '/a', 'a'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$phar->addFile(dirname(__FILE__) . '/does/not/exist'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +hi +hi +Entry phar://%saddfuncs.phar.php/a does not exist and cannot be created: phar error: invalid path "phar://%saddfuncs.phar.php/a" contains double slash +Entry a does not exist and cannot be created: phar error: file "a" in phar "%saddfuncs.phar.php" cannot be opened for writing, readable file pointers are open +phar error: unable to open file "%s/does/not/exist" to add to phar archive +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/alias_acrobatics.phpt b/ext/phar/tests/alias_acrobatics.phpt new file mode 100644 index 0000000000..1bb20a4b3a --- /dev/null +++ b/ext/phar/tests/alias_acrobatics.phpt @@ -0,0 +1,46 @@ +--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=== diff --git a/ext/phar/tests/badparameters.phpt b/ext/phar/tests/badparameters.phpt new file mode 100644 index 0000000000..a6ce37b3f9 --- /dev/null +++ b/ext/phar/tests/badparameters.phpt @@ -0,0 +1,210 @@ +--TEST-- +Phar: bad parameters to various methods +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +ini_set('phar.readonly', 1); +Phar::mungServer('hi'); +Phar::createDefaultStub(array()); +Phar::loadPhar(array()); +Phar::canCompress('hi'); +$a = new Phar(array()); +$a = new Phar(dirname(__FILE__) . '/files/frontcontroller10.phar'); +$a->convertToExecutable(array()); +$a->convertToData(array()); +$b = new PharData(dirname(__FILE__) . '/whatever.tar'); +$c = new PharData(dirname(__FILE__) . '/whatever.zip'); +$b->delete(array()); +try { +$a->delete('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->delete('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +echo $a->getPath() . "\n"; +try { +$a->setAlias('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->setAlias('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 0); +$a->setAlias(array()); +ini_set('phar.readonly', 1); +try { +$b->stopBuffering(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$a->setStub('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->setStub('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 0); +$a->setStub(array()); +ini_set('phar.readonly', 1); +try { +$b->setDefaultStub('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->setDefaultStub(array()); +try { +$a->setDefaultStub('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$a->setSignatureAlgorithm(Phar::MD5); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->setSignatureAlgorithm(Phar::MD5); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$c->setSignatureAlgorithm(Phar::MD5); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->compress(array()); +try { +$a->compress(1); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->compressFiles(array()); +try { +$a->decompressFiles(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->copy(array()); +try { +$a->copy('a', 'b'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->offsetExists(array()); +$a->offsetGet(array()); +ini_set('phar.readonly', 0); +$a->offsetSet(array()); +ini_set('phar.readonly', 1); +$b->offsetUnset(array()); +try { +$a->offsetUnset('a'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a->addEmptyDir(array()); +$a->addFile(array()); +$a->addFromString(array()); +try { +$a->setMetadata('a'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->setMetadata('a'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 0); +$a->setMetadata(1,2); +ini_set('phar.readonly', 1); +try { +$a->delMetadata(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->delMetadata(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +Warning: Phar::mungServer() expects parameter 1 to be array, string given in %sbadparameters.php on line %d + +Warning: Phar::createDefaultStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::loadPhar() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::canCompress() expects parameter 1 to be long, string given in %sbadparameters.php on line %d + +Warning: Phar::__construct() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::convertToExecutable() expects parameter 1 to be long, array given in %sbadparameters.php on line %d + +Warning: Phar::convertToData() expects parameter 1 to be long, array given in %sbadparameters.php on line %d + +Warning: PharData::delete() expects parameter 1 to be string, array given in %sbadparameters.php on line %d +Cannot write out phar archive, phar is read-only +Entry oops does not exist and cannot be deleted +%sfiles/frontcontroller10.phar +Cannot write out phar archive, phar is read-only +A Phar alias cannot be set in a plain tar archive + +Warning: Phar::setAlias() expects parameter 1 to be string, array given in %sbadparameters.php on line %d +Cannot change stub, phar is read-only +A Phar stub cannot be set in a plain tar archive + +Warning: Phar::setStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d +A Phar stub cannot be set in a plain tar archive + +Warning: Phar::setDefaultStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d +Cannot change stub: phar.readonly=1 +Cannot set signature algorithm, phar is read-only +Cannot set signature algorithm, not possible with tar-based phar archives +Cannot set signature algorithm, not possible with zip-based phar archives + +Warning: Phar::compress() expects parameter 1 to be long, array given in %sbadparameters.php on line %d +Cannot compress phar archive, phar is read-only + +Warning: Phar::compressFiles() expects parameter 1 to be long, array given in %sbadparameters.php on line %d +Phar is readonly, cannot change compression + +Warning: Phar::copy() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d +Cannot copy "a" to "b", phar is read-only + +Warning: Phar::offsetExists() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::offsetGet() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::offsetSet() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d + +Warning: PharData::offsetUnset() expects parameter 1 to be string, array given in %sbadparameters.php on line %d +Write operations disabled by INI setting + +Warning: Phar::addEmptyDir() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::addFile() expects parameter 1 to be string, array given in %sbadparameters.php on line %d + +Warning: Phar::addFromString() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d +Write operations disabled by INI setting +Cannot set metadata, not possible with tar-based phar archives + +Warning: Phar::setMetadata() expects exactly 1 parameter, 2 given in %sbadparameters.php on line %d +Write operations disabled by INI setting +Cannot delete metadata, not possible with tar-based phar archives +===DONE=== diff --git a/ext/phar/tests/bug13727.phpt b/ext/phar/tests/bug13727.phpt new file mode 100644 index 0000000000..cc7fc19a6c --- /dev/null +++ b/ext/phar/tests/bug13727.phpt @@ -0,0 +1,4135 @@ +--TEST-- +Phar: SLOW TEST bug #13727: "Number of files in the Phar" limited to 2042 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$dirName = dirname(__FILE__); +$pname = 'phar://' . $fname; +$pArchive="DataArchive.phar"; +$p = new Phar($fname, 0, $pArchive); +for ($i = 0; $i < 4*1024; $i++){ + echo("$i\n"); + if (!is_dir($fileDir="$dirName/test_data")) + mkdir($fileDir, 0777, true); + file_put_contents("$fileDir/$i", ""); + $p->addFile("$fileDir/$i", "$dirName"); +} +echo("\n Written Files($i)\n"); +?> +===DONE=== +--CLEAN-- +<?php +$dirName = dirname(__FILE__); +$fileDir="$dirName/test_data"; +for ($i = 0; $i < 4*1024; $i++){ + unlink("$fileDir/$i"); +} +rmdir($fileDir); +unlink($dirName . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__HALT_COMPILER(); +?> +--EXPECT-- +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2011 +2012 +2013 +2014 +2015 +2016 +2017 +2018 +2019 +2020 +2021 +2022 +2023 +2024 +2025 +2026 +2027 +2028 +2029 +2030 +2031 +2032 +2033 +2034 +2035 +2036 +2037 +2038 +2039 +2040 +2041 +2042 +2043 +2044 +2045 +2046 +2047 +2048 +2049 +2050 +2051 +2052 +2053 +2054 +2055 +2056 +2057 +2058 +2059 +2060 +2061 +2062 +2063 +2064 +2065 +2066 +2067 +2068 +2069 +2070 +2071 +2072 +2073 +2074 +2075 +2076 +2077 +2078 +2079 +2080 +2081 +2082 +2083 +2084 +2085 +2086 +2087 +2088 +2089 +2090 +2091 +2092 +2093 +2094 +2095 +2096 +2097 +2098 +2099 +2100 +2101 +2102 +2103 +2104 +2105 +2106 +2107 +2108 +2109 +2110 +2111 +2112 +2113 +2114 +2115 +2116 +2117 +2118 +2119 +2120 +2121 +2122 +2123 +2124 +2125 +2126 +2127 +2128 +2129 +2130 +2131 +2132 +2133 +2134 +2135 +2136 +2137 +2138 +2139 +2140 +2141 +2142 +2143 +2144 +2145 +2146 +2147 +2148 +2149 +2150 +2151 +2152 +2153 +2154 +2155 +2156 +2157 +2158 +2159 +2160 +2161 +2162 +2163 +2164 +2165 +2166 +2167 +2168 +2169 +2170 +2171 +2172 +2173 +2174 +2175 +2176 +2177 +2178 +2179 +2180 +2181 +2182 +2183 +2184 +2185 +2186 +2187 +2188 +2189 +2190 +2191 +2192 +2193 +2194 +2195 +2196 +2197 +2198 +2199 +2200 +2201 +2202 +2203 +2204 +2205 +2206 +2207 +2208 +2209 +2210 +2211 +2212 +2213 +2214 +2215 +2216 +2217 +2218 +2219 +2220 +2221 +2222 +2223 +2224 +2225 +2226 +2227 +2228 +2229 +2230 +2231 +2232 +2233 +2234 +2235 +2236 +2237 +2238 +2239 +2240 +2241 +2242 +2243 +2244 +2245 +2246 +2247 +2248 +2249 +2250 +2251 +2252 +2253 +2254 +2255 +2256 +2257 +2258 +2259 +2260 +2261 +2262 +2263 +2264 +2265 +2266 +2267 +2268 +2269 +2270 +2271 +2272 +2273 +2274 +2275 +2276 +2277 +2278 +2279 +2280 +2281 +2282 +2283 +2284 +2285 +2286 +2287 +2288 +2289 +2290 +2291 +2292 +2293 +2294 +2295 +2296 +2297 +2298 +2299 +2300 +2301 +2302 +2303 +2304 +2305 +2306 +2307 +2308 +2309 +2310 +2311 +2312 +2313 +2314 +2315 +2316 +2317 +2318 +2319 +2320 +2321 +2322 +2323 +2324 +2325 +2326 +2327 +2328 +2329 +2330 +2331 +2332 +2333 +2334 +2335 +2336 +2337 +2338 +2339 +2340 +2341 +2342 +2343 +2344 +2345 +2346 +2347 +2348 +2349 +2350 +2351 +2352 +2353 +2354 +2355 +2356 +2357 +2358 +2359 +2360 +2361 +2362 +2363 +2364 +2365 +2366 +2367 +2368 +2369 +2370 +2371 +2372 +2373 +2374 +2375 +2376 +2377 +2378 +2379 +2380 +2381 +2382 +2383 +2384 +2385 +2386 +2387 +2388 +2389 +2390 +2391 +2392 +2393 +2394 +2395 +2396 +2397 +2398 +2399 +2400 +2401 +2402 +2403 +2404 +2405 +2406 +2407 +2408 +2409 +2410 +2411 +2412 +2413 +2414 +2415 +2416 +2417 +2418 +2419 +2420 +2421 +2422 +2423 +2424 +2425 +2426 +2427 +2428 +2429 +2430 +2431 +2432 +2433 +2434 +2435 +2436 +2437 +2438 +2439 +2440 +2441 +2442 +2443 +2444 +2445 +2446 +2447 +2448 +2449 +2450 +2451 +2452 +2453 +2454 +2455 +2456 +2457 +2458 +2459 +2460 +2461 +2462 +2463 +2464 +2465 +2466 +2467 +2468 +2469 +2470 +2471 +2472 +2473 +2474 +2475 +2476 +2477 +2478 +2479 +2480 +2481 +2482 +2483 +2484 +2485 +2486 +2487 +2488 +2489 +2490 +2491 +2492 +2493 +2494 +2495 +2496 +2497 +2498 +2499 +2500 +2501 +2502 +2503 +2504 +2505 +2506 +2507 +2508 +2509 +2510 +2511 +2512 +2513 +2514 +2515 +2516 +2517 +2518 +2519 +2520 +2521 +2522 +2523 +2524 +2525 +2526 +2527 +2528 +2529 +2530 +2531 +2532 +2533 +2534 +2535 +2536 +2537 +2538 +2539 +2540 +2541 +2542 +2543 +2544 +2545 +2546 +2547 +2548 +2549 +2550 +2551 +2552 +2553 +2554 +2555 +2556 +2557 +2558 +2559 +2560 +2561 +2562 +2563 +2564 +2565 +2566 +2567 +2568 +2569 +2570 +2571 +2572 +2573 +2574 +2575 +2576 +2577 +2578 +2579 +2580 +2581 +2582 +2583 +2584 +2585 +2586 +2587 +2588 +2589 +2590 +2591 +2592 +2593 +2594 +2595 +2596 +2597 +2598 +2599 +2600 +2601 +2602 +2603 +2604 +2605 +2606 +2607 +2608 +2609 +2610 +2611 +2612 +2613 +2614 +2615 +2616 +2617 +2618 +2619 +2620 +2621 +2622 +2623 +2624 +2625 +2626 +2627 +2628 +2629 +2630 +2631 +2632 +2633 +2634 +2635 +2636 +2637 +2638 +2639 +2640 +2641 +2642 +2643 +2644 +2645 +2646 +2647 +2648 +2649 +2650 +2651 +2652 +2653 +2654 +2655 +2656 +2657 +2658 +2659 +2660 +2661 +2662 +2663 +2664 +2665 +2666 +2667 +2668 +2669 +2670 +2671 +2672 +2673 +2674 +2675 +2676 +2677 +2678 +2679 +2680 +2681 +2682 +2683 +2684 +2685 +2686 +2687 +2688 +2689 +2690 +2691 +2692 +2693 +2694 +2695 +2696 +2697 +2698 +2699 +2700 +2701 +2702 +2703 +2704 +2705 +2706 +2707 +2708 +2709 +2710 +2711 +2712 +2713 +2714 +2715 +2716 +2717 +2718 +2719 +2720 +2721 +2722 +2723 +2724 +2725 +2726 +2727 +2728 +2729 +2730 +2731 +2732 +2733 +2734 +2735 +2736 +2737 +2738 +2739 +2740 +2741 +2742 +2743 +2744 +2745 +2746 +2747 +2748 +2749 +2750 +2751 +2752 +2753 +2754 +2755 +2756 +2757 +2758 +2759 +2760 +2761 +2762 +2763 +2764 +2765 +2766 +2767 +2768 +2769 +2770 +2771 +2772 +2773 +2774 +2775 +2776 +2777 +2778 +2779 +2780 +2781 +2782 +2783 +2784 +2785 +2786 +2787 +2788 +2789 +2790 +2791 +2792 +2793 +2794 +2795 +2796 +2797 +2798 +2799 +2800 +2801 +2802 +2803 +2804 +2805 +2806 +2807 +2808 +2809 +2810 +2811 +2812 +2813 +2814 +2815 +2816 +2817 +2818 +2819 +2820 +2821 +2822 +2823 +2824 +2825 +2826 +2827 +2828 +2829 +2830 +2831 +2832 +2833 +2834 +2835 +2836 +2837 +2838 +2839 +2840 +2841 +2842 +2843 +2844 +2845 +2846 +2847 +2848 +2849 +2850 +2851 +2852 +2853 +2854 +2855 +2856 +2857 +2858 +2859 +2860 +2861 +2862 +2863 +2864 +2865 +2866 +2867 +2868 +2869 +2870 +2871 +2872 +2873 +2874 +2875 +2876 +2877 +2878 +2879 +2880 +2881 +2882 +2883 +2884 +2885 +2886 +2887 +2888 +2889 +2890 +2891 +2892 +2893 +2894 +2895 +2896 +2897 +2898 +2899 +2900 +2901 +2902 +2903 +2904 +2905 +2906 +2907 +2908 +2909 +2910 +2911 +2912 +2913 +2914 +2915 +2916 +2917 +2918 +2919 +2920 +2921 +2922 +2923 +2924 +2925 +2926 +2927 +2928 +2929 +2930 +2931 +2932 +2933 +2934 +2935 +2936 +2937 +2938 +2939 +2940 +2941 +2942 +2943 +2944 +2945 +2946 +2947 +2948 +2949 +2950 +2951 +2952 +2953 +2954 +2955 +2956 +2957 +2958 +2959 +2960 +2961 +2962 +2963 +2964 +2965 +2966 +2967 +2968 +2969 +2970 +2971 +2972 +2973 +2974 +2975 +2976 +2977 +2978 +2979 +2980 +2981 +2982 +2983 +2984 +2985 +2986 +2987 +2988 +2989 +2990 +2991 +2992 +2993 +2994 +2995 +2996 +2997 +2998 +2999 +3000 +3001 +3002 +3003 +3004 +3005 +3006 +3007 +3008 +3009 +3010 +3011 +3012 +3013 +3014 +3015 +3016 +3017 +3018 +3019 +3020 +3021 +3022 +3023 +3024 +3025 +3026 +3027 +3028 +3029 +3030 +3031 +3032 +3033 +3034 +3035 +3036 +3037 +3038 +3039 +3040 +3041 +3042 +3043 +3044 +3045 +3046 +3047 +3048 +3049 +3050 +3051 +3052 +3053 +3054 +3055 +3056 +3057 +3058 +3059 +3060 +3061 +3062 +3063 +3064 +3065 +3066 +3067 +3068 +3069 +3070 +3071 +3072 +3073 +3074 +3075 +3076 +3077 +3078 +3079 +3080 +3081 +3082 +3083 +3084 +3085 +3086 +3087 +3088 +3089 +3090 +3091 +3092 +3093 +3094 +3095 +3096 +3097 +3098 +3099 +3100 +3101 +3102 +3103 +3104 +3105 +3106 +3107 +3108 +3109 +3110 +3111 +3112 +3113 +3114 +3115 +3116 +3117 +3118 +3119 +3120 +3121 +3122 +3123 +3124 +3125 +3126 +3127 +3128 +3129 +3130 +3131 +3132 +3133 +3134 +3135 +3136 +3137 +3138 +3139 +3140 +3141 +3142 +3143 +3144 +3145 +3146 +3147 +3148 +3149 +3150 +3151 +3152 +3153 +3154 +3155 +3156 +3157 +3158 +3159 +3160 +3161 +3162 +3163 +3164 +3165 +3166 +3167 +3168 +3169 +3170 +3171 +3172 +3173 +3174 +3175 +3176 +3177 +3178 +3179 +3180 +3181 +3182 +3183 +3184 +3185 +3186 +3187 +3188 +3189 +3190 +3191 +3192 +3193 +3194 +3195 +3196 +3197 +3198 +3199 +3200 +3201 +3202 +3203 +3204 +3205 +3206 +3207 +3208 +3209 +3210 +3211 +3212 +3213 +3214 +3215 +3216 +3217 +3218 +3219 +3220 +3221 +3222 +3223 +3224 +3225 +3226 +3227 +3228 +3229 +3230 +3231 +3232 +3233 +3234 +3235 +3236 +3237 +3238 +3239 +3240 +3241 +3242 +3243 +3244 +3245 +3246 +3247 +3248 +3249 +3250 +3251 +3252 +3253 +3254 +3255 +3256 +3257 +3258 +3259 +3260 +3261 +3262 +3263 +3264 +3265 +3266 +3267 +3268 +3269 +3270 +3271 +3272 +3273 +3274 +3275 +3276 +3277 +3278 +3279 +3280 +3281 +3282 +3283 +3284 +3285 +3286 +3287 +3288 +3289 +3290 +3291 +3292 +3293 +3294 +3295 +3296 +3297 +3298 +3299 +3300 +3301 +3302 +3303 +3304 +3305 +3306 +3307 +3308 +3309 +3310 +3311 +3312 +3313 +3314 +3315 +3316 +3317 +3318 +3319 +3320 +3321 +3322 +3323 +3324 +3325 +3326 +3327 +3328 +3329 +3330 +3331 +3332 +3333 +3334 +3335 +3336 +3337 +3338 +3339 +3340 +3341 +3342 +3343 +3344 +3345 +3346 +3347 +3348 +3349 +3350 +3351 +3352 +3353 +3354 +3355 +3356 +3357 +3358 +3359 +3360 +3361 +3362 +3363 +3364 +3365 +3366 +3367 +3368 +3369 +3370 +3371 +3372 +3373 +3374 +3375 +3376 +3377 +3378 +3379 +3380 +3381 +3382 +3383 +3384 +3385 +3386 +3387 +3388 +3389 +3390 +3391 +3392 +3393 +3394 +3395 +3396 +3397 +3398 +3399 +3400 +3401 +3402 +3403 +3404 +3405 +3406 +3407 +3408 +3409 +3410 +3411 +3412 +3413 +3414 +3415 +3416 +3417 +3418 +3419 +3420 +3421 +3422 +3423 +3424 +3425 +3426 +3427 +3428 +3429 +3430 +3431 +3432 +3433 +3434 +3435 +3436 +3437 +3438 +3439 +3440 +3441 +3442 +3443 +3444 +3445 +3446 +3447 +3448 +3449 +3450 +3451 +3452 +3453 +3454 +3455 +3456 +3457 +3458 +3459 +3460 +3461 +3462 +3463 +3464 +3465 +3466 +3467 +3468 +3469 +3470 +3471 +3472 +3473 +3474 +3475 +3476 +3477 +3478 +3479 +3480 +3481 +3482 +3483 +3484 +3485 +3486 +3487 +3488 +3489 +3490 +3491 +3492 +3493 +3494 +3495 +3496 +3497 +3498 +3499 +3500 +3501 +3502 +3503 +3504 +3505 +3506 +3507 +3508 +3509 +3510 +3511 +3512 +3513 +3514 +3515 +3516 +3517 +3518 +3519 +3520 +3521 +3522 +3523 +3524 +3525 +3526 +3527 +3528 +3529 +3530 +3531 +3532 +3533 +3534 +3535 +3536 +3537 +3538 +3539 +3540 +3541 +3542 +3543 +3544 +3545 +3546 +3547 +3548 +3549 +3550 +3551 +3552 +3553 +3554 +3555 +3556 +3557 +3558 +3559 +3560 +3561 +3562 +3563 +3564 +3565 +3566 +3567 +3568 +3569 +3570 +3571 +3572 +3573 +3574 +3575 +3576 +3577 +3578 +3579 +3580 +3581 +3582 +3583 +3584 +3585 +3586 +3587 +3588 +3589 +3590 +3591 +3592 +3593 +3594 +3595 +3596 +3597 +3598 +3599 +3600 +3601 +3602 +3603 +3604 +3605 +3606 +3607 +3608 +3609 +3610 +3611 +3612 +3613 +3614 +3615 +3616 +3617 +3618 +3619 +3620 +3621 +3622 +3623 +3624 +3625 +3626 +3627 +3628 +3629 +3630 +3631 +3632 +3633 +3634 +3635 +3636 +3637 +3638 +3639 +3640 +3641 +3642 +3643 +3644 +3645 +3646 +3647 +3648 +3649 +3650 +3651 +3652 +3653 +3654 +3655 +3656 +3657 +3658 +3659 +3660 +3661 +3662 +3663 +3664 +3665 +3666 +3667 +3668 +3669 +3670 +3671 +3672 +3673 +3674 +3675 +3676 +3677 +3678 +3679 +3680 +3681 +3682 +3683 +3684 +3685 +3686 +3687 +3688 +3689 +3690 +3691 +3692 +3693 +3694 +3695 +3696 +3697 +3698 +3699 +3700 +3701 +3702 +3703 +3704 +3705 +3706 +3707 +3708 +3709 +3710 +3711 +3712 +3713 +3714 +3715 +3716 +3717 +3718 +3719 +3720 +3721 +3722 +3723 +3724 +3725 +3726 +3727 +3728 +3729 +3730 +3731 +3732 +3733 +3734 +3735 +3736 +3737 +3738 +3739 +3740 +3741 +3742 +3743 +3744 +3745 +3746 +3747 +3748 +3749 +3750 +3751 +3752 +3753 +3754 +3755 +3756 +3757 +3758 +3759 +3760 +3761 +3762 +3763 +3764 +3765 +3766 +3767 +3768 +3769 +3770 +3771 +3772 +3773 +3774 +3775 +3776 +3777 +3778 +3779 +3780 +3781 +3782 +3783 +3784 +3785 +3786 +3787 +3788 +3789 +3790 +3791 +3792 +3793 +3794 +3795 +3796 +3797 +3798 +3799 +3800 +3801 +3802 +3803 +3804 +3805 +3806 +3807 +3808 +3809 +3810 +3811 +3812 +3813 +3814 +3815 +3816 +3817 +3818 +3819 +3820 +3821 +3822 +3823 +3824 +3825 +3826 +3827 +3828 +3829 +3830 +3831 +3832 +3833 +3834 +3835 +3836 +3837 +3838 +3839 +3840 +3841 +3842 +3843 +3844 +3845 +3846 +3847 +3848 +3849 +3850 +3851 +3852 +3853 +3854 +3855 +3856 +3857 +3858 +3859 +3860 +3861 +3862 +3863 +3864 +3865 +3866 +3867 +3868 +3869 +3870 +3871 +3872 +3873 +3874 +3875 +3876 +3877 +3878 +3879 +3880 +3881 +3882 +3883 +3884 +3885 +3886 +3887 +3888 +3889 +3890 +3891 +3892 +3893 +3894 +3895 +3896 +3897 +3898 +3899 +3900 +3901 +3902 +3903 +3904 +3905 +3906 +3907 +3908 +3909 +3910 +3911 +3912 +3913 +3914 +3915 +3916 +3917 +3918 +3919 +3920 +3921 +3922 +3923 +3924 +3925 +3926 +3927 +3928 +3929 +3930 +3931 +3932 +3933 +3934 +3935 +3936 +3937 +3938 +3939 +3940 +3941 +3942 +3943 +3944 +3945 +3946 +3947 +3948 +3949 +3950 +3951 +3952 +3953 +3954 +3955 +3956 +3957 +3958 +3959 +3960 +3961 +3962 +3963 +3964 +3965 +3966 +3967 +3968 +3969 +3970 +3971 +3972 +3973 +3974 +3975 +3976 +3977 +3978 +3979 +3980 +3981 +3982 +3983 +3984 +3985 +3986 +3987 +3988 +3989 +3990 +3991 +3992 +3993 +3994 +3995 +3996 +3997 +3998 +3999 +4000 +4001 +4002 +4003 +4004 +4005 +4006 +4007 +4008 +4009 +4010 +4011 +4012 +4013 +4014 +4015 +4016 +4017 +4018 +4019 +4020 +4021 +4022 +4023 +4024 +4025 +4026 +4027 +4028 +4029 +4030 +4031 +4032 +4033 +4034 +4035 +4036 +4037 +4038 +4039 +4040 +4041 +4042 +4043 +4044 +4045 +4046 +4047 +4048 +4049 +4050 +4051 +4052 +4053 +4054 +4055 +4056 +4057 +4058 +4059 +4060 +4061 +4062 +4063 +4064 +4065 +4066 +4067 +4068 +4069 +4070 +4071 +4072 +4073 +4074 +4075 +4076 +4077 +4078 +4079 +4080 +4081 +4082 +4083 +4084 +4085 +4086 +4087 +4088 +4089 +4090 +4091 +4092 +4093 +4094 +4095 + + Written Files(4096) +===DONE=== diff --git a/ext/phar/tests/bug13786.phpt b/ext/phar/tests/bug13786.phpt new file mode 100644 index 0000000000..572d1eb9aa --- /dev/null +++ b/ext/phar/tests/bug13786.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: bug #13786: "PHP crashes on phar recreate after unlink" +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php + +try { +for ($i = 0; $i < 2; $i++) { + $fname = "DataArchive.phar"; + $path = dirname(__FILE__) . DIRECTORY_SEPARATOR . $fname; + $phar = new Phar($path); + $phar->addFromString($i, "file $i in $fname"); + var_dump(file_get_contents($phar[$i])); + unset($phar); + unlink($path); +} + +echo("\nWritten files: $i\n"); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--EXPECTF-- +string(26) "file 0 in DataArchive.phar" +unable to seek to start of file "0" while creating new phar "%sDataArchive.phar" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/create_new_and_modify.phpt b/ext/phar/tests/create_new_and_modify.phpt new file mode 100755 index 0000000000..66587de023 --- /dev/null +++ b/ext/phar/tests/create_new_and_modify.phpt @@ -0,0 +1,48 @@ +--TEST-- +Phar: create and modify phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; + +@unlink($fname); + +file_put_contents($pname . '/a.php', "brand new!\n"); + +$phar = new Phar($fname); +$sig1 = $phar->getSignature(); + +include $pname . '/a.php'; + +file_put_contents($pname .'/a.php', "modified!\n"); +file_put_contents($pname .'/b.php', "another!\n"); + +$phar = new Phar($fname); +$sig2 = $phar->getSignature(); + +var_dump($sig1['hash']); +var_dump($sig2['hash']); +var_dump($sig1['hash'] != $sig2['hash']); + +include $pname . '/a.php'; +include $pname . '/b.php'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +brand new! +string(40) "%s" +string(40) "%s" +bool(true) +modified! +another! +===DONE=== diff --git a/ext/phar/tests/create_new_phar.phpt b/ext/phar/tests/create_new_phar.phpt new file mode 100644 index 0000000000..ec57c27217 --- /dev/null +++ b/ext/phar/tests/create_new_phar.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar: create a completely new phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +<?php + +file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php', + 'brand new!'); +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +brand new! +===DONE=== diff --git a/ext/phar/tests/create_new_phar_b.phpt b/ext/phar/tests/create_new_phar_b.phpt new file mode 100755 index 0000000000..8f1298245c --- /dev/null +++ b/ext/phar/tests/create_new_phar_b.phpt @@ -0,0 +1,27 @@ +--TEST-- +Phar: create a completely new phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=1 +--FILE-- +<?php + +file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php', + 'brand new!'); +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- + +Warning: file_put_contents(phar://%screate_new_phar_b.phar.php/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d + +Warning: include(phar://%screate_new_phar_b.phar.php/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d + +Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.php/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/create_new_phar_c.phpt b/ext/phar/tests/create_new_phar_c.phpt new file mode 100755 index 0000000000..6beaa2eb61 --- /dev/null +++ b/ext/phar/tests/create_new_phar_c.phpt @@ -0,0 +1,29 @@ +--TEST-- +Phar: create a completely new phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +<?php + +file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php', + 'brand new!'); + +$phar = new Phar(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'); + +var_dump($phar->getSignature()); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +array(2) { + ["hash"]=> + string(40) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +===DONE=== diff --git a/ext/phar/tests/create_path_error.phpt b/ext/phar/tests/create_path_error.phpt new file mode 100755 index 0000000000..d3fc035860 --- /dev/null +++ b/ext/phar/tests/create_path_error.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar: create with illegal path +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; + +@unlink($fname); + +file_put_contents($pname . '/a.php?', "query"); +file_put_contents($pname . '/b.php?bla', "query"); + +var_dump(file_get_contents($pname . '/a.php')); +var_dump(file_get_contents($pname . '/b.php')); + +function error_handler($errno, $errmsg) +{ + echo "Error: $errmsg\n"; +} + +set_error_handler('error_handler'); + +$checks = array('/', '.', '../', 'a/..', 'a/', 'b//a.php'); +foreach($checks as $check) +{ + file_put_contents($pname . '/' . $check, "error"); +} + +$phar = new Phar($fname); +$checks = array("a\0"); +foreach($checks as $check) +{ + try + { + $phar[$check] = 'error'; + } + catch(Exception $e) + { + echo 'Exception: ' . $e->getMessage() . "\n"; + } +} + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +string(5) "query" +string(5) "query" +Error: file_put_contents(phar://%s//): failed to open stream: phar error: file "" in phar "%s" cannot be empty +Error: file_put_contents(phar://%s/.): failed to open stream: phar error: file "" in phar "%s" cannot be empty +Error: file_put_contents(phar://%s/../): failed to open stream: phar error: file "" in phar "%s" cannot be empty +Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: file "" in phar "%s" cannot be empty +Exception: Entry a does not exist and cannot be created: phar error: invalid path "a" contains illegal character +===DONE=== diff --git a/ext/phar/tests/delete.phpt b/ext/phar/tests/delete.phpt new file mode 100644 index 0000000000..1d98509064 --- /dev/null +++ b/ext/phar/tests/delete.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: delete test +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +include 'files/phar_test.inc'; +include $fname; +$phar = new Phar($fname); + +echo file_get_contents($pname . '/a') . "\n"; +$phar->delete('a'); +echo file_get_contents($pname . '/a') . "\n"; +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +a + +Warning: file_get_contents(phar://%sdelete.phar.php/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.php" in %sdelete.php on line 16 \ No newline at end of file diff --git a/ext/phar/tests/delete_in_phar.phpt b/ext/phar/tests/delete_in_phar.phpt new file mode 100644 index 0000000000..4842d27913 --- /dev/null +++ b/ext/phar/tests/delete_in_phar.phpt @@ -0,0 +1,48 @@ +--TEST-- +Phar: delete a file within a .phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +include 'files/phar_test.inc'; + +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; +unlink($pname . '/b/c.php'); +?> +===AFTER=== +<?php +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar.phar.php/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.php" in %sdelete_in_phar.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.php/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d + +===DONE=== + \ No newline at end of file diff --git a/ext/phar/tests/delete_in_phar_b.phpt b/ext/phar/tests/delete_in_phar_b.phpt new file mode 100755 index 0000000000..d26f51cbf1 --- /dev/null +++ b/ext/phar/tests/delete_in_phar_b.phpt @@ -0,0 +1,46 @@ +--TEST-- +Phar: delete a file within a .phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +include 'files/phar_test.inc'; + +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; +unlink($pname . '/b/c.php'); +?> +===AFTER=== +<?php +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +This is a +This is b +This is b/c + +Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d +===AFTER=== +This is a +This is b +This is b/c + +===DONE=== diff --git a/ext/phar/tests/delete_in_phar_confirm.phpt b/ext/phar/tests/delete_in_phar_confirm.phpt new file mode 100644 index 0000000000..13a8d0db29 --- /dev/null +++ b/ext/phar/tests/delete_in_phar_confirm.phpt @@ -0,0 +1,51 @@ +--TEST-- +Phar: delete a file within a .phar (confirm disk file is changed) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +include 'files/phar_test.inc'; + +include $pname . '/a.php'; +include $pname . '/b.php'; +include $pname . '/b/c.php'; +$md5 = md5_file($fname); +unlink($pname . '/b/c.php'); +clearstatcache(); +$md52 = md5_file($fname); +if ($md5 == $md52) echo 'file was not modified'; +?> +===AFTER=== +<?php +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php'; +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/b.php'; +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar_confirm.phar.php/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.php" in %sdelete_in_phar_confirm.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.php/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d + +===DONE=== diff --git a/ext/phar/tests/dir.phpt b/ext/phar/tests/dir.phpt new file mode 100644 index 0000000000..a8f9d3f889 --- /dev/null +++ b/ext/phar/tests/dir.phpt @@ -0,0 +1,92 @@ +--TEST-- +Phar: mkdir/rmdir test +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php'; +$pname2 = 'phar://' . $fname2; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php'; +$pname3 = 'phar://' . $fname3; +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::PHAR)); + +$phar->addEmptyDir('test'); +var_dump($phar['test']->isDir()); +var_dump($phar['test/']->isDir()); +copy($fname, $fname2); +mkdir($pname . '/another/dir/'); +var_dump($phar['another/dir']->isDir()); +rmdir($pname . '/another/dir/'); +copy($fname, $fname3); +clearstatcache(); +var_dump(file_exists($pname . '/another/dir/')); +var_dump(file_exists($pname2 . '/test/')); +var_dump(file_exists($pname3 . '/another/dir/')); +ini_set('phar.readonly', 1); +mkdir($pname . '/fails'); +ini_set('phar.readonly', 0); +// create new phar by mkdir +mkdir('phar://' . dirname(__FILE__) . '/ok.phar/fails'); +mkdir('phar://' . dirname(__FILE__) . '/ok.phar/fails'); +file_put_contents('phar://' . dirname(__FILE__) . '/ok.phar/sub/directory.txt', 'hi'); +mkdir('phar://' . dirname(__FILE__) . '/ok.phar/sub'); +mkdir('phar://' . dirname(__FILE__) . '/ok.phar/sub/directory.txt'); +file_put_contents(dirname(__FILE__) . '/oops.phar', '<?php this should screw em up __HALT_COMPILER();'); +mkdir('phar://' . dirname(__FILE__) . '/oops.phar/fails'); + +mkdir('phar://'); +rmdir('phar://'); +rmdir('phar://' . dirname(__FILE__) . '/unknown.phar/hi'); +ini_set('phar.readonly', 1); +rmdir($pname . '/another/dir'); +ini_set('phar.readonly', 0); +rmdir($pname); +rmdir($pname . '/'); +mkdir($pname . '/'); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php unlink(dirname(__FILE__) . '/ok.phar'); ?> +<?php unlink(dirname(__FILE__) . '/oops.phar'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) + +Warning: mkdir(): phar error: cannot create directory "phar://%sdir.phar.php/fails", write operations disabled in %sdir.php on line %d + +Warning: mkdir(): phar error: cannot create directory "fails" in phar "%sok.phar", directory already exists in %sdir.php on line %d + +Warning: mkdir(): phar error: cannot create directory "sub" in phar "%sok.phar", directory already exists in %sdir.php on line %d + +Warning: mkdir(): phar error: cannot create directory "sub/directory.txt" in phar "%sok.phar", phar error: path "sub/directory.txt" exists and is a not a directory in %sdir.php on line %d + +Warning: mkdir(): internal corruption of phar "%soops.phar" (truncated manifest at stub end) in %sdir.php on line %d + +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, 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 + +Warning: rmdir(): phar error: cannot rmdir directory "phar://%sdir.phar.php/another/dir", write operations disabled in %sdir.php on line %d + +Warning: rmdir(): phar error: cannot remove directory "" in phar "%sdir.phar.php", directory does not exist in %sdir.php on line %d + +Warning: rmdir(): phar error: cannot remove directory "" in phar "%sdir.phar.php", directory does not exist in %sdir.php on line %d + +Warning: mkdir(): phar error: cannot create directory "" in phar "%sdir.phar.php", phar error: invalid path "" must not be empty in %sdir.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/fgc_edgecases.phpt b/ext/phar/tests/fgc_edgecases.phpt new file mode 100644 index 0000000000..e899604e95 --- /dev/null +++ b/ext/phar/tests/fgc_edgecases.phpt @@ -0,0 +1,95 @@ +--TEST-- +Phar: test edge cases of file_get_contents() function interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; + +file_get_contents(array()); +chdir(dirname(__FILE__)); +file_put_contents($fname, "blah\n"); +file_put_contents("foob", "test\n"); +echo file_get_contents($fname); +unlink($fname); +mkdir($pname . '/oops'); +file_put_contents($pname . '/foo/hi', '<?php +echo file_get_contents("foo/" . basename(__FILE__)); +$context = stream_context_create(); +file_get_contents("./hi", 0, $context, 0, -1); +echo file_get_contents("foob"); +set_include_path("' . addslashes(dirname(__FILE__)) . '"); +echo file_get_contents("foob", true); +echo file_get_contents("./hi", 0, $context); +echo file_get_contents("../oops"); +echo file_get_contents("./hi", 0, $context, 50000); +ini_set("magic_quotes_runtime", 1); +echo file_get_contents("./hi"); +echo file_get_contents("./hi", 0, $context, 0, 0); +?> +'); +include $pname . '/foo/hi'; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php rmdir(dirname(__FILE__) . '/poo'); ?> +<?php unlink(dirname(__FILE__) . '/foob'); ?> +--EXPECTF-- +Warning: file_get_contents() expects parameter 1 to be string, array given in %sfgc_edgecases.php on line %d +blah +<?php +echo file_get_contents("foo/" . basename(__FILE__)); +$context = stream_context_create(); +file_get_contents("./hi", 0, $context, 0, -1); +echo file_get_contents("foob"); +set_include_path("%stests"); +echo file_get_contents("foob", true); +echo file_get_contents("./hi", 0, $context); +echo file_get_contents("../oops"); +echo file_get_contents("./hi", 0, $context, 50000); +ini_set("magic_quotes_runtime", 1); +echo file_get_contents("./hi"); +echo file_get_contents("./hi", 0, $context, 0, 0); +?> + +Warning: file_get_contents(): length must be greater than or equal to zero in phar://%sfgc_edgecases.phar.php/foo/hi on line %d +test +test +<?php +echo file_get_contents("foo/" . basename(__FILE__)); +$context = stream_context_create(); +file_get_contents("./hi", 0, $context, 0, -1); +echo file_get_contents("foob"); +set_include_path("%stests"); +echo file_get_contents("foob", true); +echo file_get_contents("./hi", 0, $context); +echo file_get_contents("../oops"); +echo file_get_contents("./hi", 0, $context, 50000); +ini_set("magic_quotes_runtime", 1); +echo file_get_contents("./hi"); +echo file_get_contents("./hi", 0, $context, 0, 0); +?> + +Warning: file_get_contents(phar://%sfgc_edgecases.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sfgc_edgecases.phar.php/foo/hi on line %d + +Warning: file_get_contents(): Failed to seek to position 50000 in the stream in phar://%sfgc_edgecases.phar.php/foo/hi on line %d +<?php +echo file_get_contents(\"foo/\" . basename(__FILE__)); +$context = stream_context_create(); +file_get_contents(\"./hi\", 0, $context, 0, -1); +echo file_get_contents(\"foob\"); +set_include_path(\"%stests\"); +echo file_get_contents(\"foob\", true); +echo file_get_contents(\"./hi\", 0, $context); +echo file_get_contents(\"../oops\"); +echo file_get_contents(\"./hi\", 0, $context, 50000); +ini_set(\"magic_quotes_runtime\", 1); +echo file_get_contents(\"./hi\"); +echo file_get_contents(\"./hi\", 0, $context, 0, 0); +?> +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/file_get_contents.phpt b/ext/phar/tests/file_get_contents.phpt new file mode 100644 index 0000000000..fcc9d64655 --- /dev/null +++ b/ext/phar/tests/file_get_contents.phpt @@ -0,0 +1,30 @@ +--TEST-- +Phar: test file_get_contents() interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$a = new Phar($fname); +$a['index.php'] = '<?php +echo file_get_contents("dir/file1.txt"); +echo file_get_contents("file1.txt", true); +?>'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub('<?php +Phar::interceptFileFuncs(); +set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +hihi===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/files/extracted.inc b/ext/phar/tests/files/extracted.inc new file mode 100644 index 0000000000..a6e52246a3 --- /dev/null +++ b/ext/phar/tests/files/extracted.inc @@ -0,0 +1 @@ +<?php var_dump(__FILE__); ?> diff --git a/ext/phar/tests/files/frontcontroller.phar b/ext/phar/tests/files/frontcontroller.phar new file mode 100644 index 0000000000..626bf48acf Binary files /dev/null and b/ext/phar/tests/files/frontcontroller.phar differ diff --git a/ext/phar/tests/files/frontcontroller.phar.inc b/ext/phar/tests/files/frontcontroller.phar.inc new file mode 100644 index 0000000000..80d42e886b --- /dev/null +++ b/ext/phar/tests/files/frontcontroller.phar.inc @@ -0,0 +1,13 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a['index.php'] = 'here is my index'; +$a->setStub('<?php +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller10.phar b/ext/phar/tests/files/frontcontroller10.phar new file mode 100644 index 0000000000..078ce75b2c Binary files /dev/null and b/ext/phar/tests/files/frontcontroller10.phar differ diff --git a/ext/phar/tests/files/frontcontroller10.phar.inc b/ext/phar/tests/files/frontcontroller10.phar.inc new file mode 100644 index 0000000000..4c139db58b --- /dev/null +++ b/ext/phar/tests/files/frontcontroller10.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller10.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller10.phar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI", "OOPSIE")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller11.phar b/ext/phar/tests/files/frontcontroller11.phar new file mode 100644 index 0000000000..61ea843222 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller11.phar differ diff --git a/ext/phar/tests/files/frontcontroller11.phar.inc b/ext/phar/tests/files/frontcontroller11.phar.inc new file mode 100644 index 0000000000..086350800b --- /dev/null +++ b/ext/phar/tests/files/frontcontroller11.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller11.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller11.phar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array(array(), "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller12.phar b/ext/phar/tests/files/frontcontroller12.phar new file mode 100644 index 0000000000..9e45587610 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller12.phar differ diff --git a/ext/phar/tests/files/frontcontroller12.phar.inc b/ext/phar/tests/files/frontcontroller12.phar.inc new file mode 100644 index 0000000000..ba17df37e1 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller12.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller12.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller12.phar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller13.phar b/ext/phar/tests/files/frontcontroller13.phar new file mode 100644 index 0000000000..750ff27a8e Binary files /dev/null and b/ext/phar/tests/files/frontcontroller13.phar differ diff --git a/ext/phar/tests/files/frontcontroller13.phar.inc b/ext/phar/tests/files/frontcontroller13.phar.inc new file mode 100644 index 0000000000..0bfef46853 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller13.phar.inc @@ -0,0 +1,14 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller13.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller13.phar'); +$a['index.php'] = '<?php +var_dump("test"); +include "oof/test.php";'; +$a['oof/test.php'] = '<?php +var_dump("oof/test.php"); +include "./hi.php";'; +$a['oof/hi.php'] = '<?php +var_dump("hi");'; +$a->setStub('<?php +Phar::webPhar(); +__HALT_COMPILER();'); \ No newline at end of file diff --git a/ext/phar/tests/files/frontcontroller14.phar b/ext/phar/tests/files/frontcontroller14.phar new file mode 100644 index 0000000000..78a42a999f Binary files /dev/null and b/ext/phar/tests/files/frontcontroller14.phar differ diff --git a/ext/phar/tests/files/frontcontroller14.phar.inc b/ext/phar/tests/files/frontcontroller14.phar.inc new file mode 100644 index 0000000000..d0ebd9a45a --- /dev/null +++ b/ext/phar/tests/files/frontcontroller14.phar.inc @@ -0,0 +1,19 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller14.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller14.phar'); +$a['html/index.php'] = '<?php +var_dump($_SERVER["PATH_INFO"]); +var_dump($_SERVER["PATH_TRANSLATED"]); +'; +$a->setStub('<?php +function s($a) +{ + return "/html/index.php"; +} +Phar::interceptFileFuncs(); +Phar::mungServer(array("PHP_SELF", "REQUEST_URI")); +Phar::webPhar("whatever", "/html/index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller16.phar b/ext/phar/tests/files/frontcontroller16.phar new file mode 100644 index 0000000000..cce5db5bb5 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller16.phar differ diff --git a/ext/phar/tests/files/frontcontroller16.phar.inc b/ext/phar/tests/files/frontcontroller16.phar.inc new file mode 100644 index 0000000000..3c9986da00 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller16.phar.inc @@ -0,0 +1,16 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller16.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller16.phar'); +$a['index.php'] = '<?php +echo "hi"; +'; +$a->setStub('<?php +try { +Phar::webPhar("test.phar", "/index.php", null, array(), array("fail", "here")); +} catch (Exception $e) { +die($e->getMessage() . "\n"); +} +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller17.phar b/ext/phar/tests/files/frontcontroller17.phar new file mode 100644 index 0000000000..b83d41fd5b Binary files /dev/null and b/ext/phar/tests/files/frontcontroller17.phar differ diff --git a/ext/phar/tests/files/frontcontroller17.phar.inc b/ext/phar/tests/files/frontcontroller17.phar.inc new file mode 100644 index 0000000000..85b8729f31 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller17.phar.inc @@ -0,0 +1,16 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller17.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller17.phar'); +$a['index.php'] = '<?php +echo "hi"; +'; +$a->setStub('<?php +try { +Phar::webPhar("test.phar", "/index.php", null, array(), "sort"); +} catch (Exception $e) { +die($e->getMessage() . "\n"); +} +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller18.phar b/ext/phar/tests/files/frontcontroller18.phar new file mode 100644 index 0000000000..c447f397ac Binary files /dev/null and b/ext/phar/tests/files/frontcontroller18.phar differ diff --git a/ext/phar/tests/files/frontcontroller18.phar.inc b/ext/phar/tests/files/frontcontroller18.phar.inc new file mode 100644 index 0000000000..847a713ba3 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller18.phar.inc @@ -0,0 +1,19 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller18.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller18.phar'); +$a['index.php'] = '<?php +echo "hi"; +'; +$a->setStub('<?php +function s($a) +{ +} +try { +Phar::webPhar("test.phar", "/index.php", null, array(), "s"); +} catch (Exception $e) { +die($e->getMessage() . "\n"); +} +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller19.phar b/ext/phar/tests/files/frontcontroller19.phar new file mode 100644 index 0000000000..bdf8ee13c2 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller19.phar differ diff --git a/ext/phar/tests/files/frontcontroller19.phar.inc b/ext/phar/tests/files/frontcontroller19.phar.inc new file mode 100644 index 0000000000..ba84ac410a --- /dev/null +++ b/ext/phar/tests/files/frontcontroller19.phar.inc @@ -0,0 +1,25 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller19.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller19.phar'); +$a['start/index.php'] = '<?php +echo "start/index.php\n"; +include "./another.php"; +'; +$a['start/another.php'] = '<?php +echo "start/another.php\n"; +include "../another.php"; +?>'; +$a['another.php'] = '<?php +echo "another.php\n"; +?>'; +$a->setStub('<?php +set_include_path("phar://" . __FILE__); +try { +Phar::webPhar("test.phar", "/start/index.php"); +} catch (Exception $e) { +die($e->getMessage() . "\n"); +} +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller2.phar b/ext/phar/tests/files/frontcontroller2.phar new file mode 100644 index 0000000000..0dd0e7f695 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller2.phar differ diff --git a/ext/phar/tests/files/frontcontroller2.phar.inc b/ext/phar/tests/files/frontcontroller2.phar.inc new file mode 100644 index 0000000000..653c79691d --- /dev/null +++ b/ext/phar/tests/files/frontcontroller2.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller2.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller2.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "a.php"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller3.phar b/ext/phar/tests/files/frontcontroller3.phar new file mode 100644 index 0000000000..afcf03af35 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller3.phar differ diff --git a/ext/phar/tests/files/frontcontroller3.phar.inc b/ext/phar/tests/files/frontcontroller3.phar.inc new file mode 100644 index 0000000000..2759d9ee45 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller3.phar.inc @@ -0,0 +1,18 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller3.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller3.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +function s($a) +{ + static $b = array("/hi" => "a.phps"); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "/index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller4.phar b/ext/phar/tests/files/frontcontroller4.phar new file mode 100644 index 0000000000..4c9a92a197 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller4.phar differ diff --git a/ext/phar/tests/files/frontcontroller4.phar.inc b/ext/phar/tests/files/frontcontroller4.phar.inc new file mode 100644 index 0000000000..5c6a43f954 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller4.phar.inc @@ -0,0 +1,18 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller4.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller4.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +function s($a) +{ + static $b = array("/hi" => false); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller5.phar b/ext/phar/tests/files/frontcontroller5.phar new file mode 100644 index 0000000000..f206b5996d Binary files /dev/null and b/ext/phar/tests/files/frontcontroller5.phar differ diff --git a/ext/phar/tests/files/frontcontroller5.phar.inc b/ext/phar/tests/files/frontcontroller5.phar.inc new file mode 100644 index 0000000000..d2d810c367 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller5.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller5.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller5.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array(0 => "oops")); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller6.phar b/ext/phar/tests/files/frontcontroller6.phar new file mode 100644 index 0000000000..e3b6bb86a1 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller6.phar differ diff --git a/ext/phar/tests/files/frontcontroller6.phar.inc b/ext/phar/tests/files/frontcontroller6.phar.inc new file mode 100644 index 0000000000..5c900eb603 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller6.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller6.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller6.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array("blah" => 100)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller7.phar b/ext/phar/tests/files/frontcontroller7.phar new file mode 100644 index 0000000000..79672809b4 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller7.phar differ diff --git a/ext/phar/tests/files/frontcontroller7.phar.inc b/ext/phar/tests/files/frontcontroller7.phar.inc new file mode 100644 index 0000000000..684970263e --- /dev/null +++ b/ext/phar/tests/files/frontcontroller7.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller7.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller7.phar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array("blah" => null)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller8.phar b/ext/phar/tests/files/frontcontroller8.phar new file mode 100644 index 0000000000..ec05ceafb0 Binary files /dev/null and b/ext/phar/tests/files/frontcontroller8.phar differ diff --git a/ext/phar/tests/files/frontcontroller8.phar.inc b/ext/phar/tests/files/frontcontroller8.phar.inc new file mode 100644 index 0000000000..1dfb654a03 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller8.phar.inc @@ -0,0 +1,19 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller8.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller8.phar'); +$a['a.phps'] = 'hio1'; +$a['a1.phps'] = '<?php var_dump($_SERVER["REQUEST_URI"], $_SERVER["PATH_INFO"]);'; +$a['a.jpg'] = 'hio2'; +$a['a.php'] = '<?php function hio(){}'; +$a['fronk.gronk'] = 'hio3'; +$a['404.php'] = 'My 404 is rawesome'; +$a['noext'] = 'hi'; +$a['unknown.ext'] = '<?php var_dump("hi");'; +$a['bigfile.txt'] = str_repeat('a', 8193); +$a['fatalerror.phps'] = '<?php oopsie_daisy();'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", "404.php", array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/frontcontroller9.phar b/ext/phar/tests/files/frontcontroller9.phar new file mode 100644 index 0000000000..39ca28c96c Binary files /dev/null and b/ext/phar/tests/files/frontcontroller9.phar differ diff --git a/ext/phar/tests/files/frontcontroller9.phar.inc b/ext/phar/tests/files/frontcontroller9.phar.inc new file mode 100644 index 0000000000..00861f6420 --- /dev/null +++ b/ext/phar/tests/files/frontcontroller9.phar.inc @@ -0,0 +1,14 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller9.phar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller9.phar'); +$a['a.phps'] = 'hio1'; +$a['a.jpg'] = 'hio2'; +$a['a.php'] = '<?php function hio(){}'; +$a['fronk.gronk'] = 'hio3'; +$a->setStub('<?php +Phar::mungServer(array()); +Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/files/md5.phar b/ext/phar/tests/files/md5.phar new file mode 100644 index 0000000000..8ca2f84dac Binary files /dev/null and b/ext/phar/tests/files/md5.phar differ diff --git a/ext/phar/tests/files/nophar.phar b/ext/phar/tests/files/nophar.phar new file mode 100644 index 0000000000..f1c5252018 Binary files /dev/null and b/ext/phar/tests/files/nophar.phar differ diff --git a/ext/phar/tests/files/nophar.phar.inc b/ext/phar/tests/files/nophar.phar.inc new file mode 100644 index 0000000000..36d5628762 --- /dev/null +++ b/ext/phar/tests/files/nophar.phar.inc @@ -0,0 +1,10 @@ +<?php +$fname = dirname(__FILE__) . '/nophar.phar'; +@unlink($fname); +$p = new Phar($fname); +$p['index.php'] = '<?php include "b/c.php";' . "\n"; +$p['web.php'] = '<?php echo "web\n";'; +$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("index.php", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";'; +$p['d'] = "in d\n"; +$p->setStub($p->createDefaultStub('index.php', 'web.php')); +?> \ No newline at end of file diff --git a/ext/phar/tests/files/phar_oo_test.inc b/ext/phar/tests/files/phar_oo_test.inc new file mode 100644 index 0000000000..9863e8da93 --- /dev/null +++ b/ext/phar/tests/files/phar_oo_test.inc @@ -0,0 +1,49 @@ +<?php + +ini_set('date.timezone', 'GMT'); + +$fname = dirname(__FILE__) . '/phar_oo_test.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; + +$files = array(); + +if (!isset($pharconfig)) $pharconfig = 0; + +switch($pharconfig) +{ + default: + case 0: + $files['a.php'] = '<?php echo "This is a.php\n"; ?>'; + $files['b.php'] = '<?php echo "This is b.php\n"; ?>'; + $files['b/c.php'] = '<?php echo "This is b/c.php\n"; ?>'; + $files['b/d.php'] = '<?php echo "This is b/d.php\n"; ?>'; + $files['e.php'] = '<?php echo "This is e.php\n"; ?>'; + break; + case 1: + $files['a.csv'] =<<<EOF +1,2,3 +2,a,b +3,"c","'e'" +EOF; + break; + case 2: + $files['a.csv'] =<<<EOF +1,2,3 +2,a,b +3,"c","'e'" +4 +5,5 + +7,777 +EOF; + break; + case 3: + $files['a.php'] = '<?php echo new new class;'; + break; +} + +$ftime = mktime(12, 0, 0, 3, 1, 2006); +include 'phar_test.inc'; + +?> \ No newline at end of file diff --git a/ext/phar/tests/files/phar_test.inc b/ext/phar/tests/files/phar_test.inc new file mode 100644 index 0000000000..a5e9d3fdc8 --- /dev/null +++ b/ext/phar/tests/files/phar_test.inc @@ -0,0 +1,76 @@ +<?php + +if (function_exists('date_default_timezone_set')) { + date_default_timezone_set('UTC'); +} + +$manifest = ''; +$glags = 0; + +foreach($files as $name => $cont) +{ + global $gflags, $files; + + $comp = NULL; + $crc32= NULL; + $clen = NULL; + $ulen = NULL; + $time = isset($ftime) ? $ftime : @mktime(12, 0, 0, 3, 1, 2006); + $flags= 0; + $perm = 0x000001B6; + $meta = NULL; + + // overwrite if array + if (is_array($cont)) + { + foreach(array('comp','crc32','clen','ulen','time','flags','perm','meta','cont') as $what) + { + if (isset($cont[$what])) + { + $$what = $cont[$what]; + } + } + } + + // create if not yet done + if (empty($comp)) $comp = $cont; + if (empty($ulen)) $ulen = strlen($cont); + if (empty($clen)) $clen = strlen($comp); + if (empty($crc32))$crc32= crc32($cont); + if (isset($meta)) $meta = serialize($meta); + + // write manifest entry + $manifest .= pack('V', strlen($name)) . $name; + $manifest .= pack('VVVVVV', $ulen, $time, $clen, $crc32, $flags|$perm, strlen($meta)) . $meta; + + // globals + $gflags |= $flags; + $files[$name] = $comp; +} + +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; +$file .= pack('V', strlen($manifest)) . $manifest; + +foreach($files as $cont) +{ + $file .= $cont; +} + +file_put_contents($fname, $file); + +if (@$gzip) { + $fp = gzopen($fname, 'w'); + fwrite($fp, $file); + fclose($fp); +} + +if (@$bz2) { + $fp = bzopen($fname, 'w'); + fwrite($fp, $file); + fclose($fp); +} + +?> \ No newline at end of file diff --git a/ext/phar/tests/files/sha1.phar b/ext/phar/tests/files/sha1.phar new file mode 100644 index 0000000000..c7e9e7e6a2 Binary files /dev/null and b/ext/phar/tests/files/sha1.phar differ diff --git a/ext/phar/tests/files/sha256.phar b/ext/phar/tests/files/sha256.phar new file mode 100644 index 0000000000..81459eef0f Binary files /dev/null and b/ext/phar/tests/files/sha256.phar differ diff --git a/ext/phar/tests/files/sha512.phar b/ext/phar/tests/files/sha512.phar new file mode 100644 index 0000000000..a7473819aa Binary files /dev/null and b/ext/phar/tests/files/sha512.phar differ diff --git a/ext/phar/tests/files/zfapp.tgz b/ext/phar/tests/files/zfapp.tgz new file mode 100644 index 0000000000..fcaec86d65 Binary files /dev/null and b/ext/phar/tests/files/zfapp.tgz differ diff --git a/ext/phar/tests/fopen.phpt b/ext/phar/tests/fopen.phpt new file mode 100644 index 0000000000..5b694d6e2d --- /dev/null +++ b/ext/phar/tests/fopen.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: test fopen() interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (substr(phpversion(), 0, 3) == '5.2') die("skip PHP >= 5.3 required for this test");?> +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$a = fopen(__FILE__, 'rb'); // this satisfies 1 line of code coverage +fclose($a); +$a = fopen(); // this satisfies another line of code coverage + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$a = new Phar($fname); +$a['index.php'] = '<?php +$a = fopen("dir/file1.txt", "r"); +echo fread($a, 2); +fclose($a); +$a = fopen("file1.txt", "r", true); +echo fread($a, 2); +fclose($a); +$a = fopen("notfound.txt", "r", true); +?>'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub('<?php +set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: fopen() expects at least 2 parameters, 0 given in %sfopen.php on line %d +hihi +Warning: fopen(notfound.txt): failed to open stream: No such file or directory in phar://%sfopen.phar.php/index.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/fopen5.2.phpt b/ext/phar/tests/fopen5.2.phpt new file mode 100644 index 0000000000..aa064f1662 --- /dev/null +++ b/ext/phar/tests/fopen5.2.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: test fopen() interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (substr(phpversion(), 0, 3) != '5.2') die("skip PHP 5.2 required for this test");?> +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$a = fopen(__FILE__, 'rb'); // this satisfies 1 line of code coverage +fclose($a); +$a = fopen(); // this satisfies another line of code coverage + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$a = new Phar($fname); +$a['index.php'] = '<?php +$a = fopen("dir/file1.txt", "r"); +echo fread($a, 2); +fclose($a); +$a = fopen("file1.txt", "r", true); +echo fread($a, 2); +fclose($a); +$a = fopen("notfound.txt", "r", true); +?>'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub('<?php +set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: fopen() expects at least 2 parameters, 0 given in %sfopen5.2.php on line %d +hihi +Warning: fopen(phar://%sfopen5.2.phar.php/notfound.txt): failed to open stream: phar error: "notfound.txt" is not a file in phar "%sfopen5.2.phar.php" in phar://%sfopen5.2.phar.php/index.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/fopen_edgecases.phpt b/ext/phar/tests/fopen_edgecases.phpt new file mode 100644 index 0000000000..4c28ff31a1 --- /dev/null +++ b/ext/phar/tests/fopen_edgecases.phpt @@ -0,0 +1,124 @@ +--TEST-- +Phar: fopen/stat/fseek/unlink/rename edge cases +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php'; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.3.phar.php'; +$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 +$a = fopen($pname . '.phar.gz', 'r'); +// test phar_open_url() with quiet stat for code coverage +var_dump(file_exists($pname . '.phar.gz/hi')); +// test open for write with new phar +$a = fopen($pname . '/hi', 'w'); +fclose($a); +// test open for write with corrupted phar +file_put_contents($fname2, '<?php oh crap __HALT_COMPILER();'); +$a = fopen($pname2 . '/hi', 'w'); +$a = fopen('phar://', 'r'); +$a = fopen('phar://foo.phar', 'r'); + +file_put_contents($pname . '/hi', 'hi'); +$a = fopen($pname . '/hi', 'r'); +var_dump(fseek($a, 1), ftell($a)); +var_dump(fseek($a, 1, SEEK_CUR), ftell($a)); +fclose($a); + +var_dump(stat('phar://')); +var_dump(stat('phar://foo.phar')); +var_dump(is_dir($pname)); + +// this tests coverage of the case where the phar exists and has no files +$phar = new Phar($fname3); +var_dump(file_exists($pname3 . '/test')); + +unlink($pname2 . '/hi'); +unlink('phar://'); +unlink('phar://foo.phar'); +unlink($pname . '/oops'); + +rename('phar://', 'phar://'); +rename($pname . '/hi', 'phar://'); +rename('phar://foo.phar/hi', 'phar://'); +rename($pname . '/hi', 'phar://foo.phar/hi'); + +ini_set('phar.readonly', 1); +rename($pname . '/hi', $pname . '/there'); +ini_set('phar.readonly', 0); +Phar::unlinkArchive($fname); +file_put_contents($pname . '/test.php', '<?php +$a = fopen("./notfound.php", "r"); +?>'); +include $pname . '/test.php'; +?> + +===DONE=== +--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 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 + +Warning: fopen(phar://): failed to open stream: phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar) in %sfopen_edgecases.php on line %d + +Warning: fopen(phar://foo.phar): failed to open stream: %s in %sfopen_edgecases.php on line %d +int(0) +int(1) +int(0) +int(2) + +Warning: stat(): stat failed for phar:// in %sfopen_edgecases.php on line %d +bool(false) + +Warning: stat(): stat failed for phar://foo.phar in %sfopen_edgecases.php on line %d +bool(false) +bool(true) +bool(false) + +Warning: unlink(): internal corruption of phar "%sfopen_edgecases.2.phar.php" (truncated manifest at stub end) in %sfopen_edgecases.php on line %d + +Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d + +Warning: unlink(): phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar) in %sfopen_edgecases.php on line %d + +Warning: unlink(): phar error: unlink failed 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 + +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 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 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 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: 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: fopen(./notfound.php): failed to open stream: No such file or directory in phar://%sfopen_edgecases.phar.php/test.php on line %d + +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/fopen_edgecases2.phpt b/ext/phar/tests/fopen_edgecases2.phpt new file mode 100644 index 0000000000..3579a2c221 --- /dev/null +++ b/ext/phar/tests/fopen_edgecases2.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: test edge cases of fopen() function interception #2 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; + +fopen(array(), 'r'); +chdir(dirname(__FILE__)); +file_put_contents($fname, "blah\n"); +file_put_contents("foob", "test\n"); +$a = fopen($fname, 'rb'); +echo fread($a, 1000); +fclose($a); +unlink($fname); +mkdir($pname . '/oops'); +file_put_contents($pname . '/foo/hi', '<?php +$context = stream_context_create(); +$a = fopen("foob", "rb", false, $context); +echo fread($a, 1000); +fclose($a); +fopen("../oops", "r"); +?> +'); +include $pname . '/foo/hi'; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php rmdir(dirname(__FILE__) . '/poo'); ?> +<?php unlink(dirname(__FILE__) . '/foob'); ?> +--EXPECTF-- +Warning: fopen() expects parameter 1 to be string, array given in %sfopen_edgecases2.php on line %d +blah +test + +Warning: fopen(phar://%sfopen_edgecases2.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sfopen_edgecases2.phar.php/foo/hi on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller1.phpt b/ext/phar/tests/frontcontroller1.phpt new file mode 100644 index 0000000000..7093323617 --- /dev/null +++ b/ext/phar/tests/frontcontroller1.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller other +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--ENV-- +SCRIPT_NAME=/frontcontroller1.php +REQUEST_URI=/frontcontroller1.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Content-type: image/jpeg +Content-length: 3 +--EXPECT-- +hio diff --git a/ext/phar/tests/frontcontroller10.phpt b/ext/phar/tests/frontcontroller10.phpt new file mode 100644 index 0000000000..2dbf1cbed8 --- /dev/null +++ b/ext/phar/tests/frontcontroller10.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller rewrite access denied +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--ENV-- +SCRIPT_NAME=/frontcontroller10.php +REQUEST_URI=/frontcontroller10.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller4.phar +--EXPECTHEADERS-- +Content-type: text/html +Status: 403 Access Denied +--EXPECT-- +<html> + <head> + <title>Access Denied + + +

    403 - File /hi Access Denied

    + + diff --git a/ext/phar/tests/frontcontroller11.phpt b/ext/phar/tests/frontcontroller11.phpt new file mode 100644 index 0000000000..3823fec191 --- /dev/null +++ b/ext/phar/tests/frontcontroller11.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type extension is not a string +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller11.php +REQUEST_URI=/frontcontroller11.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller5.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.php:2 +Stack trace: +#0 %sfrontcontroller11.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller11.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller12.phpt b/ext/phar/tests/frontcontroller12.phpt new file mode 100644 index 0000000000..e07876a41b --- /dev/null +++ b/ext/phar/tests/frontcontroller12.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type unknown int +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller12.php +REQUEST_URI=/frontcontroller12.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller6.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.php:2 +Stack trace: +#0 %sfrontcontroller12.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller12.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller13.phpt b/ext/phar/tests/frontcontroller13.phpt new file mode 100644 index 0000000000..74ed0e1b75 --- /dev/null +++ b/ext/phar/tests/frontcontroller13.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type not string/int +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller13.php +REQUEST_URI=/frontcontroller13.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller7.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.php:2 +Stack trace: +#0 %sfrontcontroller13.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller13.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller14.phpt b/ext/phar/tests/frontcontroller14.phpt new file mode 100644 index 0000000000..2bdb145c6e --- /dev/null +++ b/ext/phar/tests/frontcontroller14.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, other +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller14.php +REQUEST_URI=/frontcontroller14.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: foo/bar +Content-length: 4 +--EXPECT-- +hio2 diff --git a/ext/phar/tests/frontcontroller15.phpt b/ext/phar/tests/frontcontroller15.phpt new file mode 100644 index 0000000000..eb69ede8f5 --- /dev/null +++ b/ext/phar/tests/frontcontroller15.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type override, Phar::PHPS +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller15.php +REQUEST_URI=/frontcontroller15.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + + diff --git a/ext/phar/tests/frontcontroller16.phpt b/ext/phar/tests/frontcontroller16.phpt new file mode 100644 index 0000000000..5c6a03e16a --- /dev/null +++ b/ext/phar/tests/frontcontroller16.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, Phar::PHP +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller16.php +REQUEST_URI=/frontcontroller16.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio1 + diff --git a/ext/phar/tests/frontcontroller17.phpt b/ext/phar/tests/frontcontroller17.phpt new file mode 100644 index 0000000000..233e2e2a49 --- /dev/null +++ b/ext/phar/tests/frontcontroller17.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller mime type unknown +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller17.php +REQUEST_URI=/frontcontroller17.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: application/octet-stream +Content-length: 4 +--EXPECT-- +hio3 + diff --git a/ext/phar/tests/frontcontroller18.phpt b/ext/phar/tests/frontcontroller18.phpt new file mode 100644 index 0000000000..19aea45563 --- /dev/null +++ b/ext/phar/tests/frontcontroller18.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller18.php +REQUEST_URI=/frontcontroller18.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller9.phar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.php:2 +Stack trace: +#0 %sfrontcontroller18.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller18.php on line 2 diff --git a/ext/phar/tests/frontcontroller19.phpt b/ext/phar/tests/frontcontroller19.phpt new file mode 100644 index 0000000000..9adafa2b30 --- /dev/null +++ b/ext/phar/tests/frontcontroller19.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 2 +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller19.php +REQUEST_URI=/frontcontroller19.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller10.phar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.php:2 +Stack trace: +#0 %sfrontcontroller19.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller19.php on line 2 diff --git a/ext/phar/tests/frontcontroller2.phpt b/ext/phar/tests/frontcontroller2.phpt new file mode 100644 index 0000000000..4b1652c461 --- /dev/null +++ b/ext/phar/tests/frontcontroller2.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller PHP test +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller2.php +REQUEST_URI=/frontcontroller2.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio diff --git a/ext/phar/tests/frontcontroller20.phpt b/ext/phar/tests/frontcontroller20.phpt new file mode 100644 index 0000000000..45e2bfc25e --- /dev/null +++ b/ext/phar/tests/frontcontroller20.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 3 +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller20.php +REQUEST_URI=/frontcontroller20.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller11.phar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.php:2 +Stack trace: +#0 %sfrontcontroller20.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller20.php on line 2 diff --git a/ext/phar/tests/frontcontroller21.phpt b/ext/phar/tests/frontcontroller21.phpt new file mode 100644 index 0000000000..70d3508496 --- /dev/null +++ b/ext/phar/tests/frontcontroller21.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller $_SERVER munging success +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller21.php +REQUEST_URI=/frontcontroller21.php/index.php?test=hi +PATH_INFO=/index.php +QUERY_STRING=test=hi +--FILE_EXTERNAL-- +files/frontcontroller12.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(10) "/index.php" +string(10) "/index.php" +string(%d) "phar://%sfrontcontroller21.php/index.php" +string(18) "/index.php?test=hi" +string(32) "/frontcontroller21.php/index.php" +string(22) "/frontcontroller21.php" +string(%d) "%sfrontcontroller21.php" +string(40) "/frontcontroller21.php/index.php?test=hi" \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller22.phpt b/ext/phar/tests/frontcontroller22.phpt new file mode 100644 index 0000000000..9925ba16d3 --- /dev/null +++ b/ext/phar/tests/frontcontroller22.phpt @@ -0,0 +1,19 @@ +--TEST-- +Phar front controller include from cwd test 1 +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller22.php +REQUEST_URI=/frontcontroller22.php/index.php +PATH_INFO=/index.php +--FILE_EXTERNAL-- +files/frontcontroller13.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(4) "test" +string(12) "oof/test.php" + +Warning: include(./hi.php): failed to open stream: No such file or directory in phar://%s/oof/test.php on line %d + +Warning: include(): Failed opening './hi.php' for inclusion (include_path='%s') in phar://%soof/test.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller23.phpt b/ext/phar/tests/frontcontroller23.phpt new file mode 100644 index 0000000000..14f32dd6db --- /dev/null +++ b/ext/phar/tests/frontcontroller23.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller with generic action router test +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller23.php +REQUEST_URI=/frontcontroller23.php/hi/there +PATH_INFO=/hi/there +--FILE_EXTERNAL-- +files/frontcontroller14.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(9) "/hi/there" +string(%d) "phar://%sfrontcontroller23.php/html/index.php" \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller24.phpt b/ext/phar/tests/frontcontroller24.phpt new file mode 100644 index 0000000000..dca5a693cd --- /dev/null +++ b/ext/phar/tests/frontcontroller24.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller with custom 404 php script +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller24.php +REQUEST_URI=/frontcontroller24.php/unknown/file +PATH_INFO=/unknown/file +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +My 404 is rawesome \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller25.phpt b/ext/phar/tests/frontcontroller25.phpt new file mode 100644 index 0000000000..4d0475b078 --- /dev/null +++ b/ext/phar/tests/frontcontroller25.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller with extra path_info +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller25.php +REQUEST_URI=/frontcontroller25.php/a1.phps/extra/stuff +PATH_INFO=/a1.phps/extra/stuff +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(42) "/frontcontroller25.php/a1.phps/extra/stuff" +string(12) "/extra/stuff" \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller26.phpt b/ext/phar/tests/frontcontroller26.phpt new file mode 100644 index 0000000000..a8097b0886 --- /dev/null +++ b/ext/phar/tests/frontcontroller26.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller with unknown extension mime type +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller26.php +REQUEST_URI=/frontcontroller26.php/unknown.ext +PATH_INFO=/unknown.ext +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: application/octet-stream +--EXPECTF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller27.php +REQUEST_URI=/frontcontroller27.php/noext +PATH_INFO=/noext +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/plain +--EXPECTF-- +hi \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller28.phpt b/ext/phar/tests/frontcontroller28.phpt new file mode 100644 index 0000000000..59311120b4 --- /dev/null +++ b/ext/phar/tests/frontcontroller28.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller with huge file +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller28.php +REQUEST_URI=/frontcontroller28.php/bigfile.txt +PATH_INFO=/bigfile.txt +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/plain +--EXPECT-- +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/ext/phar/tests/frontcontroller29.phpt b/ext/phar/tests/frontcontroller29.phpt new file mode 100644 index 0000000000..64674b5a28 --- /dev/null +++ b/ext/phar/tests/frontcontroller29.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller with fatal error in php file +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller29.php +REQUEST_URI=/frontcontroller29.php/fatalerror.phps +PATH_INFO=/fatalerror.phps +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps on line 1 \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller3.phpt b/ext/phar/tests/frontcontroller3.phpt new file mode 100644 index 0000000000..1b8093542f --- /dev/null +++ b/ext/phar/tests/frontcontroller3.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller phps +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller3.php +REQUEST_URI=/frontcontroller3.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + diff --git a/ext/phar/tests/frontcontroller30.phpt b/ext/phar/tests/frontcontroller30.phpt new file mode 100644 index 0000000000..de6960c244 --- /dev/null +++ b/ext/phar/tests/frontcontroller30.phpt @@ -0,0 +1,12 @@ +--TEST-- +Phar front controller with weird SCRIPT_NAME +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/huh? +REQUEST_URI=/huh? +--FILE_EXTERNAL-- +files/frontcontroller8.phar +--EXPECTF-- +oops did not run +%a \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller31.phpt b/ext/phar/tests/frontcontroller31.phpt new file mode 100644 index 0000000000..6ec7ca1b6f --- /dev/null +++ b/ext/phar/tests/frontcontroller31.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller with invalid callback for rewrites +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller31.php +REQUEST_URI=/frontcontroller31.php +--EXPECTHEADERS-- +Content-type: text/html +--FILE_EXTERNAL-- +files/frontcontroller16.phar +--EXPECT-- +phar error: invalid rewrite callback \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller32.phpt b/ext/phar/tests/frontcontroller32.phpt new file mode 100644 index 0000000000..da9a4ef256 --- /dev/null +++ b/ext/phar/tests/frontcontroller32.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller with valid callback that is not good +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller32.php +REQUEST_URI=/frontcontroller32.php +--EXPECTHEADERS-- +Content-type: text/html +--FILE_EXTERNAL-- +files/frontcontroller17.phar +--EXPECTF-- +%ahar error: failed to call rewrite callback \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller33.phpt b/ext/phar/tests/frontcontroller33.phpt new file mode 100644 index 0000000000..e1bc2a79fb --- /dev/null +++ b/ext/phar/tests/frontcontroller33.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller with valid callback that does not return any value +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller33.php +REQUEST_URI=/frontcontroller33.php +--EXPECTHEADERS-- +Content-type: text/html +--FILE_EXTERNAL-- +files/frontcontroller18.phar +--EXPECTF-- +phar error: rewrite callback must return a string or false \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller34.phpt b/ext/phar/tests/frontcontroller34.phpt new file mode 100644 index 0000000000..636667032a --- /dev/null +++ b/ext/phar/tests/frontcontroller34.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller with cwd +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller34.php +REQUEST_URI=/frontcontroller34.php/start/index.php +PATH_INFO=/start/index.php +--EXPECTHEADERS-- +Content-type: text/html +--FILE_EXTERNAL-- +files/frontcontroller19.phar +--EXPECT-- +start/index.php +start/another.php +another.php diff --git a/ext/phar/tests/frontcontroller4.phpt b/ext/phar/tests/frontcontroller4.phpt new file mode 100644 index 0000000000..f2482b9219 --- /dev/null +++ b/ext/phar/tests/frontcontroller4.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller index.php relocate (no /) +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller4.php +REQUEST_URI=/frontcontroller4.php +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller4.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/frontcontroller5.phpt b/ext/phar/tests/frontcontroller5.phpt new file mode 100644 index 0000000000..1990a2b008 --- /dev/null +++ b/ext/phar/tests/frontcontroller5.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller index.php relocate +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller5.php +REQUEST_URI=/frontcontroller5.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller5.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/frontcontroller6.phpt b/ext/phar/tests/frontcontroller6.phpt new file mode 100644 index 0000000000..1a2cc2cd23 --- /dev/null +++ b/ext/phar/tests/frontcontroller6.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller 404 +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller6.php +REQUEST_URI=/frontcontroller6.php/notfound.php +PATH_INFO=/notfound.php +--FILE_EXTERNAL-- +files/frontcontroller.phar +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /notfound.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller7.phpt b/ext/phar/tests/frontcontroller7.phpt new file mode 100644 index 0000000000..aff2087522 --- /dev/null +++ b/ext/phar/tests/frontcontroller7.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller alternate index file +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller7.php +REQUEST_URI=/frontcontroller7.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller2.phar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller7.php/a.php +--EXPECT-- diff --git a/ext/phar/tests/frontcontroller8.phpt b/ext/phar/tests/frontcontroller8.phpt new file mode 100644 index 0000000000..36e3206d66 --- /dev/null +++ b/ext/phar/tests/frontcontroller8.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller no index file 404 +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller8.php +REQUEST_URI=/frontcontroller8.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller3.phar +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /index.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/frontcontroller9.phpt b/ext/phar/tests/frontcontroller9.phpt new file mode 100644 index 0000000000..b7af364853 --- /dev/null +++ b/ext/phar/tests/frontcontroller9.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller rewrite array +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller9.php +REQUEST_URI=/frontcontroller9.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller3.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + \ No newline at end of file diff --git a/ext/phar/tests/include_path.phpt b/ext/phar/tests/include_path.phpt new file mode 100644 index 0000000000..5f9462c260 --- /dev/null +++ b/ext/phar/tests/include_path.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: include_path with phar:// wrapper +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- + +===DONE=== +--CLEAN-- + +--EXPECTF-- +file1.php +test/file1.php + +Warning: include(file2.php): failed to open stream: No such file or directory in %sinclude_path.php on line %d + +Warning: include(): Failed opening 'file2.php' for inclusion (include_path='%sphar://%stempmanifest1.phar.php/test') in %sinclude_path.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/ini_set.phpt b/ext/phar/tests/ini_set.phpt new file mode 100644 index 0000000000..588cd4a74b --- /dev/null +++ b/ext/phar/tests/ini_set.phpt @@ -0,0 +1,28 @@ +--TEST-- +Phar: test ini_set with readonly and require_hash enabled +--SKIPIF-- + +--INI-- +phar.require_hash=1 +phar.readonly=1 +--FILE-- + +--EXPECT-- +string(1) "1" +string(1) "1" +string(1) "1" +string(1) "1" +string(1) "1" +string(1) "1" +string(1) "1" +string(1) "1" diff --git a/ext/phar/tests/ini_set_off.phpt b/ext/phar/tests/ini_set_off.phpt new file mode 100644 index 0000000000..7da07c5d8d --- /dev/null +++ b/ext/phar/tests/ini_set_off.phpt @@ -0,0 +1,85 @@ +--TEST-- +Phar: test ini_set with readonly and require_hash disabled +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- + +yes + +on + +true + +0 + +===DONE=== +--EXPECT-- +string(1) "0" +string(1) "0" +string(1) "1" +string(1) "1" +bool(true) +yes +string(1) "0" +string(1) "0" +string(3) "yes" +string(3) "yes" +bool(false) +on +string(1) "0" +string(1) "0" +string(2) "on" +string(2) "on" +bool(false) +true +string(1) "0" +string(1) "0" +bool(false) +string(4) "true" +string(4) "true" +0 +string(4) "true" +string(4) "true" +bool(true) +string(1) "0" +string(1) "0" +===DONE=== diff --git a/ext/phar/tests/invalid_alias.phpt b/ext/phar/tests/invalid_alias.phpt new file mode 100644 index 0000000000..dc0c71ed11 --- /dev/null +++ b/ext/phar/tests/invalid_alias.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: set alias with invalid alias containing / \ : or ; +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +setAlias('hi/'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + $p->setAlias('hi\\l'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + $p->setAlias('hil;'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + $p->setAlias(':hil'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Invalid alias "hi/" specified for phar "%sinvalid_alias.phar" +Invalid alias "hi\l" specified for phar "%sinvalid_alias.phar" +Invalid alias "hil;" specified for phar "%sinvalid_alias.phar" +Invalid alias ":hil" specified for phar "%sinvalid_alias.phar" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/invalid_setstubalias.phpt b/ext/phar/tests/invalid_setstubalias.phpt new file mode 100644 index 0000000000..04cb779ddb --- /dev/null +++ b/ext/phar/tests/invalid_setstubalias.phpt @@ -0,0 +1,47 @@ +--TEST-- +Phar: invalid set alias or stub via array access +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +getMessage() . "\n"; +} +try { + $p['.phar/alias.txt'] = 'hi'; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +$p = new Phar($fname2); +try { + $p['.phar/stub.php'] = 'hi'; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + $p['.phar/alias.txt'] = 'hi'; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Cannot set stub ".phar/stub.php" directly in phar "%sinvalid_setstubalias.phar.tar", use setStub +Cannot set alias ".phar/alias.txt" directly in phar "%sinvalid_setstubalias.phar.tar", use setAlias +Cannot set stub ".phar/stub.php" directly in phar "%sinvalid_setstubalias.phar.zip", use setStub +Cannot set alias ".phar/alias.txt" directly in phar "%sinvalid_setstubalias.phar.zip", use setAlias +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/metadata_read.phpt b/ext/phar/tests/metadata_read.phpt new file mode 100644 index 0000000000..c3d12d6fbd --- /dev/null +++ b/ext/phar/tests/metadata_read.phpt @@ -0,0 +1,61 @@ +--TEST-- +Phar with meta-data (read) +--SKIPIF-- + +--INI-- +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b', 'meta' => 'hi there'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); +include 'files/phar_test.inc'; + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +$phar = new Phar($fname); +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} + +unset($phar); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +NULL +string(8) "hi there" +array(2) { + [0]=> + string(2) "hi" + [1]=> + string(5) "there" +} +array(2) { + ["hi"]=> + string(5) "there" + ["foo"]=> + string(3) "bar" +} +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +===DONE=== diff --git a/ext/phar/tests/metadata_write.phpt b/ext/phar/tests/metadata_write.phpt new file mode 100755 index 0000000000..4b9930b693 --- /dev/null +++ b/ext/phar/tests/metadata_write.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar with meta-data (write) +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +"; + +$files = array(); +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b', 'meta' => 'hi there'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); +include 'files/phar_test.inc'; + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +$phar = new Phar($fname); +$phar['a']->setMetadata(42); +$phar['b']->setMetadata(NULL); +$phar['c']->setMetadata(array(25, 'foo'=>'bar')); +$phar['d']->setMetadata(true); + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} + +unset($phar); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +===DONE=== diff --git a/ext/phar/tests/metadata_write_commit.phpt b/ext/phar/tests/metadata_write_commit.phpt new file mode 100755 index 0000000000..0d0a5e56ad --- /dev/null +++ b/ext/phar/tests/metadata_write_commit.phpt @@ -0,0 +1,79 @@ +--TEST-- +Phar with meta-data (write) +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +"; + +$files = array(); +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b', 'meta' => 'hi there'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); +include 'files/phar_test.inc'; + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +$phar = new Phar($fname); +$phar->startBuffering(); +$phar['a']->setMetadata(42); +$phar['b']->setMetadata(NULL); +$phar['c']->setMetadata(array(25, 'foo'=>'bar')); +$phar['d']->setMetadata(true); + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} +$phar->stopBuffering(); + +unset($phar); + +$phar = new Phar($fname); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/mkdir.phpt b/ext/phar/tests/mkdir.phpt new file mode 100644 index 0000000000..af8bceb32c --- /dev/null +++ b/ext/phar/tests/mkdir.phpt @@ -0,0 +1,41 @@ +--TEST-- +phar: mkdir/rmdir edge cases +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +addEmptyDir('bb'); +$a->addEmptyDir('bb'); +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: mkdir(): phar error: cannot create directory "phar://", no phar archive specified in %smkdir.php on line %d + +Warning: mkdir(): phar error: cannot create directory "" in phar "foo.phar", phar error: invalid path "" must not be empty in %smkdir.php on line %d + +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, 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 + +Warning: rmdir(): phar error: cannot remove directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/mounteddir.phpt b/ext/phar/tests/mounteddir.phpt new file mode 100644 index 0000000000..c438eefb1d --- /dev/null +++ b/ext/phar/tests/mounteddir.phpt @@ -0,0 +1,109 @@ +--TEST-- +Phar: mounted manifest directory test +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +'; +$a['testit/existing.txt'] = 'oops'; +$a->setStub(''); +file_put_contents(dirname(__FILE__) . '/testit/extfile2.php', ''); +include dirname(__FILE__) . '/testit/extfile.php'; +include $fname; + +$a = opendir($pname . '/testit'); +$out = array(); +while (false !== ($b = readdir($a))) { + $out[] = $b; +} +sort($out); +foreach ($out as $b) { + echo "$b\n"; +} +$out = array(); +foreach (new Phar($pname . '/testit') as $b) { + $out[] = $b->getPathName(); +} +sort($out); +foreach ($out as $b) { + echo "$b\n"; +} +try { +Phar::mount($pname . '/testit', 'another\\..\\mistake'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +Phar::mount($pname . '/notfound', dirname(__FILE__) . '/this/does/not/exist'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +Phar::mount($pname . '/testit', dirname(__FILE__)); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +Phar::mount($pname . '/testit/extfile.php', dirname(__FILE__)); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(%d) "%sextfile.php" + + +Warning: file_get_contents(phar://%stempmanifest1.phar.php/testit/directory): failed to open stream: phar error: path "testit/directory" is a directory in phar://%stempmanifest1.phar.php/index.php on line %d + +oops +string(%d) "phar://%sextfile.php" +string(%d) "phar://%sextfile2.php" +. +.. +directory +extfile.php +extfile2.php +phar://%stempmanifest1.phar.php/testit%cdirectory +phar://%stempmanifest1.phar.php/testit%cextfile.php +phar://%stempmanifest1.phar.php/testit%cextfile2.php +Mounting of /testit to another\..\mistake within phar %stempmanifest1.phar.php failed +Mounting of /notfound to %stests/this/does/not/exist within phar %stempmanifest1.phar.php failed +Mounting of /testit to %stests within phar %stests/tempmanifest1.phar.php failed +Mounting of /testit/extfile.php to %stests within phar %stests/tempmanifest1.phar.php failed +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/nophar.phpt b/ext/phar/tests/nophar.phpt new file mode 100644 index 0000000000..d97df8af2e --- /dev/null +++ b/ext/phar/tests/nophar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar: phar run without pecl/phar with default stub +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECT-- +in b + +--ENV-- +SCRIPT_NAME=/nophar.phar +REQUEST_URI=/nophar.phar +--FILE_EXTERNAL-- +files/nophar.phar +--EXPECT-- +web diff --git a/ext/phar/tests/open_for_write_existing.phpt b/ext/phar/tests/open_for_write_existing.phpt new file mode 100644 index 0000000000..2a3ec8b824 --- /dev/null +++ b/ext/phar/tests/open_for_write_existing.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +$fp = fopen($pname . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- +extra +===DONE=== diff --git a/ext/phar/tests/open_for_write_existing_b.phpt b/ext/phar/tests/open_for_write_existing_b.phpt new file mode 100755 index 0000000000..6c3cd3e986 --- /dev/null +++ b/ext/phar/tests/open_for_write_existing_b.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) +--SKIPIF-- + +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($pname . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_b.phar.php/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d +This is b/c +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/open_for_write_existing_c.phpt b/ext/phar/tests/open_for_write_existing_c.phpt new file mode 100755 index 0000000000..9bbaaae92a --- /dev/null +++ b/ext/phar/tests/open_for_write_existing_c.phpt @@ -0,0 +1,36 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) +--SKIPIF-- + +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +$fp = fopen($pname . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_c.phar.php/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d +This is b/c +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/open_for_write_newfile.phpt b/ext/phar/tests/open_for_write_newfile.phpt new file mode 100644 index 0000000000..13114072da --- /dev/null +++ b/ext/phar/tests/open_for_write_newfile.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +$fp = fopen($pname . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +include $pname . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECT-- +This is b/c +extra +===DONE=== diff --git a/ext/phar/tests/open_for_write_newfile_b.phpt b/ext/phar/tests/open_for_write_newfile_b.phpt new file mode 100755 index 0000000000..1c136ff1d5 --- /dev/null +++ b/ext/phar/tests/open_for_write_newfile_b.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) +--SKIPIF-- + +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($pname . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +include $pname . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_b.phar.php/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line 20 +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_b.phar.php/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.php" in %sopen_for_write_newfile_b.php on line 22 + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.php/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/open_for_write_newfile_c.phpt b/ext/phar/tests/open_for_write_newfile_c.phpt new file mode 100755 index 0000000000..59b4339eb9 --- /dev/null +++ b/ext/phar/tests/open_for_write_newfile_c.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) +--SKIPIF-- + +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +include 'files/phar_test.inc'; + +$fp = fopen($pname . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $pname . '/b/c.php'; +include $pname . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_c.phar.php/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_c.phar.php/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.php" in %sopen_for_write_newfile_c.php on line %d + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.php/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d + +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/opendir.phpt b/ext/phar/tests/opendir.phpt new file mode 100644 index 0000000000..46ab7c9682 --- /dev/null +++ b/ext/phar/tests/opendir.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: test opendir() interception +--SKIPIF-- + +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub(' +===DONE=== +--CLEAN-- + +--EXPECTF-- +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 error: invalid url or non-existent phar "phar://hi.phar" +phar url "phar://hi.phar" is unknown in %sopendir.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/opendir_edgecases.phpt b/ext/phar/tests/opendir_edgecases.phpt new file mode 100644 index 0000000000..d330d27ff3 --- /dev/null +++ b/ext/phar/tests/opendir_edgecases.phpt @@ -0,0 +1,46 @@ +--TEST-- +Phar: test edge cases of opendir() function interception +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +'); +include $pname . '/foo'; +?> +===DONE=== +--CLEAN-- + + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +getStub()); +var_dump($p->isBuffering()); +$p->startBuffering(); +var_dump($p->isBuffering()); +$p['a.php'] = 'setStub(''); +include 'phar://brandnewphar.phar/a.php'; +var_dump($p->getStub()); +$p['b.php'] = 'setStub('getStub()); +$p->stopBuffering(); +echo "===COMMIT===\n"; +var_dump($p->isBuffering()); +include 'phar://brandnewphar.phar/a.php'; +include 'phar://brandnewphar.phar/b.php'; +var_dump($p->getStub()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(false) +string(5) "Hello" +string(84) " +" +string(5) "World" +string(85) " +" +===COMMIT=== +bool(true) +string(5) "Hello" +string(5) "World" +string(85) " +" +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory1.phpt b/ext/phar/tests/phar_buildfromdirectory1.phpt new file mode 100644 index 0000000000..505b15036f --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory1.phpt @@ -0,0 +1,28 @@ +--TEST-- +Phar::buildFromDirectory() - readonly +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory(1); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(24) "UnexpectedValueException" +Cannot write to archive - write operations restricted by INI setting +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory2.phpt b/ext/phar/tests/phar_buildfromdirectory2.phpt new file mode 100644 index 0000000000..fcad4725a7 --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory2.phpt @@ -0,0 +1,27 @@ +--TEST-- +Phar::buildFromDirectory() - non-directory passed as first parameter +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory(1); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(24) "UnexpectedValueException" +RecursiveDirectoryIterator::__construct(1): failed to open dir: No such file or directory +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory3.phpt b/ext/phar/tests/phar_buildfromdirectory3.phpt new file mode 100644 index 0000000000..435bbdfba6 --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory3.phpt @@ -0,0 +1,27 @@ +--TEST-- +Phar::buildFromDirectory() - object passed as second parameter +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory('files', new stdClass); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: Phar::buildFromDirectory() expects parameter 2 to be string, object given in %sphar_buildfromdirectory3.php on line %d +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory4.phpt b/ext/phar/tests/phar_buildfromdirectory4.phpt new file mode 100644 index 0000000000..cf11d62af6 --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory4.phpt @@ -0,0 +1,50 @@ +--TEST-- +Phar::buildFromDirectory(), directory exists +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory(dirname(__FILE__) . '/testdir'); + asort($a); + var_dump($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} + +var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar')); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(4) { + ["file1.txt"]=> + string(%d) "%stestdir%cfile1.txt" + ["file2.txt"]=> + string(%d) "%stestdir%cfile2.txt" + ["file3.txt"]=> + string(%d) "%stestdir%cfile3.txt" + ["file4.txt"]=> + string(%d) "%stestdir%cfile4.txt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory5.phpt b/ext/phar/tests/phar_buildfromdirectory5.phpt new file mode 100644 index 0000000000..51e5cec691 --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory5.phpt @@ -0,0 +1,50 @@ +--TEST-- +Phar::buildFromDirectory() with matching regex +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory(dirname(__FILE__) . '/testdir', '/\.txt/'); + asort($a); + var_dump($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} + +var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar')); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(4) { + ["file1.txt"]=> + string(%d) "%stestdir%cfile1.txt" + ["file2.txt"]=> + string(%d) "%stestdir%cfile2.txt" + ["file3.txt"]=> + string(%d) "%stestdir%cfile3.txt" + ["file4.txt"]=> + string(%d) "%stestdir%cfile4.txt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_buildfromdirectory6.phpt b/ext/phar/tests/phar_buildfromdirectory6.phpt new file mode 100644 index 0000000000..2edd0962f1 --- /dev/null +++ b/ext/phar/tests/phar_buildfromdirectory6.phpt @@ -0,0 +1,40 @@ +--TEST-- +Phar::buildFromDirectory() with non-matching regex +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromDirectory(dirname(__FILE__) . '/testdir', '/\.php/')); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} + +var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar')); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +array(0) { +} +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator1.phpt b/ext/phar/tests/phar_buildfromiterator1.phpt new file mode 100644 index 0000000000..f75823f94c --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator1.phpt @@ -0,0 +1,28 @@ +--TEST-- +Phar::buildFromIterator() readonly +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromIterator(1); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(24) "UnexpectedValueException" +Cannot write out phar archive, phar is read-only +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator10.phpt b/ext/phar/tests/phar_buildfromiterator10.phpt new file mode 100644 index 0000000000..3f03245727 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator10.phpt @@ -0,0 +1,98 @@ +--TEST-- +Phar::buildFromIterator() RegexIterator(RecursiveIteratorIterator), SplFileInfo as current +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromIterator(new RegexIterator($iter, '/_\d{3}\.phpt$/'), dirname(__FILE__) . DIRECTORY_SEPARATOR); + asort($a); + var_dump($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(33) { + ["phar_ctx_001.phpt"]=> + string(%d) "%sphar_ctx_001.phpt" + ["phar_get_supported_signatures_001.phpt"]=> + string(%d) "%sphar_get_supported_signatures_001.phpt" + ["phar_get_supported_signatures_002.phpt"]=> + string(%d) "%sphar_get_supported_signatures_002.phpt" + ["phar_oo_001.phpt"]=> + string(%d) "%sphar_oo_001.phpt" + ["phar_oo_002.phpt"]=> + string(%d) "%sphar_oo_002.phpt" + ["phar_oo_003.phpt"]=> + string(%d) "%sphar_oo_003.phpt" + ["phar_oo_004.phpt"]=> + string(%d) "%sphar_oo_004.phpt" + ["phar_oo_005.phpt"]=> + string(%d) "%sphar_oo_005.phpt" + ["phar_oo_006.phpt"]=> + string(%d) "%sphar_oo_006.phpt" + ["phar_oo_007.phpt"]=> + string(%d) "%sphar_oo_007.phpt" + ["phar_oo_008.phpt"]=> + string(%d) "%sphar_oo_008.phpt" + ["phar_oo_009.phpt"]=> + string(%d) "%sphar_oo_009.phpt" + ["phar_oo_010.phpt"]=> + string(%d) "%sphar_oo_010.phpt" + ["phar_oo_011.phpt"]=> + string(%d) "%sphar_oo_011.phpt" + ["phar_oo_012.phpt"]=> + string(%d) "%sphar_oo_012.phpt" + ["phar_oo_compressed_001.phpt"]=> + string(%d) "%sphar_oo_compressed_001.phpt" + ["phar_oo_compressed_002.phpt"]=> + string(%d) "%sphar_oo_compressed_002.phpt" + ["phpinfo_001.phpt"]=> + string(%d) "%sphpinfo_001.phpt" + ["phpinfo_002.phpt"]=> + string(%d) "%sphpinfo_002.phpt" + ["phpinfo_003.phpt"]=> + string(%d) "%sphpinfo_003.phpt" + ["phpinfo_004.phpt"]=> + string(%d) "%sphpinfo_004.phpt" + ["tar/tar_001.phpt"]=> + string(%d) "%star%ctar_001.phpt" + ["tar/tar_002.phpt"]=> + string(%d) "%star%ctar_002.phpt" + ["tar/tar_003.phpt"]=> + string(%d) "%star%ctar_003.phpt" + ["tar/tar_004.phpt"]=> + string(%d) "%star%ctar_004.phpt" + ["zip/corrupt_001.phpt"]=> + string(%d) "%szip%ccorrupt_001.phpt" + ["zip/corrupt_002.phpt"]=> + string(%d) "%szip%ccorrupt_002.phpt" + ["zip/corrupt_003.phpt"]=> + string(%d) "%szip%ccorrupt_003.phpt" + ["zip/corrupt_004.phpt"]=> + string(%d) "%szip%ccorrupt_004.phpt" + ["zip/corrupt_005.phpt"]=> + string(%d) "%szip%ccorrupt_005.phpt" + ["zip/corrupt_006.phpt"]=> + string(%d) "%szip%ccorrupt_006.phpt" + ["zip/corrupt_007.phpt"]=> + string(%d) "%szip%ccorrupt_007.phpt" + ["zip/corrupt_008.phpt"]=> + string(%d) "%szip%ccorrupt_008.phpt" +} +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator2.phpt b/ext/phar/tests/phar_buildfromiterator2.phpt new file mode 100644 index 0000000000..cdc2df1050 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator2.phpt @@ -0,0 +1,26 @@ +--TEST-- +Phar::buildFromIterator() wrong object +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromIterator(new stdClass); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: Phar::buildFromIterator() expects parameter 1 to be Traversable, object given in %sphar_buildfromiterator2.php on line %d +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator3.phpt b/ext/phar/tests/phar_buildfromiterator3.phpt new file mode 100644 index 0000000000..5fca706041 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator3.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar::buildFromIterator() iterator, but object passed +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + $phar->buildFromIterator(new myIterator(array()), new stdClass); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: Phar::buildFromIterator() expects parameter 2 to be string, object given in %sphar_buildfromiterator3.php on line %d +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator4.phpt b/ext/phar/tests/phar_buildfromiterator4.phpt new file mode 100644 index 0000000000..3c20460d53 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator4.phpt @@ -0,0 +1,64 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file passed in +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "%sphar_buildfromiterator4.phpt" +} +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator5.phpt b/ext/phar/tests/phar_buildfromiterator5.phpt new file mode 100644 index 0000000000..3bd2cec78c --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator5.phpt @@ -0,0 +1,59 @@ +--TEST-- +Phar::buildFromIterator() iterator, iterator returns non-string +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass)))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid value (must return a string) +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator6.phpt b/ext/phar/tests/phar_buildfromiterator6.phpt new file mode 100644 index 0000000000..ae73bbd479 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator6.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, key is int +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid key (must return a string) +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator7.phpt b/ext/phar/tests/phar_buildfromiterator7.phpt new file mode 100644 index 0000000000..38d2e1a5f2 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator7.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, file can't be opened +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt" +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator8.phpt b/ext/phar/tests/phar_buildfromiterator8.phpt new file mode 100644 index 0000000000..d382b82ee0 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator8.phpt @@ -0,0 +1,96 @@ +--TEST-- +Phar::buildFromIterator() RegexIterator(DirectoryIterator), SplFileInfo as current +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^\d{0,3}\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR); + asort($a); + var_dump($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(33) { + ["001.phpt"]=> + string(%d) "%s001.phpt" + ["002.phpt"]=> + string(%d) "%s002.phpt" + ["003.phpt"]=> + string(%d) "%s003.phpt" + ["004.phpt"]=> + string(%d) "%s004.phpt" + ["005.phpt"]=> + string(%d) "%s005.phpt" + ["006.phpt"]=> + string(%d) "%s006.phpt" + ["007.phpt"]=> + string(%d) "%s007.phpt" + ["008.phpt"]=> + string(%d) "%s008.phpt" + ["009.phpt"]=> + string(%d) "%s009.phpt" + ["010.phpt"]=> + string(%d) "%s010.phpt" + ["011.phpt"]=> + string(%d) "%s011.phpt" + ["012.phpt"]=> + string(%d) "%s012.phpt" + ["013.phpt"]=> + string(%d) "%s013.phpt" + ["014.phpt"]=> + string(%d) "%s014.phpt" + ["015.phpt"]=> + string(%d) "%s015.phpt" + ["016.phpt"]=> + string(%d) "%s016.phpt" + ["017.phpt"]=> + string(%d) "%s017.phpt" + ["018.phpt"]=> + string(%d) "%s018.phpt" + ["019.phpt"]=> + string(%d) "%s019.phpt" + ["020.phpt"]=> + string(%d) "%s020.phpt" + ["021.phpt"]=> + string(%d) "%s021.phpt" + ["022.phpt"]=> + string(%d) "%s022.phpt" + ["023.phpt"]=> + string(%d) "%s023.phpt" + ["024.phpt"]=> + string(%d) "%s024.phpt" + ["025.phpt"]=> + string(%d) "%s025.phpt" + ["026.phpt"]=> + string(%d) "%s026.phpt" + ["027.phpt"]=> + string(%d) "%s027.phpt" + ["028.phpt"]=> + string(%d) "%s028.phpt" + ["029.phpt"]=> + string(%d) "%s029.phpt" + ["030.phpt"]=> + string(%d) "%s030.phpt" + ["031.phpt"]=> + string(%d) "%s031.phpt" + ["032.phpt"]=> + string(%d) "%s032.phpt" + ["033.phpt"]=> + string(%d) "%s033.phpt" +} +===DONE=== diff --git a/ext/phar/tests/phar_buildfromiterator9.phpt b/ext/phar/tests/phar_buildfromiterator9.phpt new file mode 100644 index 0000000000..0b56307545 --- /dev/null +++ b/ext/phar/tests/phar_buildfromiterator9.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file resource passed in +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r'))))); + fclose($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "[stream]" +} +===DONE=== diff --git a/ext/phar/tests/phar_bz2.phpt b/ext/phar/tests/phar_bz2.phpt new file mode 100644 index 0000000000..71b10f9092 --- /dev/null +++ b/ext/phar/tests/phar_bz2.phpt @@ -0,0 +1,63 @@ +--TEST-- +Phar: bzipped phar +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setAlias('another'); +$b = new Phar($fname2); +var_dump($b->isFileFormat(Phar::PHAR)); +var_dump($b->isCompressed() == Phar::BZ2); +// additional code coverage +$b->isFileFormat(array()); +try { +$b->isFileFormat(25); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(9) "it worked" +string(%d) "phar://%sphar_bz2.phar/tar_004.php" +bool(true) +bool(true) + +Warning: Phar::isFileFormat() expects parameter 1 to be long, array given in %sphar_bz2.php on line %d +Unknown file format specified +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_commitwrite.phpt b/ext/phar/tests/phar_commitwrite.phpt new file mode 100644 index 0000000000..63878355b0 --- /dev/null +++ b/ext/phar/tests/phar_commitwrite.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar::setStub()/stopBuffering() +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump(strlen($p->getStub())); +$p->setStub(""); +var_dump($p->getStub()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +int(6651) +string(200) " +" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_convert_again.phpt b/ext/phar/tests/phar_convert_again.phpt new file mode 100644 index 0000000000..4543a238d5 --- /dev/null +++ b/ext/phar/tests/phar_convert_again.phpt @@ -0,0 +1,218 @@ +--TEST-- +Phar::conversion to other formats +--SKIPIF-- + + + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +$zip = $phar->convertToData(Phar::ZIP); +echo $zip->getPath() . "\n"; +$tgz = $phar->convertToData(Phar::TAR, Phar::GZ); +echo $tgz->getPath() . "\n"; +$tbz = $phar->convertToData(Phar::TAR, Phar::BZ2); +echo $tbz->getPath() . "\n"; +try { +$phar = $tbz->convertToExecutable(Phar::PHAR, Phar::NONE); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +copy($tbz->getPath(), $fname2); +$tbz = new PharData($fname2); +$phar = $tbz->convertToExecutable(Phar::PHAR, Phar::NONE); +echo $phar->getPath() . "\n"; +$phar['a'] = 'hi'; +$phar['a']->setMetadata('hi'); +$zip = $phar->convertToExecutable(Phar::ZIP); +echo $zip->getPath() . "\n"; +echo $zip['a']->getMetadata() . "\n"; +$data = $zip->convertToData(); +echo $data->getPath() . "\n"; +// extra code coverage +try { +$data->setStub('hi'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setDefaultStub(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setAlias('hi'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setSignatureAlgorithm(Phar::MD5); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$tar = $phar->convertToExecutable(Phar::TAR); +echo $tar->getPath() . "\n"; +$data = $tar->convertToData(); +echo $data->getPath() . "\n"; +$tgz = $tar->convertToExecutable(null, Phar::GZ); +echo $tgz->getPath() . "\n"; +try { +$tgz->convertToExecutable(25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToExecutable(Phar::ZIP, Phar::GZ); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToExecutable(Phar::ZIP, Phar::BZ2); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$phar->convertToData(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToData(Phar::PHAR); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToData(25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToData(Phar::ZIP, Phar::GZ); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToData(Phar::ZIP, Phar::BZ2); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToExecutable(Phar::TAR, 25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$tgz->convertToData(Phar::TAR, 25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +// extra code coverage +try { +$data->setStub('hi'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setAlias('hi'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setDefaultStub(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$data->setSignatureAlgorithm(Phar::MD5); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +try { +$tgz->convertToData(Phar::TAR, Phar::GZ, '.phar.tgz.oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +try { +$phar->convertToExecutable(Phar::TAR, Phar::GZ, '.tgz.oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +try { +$tgz->convertToData(Phar::TAR, Phar::GZ, '.phar/.tgz.oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +%sphar_convert_again.zip +%sphar_convert_again.tar.gz +%sphar_convert_again.tar.bz2 +Unable to add newly converted phar "%sphar_convert_again.phar" to the list of phars, a phar with that name already exists +%sphar_convert_again2.phar +%sphar_convert_again2.phar.zip +hi +%sphar_convert_again2.zip +A Phar stub cannot be set in a plain zip archive +A Phar stub cannot be set in a plain zip archive +A Phar alias cannot be set in a plain zip archive +Cannot set signature algorithm, not possible with zip-based phar archives +%sphar_convert_again2.phar.tar +%sphar_convert_again2.tar +%sphar_convert_again2.phar.tar.gz +Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP +Cannot compress entire archive with gzip, zip archives do not support whole-archive compression +Cannot compress entire archive with bz2, zip archives do not support whole-archive compression +Cannot write out data phar archive, use Phar::TAR or Phar::ZIP +Cannot write out data phar archive, use Phar::TAR or Phar::ZIP +Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP +Cannot compress entire archive with gzip, zip archives do not support whole-archive compression +Cannot compress entire archive with bz2, zip archives do not support whole-archive compression +Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2 +Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2 +A Phar stub cannot be set in a plain tar archive +A Phar alias cannot be set in a plain tar archive +A Phar stub cannot be set in a plain tar archive +Cannot set signature algorithm, not possible with tar-based phar archives +data phar "%sphar_convert_again2.phar.tgz.oops" has invalid extension phar.tgz.oops +phar "%sphar_convert_again2.tgz.oops" has invalid extension tgz.oops +data phar "%sphar_convert_again2.phar/.tgz.oops" has invalid extension phar/.tgz.oops +===DONE=== diff --git a/ext/phar/tests/phar_convert_repeated.phpt b/ext/phar/tests/phar_convert_repeated.phpt new file mode 100644 index 0000000000..b2ef195ea7 --- /dev/null +++ b/ext/phar/tests/phar_convert_repeated.phpt @@ -0,0 +1,149 @@ +--TEST-- +Phar::convertToZip|Tar|Phar() repeated (phar_based archives) +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +echo "=================== new Phar() =======================\n"; +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToTar() =====================\n"; + +$phar = $phar->convertToExecutable(Phar::TAR); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToZip() =====================\n"; + +$phar = $phar->convertToExecutable(Phar::ZIP); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToPhar() ====================\n"; + +$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.2.phar'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump(strlen($phar->getStub())); +var_dump($phar->getAlias()); + +echo "================= convertToZip() =====================\n"; + +$phar = $phar->convertToExecutable(Phar::ZIP, Phar::NONE, '.2.phar.zip'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToTar() =====================\n"; + +$phar = $phar->convertToExecutable(Phar::TAR, Phar::NONE, '2.phar.tar'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToZip() =====================\n"; + +$phar = $phar->convertToExecutable(Phar::ZIP, Phar::NONE, '3.phar.zip'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +=================== new Phar() ======================= +bool(true) +bool(false) +bool(false) +string(48) "" +string(3) "hio" +================= convertToTar() ===================== +bool(false) +bool(true) +bool(false) +string(60) " +--INI-- +phar.readonly=1 +--FILE-- +isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToTar() =====================\n"; + +$phar = $phar->convertToData(Phar::TAR); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToZip() =====================\n"; + +$phar = $phar->convertToData(Phar::ZIP, Phar::NONE, '.1.zip'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToPhar() ====================\n"; + +try { + $phar = $phar->convertToExecutable(Phar::PHAR); + var_dump($phar->isFileFormat(Phar::PHAR)); + var_dump($phar->isFileFormat(Phar::TAR)); + var_dump($phar->isFileFormat(Phar::ZIP)); + var_dump(strlen($phar->getStub())); + var_dump($phar->getAlias()); +} catch(Exception $e) { + echo $e->getMessage()."\n"; +} + +echo "================ convertToTar(GZ) ====================\n"; + +$phar = $phar->convertToData(Phar::TAR, Phar::GZ, '.2.tar'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); + +echo "================= convertToPhar() ====================\n"; + +try { + $phar = $phar->convertToExecutable(Phar::PHAR); + var_dump($phar->isFileFormat(Phar::PHAR)); + var_dump($phar->isFileFormat(Phar::TAR)); + var_dump($phar->isFileFormat(Phar::ZIP)); + var_dump(strlen($phar->getStub())); + var_dump($phar->getAlias()); +} catch(Exception $e) { + echo $e->getMessage()."\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +=================== new PharData() ================== +bool(false) +bool(false) +bool(true) +string(0) "" +NULL +================= convertToTar() ===================== +bool(false) +bool(true) +bool(false) +string(0) "" +NULL +================= convertToZip() ===================== +bool(false) +bool(false) +bool(true) +string(0) "" +NULL +================= convertToPhar() ==================== +Cannot write out executable phar archive, phar is read-only +================ convertToTar(GZ) ==================== +bool(false) +bool(true) +bool(false) +string(0) "" +NULL +================= convertToPhar() ==================== +Cannot write out executable phar archive, phar is read-only +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_convert_tar.phpt b/ext/phar/tests/phar_convert_tar.phpt new file mode 100644 index 0000000000..d4031ec32f --- /dev/null +++ b/ext/phar/tests/phar_convert_tar.phpt @@ -0,0 +1,57 @@ +--TEST-- +Phar::convertToTar() +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +$phar = $phar->convertToExecutable(Phar::TAR); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +copy($fname2, $fname3); + +$phar = new Phar($fname3); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +string(48) "" +bool(true) +string(60) " + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed()); +var_dump($phar->getStub()); + +$phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed()); +var_dump($phar->getStub()); + +copy($fname2, $fname3); + +$phar = new Phar($fname3); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed() == Phar::GZ); +var_dump($phar->getStub()); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +bool(false) +string(48) "" +bool(true) +int(4096) +string(60) " + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed()); +var_dump($phar->getStub()); + +$phar = $phar->convertToExecutable(Phar::TAR, Phar::BZ2); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed()); +var_dump($phar->getStub()); + +copy($fname2 . '.bz2', $fname3); + +$phar = new Phar($fname3); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->isCompressed() == Phar::BZ2); +var_dump($phar->getStub()); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +bool(false) +string(48) "" +bool(true) +int(8192) +string(60) " +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); + +$phar = $phar->convertToExecutable(Phar::ZIP); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); + +copy($fname2, $fname3); + +$phar = new Phar($fname3); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +string(48) "" +bool(true) +string(60) " + + +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +startBuffering(); + $p->copy('a', 'b'); + echo file_get_contents($p['b']->getPathName()); + $p['a']->compress(Phar::GZ); + $p['b']->setMetadata('a'); + $p->copy('b', 'c'); + $p->stopBuffering(); + echo file_get_contents($p['c']->getPathName()); + copy($fname, $fname2); + $p->copy('a', $ename); +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly',1); +$p2 = new Phar($fname2); +echo "\n"; +echo 'a: ' , file_get_contents($p2['a']->getPathName()); +echo 'b: ' ,file_get_contents($p2['b']->getPathName()); +echo 'c: ' ,file_get_contents($p2['c']->getPathName()), $p2['c']->getMetaData(), "\n"; +ini_set('phar.readonly', 0); +try { +$p2->copy('notexisting', 'another'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$p2->copy('a', 'b'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$p2['a']->compress(Phar::GZ); +$p2->copy('a', 'd'); +echo $p2['d']->getContent() . "\n"; +?> +===DONE=== +--CLEAN-- + + +--EXPECTF-- +hihifile "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s + +a: hib: hic: hia +file "notexisting" cannot be copied to file "another", file does not exist in %sphar_copy2.phar.php +file "a" cannot be copied to file "b", file must not already exist in phar %sphar_copy2.phar.php +hi +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_create_in_cwd.phpt b/ext/phar/tests/phar_create_in_cwd.phpt new file mode 100644 index 0000000000..83de7bed28 --- /dev/null +++ b/ext/phar/tests/phar_create_in_cwd.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: attempt to create a Phar with relative path +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +getStub())); + $p->setStub(""); + var_dump($p->getStub()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +int(6651) +string(200) " +" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_createdefaultstub.phpt b/ext/phar/tests/phar_createdefaultstub.phpt new file mode 100644 index 0000000000..a8648dc311 --- /dev/null +++ b/ext/phar/tests/phar_createdefaultstub.phpt @@ -0,0 +1,929 @@ +--TEST-- +Phar: Phar::createDefaultStub() with and without arg +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +echo "============================================================================\n"; +echo "============================================================================\n"; +echo "============================================================================\n"; +echo "============================================================================\n"; +try { +var_dump(Phar::createDefaultStub('my/custom/thingy.php', 'the/web.php')); +echo "============================================================================\n"; +echo "============================================================================\n"; +var_dump(strlen(Phar::createDefaultStub('index.php', str_repeat('a', 400)))); +var_dump(Phar::createDefaultStub('hio', str_repeat('a', 401))); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECT-- +string(6651) " 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "\n \n File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'index.php'; +const LEN = 6653; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?>" +============================================================================ +============================================================================ +string(6662) "<?php + +$web = 'index.php'; + +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} + +if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'my/custom/thingy.php'; +const LEN = 6664; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?>" +============================================================================ +============================================================================ +int(7042) +============================================================================ +============================================================================ +Illegal filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed +============================================================================ +============================================================================ +============================================================================ +============================================================================ +string(6664) "<?php + +$web = 'the/web.php'; + +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} + +if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'my/custom/thingy.php'; +const LEN = 6666; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?>" +============================================================================ +============================================================================ +int(7042) +Illegal web filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed +===DONE=== diff --git a/ext/phar/tests/phar_ctx_001.phpt b/ext/phar/tests/phar_ctx_001.phpt new file mode 100644 index 0000000000..13b4d6a781 --- /dev/null +++ b/ext/phar/tests/phar_ctx_001.phpt @@ -0,0 +1,100 @@ +--TEST-- +Phar context +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$context = stream_context_create(array('phar'=> array('compress'=>Phar::GZ, 'metadata' => array(2, 'hi' => 3)))); +$context2 = stream_context_create(array('phar' => array('metadata' => array(4)))); + +file_put_contents($pname . '/a', 'new a', 0); // no compression +file_put_contents($pname . '/b', 'new b', 0, $context); +file_put_contents($pname . '/d', 'new d', 0, $context2); + +$phar = new Phar($fname); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump($phar['a']->getMetaData()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump($phar['b']->getMetaData()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); +var_dump($phar['c']->getMetaData()); +var_dump(file_get_contents($pname . '/d')); +var_dump($phar['d']->isCompressed()); +var_dump($phar['d']->getMetaData()); +$context2 = stream_context_create(array('phar' => array('metadata' => array(4)))); +$fp = fopen($pname . '/b', 'r+', 0, $context2); +fclose($fp); +?> +==AFTER== +<?php +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump($phar['b']->getMetaData()); +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECT-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(5) "new a" +bool(false) +NULL +string(5) "new b" +bool(true) +array(2) { + [0]=> + int(2) + ["hi"]=> + int(3) +} +string(1) "c" +bool(false) +NULL +string(5) "new d" +bool(false) +array(1) { + [0]=> + int(4) +} +==AFTER== +string(5) "new b" +bool(true) +array(1) { + [0]=> + int(4) +} +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_decompress.phpt b/ext/phar/tests/phar_decompress.phpt new file mode 100644 index 0000000000..ae199eb03b --- /dev/null +++ b/ext/phar/tests/phar_decompress.phpt @@ -0,0 +1,69 @@ +--TEST-- +Phar::decompress() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.gz'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +$gz = $phar->compress(Phar::GZ); +copy($gz->getPath(), $fname2); +$a = new Phar($fname2); +var_dump($a->isCompressed()); +$unc = $a->compress(Phar::NONE); +echo $unc->getPath() . "\n"; +$unc2 = $gz->decompress(); +echo $unc2->getPath() . "\n"; +$unc3 = $gz->decompress('hooba.phar'); +echo $unc3->getPath() . "\n"; +$gz->decompress(array()); +$zip = $phar->convertToData(Phar::ZIP); +ini_set('phar.readonly', 1); +try { +$gz->decompress(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$zip->decompress(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.zip'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.hooba.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.gz'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.gz'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar'); +?> +--EXPECTF-- +int(4096) +%sphar_decompress2.phar +%sphar_decompress.phar +%sphar_decompress.hooba.phar + +Warning: Phar::decompress() expects parameter 1 to be string, array given in %sphar_decompress.php on line %d +Cannot decompress phar archive, phar is read-only +Cannot decompress zip-based archives with whole-archive compression +===DONE=== diff --git a/ext/phar/tests/phar_dir_iterate.phpt b/ext/phar/tests/phar_dir_iterate.phpt new file mode 100644 index 0000000000..2ee2cb5529 --- /dev/null +++ b/ext/phar/tests/phar_dir_iterate.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar object: iterate test with sub-directories and RecursiveIteratorIterator +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; + +$phar = new Phar($fname); +$phar['top.txt'] = 'hi'; +$phar['sub/top.txt'] = 'there'; +$phar['another.file.txt'] = 'wowee'; +$newphar = new Phar($fname); +foreach (new RecursiveIteratorIterator($newphar) as $path => $obj) { + var_dump($obj->getPathName()); +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +string(%d) "phar://%sphar_dir_iterate.phar.php%canother.file.txt" +string(%d) "phar://%sphar_dir_iterate.phar.php%csub%ctop.txt" +string(%d) "phar://%sphar_dir_iterate.phar.php%ctop.txt" +===DONE=== diff --git a/ext/phar/tests/phar_extract.phpt b/ext/phar/tests/phar_extract.phpt new file mode 100644 index 0000000000..82e5f8d191 --- /dev/null +++ b/ext/phar/tests/phar_extract.phpt @@ -0,0 +1,131 @@ +--TEST-- +Phar: Phar::extractTo() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/tempmanifest1.phar.php'; +$pname = 'phar://' . $fname; + +$a = new Phar($fname); +$a['file1.txt'] = 'hi'; +$a['file2.txt'] = 'hi2'; +$a['subdir/ectory/file.txt'] = 'hi3'; +$a->mount($pname . '/mount', __FILE__); +$a->addEmptyDir('one/level'); + +$a->extractTo(dirname(__FILE__) . '/extract', 'mount'); +$a->extractTo(dirname(__FILE__) . '/extract'); +$out = array(); +foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(dirname(__FILE__) . '/extract'), RecursiveIteratorIterator::CHILD_FIRST) as $p => $b) { + $out[] = $p; +} +sort($out); +foreach ($out as $b) { +echo "$b\n"; +} + +$a->extractTo(dirname(__FILE__) . '/extract1', 'file1.txt'); +var_dump(file_get_contents(dirname(__FILE__) . '/extract1/file1.txt')); +$a->extractTo(dirname(__FILE__) . '/extract1', 'subdir/ectory/file.txt'); +var_dump(file_get_contents(dirname(__FILE__) . '/extract1/subdir/ectory/file.txt')); + +$a->extractTo(dirname(__FILE__) . '/extract2', array('file2.txt', 'one/level')); +var_dump(file_get_contents(dirname(__FILE__) . '/extract2/file2.txt')); +var_dump(is_dir(dirname(__FILE__) . '/extract2/one/level')); +try { +$a->extractTo(dirname(__FILE__) . '/whatever', 134); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +$a->extractTo(array()); +try { +$a->extractTo(''); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +file_put_contents(dirname(__FILE__) . '/oops', 'I is file'); +try { +$a->extractTo(dirname(__FILE__) . '/oops', 'file1.txt'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$a->extractTo(dirname(__FILE__) . '/oops1', array(array(), 'file1.txt')); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$a->extractTo(dirname(__FILE__) . '/extract', 'file1.txt'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +file_put_contents(dirname(__FILE__) . '/extract/file1.txt', 'first'); +var_dump(file_get_contents(dirname(__FILE__) . '/extract/file1.txt')); +$a->extractTo(dirname(__FILE__) . '/extract', 'file1.txt', true); +var_dump(file_get_contents(dirname(__FILE__) . '/extract/file1.txt')); +try { +$a->extractTo(str_repeat('a', 20000), 'file1.txt'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +$a[str_repeat('a', 20000)] = 'long'; +try { +$a->extractTo(dirname(__FILE__) . '/extract', str_repeat('a', 20000)); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +@rmdir(dirname(__FILE__) . '/whatever'); +@unlink(dirname(__FILE__) . '/oops'); +@rmdir(dirname(__FILE__) . '/oops1'); +@unlink(dirname(__FILE__) . '/tempmanifest1.phar.php'); +$e = dirname(__FILE__) . '/extract/'; +@unlink($e . 'file1.txt'); +@unlink($e . 'file2.txt'); +@unlink($e . 'subdir/ectory/file.txt'); +@rmdir($e . 'subdir/ectory'); +@rmdir($e . 'subdir'); +@rmdir($e . 'one/level'); +@rmdir($e . 'one'); +@rmdir($e); +$e = dirname(__FILE__) . '/extract1/'; +@unlink($e . 'file1.txt'); +@unlink($e . 'subdir/ectory/file.txt'); +@rmdir($e . 'subdir/ectory'); +@rmdir($e . 'subdir'); +@rmdir($e); +$e = dirname(__FILE__) . '/extract2/'; +@unlink($e . 'file2.txt'); +@rmdir($e . 'one/level'); +@rmdir($e . 'one'); +@rmdir($e); +?> +--EXPECTF-- +%sextract%cfile1.txt +%sextract%cfile2.txt +%sextract%cone +%sextract%csubdir +%sextract%csubdir%cectory +%sextract%csubdir%cectory%cfile.txt +string(2) "hi" +string(3) "hi3" +string(3) "hi2" +bool(false) +Invalid argument, expected a filename (string) or array of filenames + +Warning: Phar::extractTo() expects parameter 1 to be string, array given in %sphar_extract.php on line %d +Invalid argument, extraction path must be non-zero length +Unable to use path "%soops" for extraction, it is a file, must be a directory +Invalid argument, array of filenames to extract contains non-string value +Extraction from phar "%stempmanifest1.phar.php" failed: Cannot extract "file1.txt" to "%sextract/file1.txt", path already exists +string(5) "first" +string(2) "hi" +Cannot extract to "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", destination directory is too long for filesystem +Extraction from phar "%stempmanifest1.phar.php" failed: Cannot extract "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..." to "%s...", extracted filename is too long for filesystem +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_get_supported_signatures_001.phpt b/ext/phar/tests/phar_get_supported_signatures_001.phpt new file mode 100644 index 0000000000..f672c0024b --- /dev/null +++ b/ext/phar/tests/phar_get_supported_signatures_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar::getSupportedSignatures() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (extension_loaded("hash")) die("skip extension hash conflicts"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +var_dump(Phar::getSupportedSignatures()); +?> +===DONE=== +?> +--EXPECT-- +array(2) { + [0]=> + string(3) "MD5" + [1]=> + string(5) "SHA-1" +} +===DONE=== diff --git a/ext/phar/tests/phar_get_supported_signatures_002.phpt b/ext/phar/tests/phar_get_supported_signatures_002.phpt new file mode 100644 index 0000000000..ba86947d5d --- /dev/null +++ b/ext/phar/tests/phar_get_supported_signatures_002.phpt @@ -0,0 +1,26 @@ +--TEST-- +Phar::getSupportedSignatures() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("hash")) die("skip extension hash required"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +var_dump(Phar::getSupportedSignatures()); +?> +===DONE=== +?> +--EXPECT-- +array(4) { + [0]=> + string(3) "MD5" + [1]=> + string(5) "SHA-1" + [2]=> + string(7) "SHA-256" + [3]=> + string(7) "SHA-512" +} +===DONE=== diff --git a/ext/phar/tests/phar_get_supportedcomp1.phpt b/ext/phar/tests/phar_get_supportedcomp1.phpt new file mode 100644 index 0000000000..d32e12c0ab --- /dev/null +++ b/ext/phar/tests/phar_get_supportedcomp1.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar::getSupportedCompression() (bz2 and zlib) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +var_dump(Phar::getSupportedCompression()); +?> +===DONE=== +--EXPECT-- +array(2) { + [0]=> + string(2) "GZ" + [1]=> + string(5) "BZIP2" +} +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_get_supportedcomp2.phpt b/ext/phar/tests/phar_get_supportedcomp2.phpt new file mode 100644 index 0000000000..c607724918 --- /dev/null +++ b/ext/phar/tests/phar_get_supportedcomp2.phpt @@ -0,0 +1,20 @@ +--TEST-- +Phar::getSupportedCompression() (bz2 only) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?> +<?php if (extension_loaded("zlib")) die("skip zlib is available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +var_dump(Phar::getSupportedCompression()); +?> +===DONE=== +--EXPECT-- +array(1) { + [0]=> + string(5) "BZIP2" +} +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_get_supportedcomp3.phpt b/ext/phar/tests/phar_get_supportedcomp3.phpt new file mode 100644 index 0000000000..c300407f3f --- /dev/null +++ b/ext/phar/tests/phar_get_supportedcomp3.phpt @@ -0,0 +1,20 @@ +--TEST-- +Phar::getSupportedCompression() (zlib only) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (extension_loaded("bz2")) die("skip bz2 is available"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php +var_dump(Phar::getSupportedCompression()); +?> +===DONE=== +--EXPECT-- +array(1) { + [0]=> + string(2) "GZ" +} +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_get_supportedcomp4.phpt b/ext/phar/tests/phar_get_supportedcomp4.phpt new file mode 100644 index 0000000000..fba2c71bfc --- /dev/null +++ b/ext/phar/tests/phar_get_supportedcomp4.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar::getSupportedCompression() (none) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (extension_loaded("bz2")) die("skip bz2 is available"); ?> +<?php if (extension_loaded("zlib")) die("skip zlib is available"); ?> +--FILE-- +<?php +var_dump(Phar::getSupportedCompression()); +?> +===DONE=== +--EXPECT-- +array(0) { +} +===DONE=== diff --git a/ext/phar/tests/phar_gobyebye.phpt b/ext/phar/tests/phar_gobyebye.phpt new file mode 100644 index 0000000000..d55bef0c30 --- /dev/null +++ b/ext/phar/tests/phar_gobyebye.phpt @@ -0,0 +1,44 @@ +--TEST-- +Phar: test edge cases of intercepted functions when the underlying phar archive has been unlinkArchive()d +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.php'; +$pname = 'phar://' . $fname; +file_put_contents($fname2, '<?php Phar::unlinkArchive("' . addslashes($fname) . '");'); +file_put_contents($pname . '/foo/hi', '<?php +include "' . addslashes($fname2) . '"; +readfile("foo/hi"); +fopen("foo/hi", "r"); +echo file_get_contents("foo/hi"); +var_dump(is_file("foo/hi"),is_link("foo/hi"),is_dir("foo/hi"),file_exists("foo/hi"),stat("foo/hi")); +opendir("foo/hi"); +?> +'); +include $pname . '/foo/hi'; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.php'); ?> +--EXPECTF-- +Warning: readfile(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d + +Warning: fopen(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d + +Warning: file_get_contents(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d + +Warning: stat(): stat failed for foo/hi in phar://%sphar_gobyebye.phar.php/foo/hi on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) + +Warning: opendir(foo/hi): failed to open dir: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_gzip.phpt b/ext/phar/tests/phar_gzip.phpt new file mode 100644 index 0000000000..f472949c05 --- /dev/null +++ b/ext/phar/tests/phar_gzip.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar: gzipped phar +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?> +<?php if (version_compare(phpversion(), '5.2.6', '<')) die("skip zlib is buggy in PHP < 5.2.6"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/phar_gzip.phar'; +$pname = 'phar://' . $fname; +$fname2 = dirname(__FILE__) . '/phar_gzip.2.phar'; +$pname2 = 'phar://' . $fname2; + +$file = '<?php +Phar::mapPhar(); +var_dump("it worked"); +include "phar://" . __FILE__ . "/tar_004.php"; +__HALT_COMPILER();'; + +$files = array(); +$files['tar_004.php'] = '<?php var_dump(__FILE__);'; +$files['internal/file/here'] = "hi there!\n"; +$files['internal/dir/'] = ''; +$files['dir/'] = ''; +$gzip = true; + +include 'files/phar_test.inc'; + +include $fname; + +$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); +?> +===DONE=== +--CLEAN-- +<?php +@unlink(dirname(__FILE__) . '/phar_gzip.phar'); +@unlink(dirname(__FILE__) . '/phar_gzip.2.phar'); +?> +--EXPECTF-- +string(9) "it worked" +string(%d) "phar://%sphar_gzip.phar/tar_004.php" +bool(true) +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_isvalidpharfilename.phpt b/ext/phar/tests/phar_isvalidpharfilename.phpt new file mode 100644 index 0000000000..9c953ee88a --- /dev/null +++ b/ext/phar/tests/phar_isvalidpharfilename.phpt @@ -0,0 +1,140 @@ +--TEST-- +Phar: Phar::isValidPharFilename() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=1 +--FILE-- +<?php +chdir(dirname(__FILE__)); +Phar::isValidPharFilename(array()); +echo "*\n"; +var_dump(Phar::isValidPharFilename('*')); +var_dump(Phar::isValidPharFilename('*', true)); +var_dump(Phar::isValidPharFilename('*', false)); + +echo "\nboo.phar\n"; +var_dump(Phar::isValidPharFilename('boo.phar')); +var_dump(Phar::isValidPharFilename('boo.phar', true)); +var_dump(Phar::isValidPharFilename('boo.phar', false)); + +echo "\nboo.tar\n"; +var_dump(Phar::isValidPharFilename('boo.tar')); +var_dump(Phar::isValidPharFilename('boo.tar', true)); +var_dump(Phar::isValidPharFilename('boo.tar', false)); + +echo "\nboo.phar.tar\n"; +var_dump(Phar::isValidPharFilename('boo.phar.tar')); +var_dump(Phar::isValidPharFilename('boo.phar.tar', true)); +var_dump(Phar::isValidPharFilename('boo.phar.tar', false)); + +mkdir(dirname(__FILE__) . '/.phar'); + +echo "\n.phar/boo.tar\n"; +var_dump(Phar::isValidPharFilename('.phar/boo.tar')); +var_dump(Phar::isValidPharFilename('.phar/boo.tar', true)); +var_dump(Phar::isValidPharFilename('.phar/boo.tar', false)); + +echo "\n.phar.tar\n"; +var_dump(Phar::isValidPharFilename('.phar.tar')); +var_dump(Phar::isValidPharFilename('.phar.tar', true)); +var_dump(Phar::isValidPharFilename('.phar.tar', false)); + +echo "\n.phar.phar\n"; +var_dump(Phar::isValidPharFilename('.phar.phar')); +var_dump(Phar::isValidPharFilename('.phar.phar', true)); +var_dump(Phar::isValidPharFilename('.phar.phar', false)); + +echo "\n.phar.phart\n"; +var_dump(Phar::isValidPharFilename('.phar.phart')); +var_dump(Phar::isValidPharFilename('.phar.phart', true)); +var_dump(Phar::isValidPharFilename('.phar.phart', false)); + +echo "\nmy.pharmy\n"; +var_dump(Phar::isValidPharFilename('my.pharmy')); +var_dump(Phar::isValidPharFilename('my.pharmy', true)); +var_dump(Phar::isValidPharFilename('my.pharmy', false)); + +echo "\nphar.zip\n"; +var_dump(Phar::isValidPharFilename('phar.zip')); +var_dump(Phar::isValidPharFilename('phar.zip', true)); +var_dump(Phar::isValidPharFilename('phar.zip', false)); + +echo "\nphar.zip.phar\n"; +var_dump(Phar::isValidPharFilename('phar.zip.phar')); +var_dump(Phar::isValidPharFilename('phar.zip.phar', true)); +var_dump(Phar::isValidPharFilename('phar.zip.phar', false)); + +echo "\ndir.phar.php\n"; +var_dump(Phar::isValidPharFilename('dir.phar.php')); +var_dump(Phar::isValidPharFilename('dir.phar.php', true)); +var_dump(Phar::isValidPharFilename('dir.phar.php', false)); + +?> +===DONE=== +--CLEAN-- +<?php +rmdir(dirname(__FILE__) . '/.phar'); +--EXPECTF-- +Warning: Phar::isValidPharFilename() expects parameter 1 to be string, array given in %sphar_isvalidpharfilename.php on line %d +* +bool(false) +bool(false) +bool(false) + +boo.phar +bool(true) +bool(true) +bool(false) + +boo.tar +bool(false) +bool(false) +bool(true) + +boo.phar.tar +bool(true) +bool(true) +bool(false) + +.phar/boo.tar +bool(false) +bool(false) +bool(true) + +.phar.tar +bool(false) +bool(false) +bool(true) + +.phar.phar +bool(true) +bool(true) +bool(false) + +.phar.phart +bool(false) +bool(false) +bool(true) + +my.pharmy +bool(false) +bool(false) +bool(true) + +phar.zip +bool(false) +bool(false) +bool(true) + +phar.zip.phar +bool(true) +bool(true) +bool(false) + +dir.phar.php +bool(true) +bool(true) +bool(false) +===DONE=== + diff --git a/ext/phar/tests/phar_magic.phpt b/ext/phar/tests/phar_magic.phpt new file mode 100644 index 0000000000..f6a0a675ef --- /dev/null +++ b/ext/phar/tests/phar_magic.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: include/fopen magic +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$p = new Phar($fname); +$p['a'] = '<?php include "b/c.php";' . "\n"; +$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("a", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";'; +$p['d'] = "in d\n"; +$p->setStub('<?php +set_include_path("phar://" . __FILE__); +include "phar://" . __FILE__ . "/a"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__HALT_COMPILER(); +?> +--EXPECTF-- +in b +<?php include "b/c.php"; +in d +===DONE=== diff --git a/ext/phar/tests/phar_metadata_read.phpt b/ext/phar/tests/phar_metadata_read.phpt new file mode 100644 index 0000000000..bda411f740 --- /dev/null +++ b/ext/phar/tests/phar_metadata_read.phpt @@ -0,0 +1,95 @@ +--TEST-- +Phar with metadata (read) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$pmeta = 'hi there'; +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); +include 'files/phar_test.inc'; + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +$phar = new Phar($fname); +var_dump($phar->hasMetaData()); +var_dump($phar->getMetaData()); +var_dump($phar->delMetaData()); +var_dump($phar->getMetaData()); +var_dump($phar->delMetaData()); +var_dump($phar->getMetaData()); +foreach($files as $name => $cont) { + echo " meta $name\n"; + var_dump($phar[$name]->hasMetadata()); + var_dump($phar[$name]->getMetadata()); + var_dump($phar[$name]->delMetadata()); + var_dump($phar[$name]->getMetadata()); +} + +unset($phar); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +bool(true) +string(8) "hi there" +bool(true) +NULL +bool(true) +NULL + meta a +bool(false) +NULL +bool(true) +NULL + meta b +bool(false) +NULL +bool(true) +NULL + meta c +bool(true) +array(2) { + [0]=> + string(2) "hi" + [1]=> + string(5) "there" +} +bool(true) +NULL + meta d +bool(true) +array(2) { + ["hi"]=> + string(5) "there" + ["foo"]=> + string(3) "bar" +} +bool(true) +NULL +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +===DONE=== diff --git a/ext/phar/tests/phar_metadata_write.phpt b/ext/phar/tests/phar_metadata_write.phpt new file mode 100644 index 0000000000..6df7ba4faf --- /dev/null +++ b/ext/phar/tests/phar_metadata_write.phpt @@ -0,0 +1,71 @@ +--TEST-- +Phar with metadata (write) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b', 'meta' => 'hi there'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); +include 'files/phar_test.inc'; + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +$phar = new Phar($fname); +var_dump($phar->getMetadata()); +$phar->setMetadata(array('my' => 'friend')); +$phar->setMetadata(array('my' => 'friend')); +var_dump($phar->getMetadata()); +$phar['a']->setMetadata(42); +$phar['b']->setMetadata(NULL); +$phar['c']->setMetadata(array(25, 'foo'=>'bar')); +$phar['d']->setMetadata(true); + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} + +unset($phar); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +NULL +array(1) { + ["my"]=> + string(6) "friend" +} +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +===DONE=== diff --git a/ext/phar/tests/phar_mount.phpt b/ext/phar/tests/phar_mount.phpt new file mode 100644 index 0000000000..80f8cda389 --- /dev/null +++ b/ext/phar/tests/phar_mount.phpt @@ -0,0 +1,63 @@ +--TEST-- +Phar: Phar::mount +--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') . '.phar.tar'; + +$a = new Phar($fname); +$a['index.php'] = '<?php +Phar::mount("testit", "' . addslashes(__FILE__) . '"); +try { +Phar::mount("testit", "' . addslashes(__FILE__) . '"); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +Phar::mount("' . addslashes($pname) . '/testit1", "' . addslashes(__FILE__) . '"); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?>'; +$a->setStub('<?php +set_include_path("phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +Phar::mount($pname . '/testit1', __FILE__); +include $fname; +// test copying of a phar with mounted entries +$b = $a->convertToExecutable(Phar::TAR); +$b->setStub('<?php +set_include_path("phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +try { +include $fname2; +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +try { +Phar::mount($pname . '/oops', '/home/oops/../../etc/passwd:'); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +Phar::mount($pname . '/testit2', $pname . '/testit1'); +echo substr($a['testit2']->getContent(),0, 50),"\n"; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- +Mounting of testit to %sphar_mount.php within phar %sphar_mount.phar.php failed +Can only mount internal paths within a phar archive, use a relative path instead of "phar://%sphar_mount.phar.php/testit1" +Mounting of testit to %sphar_mount.php within phar %sphar_mount.phar.tar failed +Mounting of /oops to /home/oops/../../etc/passwd: within phar %sphar_mount.phar.php failed +<?php +$fname = dirname(__FILE__) . '/' . basename( +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_offset_get_error.phpt b/ext/phar/tests/phar_offset_get_error.phpt new file mode 100755 index 0000000000..ad0223697d --- /dev/null +++ b/ext/phar/tests/phar_offset_get_error.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar: ignore filenames starting with / on offsetSet +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://'.$fname; +$iname = '/file.txt'; +$ename = '/error/..'; + +$p = new Phar($fname); +$p[$iname] = "foobar\n"; + +try +{ + $p[$ename] = "foobar\n"; +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} + +include($pname . $iname); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +Entry /error/.. does not exist and cannot be created: phar error: invalid path "/error/.." contains upper directory reference +foobar +===DONE=== diff --git a/ext/phar/tests/phar_oo_001.phpt b/ext/phar/tests/phar_oo_001.phpt new file mode 100755 index 0000000000..81d57d1bfc --- /dev/null +++ b/ext/phar/tests/phar_oo_001.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar object: basics +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->getVersion()); +var_dump(count($phar)); + +class MyPhar extends Phar +{ + function __construct() + { + } +} + +try +{ + $phar = new MyPhar(); + var_dump($phar->getVersion()); +} +catch (BadMethodCallException $e) +{ + var_dump($e->getMessage()); +} +try { + $phar = new Phar('test.phar'); + $phar->__construct('oops'); +} catch (BadMethodCallException $e) +{ + var_dump($e->getMessage()); +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +string(5) "1.0.0" +int(5) +string(50) "Cannot call method on an uninitialized Phar object" +string(29) "Cannot call constructor twice" +===DONE=== diff --git a/ext/phar/tests/phar_oo_002.phpt b/ext/phar/tests/phar_oo_002.phpt new file mode 100755 index 0000000000..9bb28689d9 --- /dev/null +++ b/ext/phar/tests/phar_oo_002.phpt @@ -0,0 +1,137 @@ +--TEST-- +Phar object: iterator & entries +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileInfo'); +foreach($phar as $name => $ent) +{ + var_dump(str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name)); + var_dump($ent->getFilename()); + var_dump($ent->getSize()); + var_dump($ent->getType()); + var_dump($ent->isWritable()); + var_dump($ent->isReadable()); + var_dump($ent->isExecutable()); + var_dump($ent->isFile()); + var_dump($ent->isDir()); + var_dump($ent->isLink()); + var_dump($ent->getCTime()); + var_dump($ent->getMTime()); + var_dump($ent->getATime()); +} + +echo "==RECURSIVE==\n"; + +$phar = new Phar($fname); +foreach(new RecursiveIteratorIterator($phar) as $name => $ent) +{ + var_dump(str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name)); + var_dump(str_replace('\\', '/', $ent->getFilename())); + var_dump($ent->getCompressedSize()); + var_dump($ent->isCRCChecked()); + var_dump($ent->isCRCChecked() ? $ent->getCRC32() : NULL); + var_dump($ent->getPharFlags()); +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +string(42) "phar://*/files/phar_oo_test.phar.php%ca.php" +string(5) "a.php" +int(32) +string(4) "file" +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +int(1141214400) +int(1141214400) +int(1141214400) +string(38) "phar://*/files/phar_oo_test.phar.php%cb" +string(1) "b" +int(0) +string(3) "dir" +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +int(1141214400) +int(1141214400) +int(1141214400) +string(42) "phar://*/files/phar_oo_test.phar.php%cb.php" +string(5) "b.php" +int(32) +string(4) "file" +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +int(1141214400) +int(1141214400) +int(1141214400) +string(42) "phar://*/files/phar_oo_test.phar.php%ce.php" +string(5) "e.php" +int(32) +string(4) "file" +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +int(1141214400) +int(1141214400) +int(1141214400) +==RECURSIVE== +string(42) "phar://*/files/phar_oo_test.phar.php%ca.php" +string(5) "a.php" +int(32) +bool(false) +NULL +int(0) +string(44) "phar://*/files/phar_oo_test.phar.php%cb%cc.php" +string(5) "c.php" +int(34) +bool(false) +NULL +int(0) +string(44) "phar://*/files/phar_oo_test.phar.php%cb%cd.php" +string(5) "d.php" +int(34) +bool(false) +NULL +int(0) +string(42) "phar://*/files/phar_oo_test.phar.php%cb.php" +string(5) "b.php" +int(32) +bool(false) +NULL +int(0) +string(42) "phar://*/files/phar_oo_test.phar.php%ce.php" +string(5) "e.php" +int(32) +bool(false) +NULL +int(0) +===DONE=== diff --git a/ext/phar/tests/phar_oo_003.phpt b/ext/phar/tests/phar_oo_003.phpt new file mode 100755 index 0000000000..9d24b1919b --- /dev/null +++ b/ext/phar/tests/phar_oo_003.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar object: entry & openFile() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass(); +foreach($phar as $name => $ent) +{ + var_dump($ent->getFilename()); + if ($ent->isDir()) { + var_dump('DIR'); + } else { + var_dump($ent->openFile()->fgets()); + include $ent->getPathName(); + } +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +string(5) "a.php" +string(32) "<?php echo "This is a.php\n"; ?>" +This is a.php +string(1) "b" +string(3) "DIR" +string(5) "b.php" +string(32) "<?php echo "This is b.php\n"; ?>" +This is b.php +string(5) "e.php" +string(32) "<?php echo "This is e.php\n"; ?>" +This is e.php +===DONE=== diff --git a/ext/phar/tests/phar_oo_004.phpt b/ext/phar/tests/phar_oo_004.phpt new file mode 100755 index 0000000000..4f72b3678d --- /dev/null +++ b/ext/phar/tests/phar_oo_004.phpt @@ -0,0 +1,126 @@ +--TEST-- +Phar and DirectoryIterator +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +$it = new DirectoryIterator('phar://'.$fname); + +foreach($it as $name => $ent) +{ + var_dump($name); + var_dump($ent->getFilename()); + var_dump($ent->isDir()); + var_dump($ent->isDot()); +} + +?> +===MANUAL=== +<?php + +class MyDirectoryIterator extends DirectoryIterator +{ + function __construct($dir) + { + echo __METHOD__ . "\n"; + parent::__construct($dir); + } + + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } +} + +$it = new MyDirectoryIterator('phar://'.$fname); + +foreach($it as $name => $ent) +{ + var_dump($name); + var_dump($ent->getFilename()); +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +int(0) +string(5) "a.php" +bool(false) +bool(false) +int(1) +string(1) "b" +bool(true) +bool(false) +int(2) +string(5) "b.php" +bool(false) +bool(false) +int(3) +string(5) "e.php" +bool(false) +bool(false) +===MANUAL=== +MyDirectoryIterator::__construct +MyDirectoryIterator::rewind +MyDirectoryIterator::valid +MyDirectoryIterator::current +MyDirectoryIterator::key +int(0) +string(5) "a.php" +MyDirectoryIterator::next +MyDirectoryIterator::valid +MyDirectoryIterator::current +MyDirectoryIterator::key +int(1) +string(1) "b" +MyDirectoryIterator::next +MyDirectoryIterator::valid +MyDirectoryIterator::current +MyDirectoryIterator::key +int(2) +string(5) "b.php" +MyDirectoryIterator::next +MyDirectoryIterator::valid +MyDirectoryIterator::current +MyDirectoryIterator::key +int(3) +string(5) "e.php" +MyDirectoryIterator::next +MyDirectoryIterator::valid +===DONE=== diff --git a/ext/phar/tests/phar_oo_005.phpt b/ext/phar/tests/phar_oo_005.phpt new file mode 100755 index 0000000000..687cf59d07 --- /dev/null +++ b/ext/phar/tests/phar_oo_005.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar and RecursiveDirectoryIterator +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; +$fname = str_replace('\\', '/', $fname); + +$it = new RecursiveDirectoryIterator('phar://'.$fname); +$it = new RecursiveIteratorIterator($it); + +foreach($it as $name => $ent) +{ + var_dump(str_replace(array('\\', $fname), array('/', '*'), $name)); + var_dump(str_replace(array('\\', $fname), array('/', '*'), $ent->getPathname())); + var_dump(str_replace('\\', '/', $it->getSubPath())); + var_dump(str_replace('\\', '/', $it->getSubPathName())); + $sub = $it->getPathInfo(); + var_dump(str_replace('\\', '/', $sub->getFilename())); +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +string(14) "phar://*/a.php" +string(14) "phar://*/a.php" +string(0) "" +string(5) "a.php" +string(21) "phar_oo_test.phar.php" +string(16) "phar://*/b/c.php" +string(16) "phar://*/b/c.php" +string(1) "b" +string(7) "b/c.php" +string(1) "b" +string(16) "phar://*/b/d.php" +string(16) "phar://*/b/d.php" +string(1) "b" +string(7) "b/d.php" +string(1) "b" +string(14) "phar://*/b.php" +string(14) "phar://*/b.php" +string(0) "" +string(5) "b.php" +string(21) "phar_oo_test.phar.php" +string(14) "phar://*/e.php" +string(14) "phar://*/e.php" +string(0) "" +string(5) "e.php" +string(21) "phar_oo_test.phar.php" +===DONE=== diff --git a/ext/phar/tests/phar_oo_006.phpt b/ext/phar/tests/phar_oo_006.phpt new file mode 100755 index 0000000000..556c98ce0b --- /dev/null +++ b/ext/phar/tests/phar_oo_006.phpt @@ -0,0 +1,52 @@ +--TEST-- +Phar object: array access +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +class MyFile extends SplFileObject +{ + function __construct($what) + { + echo __METHOD__ . "($what)\n"; + parent::__construct($what); + } +} + +$phar = new Phar($fname); +try +{ + $phar->setFileClass('SplFileInfo'); +} +catch (UnexpectedValueException $e) +{ + echo $e->getMessage() . "\n"; +} +$phar->setInfoClass('MyFile'); + +echo $phar['a.php']->getFilename() . "\n"; +echo $phar['b/c.php']->getFilename() . "\n"; +echo $phar['b.php']->getFilename() . "\n"; + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +SplFileInfo::setFileClass() expects parameter 1 to be a class name derived from SplFileObject, 'SplFileInfo' given +MyFile::__construct(phar://%s/a.php) +a.php +MyFile::__construct(phar://%s/b/c.php) +c.php +MyFile::__construct(phar://%s/b.php) +b.php +===DONE=== diff --git a/ext/phar/tests/phar_oo_007.phpt b/ext/phar/tests/phar_oo_007.phpt new file mode 100755 index 0000000000..48807660ff --- /dev/null +++ b/ext/phar/tests/phar_oo_007.phpt @@ -0,0 +1,87 @@ +--TEST-- +Phar object: access through SplFileObject +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +class MyFile extends SplFileObject +{ + function __construct($name) + { + echo __METHOD__ . "(" . str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name) . ")\n"; + parent::__construct($name); + } +} + +$phar = new Phar($fname); +$phar->setInfoClass('MyFile'); + +$f = $phar['a.php']; + +$s = $f->fstat(); + +var_dump($s['atime']); +var_dump($s['ctime']); +var_dump($s['mtime']); + +var_dump($f->ftell()); +var_dump($f->eof()); +var_dump($f->fgets()); +var_dump($f->eof()); +var_dump($f->fseek(20)); +var_dump($f->ftell()); +var_dump($f->fgets()); +var_dump($f->rewind()); +var_dump($f->ftell()); +var_dump($f->fgets()); +var_dump($f->ftell()); + +?> +===AGAIN=== +<?php + +$f = $phar['a.php']; + +var_dump($f->ftell()); +var_dump($f->eof()); +var_dump($f->fgets()); +var_dump($f->eof()); + +//unset($f); without unset we check for working refcounting + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +MyFile::__construct(phar://*/files/phar_oo_test.phar.php/a.php) +int(1141214400) +int(1141214400) +int(1141214400) +int(0) +bool(false) +string(32) "<?php echo "This is a.php\n"; ?>" +bool(true) +int(0) +int(20) +string(12) "a.php\n"; ?>" +NULL +int(0) +string(32) "<?php echo "This is a.php\n"; ?>" +int(32) +===AGAIN=== +MyFile::__construct(phar://*/files/phar_oo_test.phar.php/a.php) +int(0) +bool(false) +string(32) "<?php echo "This is a.php\n"; ?>" +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_oo_008.phpt b/ext/phar/tests/phar_oo_008.phpt new file mode 100755 index 0000000000..80d1ece0ca --- /dev/null +++ b/ext/phar/tests/phar_oo_008.phpt @@ -0,0 +1,119 @@ +--TEST-- +Phar object: iterating via SplFileObject +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 1; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileObject'); + +$f = $phar['a.csv']; +echo "===1===\n"; +foreach($f as $k => $v) +{ + echo "$k=>$v\n"; +} + +$f->setFlags(SplFileObject::DROP_NEW_LINE); + +echo "===2===\n"; +foreach($f as $k => $v) +{ + echo "$k=>$v\n"; +} + +class MyCSVFile extends SplFileObject +{ + function current() + { + return parent::fgetcsv(',', '"'); + } +} + +$phar->setInfoClass('MyCSVFile'); +$v = $phar['a.csv']; + +echo "===3===\n"; +while(!$v->eof()) +{ + echo $v->key() . "=>" . join('|',$v->fgetcsv()) . "\n"; +} + +echo "===4===\n"; +$v->rewind(); +while(!$v->eof()) +{ + $l = $v->fgetcsv(); + echo $v->key() . "=>" . join('|',$l) . "\n"; +} + +echo "===5===\n"; +foreach($v as $k => $d) +{ + echo "$k=>" . join('|',$d) . "\n"; +} + +class MyCSVFile2 extends SplFileObject +{ + function getCurrentLine() + { + echo __METHOD__ . "\n"; + return parent::fgetcsv(',', '"'); + } +} + +$phar->setInfoClass('MyCSVFile2'); +$v = $phar['a.csv']; + +echo "===6===\n"; +foreach($v as $k => $d) +{ + echo "$k=>" . join('|',$d) . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +===1=== +0=>1,2,3 + +1=>2,a,b + +2=>3,"c","'e'" +===2=== +0=>1,2,3 +1=>2,a,b +2=>3,"c","'e'" +===3=== +0=>1|2|3 +0=>2|a|b +1=>3|c|'e' +===4=== +0=>1|2|3 +1=>2|a|b +2=>3|c|'e' +===5=== +0=>1|2|3 +1=>2|a|b +2=>3|c|'e' +===6=== +MyCSVFile2::getCurrentLine +1=>1|2|3 +MyCSVFile2::getCurrentLine +3=>2|a|b +MyCSVFile2::getCurrentLine +5=>3|c|'e' +===DONE=== diff --git a/ext/phar/tests/phar_oo_009.phpt b/ext/phar/tests/phar_oo_009.phpt new file mode 100755 index 0000000000..6abd03ee30 --- /dev/null +++ b/ext/phar/tests/phar_oo_009.phpt @@ -0,0 +1,56 @@ +--TEST-- +Phar object: iterating via SplFileObject and reading csv +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!defined('SplFileObject::READ_CSV') || !defined('SplFileObject::SKIP_EMPTY')) die('skip newer SPL version is required'); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 2; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileObject'); + +$f = $phar['a.csv']; +$f->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE); +foreach($f as $k => $v) +{ + echo "$k=>$v\n"; +} + +?> +===CSV=== +<?php + +$f->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE | SplFileObject::READ_CSV); +foreach($f as $k => $v) +{ + echo "$k=>" . join('|', $v) . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +0=>1,2,3 +1=>2,a,b +2=>3,"c","'e'" +3=>4 +4=>5,5 +5=>7,777 +===CSV=== +0=>1|2|3 +1=>2|a|b +2=>3|c|'e' +3=>4 +4=>5|5 +6=>7|777 +===DONE=== diff --git a/ext/phar/tests/phar_oo_010.phpt b/ext/phar/tests/phar_oo_010.phpt new file mode 100755 index 0000000000..4e4435a7bb --- /dev/null +++ b/ext/phar/tests/phar_oo_010.phpt @@ -0,0 +1,55 @@ +--TEST-- +Phar object: ArrayAccess and isset +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 0; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); + +var_dump(isset($phar['a.php'])); +var_dump(isset($phar['b.php'])); +var_dump(isset($phar['b/c.php'])); +var_dump(isset($phar['b/d.php'])); +var_dump(isset($phar['e.php'])); + +?> +===DIR=== +<?php +var_dump(isset($phar['b'])); +?> +===NA=== +<?php +var_dump(isset($phar['a'])); +var_dump(isset($phar['b/c'])); +var_dump(isset($phar[12])); +var_dump(isset($phar['b'])); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +===DIR=== +bool(false) +===NA=== +bool(false) +bool(false) +bool(false) +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_011.phpt b/ext/phar/tests/phar_oo_011.phpt new file mode 100644 index 0000000000..236009b7e4 --- /dev/null +++ b/ext/phar/tests/phar_oo_011.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar object: add file +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 0; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileObject'); + +$phar['f.php'] = 'hi'; +var_dump(isset($phar['f.php'])); +echo $phar['f.php']; +echo "\n"; + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +bool(true) +hi +===DONE=== diff --git a/ext/phar/tests/phar_oo_011b.phpt b/ext/phar/tests/phar_oo_011b.phpt new file mode 100755 index 0000000000..37a0e570a5 --- /dev/null +++ b/ext/phar/tests/phar_oo_011b.phpt @@ -0,0 +1,39 @@ +--TEST-- +Phar object: add file +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +<?php + +try +{ + $pharconfig = 0; + + require_once 'files/phar_oo_test.inc'; + + $phar = new Phar($fname); + + $phar['f.php'] = 'hi'; + var_dump(isset($phar['f.php'])); + echo $phar['f.php']; + echo "\n"; +} +catch (BadMethodCallException $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +Exception: Write operations disabled by INI setting +===DONE=== diff --git a/ext/phar/tests/phar_oo_012.phpt b/ext/phar/tests/phar_oo_012.phpt new file mode 100644 index 0000000000..e79ac0960e --- /dev/null +++ b/ext/phar/tests/phar_oo_012.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar object: unset file +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 0; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileObject'); + +$phar['f.php'] = 'hi'; +var_dump(isset($phar['f.php'])); +echo $phar['f.php']; +echo "\n"; +unset($phar['f.php']); +var_dump(isset($phar['f.php'])); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +bool(true) +hi +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_012_confirm.phpt b/ext/phar/tests/phar_oo_012_confirm.phpt new file mode 100644 index 0000000000..58a3be87b3 --- /dev/null +++ b/ext/phar/tests/phar_oo_012_confirm.phpt @@ -0,0 +1,40 @@ +--TEST-- +Phar object: unset file (confirm disk file is changed) +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$pharconfig = 0; + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +$phar->setInfoClass('SplFileObject'); + +$phar['f.php'] = 'hi'; +var_dump(isset($phar['f.php'])); +echo $phar['f.php']; +echo "\n"; +$md5 = md5_file($fname); +unset($phar['f.php']); +$md52 = md5_file($fname); +if ($md5 == $md52) echo 'File on disk has not changed'; +var_dump(isset($phar['f.php'])); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +bool(true) +hi +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_012b.phpt b/ext/phar/tests/phar_oo_012b.phpt new file mode 100755 index 0000000000..01cf776986 --- /dev/null +++ b/ext/phar/tests/phar_oo_012b.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar object: unset file +--SKIPIF-- +<?php if (!extension_loaded('phar')) die('skip'); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=0 +--FILE-- +<?php + +try +{ + $pharconfig = 0; + + require_once 'files/phar_oo_test.inc'; + + $phar = new Phar($fname); + $phar->setInfoClass('SplFileObject'); + + $phar['f.php'] = 'hi'; + var_dump(isset($phar['f.php'])); + echo $phar['f.php']; + echo "\n"; + unset($phar['f.php']); + var_dump(isset($phar['f.php'])); +} +catch (BadMethodCallException $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +Exception: Write operations disabled by INI setting +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressallbz2.phpt b/ext/phar/tests/phar_oo_compressallbz2.phpt new file mode 100644 index 0000000000..3f52227194 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressallbz2.phpt @@ -0,0 +1,66 @@ +--TEST-- +Phar::compressFiles(Phar::BZ2) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar = new Phar($fname); +$phar->compressFiles(Phar::BZ2); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed(Phar::GZ)); +var_dump($phar['a']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(false) +bool(true) +string(1) "b" +bool(false) +bool(true) +string(1) "c" +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressallgz.phpt b/ext/phar/tests/phar_oo_compressallgz.phpt new file mode 100644 index 0000000000..55e7435f95 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressallgz.phpt @@ -0,0 +1,71 @@ +--TEST-- +Phar::compressFiles(Phar::GZ) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar = new Phar($fname); +$phar->compressFiles(Phar::GZ); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed(Phar::GZ)); +var_dump($phar['a']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +try { +$phar->compressFiles(25); +} 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') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(true) +bool(false) +string(1) "b" +bool(true) +bool(false) +string(1) "c" +bool(true) +bool(false) +Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2 +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressed_001.phpt b/ext/phar/tests/phar_oo_compressed_001.phpt new file mode 100644 index 0000000000..af02012573 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressed_001.phpt @@ -0,0 +1,68 @@ +--TEST-- +Phar: PharFileInfo::compress(Phar::GZ) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar['a'] = 'new a'; +$phar['a']->decompress(); +$phar['b'] = 'new b'; +$phar['b']->compress(Phar::GZ); +$phar['d'] = 'new d'; + +$phar = new Phar($fname); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); +var_dump(file_get_contents($pname . '/d')); +var_dump($phar['d']->isCompressed()); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(5) "new a" +bool(false) +string(5) "new b" +bool(true) +string(1) "c" +bool(false) +string(5) "new d" +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressed_001b.phpt b/ext/phar/tests/phar_oo_compressed_001b.phpt new file mode 100755 index 0000000000..6d4c732862 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressed_001b.phpt @@ -0,0 +1,68 @@ +--TEST-- +Phar: PharFileInfo::compress(Phar::BZ2) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar['a'] = 'new a'; +$phar['a']->decompress(); +$phar['b'] = 'new b'; +$phar['b']->compress(Phar::BZ2); +$phar['d'] = 'new d'; + +$phar = new Phar($fname); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); +var_dump(file_get_contents($pname . '/d')); +var_dump($phar['d']->isCompressed()); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(5) "new a" +bool(false) +string(5) "new b" +bool(true) +string(1) "c" +bool(false) +string(5) "new d" +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressed_002.phpt b/ext/phar/tests/phar_oo_compressed_002.phpt new file mode 100755 index 0000000000..d03d6f1a98 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressed_002.phpt @@ -0,0 +1,73 @@ +--TEST-- +Phar: context/compress=GZ +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$context = stream_context_create(array('phar'=>array('compress'=>Phar::GZ))); + +file_put_contents($pname . '/b', 'new b'); +file_put_contents($pname . '/c', 'new c', 0, $context); +file_put_contents($pname . '/d', 'new d'); +file_put_contents($pname . '/e', 'new e', 0, $context); + +$phar = new Phar($fname); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); +var_dump(file_get_contents($pname . '/d')); +var_dump($phar['d']->isCompressed()); +var_dump(file_get_contents($pname . '/e')); +var_dump($phar['e']->isCompressed()); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(false) +string(5) "new b" +bool(false) +string(5) "new c" +bool(true) +string(5) "new d" +bool(false) +string(5) "new e" +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_oo_compressed_002b.phpt b/ext/phar/tests/phar_oo_compressed_002b.phpt new file mode 100755 index 0000000000..0e167012b7 --- /dev/null +++ b/ext/phar/tests/phar_oo_compressed_002b.phpt @@ -0,0 +1,73 @@ +--TEST-- +Phar: context/compress=BZip2 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$context = stream_context_create(array('phar'=>array('compress'=>Phar::BZ2))); + +file_put_contents($pname . '/b', 'new b'); +file_put_contents($pname . '/c', 'new c', 0, $context); +file_put_contents($pname . '/d', 'new d'); +file_put_contents($pname . '/e', 'new e', 0, $context); + +$phar = new Phar($fname); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); +var_dump(file_get_contents($pname . '/d')); +var_dump($phar['d']->isCompressed()); +var_dump(file_get_contents($pname . '/e')); +var_dump($phar['e']->isCompressed()); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(false) +string(5) "new b" +bool(false) +string(5) "new c" +bool(true) +string(5) "new d" +bool(false) +string(5) "new e" +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_oo_getcontents.phpt b/ext/phar/tests/phar_oo_getcontents.phpt new file mode 100644 index 0000000000..e42bca46fc --- /dev/null +++ b/ext/phar/tests/phar_oo_getcontents.phpt @@ -0,0 +1,39 @@ +--TEST-- +Phar object: getContent() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; + +$phar = new Phar($fname); +$phar['a/b'] = 'file contents +this works'; +$phar->addEmptyDir('hi'); +echo $phar['a/b']->getContent() . "\n"; +try { +echo $phar['a']->getContent(), "\n"; +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +echo $phar['hi']->getContent(), "\n"; +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__halt_compiler(); +?> +--EXPECTF-- +file contents +this works +Phar error: Cannot retrieve contents, "a" in phar "%sphar_oo_getcontents.phar.php" is a directory +Phar error: Cannot retrieve contents, "hi" in phar "%sphar_oo_getcontents.phar.php" is a directory +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_oo_getcontentsgz.phpt b/ext/phar/tests/phar_oo_getcontentsgz.phpt new file mode 100644 index 0000000000..a480a69637 --- /dev/null +++ b/ext/phar/tests/phar_oo_getcontentsgz.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar object: getContent() (verify it works with compression) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php'; + +$phar = new Phar($fname); +$phar['a'] = 'file contents +this works'; +$phar['a']->compress(Phar::GZ); +copy($fname, $fname2); +$phar2 = new Phar($fname2); +var_dump($phar2['a']->isCompressed()); +echo $phar2['a']->getContent() . "\n"; +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +bool(true) +file contents +this works +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/phar_oo_getmodified.phpt b/ext/phar/tests/phar_oo_getmodified.phpt new file mode 100644 index 0000000000..d531393281 --- /dev/null +++ b/ext/phar/tests/phar_oo_getmodified.phpt @@ -0,0 +1,36 @@ +--TEST-- +Phar::getModified() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->getModified()); +$phar->compressFiles(Phar::GZ); +var_dump($phar->getModified()); +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_oo_iswriteable.phpt b/ext/phar/tests/phar_oo_iswriteable.phpt new file mode 100644 index 0000000000..9fbca2c9ea --- /dev/null +++ b/ext/phar/tests/phar_oo_iswriteable.phpt @@ -0,0 +1,84 @@ +--TEST-- +Phar::isWriteable +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$pname = 'phar://hio'; +$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>'; +$files['dir/'] = ''; +$hasdir = 1; +include 'files/phar_test.inc'; +$a = new Phar($fname); +$b = new PharData($fname2); +$b['test'] = 'hi'; + +var_dump($a['a.php']->isWritable()); +var_dump($a['a.php']->isReadable()); +$a['a.php']->chmod(000); +var_dump($a['a.php']->isWritable()); +var_dump($a['a.php']->isReadable()); +$a['a.php']->chmod(0666); +var_dump($a['a.php']->isWritable()); +var_dump($a['a.php']->isReadable()); +ini_set('phar.readonly',1); +clearstatcache(); +var_dump($a['a.php']->isWritable()); +var_dump($a['a.php']->isReadable()); +ini_set('phar.readonly',0); +clearstatcache(); +var_dump($a['a.php']->isWritable()); +var_dump($a['a.php']->isReadable()); +?> +archive +<?php +ini_set('phar.readonly',0); +$p = new Phar('doesnotexisthere.phar'); +var_dump($p->isWritable()); +clearstatcache(); +var_dump($a->isWritable()); +var_dump($b->isWritable()); +ini_set('phar.readonly',1); +clearstatcache(); +var_dump($a->isWritable()); +var_dump($b->isWritable()); +chmod($fname2, 000); +clearstatcache(); +var_dump($a->isWritable()); +var_dump($b->isWritable()); +chmod($fname2, 0666); +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(false) +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(true) +archive +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_nosig.phpt b/ext/phar/tests/phar_oo_nosig.phpt new file mode 100644 index 0000000000..d99222e12c --- /dev/null +++ b/ext/phar/tests/phar_oo_nosig.phpt @@ -0,0 +1,24 @@ +--TEST-- +Phar::getSignature() no signature +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.require_hash=0 +--FILE-- +<?php + +require_once 'files/phar_oo_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->getSignature()); +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php'); +__halt_compiler(); +?> +--EXPECT-- +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_oo_uncompressall.phpt b/ext/phar/tests/phar_oo_uncompressall.phpt new file mode 100644 index 0000000000..19cf953197 --- /dev/null +++ b/ext/phar/tests/phar_oo_uncompressall.phpt @@ -0,0 +1,80 @@ +--TEST-- +Phar::decompressFiles() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); + +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar = new Phar($fname); +$phar->compressFiles(Phar::GZ); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed(Phar::GZ)); +var_dump($phar['a']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); + +$phar->decompressFiles(); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['a']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['a']->isCompressed()); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +?> +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(true) +bool(false) +string(1) "b" +bool(true) +bool(false) +string(1) "c" +bool(true) +bool(false) +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +===DONE=== diff --git a/ext/phar/tests/phar_running.phpt b/ext/phar/tests/phar_running.phpt new file mode 100644 index 0000000000..2d132b9ac7 --- /dev/null +++ b/ext/phar/tests/phar_running.phpt @@ -0,0 +1,29 @@ +--TEST-- +Phar: Phar::running() +--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; + +$phar = new Phar($fname); +$phar['index.php'] = '<?php +Phar::running(array()); +var_dump(Phar::running()); +var_dump(Phar::running(false)); +?>'; +include $pname . '/index.php'; +var_dump(Phar::running()); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Warning: Phar::running() expects parameter 1 to be boolean, array given in phar://%sphar_running.phar.php/index.php on line 2 +string(%d) "phar://%sphar_running.phar.php" +string(%d) "%sphar_running.phar.php" +string(0) "" +===DONE=== diff --git a/ext/phar/tests/phar_setalias.phpt b/ext/phar/tests/phar_setalias.phpt new file mode 100644 index 0000000000..ef9fa283d5 --- /dev/null +++ b/ext/phar/tests/phar_setalias.phpt @@ -0,0 +1,36 @@ +--TEST-- +Phar::setAlias() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php'); +__HALT_COMPILER(); +?> +--EXPECT-- +hio +test +===DONE=== diff --git a/ext/phar/tests/phar_setalias2.phpt b/ext/phar/tests/phar_setalias2.phpt new file mode 100644 index 0000000000..901e4d2ebd --- /dev/null +++ b/ext/phar/tests/phar_setalias2.phpt @@ -0,0 +1,51 @@ +--TEST-- +Phar::setAlias() error +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; +$b = $phar; +$phar = new Phar(dirname(__FILE__) . '/notphar.phar'); +try { + $phar->setAlias('test'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + $b = new Phar(dirname(__FILE__) . '/nope.phar', 0, 'test'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php'); +unlink(dirname(__FILE__) . '/notphar.phar'); +__HALT_COMPILER(); +?> +--EXPECTF-- +hio +test +alias "test" is already used for archive "%sphar_setalias2.phar.php" and cannot be used for other archives +alias "test" is already used for archive "%sphar_setalias2.phar.php" cannot be overloaded with "%snope.phar" +===DONE=== diff --git a/ext/phar/tests/phar_setdefaultstub.phpt b/ext/phar/tests/phar_setdefaultstub.phpt new file mode 100644 index 0000000000..a36c005eac --- /dev/null +++ b/ext/phar/tests/phar_setdefaultstub.phpt @@ -0,0 +1,944 @@ +--TEST-- +Phar: Phar::setDefaultStub() with and without arg +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; + +$phar = new Phar($fname); +$phar['a.php'] = '<php echo "this is a\n"; ?>'; +$phar['b.php'] = '<php echo "this is b\n"; ?>'; +$phar->setDefaultStub(); +$phar->stopBuffering(); + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +$phar->setDefaultStub('my/custom/thingy.php'); +$phar->stopBuffering(); +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +$phar->setDefaultStub('my/custom/thingy.php', 'the/web.php'); +$phar->stopBuffering(); +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub(str_repeat('a', 400)); + $phar->stopBuffering(); + var_dump(strlen($phar->getStub())); + + $phar->setDefaultStub(str_repeat('a', 401)); + $phar->stopBuffering(); + var_dump(strlen($phar->getStub())); + +} catch(Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +?> +--EXPECT-- +string(6653) "<?php + +$web = 'index.php'; + +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} + +if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'index.php'; +const LEN = 6653; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?> +" +============================================================================ +============================================================================ +string(6664) "<?php + +$web = 'index.php'; + +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} + +if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'my/custom/thingy.php'; +const LEN = 6664; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?> +" +============================================================================ +============================================================================ +string(6666) "<?php + +$web = 'the/web.php'; + +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path()); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} + +if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); + +header("Cache-Control: no-cache, must-revalidate"); +header("Pragma: no-cache"); + +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include $web; +return; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +exit; +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} + +class Extract_Phar +{ +static $temp; +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'my/custom/thingy.php'; +const LEN = 6666; + +static function go($return = false) +{ +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; + +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); + +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} + +$info = self::_unpack($m); +$f = $info['c']; + +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled -' . +' gzinflate() function needed for zlib-compressed .phars'); +} +} + +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled -' . +' bzdecompress() function needed for bz2-compressed .phars'); +} +} + +$temp = self::tmpdir(); + +if (!$temp || !is_writable($temp)) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== false) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) || !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} + +$temp .= '/pharextract/'.basename(__FILE__, '.phar'); +self::$temp = $temp; +self::$origdir = getcwd(); +@mkdir($temp, 0777, true); +$temp = realpath($temp); + +if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) { +self::_removeTmpFiles($temp, getcwd()); +@mkdir($temp, 0777, true); +@file_put_contents($temp . '/' . md5_file(__FILE__), ''); + +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); + +if ($path[strlen($path) - 1] == '/') { +@mkdir($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +} +} + +chdir($temp); + +if (!$return) { +include self::START; +} +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) { +return $var; +} +if (is_dir('/temp') || mkdir('/temp')) { +return realpath('/temp'); +} +return false; +} +if ($var = getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); + $l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; + +for ($i = 0; $i < $info[1]; $i++) { + $len = unpack('V', substr($m, $start, 4)); +$start += 4; + $savepath = substr($m, $start, $len[1]); +$start += $len[1]; + $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; + +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} + +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} + +if (strlen($data) != $entry[0]) { +die("Invalid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} + +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Invalid internal .phar file (checksum error)"); +} + +return $data; +} + +static function _removeTmpFiles($temp, $origdir) +{ +chdir($temp); + +foreach (glob('*') as $f) { +if (file_exists($f)) { +is_dir($f) ? @rmdir($f) : @unlink($f); +if (file_exists($f) && is_dir($f)) { +self::_removeTmpFiles($f, getcwd()); +} +} +} + +@rmdir($temp); +clearstatcache(); +chdir($origdir); +} +} + +Extract_Phar::go(); +__HALT_COMPILER(); ?> +" +============================================================================ +============================================================================ +int(7044) +Illegal filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed +===DONE=== diff --git a/ext/phar/tests/phar_setsignaturealgo1.phpt b/ext/phar/tests/phar_setsignaturealgo1.phpt new file mode 100644 index 0000000000..edc032e7be --- /dev/null +++ b/ext/phar/tests/phar_setsignaturealgo1.phpt @@ -0,0 +1,69 @@ +--TEST-- +Phar::setSignatureAlgorithm() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if ( extension_loaded("hash")) die("skip extension hash conflicts"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar'); +$p['file1.txt'] = 'hi'; +var_dump($p->getSignature()); +$p->setSignatureAlgorithm(Phar::MD5); +var_dump($p->getSignature()); +$p->setSignatureAlgorithm(Phar::SHA1); +var_dump($p->getSignature()); +try { +$p->setSignatureAlgorithm(Phar::SHA256); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +try { +$p->setSignatureAlgorithm(Phar::SHA512); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +try { +$p->setSignatureAlgorithm(Phar::PGP); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/brandnewphar.phar'); +?> +--EXPECTF-- +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(3) "MD5" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +string (82) "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled" +string (82) "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled" +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +===DONE=== diff --git a/ext/phar/tests/phar_setsignaturealgo2.phpt b/ext/phar/tests/phar_setsignaturealgo2.phpt new file mode 100644 index 0000000000..cc83281b22 --- /dev/null +++ b/ext/phar/tests/phar_setsignaturealgo2.phpt @@ -0,0 +1,79 @@ +--TEST-- +Phar::setSupportedSignatures() with hash +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("hash")) die("skip extension hash required"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar'); +$p['file1.txt'] = 'hi'; +var_dump($p->getSignature()); +$p->setSignatureAlgorithm(Phar::MD5); +var_dump($p->getSignature()); +$p->setSignatureAlgorithm(Phar::SHA1); +var_dump($p->getSignature()); +try { +$p->setSignatureAlgorithm(Phar::SHA256); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +try { +$p->setSignatureAlgorithm(Phar::SHA512); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +try { +$p->setSignatureAlgorithm(Phar::PGP); +var_dump($p->getSignature()); +} catch (Exception $e) { +echo $e->getMessage(); +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/brandnewphar.phar'); +?> +--EXPECTF-- +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(3) "MD5" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(7) "SHA-256" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(7) "SHA-512" +} +array(2) { + ["hash"]=> + string(%d) "%s" + ["hash_type"]=> + string(5) "SHA-1" +} +===DONE=== diff --git a/ext/phar/tests/phar_stub.phpt b/ext/phar/tests/phar_stub.phpt new file mode 100644 index 0000000000..ed306816e2 --- /dev/null +++ b/ext/phar/tests/phar_stub.phpt @@ -0,0 +1,92 @@ +--TEST-- +Phar::setStub() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; +$fp = fopen($fname, 'rb'); +//// 1 +echo fread($fp, strlen($file)) . "\n"; +fclose($fp); +$phar = new Phar($fname); +$file = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>'; + +//// 2 +$phar->setStub($file); +$fp = fopen($fname, 'rb'); +echo fread($fp, strlen($file)) . "\n"; +fclose($fp); + +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php'; +$file = '<?php echo "third stub\n"; __HALT_COMPILER(); ?>'; +$fp = fopen($fname2, 'wb'); +fwrite($fp, $file); +fclose($fp); +$fp = fopen($fname2, 'rb'); + +//// 3 +$phar->setStub($fp); +fclose($fp); + +$fp = fopen($fname, 'rb'); +echo fread($fp, strlen($file)) . "\n"; +fclose($fp); + +$fp = fopen($fname2, 'ab'); +fwrite($fp, 'booya'); +fclose($fp); +echo file_get_contents($fname2) . "\n"; + +$fp = fopen($fname2, 'rb'); + +//// 4 +$phar->setStub($fp, strlen($file)); +fclose($fp); + +$fp = fopen($fname, 'rb'); +echo fread($fp, strlen($file)) . "\n"; +if (fread($fp, strlen('booya')) == 'booya') { + echo 'failed - copied booya'; +} +fclose($fp); +$phar['testing'] = 'hi'; + +// ensure stub is not overwritten +$fp = fopen($fname, 'rb'); +echo fread($fp, strlen($file)) . "\n"; +if (fread($fp, strlen('booya')) == 'booya') { + echo 'failed - copied booya'; +} +fclose($fp); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php'); +__HALT_COMPILER(); +?> +--EXPECT-- +<?php echo "first stub\n"; __HALT_COMPILER(); ?> +<?php echo "second stub\n"; __HALT_COMPILER(); ?> +<?php echo "third stub\n"; __HALT_COMPILER(); ?> +<?php echo "third stub\n"; __HALT_COMPILER(); ?>booya +<?php echo "third stub\n"; __HALT_COMPILER(); ?> +<?php echo "third stub\n"; __HALT_COMPILER(); ?> +===DONE=== diff --git a/ext/phar/tests/phar_stub_error.phpt b/ext/phar/tests/phar_stub_error.phpt new file mode 100755 index 0000000000..99f313bc2f --- /dev/null +++ b/ext/phar/tests/phar_stub_error.phpt @@ -0,0 +1,56 @@ +--TEST-- +Phar::setStub()/getStub() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +$newstub = '<?php echo "second stub\n"; _x_HALT_COMPILER(); ?>'; +try +{ + $phar->setStub($newstub); +} +catch(exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +$phar->stopBuffering(); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__HALT_COMPILER(); +?> +--EXPECTF-- +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +bool(true) +Exception: illegal stub for phar "%sphar_stub_error.phar.php" +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +bool(true) +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_stub_write.phpt b/ext/phar/tests/phar_stub_write.phpt new file mode 100755 index 0000000000..9e5d6d5635 --- /dev/null +++ b/ext/phar/tests/phar_stub_write.phpt @@ -0,0 +1,64 @@ +--TEST-- +Phar::setStub()/getStub() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +$stub = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>'; +$sexp = $stub . "\r\n"; + +$phar->setStub($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); +$phar->stopBuffering(); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); + +$phar = new Phar($fname); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__HALT_COMPILER(); +?> +--EXPECT-- +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +bool(true) +string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?> +" +bool(false) +bool(true) +string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?> +" +bool(false) +bool(true) +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_stub_write_file.phpt b/ext/phar/tests/phar_stub_write_file.phpt new file mode 100755 index 0000000000..c5a0a1eba9 --- /dev/null +++ b/ext/phar/tests/phar_stub_write_file.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar::setStub()/getStub() from file +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +allow_url_fopen=1 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +$stub = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>'; +$sexp = $stub . "\r\n"; +$stub = fopen('data://,'.$stub, 'r'); +$phar->setStub($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); +$phar->stopBuffering(); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); + +$phar = new Phar($fname); +var_dump($phar->getStub() == $stub); +var_dump($phar->getStub() == $sexp); + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); +__HALT_COMPILER(); +?> +--EXPECT-- +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +bool(true) +string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?> +" +bool(false) +bool(true) +string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?> +" +bool(false) +bool(true) +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_unlinkarchive.phpt b/ext/phar/tests/phar_unlinkarchive.phpt new file mode 100644 index 0000000000..910ef873d2 --- /dev/null +++ b/ext/phar/tests/phar_unlinkarchive.phpt @@ -0,0 +1,108 @@ +--TEST-- +Phar::unlinkArchive() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php + +try { +Phar::unlinkArchive(""); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pdname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; + +try { +Phar::unlinkArchive($fname); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +file_put_contents($pdname, 'blahblah'); +try { +Phar::unlinkArchive($pdname); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +Phar::unlinkArchive(array()); + +$pname = 'phar://' . $fname; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip'; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip'; +$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'files/phar_test.inc'; + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); +try { +Phar::unlinkArchive($fname); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +$phar = $phar->convertToExecutable(Phar::ZIP); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); + +copy($fname2, $fname3); + +$phar = new Phar($fname3); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); + +Phar::unlinkArchive($fname); +var_dump(file_exists($fname)); +$phar = new Phar($fname); +var_dump(count($phar)); +$phar['evil.php'] = '<?php +try { +Phar::unlinkArchive(Phar::running(false)); +} catch (Exception $e) {echo $e->getMessage(),"\n";} +var_dump(Phar::running(false)); +include Phar::running(true) . "/another.php"; +?>'; +$phar['another.php'] = "hi\n"; +unset($phar); +include $pname . '/evil.php'; +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); +__HALT_COMPILER(); +?> +--EXPECTF-- +Unknown phar archive "" +Unknown phar archive "%sphar_unlinkarchive.phar" +Unknown phar archive "%sphar_unlinkarchive.phar.tar": internal corruption of phar "%sphar_unlinkarchive.phar.tar" (truncated entry) + +Warning: Phar::unlinkArchive() expects parameter 1 to be string, array given in %sphar_unlinkarchive.php on line %d +bool(false) +string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>" +phar archive "%sphar_unlinkarchive.phar" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive() +bool(true) +string(60) "<?php // zip-based phar archive stub file +__HALT_COMPILER();" +bool(true) +string(60) "<?php // zip-based phar archive stub file +__HALT_COMPILER();" +bool(false) +int(0) +phar archive "%sphar_unlinkarchive.phar" cannot be unlinked from within itself +string(%d) "%sphar_unlinkarchive.phar" +hi +===DONE=== diff --git a/ext/phar/tests/pharfileinfo_chmod.phpt b/ext/phar/tests/pharfileinfo_chmod.phpt new file mode 100644 index 0000000000..e99be5d6b9 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_chmod.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: PharFileInfo::chmod extra code coverage +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; + +$phar = new Phar($fname); + +$phar['a/b'] = 'hi there'; + +$b = $phar['a/b']; +try { +$phar['a']->chmod(066); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +$b->chmod(array()); +lstat($pname . '/a/b'); // sets BG(CurrentLStatFile) +$b->chmod(0666); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +--EXPECTF-- +Phar entry "a" is a temporary directory (not an actual entry in the archive), cannot chmod + +Warning: PharFileInfo::chmod() expects parameter 1 to be long, array given in %spharfileinfo_chmod.php on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/pharfileinfo_compression.phpt b/ext/phar/tests/pharfileinfo_compression.phpt new file mode 100644 index 0000000000..fbac499127 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_compression.phpt @@ -0,0 +1,94 @@ +--TEST-- +Phar: PharFileInfo compression-related methods +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?> +<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; + +$phar = new Phar($fname); + +$phar['a/b'] = 'hi there'; + +$b = $phar['a/b']; + +$b->isCompressed(array()); +try { +$b->isCompressed(25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$b->compress(25); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$tar = $phar->convertToData(Phar::TAR); + +$c = $tar['a/b']; +try { +$c->compress(Phar::GZ); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$phar['a']->compress(Phar::GZ); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 1); +try { +$b->compress(Phar::GZ); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 0); +var_dump($b->compress(Phar::GZ)); +var_dump($b->compress(Phar::GZ)); +var_dump($b->compress(Phar::BZ2)); +var_dump($b->compress(Phar::BZ2)); + +echo "decompress\n"; + +ini_set('phar.readonly', 1); +try { +$phar['a/b']->decompress(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly', 0); +try { +$phar['a']->decompress(); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +var_dump($b->decompress()); +var_dump($b->decompress()); + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?> +--EXPECTF-- +Warning: PharFileInfo::isCompressed() expects parameter 1 to be long, array given in %spharfileinfo_compression.php on line 11 +Unknown compression type specified +Unknown compression type specified +Cannot compress with Gzip compression, not possible with tar-based phar archives +Phar entry is a directory, cannot set compression +Phar is readonly, cannot change compression +bool(true) +bool(true) +bool(true) +bool(true) +decompress +Phar is readonly, cannot decompress +Phar entry is a directory, cannot set compression +bool(true) +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/pharfileinfo_construct.phpt b/ext/phar/tests/pharfileinfo_construct.phpt new file mode 100644 index 0000000000..480c1222c4 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_construct.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar: PharFileInfo::__construct +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; + +try { +file_put_contents($fname, 'blah'); +$a = new PharFileInfo($pname . '/oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +unlink($fname); +} + +$a = new PharFileInfo(array()); + +$a = new Phar($fname); +$a['a'] = 'hi'; +$b = $a['a']; + +try { +$a = new PharFileInfo($pname . '/oops/I/do/not/exist'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +try { +$b->__construct('oops'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +try { +$a = new PharFileInfo(__FILE__); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +--EXPECTF-- +Cannot open phar file 'phar://%spharfileinfo_construct.phar/oops': internal corruption of phar "%spharfileinfo_construct.phar" (truncated entry) + +Warning: PharFileInfo::__construct() expects parameter 1 to be string, array given in %spharfileinfo_construct.php on line %d +Cannot access phar file entry '/oops/I/do/not/exist' in archive '%spharfileinfo_construct.phar' +Cannot call constructor twice +'%spharfileinfo_construct.php' is not a valid phar archive URL (must have at least phar://filename.phar) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/pharfileinfo_destruct.phpt b/ext/phar/tests/pharfileinfo_destruct.phpt new file mode 100644 index 0000000000..48a58c0d09 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_destruct.phpt @@ -0,0 +1,25 @@ +--TEST-- +Phar: PharFileInfo::__destruct +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; + +$a = new Phar($fname); +$a['a/subdir/here'] = 'hi'; + +$b = new PharFileInfo($pname . '/a/subdir'); +unset($b); + +$b = new PharFileInfo($pname . '/a/subdir/here'); +unset($b); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +--EXPECTF-- +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/pharfileinfo_getcrc32.phpt b/ext/phar/tests/pharfileinfo_getcrc32.phpt new file mode 100644 index 0000000000..dfa12f4ca4 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_getcrc32.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: PharFileInfo::getCRC32 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +// compressed file length does not match incompressed lentgh for an uncompressed file + +$files = array(); +$files['a/subdir/here'] = array('cont'=>'a','ulen'=>1,'clen'=>1);; +include 'files/phar_test.inc'; + +$b = new PharFileInfo($pname . '/a/subdir'); +try { +var_dump($b->getCRC32()); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} + +$b = new PharFileInfo($pname . '/a/subdir/here'); +try { +var_dump($b->getCRC32()); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +$a = file_get_contents($pname . '/a/subdir/here'); +try { +var_dump($b->getCRC32()); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +--EXPECTF-- +Phar entry is a directory, does not have a CRC +Phar entry was not CRC checked +int(%s) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/pharfileinfo_setmetadata.phpt b/ext/phar/tests/pharfileinfo_setmetadata.phpt new file mode 100644 index 0000000000..8589fcb1d8 --- /dev/null +++ b/ext/phar/tests/pharfileinfo_setmetadata.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar: PharFileInfo::setMetadata/delMetadata extra code coverage +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$pname = 'phar://' . $fname; + +$phar = new Phar($fname); + +$phar['a/b'] = 'hi there'; +$tar = $phar->convertToData(Phar::TAR); + +$b = $phar['a/b']; +try { +$tar['a/b']->setMetadata('hi'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$tar['a/b']->delMetadata(); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$phar['a']->setMetadata('hi'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$phar['a']->delMetadata(); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +ini_set('phar.readonly', 1); +try { +$b->setMetadata('hi'); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +try { +$b->delMetadata(); +} catch (Exception $e) { +echo $e->getMessage(), "\n"; +} +ini_set('phar.readonly', 0); +$b->setMetadata(1,2,3); +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?> +--EXPECTF-- +Cannot set metadata, not possible with tar-based phar archives +Cannot delete metadata, not possible with tar-based phar archives +Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata +Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata +Write operations disabled by phar.readonly INI setting +Write operations disabled by phar.readonly INI setting + +Warning: PharFileInfo::setMetadata() expects exactly 1 parameter, 3 given in %spharfileinfo_setmetadata.php on line %d +===DONE=== diff --git a/ext/phar/tests/phpinfo_001.phpt b/ext/phar/tests/phpinfo_001.phpt new file mode 100644 index 0000000000..7b31185827 --- /dev/null +++ b/ext/phar/tests/phpinfo_001.phpt @@ -0,0 +1,59 @@ +--TEST-- +Phar: phpinfo display 1 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +phpinfo(INFO_MODULES); +ini_set('phar.readonly',1); +ini_set('phar.require_hash',1); +phpinfo(INFO_MODULES); +?> +===DONE=== +--EXPECTF-- +%aPhar + +Phar: PHP Archive support => enabled +Phar EXT version => %s +Phar API version => 1.1.1 +CVS revision => %sRevision: %s $ +Phar-based phar archives => enabled +Tar-based phar archives => enabled +ZIP-based phar archives => enabled +gzip compression => enabled +bzip2 compression => enabled + + +Phar based on pear/PHP_Archive, original concept by Davey Shafik. +Phar fully realized by Gregory Beaver and Marcus Boerger. +Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle. +Directive => Local Value => Master Value +phar.readonly => Off => Off +phar.require_hash => Off => Off +%a +Phar + +Phar: PHP Archive support => enabled +Phar EXT version => %s +Phar API version => 1.1.1 +CVS revision => %sRevision: %s $ +Phar-based phar archives => enabled +Tar-based phar archives => enabled +ZIP-based phar archives => enabled +gzip compression => enabled +bzip2 compression => enabled + + +Phar based on pear/PHP_Archive, original concept by Davey Shafik. +Phar fully realized by Gregory Beaver and Marcus Boerger. +Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle. +Directive => Local Value => Master Value +phar.readonly => On => Off +phar.require_hash => On => Off +%a +===DONE=== diff --git a/ext/phar/tests/phpinfo_002.phpt b/ext/phar/tests/phpinfo_002.phpt new file mode 100644 index 0000000000..1e0e567aff --- /dev/null +++ b/ext/phar/tests/phpinfo_002.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar: phpinfo display 2 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=1 +--FILE-- +<?php +phpinfo(INFO_MODULES); +?> +===DONE=== +--EXPECTF-- +%a +Phar + +Phar: PHP Archive support => enabled +Phar EXT version => %s +Phar API version => 1.1.1 +CVS revision => %sRevision: %s $ +Phar-based phar archives => enabled +Tar-based phar archives => enabled +ZIP-based phar archives => enabled +gzip compression => enabled +bzip2 compression => enabled + + +Phar based on pear/PHP_Archive, original concept by Davey Shafik. +Phar fully realized by Gregory Beaver and Marcus Boerger. +Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle. +Directive => Local Value => Master Value +phar.readonly => On => On +phar.require_hash => On => On +%a +===DONE=== diff --git a/ext/phar/tests/phpinfo_003.phpt b/ext/phar/tests/phpinfo_003.phpt new file mode 100644 index 0000000000..5894c83ea8 --- /dev/null +++ b/ext/phar/tests/phpinfo_003.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar: phpinfo display 3 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (extension_loaded("zlib")) die("skip zlib loaded"); ?> +<?php if (extension_loaded("bz2")) die("skip bz2 loaded"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=1 +--FILE-- +<?php +phpinfo(INFO_MODULES); +?> +===DONE=== +--EXPECTF-- +%a +Phar + +Phar: PHP Archive support => enabled +Phar EXT version => %s +Phar API version => 1.1.1 +CVS revision => $Revision$ +Phar-based phar archives => enabled +Tar-based phar archives => enabled +ZIP-based phar archives => enabled +gzip compression => disabled (install ext/zlib) +bzip2 compression => disabled (install pecl/bz2) + + +Phar based on pear/PHP_Archive, original concept by Davey Shafik. +Phar fully realized by Gregory Beaver and Marcus Boerger. +Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle. +Directive => Local Value => Master Value +phar.readonly => On => On +phar.require_hash => On => On +%a +===DONE=== diff --git a/ext/phar/tests/phpinfo_004.phpt b/ext/phar/tests/phpinfo_004.phpt new file mode 100644 index 0000000000..1dbccda889 --- /dev/null +++ b/ext/phar/tests/phpinfo_004.phpt @@ -0,0 +1,66 @@ +--TEST-- +Phar: phpinfo display 4 +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?> +<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--POST-- +a=b +--FILE-- +<?php +phpinfo(INFO_MODULES); +ini_set('phar.readonly',1); +ini_set('phar.require_hash',1); +phpinfo(INFO_MODULES); +?> +===DONE=== +--EXPECTF-- +%a<br /> +<h2><a name="module_Phar">Phar</a></h2> +<table border="0" cellpadding="3" width="600"> +<tr class="h"><th>Phar: PHP Archive support</th><th>enabled</th></tr> +<tr><td class="e">Phar EXT version </td><td class="v">%s </td></tr> +<tr><td class="e">Phar API version </td><td class="v">1.1.1 </td></tr> +<tr><td class="e">CVS revision </td><td class="v">%sRevision: %s $ </td></tr> +<tr><td class="e">Phar-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">Tar-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">ZIP-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">gzip compression </td><td class="v">enabled </td></tr> +<tr><td class="e">bzip2 compression </td><td class="v">enabled </td></tr> +</table><br /> +<table border="0" cellpadding="3" width="600"> +<tr class="v"><td> +Phar based on pear/PHP_Archive, original concept by Davey Shafik.<br />Phar fully realized by Gregory Beaver and Marcus Boerger.<br />Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.</td></tr> +</table><br /> +<table border="0" cellpadding="3" width="600"> +<tr class="h"><th>Directive</th><th>Local Value</th><th>Master Value</th></tr> +<tr><td class="e">phar.readonly</td><td class="v">Off</td><td class="v">Off</td></tr> +<tr><td class="e">phar.require_hash</td><td class="v">Off</td><td class="v">Off</td></tr> +</table><br /> +%a<br /> +<h2><a name="module_Phar">Phar</a></h2> +<table border="0" cellpadding="3" width="600"> +<tr class="h"><th>Phar: PHP Archive support</th><th>enabled</th></tr> +<tr><td class="e">Phar EXT version </td><td class="v">%s </td></tr> +<tr><td class="e">Phar API version </td><td class="v">1.1.1 </td></tr> +<tr><td class="e">CVS revision </td><td class="v">%sRevision: %s $ </td></tr> +<tr><td class="e">Phar-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">Tar-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">ZIP-based phar archives </td><td class="v">enabled </td></tr> +<tr><td class="e">gzip compression </td><td class="v">enabled </td></tr> +<tr><td class="e">bzip2 compression </td><td class="v">enabled </td></tr> +</table><br /> +<table border="0" cellpadding="3" width="600"> +<tr class="v"><td> +Phar based on pear/PHP_Archive, original concept by Davey Shafik.<br />Phar fully realized by Gregory Beaver and Marcus Boerger.<br />Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.</td></tr> +</table><br /> +<table border="0" cellpadding="3" width="600"> +<tr class="h"><th>Directive</th><th>Local Value</th><th>Master Value</th></tr> +<tr><td class="e">phar.readonly</td><td class="v">On</td><td class="v">Off</td></tr> +<tr><td class="e">phar.require_hash</td><td class="v">On</td><td class="v">Off</td></tr> +</table><br /> +%a<br /> +</div></body></html>===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/readfile.phpt b/ext/phar/tests/readfile.phpt new file mode 100644 index 0000000000..60fdad1792 --- /dev/null +++ b/ext/phar/tests/readfile.phpt @@ -0,0 +1,30 @@ +--TEST-- +Phar: test readfile() interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$a = new Phar($fname); +$a['index.php'] = '<?php +readfile("dir/file1.txt"); +readfile("file1.txt", true); +?>'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub('<?php +Phar::interceptFileFuncs(); +set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECT-- +hihi===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/readfile_edgecases.phpt b/ext/phar/tests/readfile_edgecases.phpt new file mode 100644 index 0000000000..1a78d7b5b0 --- /dev/null +++ b/ext/phar/tests/readfile_edgecases.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar: test edge cases of readfile() function interception +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; + +readfile(array()); +chdir(dirname(__FILE__)); +file_put_contents($fname, "blah\n"); +file_put_contents("foob", "test\n"); +readfile($fname); +unlink($fname); +mkdir($pname . '/oops'); +file_put_contents($pname . '/foo/hi', '<?php +readfile("foo/" . basename(__FILE__)); +$context = stream_context_create(); +readfile("foob"); +set_include_path("' . addslashes(dirname(__FILE__)) . '"); +readfile("foob", true); +readfile("./hi", 0, $context); +readfile("../oops"); +?> +'); +include $pname . '/foo/hi'; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +<?php rmdir(dirname(__FILE__) . '/poo'); ?> +<?php unlink(dirname(__FILE__) . '/foob'); ?> +--EXPECTF-- +Warning: readfile() expects parameter 1 to be string, array given in %sreadfile_edgecases.php on line %d +blah +<?php +readfile("foo/" . basename(__FILE__)); +$context = stream_context_create(); +readfile("foob"); +set_include_path("%stests"); +readfile("foob", true); +readfile("./hi", 0, $context); +readfile("../oops"); +?> +test +test +<?php +readfile("foo/" . basename(__FILE__)); +$context = stream_context_create(); +readfile("foob"); +set_include_path("%stests"); +readfile("foob", true); +readfile("./hi", 0, $context); +readfile("../oops"); +?> + +Warning: readfile(phar://%sreadfile_edgecases.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sreadfile_edgecases.phar.php/foo/hi on line %d +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/refcount1.phpt b/ext/phar/tests/refcount1.phpt new file mode 100644 index 0000000000..234d49111c --- /dev/null +++ b/ext/phar/tests/refcount1.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (version_compare(PHP_VERSION, "5.3", "<")) die("skip requires 5.3 or later"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php __HALT_COMPILER(); ?>"; + +$files = array(); +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +include 'files/phar_test.inc'; + +$fp = fopen($pname . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); +echo "===CLOSE===\n"; +$p = new Phar($fname); +$b = fopen($pname . '/b/c.php', 'rb'); +$a = $p['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($pname . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $pname . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.php/b" + ["fileName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.php/b/c.php" +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.php", has open file pointers, cannot unlink in %srefcount1.php on line %d +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.php/b" + ["fileName":"SplFileInfo":private]=> + string(%s) "phar://%srefcount1.phar.php/b/c.php" +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/refcount1_5_2.phpt b/ext/phar/tests/refcount1_5_2.phpt new file mode 100755 index 0000000000..bf2c2b76b3 --- /dev/null +++ b/ext/phar/tests/refcount1_5_2.phpt @@ -0,0 +1,64 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +<?php if (version_compare(PHP_VERSION, "5.3", ">")) die("skip requires 5.2 or earlier"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$alias = 'phar://' . $fname; + +$phar = new Phar($fname); +$phar->setStub("<?php __HALT_COMPILER(); ?>"); +$phar->setAlias('hio'); + +$files = array(); + +$files['a.php'] = '<?php echo "This is a\n"; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); + +echo "===CLOSE===\n"; + +$b = fopen($alias . '/b/c.php', 'rb'); +$a = $phar['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($alias . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?> +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/rename.phpt b/ext/phar/tests/rename.phpt new file mode 100644 index 0000000000..c73c98ec81 --- /dev/null +++ b/ext/phar/tests/rename.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: rename test +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$pname = 'phar://' . $fname; +$file = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$files = array(); +$files['a'] = 'a'; +include 'files/phar_test.inc'; +include $fname; + +echo file_get_contents($pname . '/a') . "\n"; +rename($pname . '/a', $pname . '/b'); +echo file_get_contents($pname . '/b') . "\n"; +echo file_get_contents($pname . '/a') . "\n"; +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +a +a + +Warning: file_get_contents(phar://%srename.phar.php/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.php" in %srename.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/security.phpt b/ext/phar/tests/security.phpt new file mode 100644 index 0000000000..2d54db7908 --- /dev/null +++ b/ext/phar/tests/security.phpt @@ -0,0 +1,36 @@ +--TEST-- +Phar: test to ensure phar.readonly cannot be circumvented +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.php'; +$a = new Phar($fname); +$a->setStub('<?php +Phar::mapPhar(); +$phar = new Phar(__FILE__); +var_dump($phar->isWritable()); +try { +$phar["b"] = "should not work!"; +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +__HALT_COMPILER(); +?>'); +$a['hi'] = 'hi'; +unset($a); +copy($fname, $fname2); +Phar::unlinkArchive($fname); +ini_set('phar.readonly', 1); +include $fname2; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.php'); ?> +--EXPECT-- +bool(false) +Write operations disabled by INI setting +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/stat.phpt b/ext/phar/tests/stat.phpt new file mode 100644 index 0000000000..020fc24f86 --- /dev/null +++ b/ext/phar/tests/stat.phpt @@ -0,0 +1,215 @@ +--TEST-- +Phar: test stat function interceptions +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--INI-- +phar.require_hash=1 +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +var_dump(stat("")); + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$a = new Phar($fname); +$a['index.php'] = '<?php +echo "stat\n"; +var_dump(stat("dir/file1.txt")); +echo "lstat\n"; +var_dump(lstat("dir/file1.txt")); +echo "fileperms\n"; +var_dump(fileperms("dir/file1.txt")); +echo "fileinode\n"; +var_dump(fileinode("dir/file1.txt")); +echo "filesize\n"; +var_dump(filesize("dir/file1.txt")); +echo "fileowner\n"; +var_dump(fileowner("dir/file1.txt")); +echo "filegroup\n"; +var_dump(filegroup("dir/file1.txt")); +echo "filemtime\n"; +var_dump(filemtime("dir/file1.txt")); +echo "fileatime\n"; +var_dump(fileatime("dir/file1.txt")); +echo "filectime\n"; +var_dump(filectime("dir/file1.txt")); +echo "filetype\n"; +var_dump(filetype("dir/file1.txt")); +echo "is_writable\n"; +var_dump(is_writable("dir/file1.txt")); +echo "is_writeable\n"; +var_dump(is_writeable("dir/file1.txt")); +echo "is_readable\n"; +var_dump(is_readable("dir/file1.txt")); +echo "is_executable\n"; +var_dump(is_executable("dir/file1.txt")); +echo "file_exists\n"; +var_dump(file_exists("dir/file1.txt")); +echo "is_dir\n"; +var_dump(is_dir("dir/file1.txt")); +echo "is_file\n"; +var_dump(is_file("dir/file1.txt")); +echo "is_link\n"; +var_dump(is_link("dir/file1.txt")); +?>'; +$a['dir/file1.txt'] = 'hi'; +$a['dir/file2.txt'] = 'hi2'; +$a['dir/file3.txt'] = 'hi3'; +$a->setStub('<?php +set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__); +include "index.php"; +__HALT_COMPILER();'); +include $fname; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +bool(false) +stat +array(26) { + [0]=> + int(12) + [1]=> + int(%d) + [2]=> + int(33206) + [3]=> + int(1) + [4]=> + int(0) + [5]=> + int(0) + [6]=> + int(%s) + [7]=> + int(2) + [8]=> + int(%d) + [9]=> + int(%d) + [10]=> + int(%d) + [11]=> + int(%s) + [12]=> + int(%s) + ["dev"]=> + int(12) + ["ino"]=> + int(%d) + ["mode"]=> + int(33206) + ["nlink"]=> + int(1) + ["uid"]=> + int(0) + ["gid"]=> + int(0) + ["rdev"]=> + int(%s) + ["size"]=> + int(2) + ["atime"]=> + int(%d) + ["mtime"]=> + int(%d) + ["ctime"]=> + int(%d) + ["blksize"]=> + int(%s) + ["blocks"]=> + int(%s) +} +lstat +array(26) { + [0]=> + int(12) + [1]=> + int(%d) + [2]=> + int(33206) + [3]=> + int(1) + [4]=> + int(0) + [5]=> + int(0) + [6]=> + int(%s) + [7]=> + int(2) + [8]=> + int(%d) + [9]=> + int(%d) + [10]=> + int(%d) + [11]=> + int(%s) + [12]=> + int(%s) + ["dev"]=> + int(12) + ["ino"]=> + int(%d) + ["mode"]=> + int(33206) + ["nlink"]=> + int(1) + ["uid"]=> + int(0) + ["gid"]=> + int(0) + ["rdev"]=> + int(%s) + ["size"]=> + int(2) + ["atime"]=> + int(%d) + ["mtime"]=> + int(%d) + ["ctime"]=> + int(%d) + ["blksize"]=> + int(%s) + ["blocks"]=> + int(%s) +} +fileperms +int(33206) +fileinode +int(%d) +filesize +int(2) +fileowner +int(0) +filegroup +int(0) +filemtime +int(%d) +fileatime +int(%d) +filectime +int(%d) +filetype +string(4) "file" +is_writable +bool(true) +is_writeable +bool(false) +is_readable +bool(true) +is_executable +bool(false) +file_exists +bool(true) +is_dir +bool(false) +is_file +bool(true) +is_link +bool(false) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/stat2.phpt b/ext/phar/tests/stat2.phpt new file mode 100644 index 0000000000..6e911028ca --- /dev/null +++ b/ext/phar/tests/stat2.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar: test stat function interceptions and is_file/is_link edge cases (PHP 5.2) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (substr(phpversion(), 0, 3) != '5.2') die("skip PHP 5.2 required for this test");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +is_file(); +is_link(); +var_dump(is_file(__FILE__)); + +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +copy(dirname(__FILE__) . '/tar/files/links.tar', $fname2); +$a = new PharData($fname2); +$b = $a->convertToExecutable(); +unset($a); +Phar::unlinkArchive($fname2); +$b['foo/stat.php'] = '<?php +echo "is_link\n"; +var_dump(is_link("./stat.php"),is_file("./stat.php"), is_link("./oops"), is_file("./oops")); +var_dump(is_link("testit/link"), filetype("testit/link"), filetype("testit"), is_file("testit/link")); +echo "not found\n"; +var_dump(is_link("notfound")); +echo "dir\n"; +var_dump(is_dir("./bar"), is_file("foo/bar/blah")); +?>'; +$b->addEmptyDir('foo/bar/blah'); +$b->setStub('<?php +include "phar://" . __FILE__ . "/foo/stat.php"; +__HALT_COMPILER();'); +include $fname3; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?> +--EXPECTF-- +Warning: Wrong parameter count for is_file() in %sstat2.php on line %d + +Warning: Wrong parameter count for is_link() in %sstat2.php on line %d +bool(true) +is_link +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +string(4) "link" +string(3) "dir" +bool(true) +not found +bool(false) +dir +bool(true) +bool(false) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/stat2_5.3.phpt b/ext/phar/tests/stat2_5.3.phpt new file mode 100644 index 0000000000..58ca54a16a --- /dev/null +++ b/ext/phar/tests/stat2_5.3.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar: test stat function interceptions and is_file/is_link edge cases (PHP 5.3+) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +<?php if (substr(phpversion(), 0, 3) == '5.2') die("skip PHP 5.3+ required for this test");?> +--INI-- +phar.readonly=0 +--FILE-- +<?php +Phar::interceptFileFuncs(); +is_file(); +is_link(); +var_dump(is_file(__FILE__)); + +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +copy(dirname(__FILE__) . '/tar/files/links.tar', $fname2); +$a = new PharData($fname2); +$b = $a->convertToExecutable(Phar::TAR, Phar::NONE, '.3.phar.tar'); +unset($a); +Phar::unlinkArchive($fname2); +$b['foo/stat.php'] = '<?php +echo "is_link\n"; +var_dump(is_link("./stat.php"),is_file("./stat.php"), is_link("./oops"), is_file("./oops")); +var_dump(is_link("testit/link"), filetype("testit/link"), filetype("testit"), is_file("testit/link")); +echo "not found\n"; +var_dump(is_link("notfound")); +echo "dir\n"; +var_dump(is_dir("./bar"), is_file("foo/bar/blah")); +?>'; +$b->addEmptyDir('foo/bar/blah'); +$b->setStub('<?php +include "phar://" . __FILE__ . "/foo/stat.php"; +__HALT_COMPILER();'); +include $fname3; +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?> +--EXPECTF-- +Warning: is_file() expects exactly 1 parameter, 0 given in %sstat2_5.3.php on line %d + +Warning: is_link() expects exactly 1 parameter, 0 given in %sstat2_5.3.php on line %d +bool(true) +is_link +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +string(4) "link" +string(3) "dir" +bool(true) +not found +bool(false) +dir +bool(true) +bool(false) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/033.phpt b/ext/phar/tests/tar/033.phpt new file mode 100644 index 0000000000..29223e49e3 --- /dev/null +++ b/ext/phar/tests/tar/033.phpt @@ -0,0 +1,50 @@ +--TEST-- +Phar::chmod tar-based +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://hio'; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); + +try { + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0777); + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0666); + var_dump($phar['a.php']->isExecutable()); + echo "test dir\n"; + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0000); + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0666); + var_dump($phar['test']->isReadable()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); +?> +--EXPECTF-- +bool(false) +bool(true) +bool(false) +test dir +bool(true) +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/033a.phpt b/ext/phar/tests/tar/033a.phpt new file mode 100644 index 0000000000..09b5446aec --- /dev/null +++ b/ext/phar/tests/tar/033a.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar::chmod tar-based +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://hio'; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +try { + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0777); + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0666); + var_dump($phar['a.php']->isExecutable()); + echo "test dir\n"; + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0000); + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0666); + var_dump($phar['test']->isReadable()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); +?> +--EXPECTF-- +bool(false) +Cannot modify permissions for file "a.php" in phar "%s033a.phar.tar", write operations are prohibited +===DONE=== diff --git a/ext/phar/tests/tar/alias_acrobatics.phpt b/ext/phar/tests/tar/alias_acrobatics.phpt new file mode 100644 index 0000000000..d08dc0467c --- /dev/null +++ b/ext/phar/tests/tar/alias_acrobatics.phpt @@ -0,0 +1,46 @@ +--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=== diff --git a/ext/phar/tests/tar/badalias.phpt b/ext/phar/tests/tar/badalias.phpt new file mode 100644 index 0000000000..441fc03ae7 --- /dev/null +++ b/ext/phar/tests/tar/badalias.phpt @@ -0,0 +1,25 @@ +--TEST-- +Phar: invalid aliases +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?> +<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?> +--FILE-- +<?php +$e = dirname(__FILE__) . '/files/'; +for ($i = 1; $i <= 5; $i++) { +try { +new Phar($e . "badalias$i.phar.tar"); +} catch (Exception $ee) { +echo $ee->getMessage(), "\n"; +} +} +?> +===DONE=== +--EXPECTF-- +phar error: invalid alias "hi/thereaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..." in tar-based phar "%sbadalias1.phar.tar" +phar error: invalid alias "hi\there" in tar-based phar "%sbadalias2.phar.tar" +phar error: invalid alias "hi;there" in tar-based phar "%sbadalias3.phar.tar" +phar error: invalid alias "hi:there" in tar-based phar "%sbadalias4.phar.tar" +phar error: tar-based phar "%sbadalias5.phar.tar" has alias that is larger than 511 bytes, cannot process +===DONE=== diff --git a/ext/phar/tests/tar/badchecksum.phpt b/ext/phar/tests/tar/badchecksum.phpt new file mode 100644 index 0000000000..fae19b153d --- /dev/null +++ b/ext/phar/tests/tar/badchecksum.phpt @@ -0,0 +1,30 @@ +--TEST-- +Phar: tar with bad checksum +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$pname = 'phar://' . $fname; + +include dirname(__FILE__) . '/files/corrupt_tarmaker.php.inc'; +$a = new corrupt_tarmaker($fname, 'none'); +$a->init(); +$a->addFile('hithere', 'contents', null, 'checksum'); +$a->close(); + +try { + $p = new PharData($fname); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); +?> +--EXPECTF-- +phar error: "%sbadchecksum.tar" is a corrupted tar file (checksum mismatch of file "hithere") +===DONE=== diff --git a/ext/phar/tests/tar/bignames.phpt b/ext/phar/tests/tar/bignames.phpt new file mode 100644 index 0000000000..19d5f638e1 --- /dev/null +++ b/ext/phar/tests/tar/bignames.phpt @@ -0,0 +1,35 @@ +--TEST-- +Phar: tar with huge filenames +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.tar'; +$pname = 'phar://' . $fname; + +$p1 = new PharData($fname); +$p1[str_repeat('a', 101)] = 'hi'; +$p1[str_repeat('a', 255)] = 'hi2'; +copy($fname, $fname2); +$p2 = new PharData($fname2); +echo $p2[str_repeat('a', 101)]->getContent() . "\n"; +echo $p2[str_repeat('a', 255)]->getContent() . "\n"; + +try { + $p2[str_repeat('a', 400)] = 'yuck'; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.tar'); +?> +--EXPECTF-- +hi +hi2 +tar-based phar "%sbignames.2.tar" cannot be created, filename "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" is too long for tar file format +===DONE=== diff --git a/ext/phar/tests/tar/create_new_and_modify.phpt b/ext/phar/tests/tar/create_new_and_modify.phpt new file mode 100644 index 0000000000..8062fda769 --- /dev/null +++ b/ext/phar/tests/tar/create_new_and_modify.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: create and modify tar-based phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php'; +$pname = 'phar://' . $fname; + +@unlink($fname); + +file_put_contents($pname . '/a.php', "brand new!\n"); + +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::TAR)); +$sig1 = md5_file($fname); + +include $pname . '/a.php'; + +file_put_contents($pname .'/a.php', "modified!\n"); +file_put_contents($pname .'/b.php', "another!\n"); + +$phar = new Phar($fname); +$sig2 = md5_file($fname); + +var_dump($sig1 != $sig2); + +include $pname . '/a.php'; +include $pname . '/b.php'; + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php'); ?> +--EXPECTF-- +bool(true) +brand new! +bool(true) +modified! +another! +===DONE=== diff --git a/ext/phar/tests/tar/create_new_phar_b.phpt b/ext/phar/tests/tar/create_new_phar_b.phpt new file mode 100644 index 0000000000..a608be4705 --- /dev/null +++ b/ext/phar/tests/tar/create_new_phar_b.phpt @@ -0,0 +1,27 @@ +--TEST-- +Phar: create a completely new tar-based phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=1 +phar.require_hash=1 +--FILE-- +<?php + +file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php', + 'brand new!'); +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- + +Warning: file_put_contents(phar://%screate_new_phar_b.phar.tar/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d + +Warning: include(phar://%screate_new_phar_b.phar.tar/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d + +Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.tar/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/tar/delete.phpt b/ext/phar/tests/tar/delete.phpt new file mode 100644 index 0000000000..32b2b1e28b --- /dev/null +++ b/ext/phar/tests/tar/delete.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: delete test, tar-based phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://' . $fname; +$stub = "<?php +Phar::mapPhar('hio'); +__HALT_COMPILER(); ?>"; + +$phar = new Phar($fname); +$phar['a'] = 'a'; +$phar->setStub($stub); +$phar->stopBuffering(); + +echo file_get_contents($alias . '/a') . "\n"; +$phar->delete('a'); +echo file_get_contents($alias . '/a') . "\n"; + +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- +a + +Warning: file_get_contents(phar://%sdelete.phar.tar/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.tar" in %sdelete.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/tar/delete_in_phar.phpt b/ext/phar/tests/tar/delete_in_phar.phpt new file mode 100644 index 0000000000..91ef4a2046 --- /dev/null +++ b/ext/phar/tests/tar/delete_in_phar.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: delete a file within a tar-based .phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://' . $fname; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; ?>'; +$phar['b.php'] = '<?php echo "This is b\n"; ?>'; +$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +$phar->setStub('<?php __HALT_COMPILER(); ?>'); +$phar->stopBuffering(); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +unlink($alias . '/b/c.php'); + +?> +===AFTER=== +<?php +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar.phar.tar/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.tar" in %sdelete_in_phar.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.tar/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d + +===DONE=== diff --git a/ext/phar/tests/tar/delete_in_phar_b.phpt b/ext/phar/tests/tar/delete_in_phar_b.phpt new file mode 100644 index 0000000000..2af1c66deb --- /dev/null +++ b/ext/phar/tests/tar/delete_in_phar_b.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: delete a file within a tar-based .phar +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://' . $fname; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; ?>'; +$phar['b.php'] = '<?php echo "This is b\n"; ?>'; +$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +$phar->setStub('<?php __HALT_COMPILER(); ?>'); +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +unlink($alias . '/b/c.php'); + +?> +===AFTER=== +<?php +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- +This is a +This is b +This is b/c + +Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d +===AFTER=== +This is a +This is b +This is b/c + +===DONE=== diff --git a/ext/phar/tests/tar/delete_in_phar_confirm.phpt b/ext/phar/tests/tar/delete_in_phar_confirm.phpt new file mode 100644 index 0000000000..707bcbd0ed --- /dev/null +++ b/ext/phar/tests/tar/delete_in_phar_confirm.phpt @@ -0,0 +1,52 @@ +--TEST-- +Phar: delete a file within a tar-based .phar (confirm disk file is changed) +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://' . $fname; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; ?>'; +$phar['b.php'] = '<?php echo "This is b\n"; ?>'; +$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>'; +$phar->setStub('<?php __HALT_COMPILER(); ?>'); +$phar->stopBuffering(); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +$md5 = md5_file($fname); +unlink($alias . '/b/c.php'); +clearstatcache(); +$md52 = md5_file($fname); +if ($md5 == $md52) echo 'file was not modified'; +?> +===AFTER=== +<?php +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php'; +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/b.php'; +include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/b/c.php'; +?> + +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?> +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar_confirm.phar.tar/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.tar" in %sdelete_in_phar_confirm.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.tar/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d + +===DONE=== diff --git a/ext/phar/tests/tar/dir.phpt b/ext/phar/tests/tar/dir.phpt new file mode 100644 index 0000000000..53bf65f9a7 --- /dev/null +++ b/ext/phar/tests/tar/dir.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: mkdir/rmdir test tar-based +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php'; +$pname = 'phar://' . $fname; +$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php'; +$pname2 = 'phar://' . $fname2; +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php'; +$pname3 = 'phar://' . $fname3; +$phar = new Phar($fname); +var_dump($phar->isFileFormat(Phar::TAR)); + +$phar->addEmptyDir('test'); +var_dump($phar['test']->isDir()); +var_dump($phar['test/']->isDir()); +copy($fname, $fname2); +mkdir($pname . '/another/dir/'); +var_dump($phar['another/dir']->isDir()); +rmdir($pname . '/another/dir/'); +copy($fname, $fname3); +clearstatcache(); +var_dump(file_exists($pname . '/another/dir/')); +var_dump(file_exists($pname2 . '/test/')); +var_dump(file_exists($pname3 . '/another/dir/')); +?> +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?> +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) diff --git a/ext/phar/tests/tar/exists_as_phar.phpt b/ext/phar/tests/tar/exists_as_phar.phpt new file mode 100644 index 0000000000..9a8cfc81f0 --- /dev/null +++ b/ext/phar/tests/tar/exists_as_phar.phpt @@ -0,0 +1,38 @@ +--TEST-- +Phar: phar-based phar named with ".tar" fails +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar'; +$tname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; +$alias = 'phar://hio'; + +$phar = new Phar($fname); +$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); +copy($fname, $tname); +$phar->setAlias('hio2'); + +try { + $p = new Phar($tname); +} 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') . '.phar'); +?> +--EXPECTF-- +phar tar error: "%sexists_as_phar.phar.tar" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar +===DONE=== diff --git a/ext/phar/tests/tar/files/badalias1.phar.tar b/ext/phar/tests/tar/files/badalias1.phar.tar new file mode 100644 index 0000000000..6cd4716d8f Binary files /dev/null and b/ext/phar/tests/tar/files/badalias1.phar.tar differ diff --git a/ext/phar/tests/tar/files/badalias2.phar.tar b/ext/phar/tests/tar/files/badalias2.phar.tar new file mode 100644 index 0000000000..5face85827 Binary files /dev/null and b/ext/phar/tests/tar/files/badalias2.phar.tar differ diff --git a/ext/phar/tests/tar/files/badalias3.phar.tar b/ext/phar/tests/tar/files/badalias3.phar.tar new file mode 100644 index 0000000000..ab36e1f343 Binary files /dev/null and b/ext/phar/tests/tar/files/badalias3.phar.tar differ diff --git a/ext/phar/tests/tar/files/badalias4.phar.tar b/ext/phar/tests/tar/files/badalias4.phar.tar new file mode 100644 index 0000000000..c54e31d4fc Binary files /dev/null and b/ext/phar/tests/tar/files/badalias4.phar.tar differ diff --git a/ext/phar/tests/tar/files/badalias5.phar.tar b/ext/phar/tests/tar/files/badalias5.phar.tar new file mode 100644 index 0000000000..dd52b6ac7d Binary files /dev/null and b/ext/phar/tests/tar/files/badalias5.phar.tar differ diff --git a/ext/phar/tests/tar/files/biglink.tar b/ext/phar/tests/tar/files/biglink.tar new file mode 100644 index 0000000000..43bbf58423 Binary files /dev/null and b/ext/phar/tests/tar/files/biglink.tar differ diff --git a/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc new file mode 100644 index 0000000000..b0eba6cc69 --- /dev/null +++ b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc @@ -0,0 +1,177 @@ +<?php +// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests +class corrupt_tarmaker +{ + /** + * Path to archive file + * + * @var string + */ + protected $archive; + /** + * Temporary stream used for creating the archive + * + * @var stream + */ + protected $tmp; + protected $path; + protected $compress; + function __construct($path, $compress = 'zlib') + { + $this->compress = $compress; + if ($compress === 'bz2' && !function_exists('bzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'bzip2 extension not available'); + } + if ($compress === 'zlib' && !function_exists('gzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'zlib extension not available'); + } + $this->path = $path; + } + + /** + * save a file inside this package + * + * This code is modified from Vincent Lascaux's File_Archive + * package, which is licensed under the LGPL license. + * @param string relative path within the package + * @param string|resource file contents or open file handle + */ + function addFile($path, $fileOrStream, $stat = null, $corrupt = null) + { + clearstatcache(); + if ($stat === null) { + if (is_resource($fileOrStream)) { + $stat = fstat($fileOrStream); + } else { + $stat = array( + 'mode' => 0x8000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => strlen($fileOrStream), + 'mtime' => time(), + ); + } + } + + $link = null; + if ($stat['mode'] & 0xA000 && $corrupt === 'symlink') { + $type = 2; // Symbolic Link + $link = $fileOrStream; + $stat['size'] = 0; + $fileOrStream = ''; + } else if ($stat['mode'] & 0xA000) { + $type = 1; // Link + $link = $fileOrStream; + $stat['size'] = 0; + $fileOrStream = ''; + } else if ($stat['mode'] & 0x4000) { + $type = 5; // Directory + } else if ($stat['mode'] & 0x8000) { + $type = 0; // Regular + } else { + $type = 9; // Unknown + } + + $filePrefix = ''; + if (strlen($path) > 255) { + throw new Exception( + "$path is too long, must be 255 characters or less" + ); + } else if (strlen($path) > 100) { + $filePrefix = substr($path, 0, strlen($path)-100); + $path = substr($path, -100); + } + + $block = pack('a100a8a8a8a12A12', + $path, + decoct($stat['mode']), + sprintf('%6s ',decoct($stat['uid'])), + sprintf('%6s ',decoct($stat['gid'])), + sprintf('%11s ',decoct($stat['size'])), + sprintf('%11s ',decoct($stat['mtime'])) + ); + + $blockend = pack('a1a100a6a2a32a32a8a8a155a12', + $type, + $link, + 'ustar', + '00', + 'Pyrus', + 'Pyrus', + '', + '', + $filePrefix, + ''); + + $checkheader = array_merge(str_split($block), str_split($blockend)); + if (!function_exists('_pear2tarchecksum')) { + function _pear2tarchecksum($a, $b) {return $a + ord($b);} + } + $checksum = 256; // 8 * ord(' '); + $checksum += array_reduce($checkheader, '_pear2tarchecksum'); + + if ($corrupt === 'checksum') $checksum++; + $checksum = pack('a8', sprintf('%6s ', decoct($checksum))); + + fwrite($this->tmp, $block . $checksum . $blockend, 512); + if (is_resource($fileOrStream)) { + stream_copy_to_stream($fileOrStream, $this->tmp); + if ($stat['size'] % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - $stat['size'] % 512)); + } + } else { + fwrite($this->tmp, $fileOrStream); + if (strlen($fileOrStream) && !isset($link) && strlen($fileOrStream) % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512)); + } + } + } + + /** + * Initialize the package creator + */ + function init() + { + switch ($this->compress) { + case 'zlib' : + $this->tmp = gzopen($this->path, 'wb'); + break; + case 'bz2' : + $this->tmp = bzopen($this->path, 'w'); + break; + case 'none' : + $this->tmp = fopen($this->path, 'wb'); + break; + default : + throw new Exception( + 'unknown compression type ' . $this->compress); + } + } + + /** + * Create an internal directory, creating parent directories as needed + * + * @param string $dir + */ + function mkdir($dir) + { + $this->addFile($dir, "", array( + 'mode' => 0x4000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => 0, + 'mtime' => time(), + )); + } + + /** + * Finish saving the package + */ + function close() + { + fwrite($this->tmp, pack('a1024', '')); + fclose($this->tmp); + } +} \ No newline at end of file diff --git a/ext/phar/tests/tar/files/frontcontroller.phar.inc b/ext/phar/tests/tar/files/frontcontroller.phar.inc new file mode 100644 index 0000000000..6f426e8864 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller.phar.inc @@ -0,0 +1,13 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a['index.php'] = 'here is my index'; +$a->setStub('<?php +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller.phar.tar b/ext/phar/tests/tar/files/frontcontroller.phar.tar new file mode 100644 index 0000000000..522d097845 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller10.phar.inc b/ext/phar/tests/tar/files/frontcontroller10.phar.inc new file mode 100644 index 0000000000..5b132fa117 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller10.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller10.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller10.phar.tar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI", "OOPSIE")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller10.phar.tar b/ext/phar/tests/tar/files/frontcontroller10.phar.tar new file mode 100644 index 0000000000..d43ed916a1 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller10.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller11.phar.inc b/ext/phar/tests/tar/files/frontcontroller11.phar.inc new file mode 100644 index 0000000000..2fa15f097e --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller11.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller11.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller11.phar.tar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array(array(), "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller11.phar.tar b/ext/phar/tests/tar/files/frontcontroller11.phar.tar new file mode 100644 index 0000000000..c8f98a1e78 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller11.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller12.phar.inc b/ext/phar/tests/tar/files/frontcontroller12.phar.inc new file mode 100644 index 0000000000..693ef0aa01 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller12.phar.inc @@ -0,0 +1,20 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller12.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller12.phar.tar'); +$a['index.php'] = '<?php +var_dump($_SERVER["PHP_SELF"]); +var_dump($_SERVER["SCRIPT_NAME"]); +var_dump($_SERVER["SCRIPT_FILENAME"]); +var_dump($_SERVER["REQUEST_URI"]); +var_dump($_SERVER["PHAR_PHP_SELF"]); +var_dump($_SERVER["PHAR_SCRIPT_NAME"]); +var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]); +var_dump($_SERVER["PHAR_REQUEST_URI"]); +'; +$a->setStub('<?php +Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI")); +Phar::webPhar(); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller12.phar.tar b/ext/phar/tests/tar/files/frontcontroller12.phar.tar new file mode 100644 index 0000000000..06e7e59b03 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller12.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller2.phar.inc b/ext/phar/tests/tar/files/frontcontroller2.phar.inc new file mode 100644 index 0000000000..8ae1171a38 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller2.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller2.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller2.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "a.php"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller2.phar.tar b/ext/phar/tests/tar/files/frontcontroller2.phar.tar new file mode 100644 index 0000000000..857b116890 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller2.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller3.phar.inc b/ext/phar/tests/tar/files/frontcontroller3.phar.inc new file mode 100644 index 0000000000..9729d0065b --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller3.phar.inc @@ -0,0 +1,18 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller3.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller3.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +function s($a) +{ + static $b = array("/hi" => "a.phps"); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "/index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller3.phar.tar b/ext/phar/tests/tar/files/frontcontroller3.phar.tar new file mode 100644 index 0000000000..f733884d12 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller3.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller4.phar.inc b/ext/phar/tests/tar/files/frontcontroller4.phar.inc new file mode 100644 index 0000000000..eb1d56f0d4 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller4.phar.inc @@ -0,0 +1,18 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller4.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller4.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +function s($a) +{ + static $b = array("/hi" => false); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller4.phar.tar b/ext/phar/tests/tar/files/frontcontroller4.phar.tar new file mode 100644 index 0000000000..5d11af499c Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller4.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller5.phar.inc b/ext/phar/tests/tar/files/frontcontroller5.phar.inc new file mode 100644 index 0000000000..d6204c7d97 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller5.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller5.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller5.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array(0 => "oops")); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller5.phar.tar b/ext/phar/tests/tar/files/frontcontroller5.phar.tar new file mode 100644 index 0000000000..e6e9015bf8 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller5.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller6.phar.inc b/ext/phar/tests/tar/files/frontcontroller6.phar.inc new file mode 100644 index 0000000000..66212d82e8 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller6.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller6.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller6.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array("blah" => 100)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller6.phar.tar b/ext/phar/tests/tar/files/frontcontroller6.phar.tar new file mode 100644 index 0000000000..d30b7ab9eb Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller6.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller7.phar.inc b/ext/phar/tests/tar/files/frontcontroller7.phar.inc new file mode 100644 index 0000000000..74adf2c008 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller7.phar.inc @@ -0,0 +1,12 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller7.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller7.phar.tar'); +$a['a.php'] = 'hio'; +$a['a.jpg'] = 'hio'; +$a['a.phps'] = '<?php function hio(){}'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array("blah" => null)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller7.phar.tar b/ext/phar/tests/tar/files/frontcontroller7.phar.tar new file mode 100644 index 0000000000..c7ccc940c1 Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller7.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller8.phar.inc b/ext/phar/tests/tar/files/frontcontroller8.phar.inc new file mode 100644 index 0000000000..f51a762806 --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller8.phar.inc @@ -0,0 +1,13 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller8.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller8.phar.tar'); +$a['a.phps'] = 'hio1'; +$a['a.jpg'] = 'hio2'; +$a['a.php'] = '<?php function hio(){}'; +$a['fronk.gronk'] = 'hio3'; +$a->setStub('<?php +Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller8.phar.tar b/ext/phar/tests/tar/files/frontcontroller8.phar.tar new file mode 100644 index 0000000000..98495717ce Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller8.phar.tar differ diff --git a/ext/phar/tests/tar/files/frontcontroller9.phar.inc b/ext/phar/tests/tar/files/frontcontroller9.phar.inc new file mode 100644 index 0000000000..758ce4ff4e --- /dev/null +++ b/ext/phar/tests/tar/files/frontcontroller9.phar.inc @@ -0,0 +1,14 @@ +<?php +@unlink(dirname(__FILE__) . '/frontcontroller9.phar.tar'); +$a = new Phar(dirname(__FILE__) . '/frontcontroller9.phar.tar'); +$a['a.phps'] = 'hio1'; +$a['a.jpg'] = 'hio2'; +$a['a.php'] = '<?php function hio(){}'; +$a['fronk.gronk'] = 'hio3'; +$a->setStub('<?php +Phar::mungServer(array()); +Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/tar/files/frontcontroller9.phar.tar b/ext/phar/tests/tar/files/frontcontroller9.phar.tar new file mode 100644 index 0000000000..481864c1cf Binary files /dev/null and b/ext/phar/tests/tar/files/frontcontroller9.phar.tar differ diff --git a/ext/phar/tests/tar/files/links.tar b/ext/phar/tests/tar/files/links.tar new file mode 100644 index 0000000000..6cd22df2bc Binary files /dev/null and b/ext/phar/tests/tar/files/links.tar differ diff --git a/ext/phar/tests/tar/files/make_invalid_tar.php.inc b/ext/phar/tests/tar/files/make_invalid_tar.php.inc new file mode 100644 index 0000000000..c18bd199b3 --- /dev/null +++ b/ext/phar/tests/tar/files/make_invalid_tar.php.inc @@ -0,0 +1,9 @@ +<?php +include dirname(__FILE__) . '/tarmaker.php.inc'; +class corrupter extends tarmaker { +function close() +{ + fwrite($this->tmp, 'oopsie'); + fclose($this->tmp); +} +} \ No newline at end of file diff --git a/ext/phar/tests/tar/files/subdirlink.tar b/ext/phar/tests/tar/files/subdirlink.tar new file mode 100644 index 0000000000..5463a4942d Binary files /dev/null and b/ext/phar/tests/tar/files/subdirlink.tar differ diff --git a/ext/phar/tests/tar/files/tarmaker.php.inc b/ext/phar/tests/tar/files/tarmaker.php.inc new file mode 100644 index 0000000000..902507881a --- /dev/null +++ b/ext/phar/tests/tar/files/tarmaker.php.inc @@ -0,0 +1,169 @@ +<?php +// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests +class tarmaker +{ + /** + * Path to archive file + * + * @var string + */ + protected $archive; + /** + * Temporary stream used for creating the archive + * + * @var stream + */ + protected $tmp; + protected $path; + protected $compress; + function __construct($path, $compress = 'zlib') + { + $this->compress = $compress; + if ($compress === 'bz2' && !function_exists('bzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'bzip2 extension not available'); + } + if ($compress === 'zlib' && !function_exists('gzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'zlib extension not available'); + } + $this->path = $path; + } + + /** + * save a file inside this package + * + * This code is modified from Vincent Lascaux's File_Archive + * package, which is licensed under the LGPL license. + * @param string relative path within the package + * @param string|resource file contents or open file handle + */ + function addFile($path, $fileOrStream, $stat = null) + { + clearstatcache(); + if ($stat === null) { + if (is_resource($fileOrStream)) { + $stat = fstat($fileOrStream); + } else { + $stat = array( + 'mode' => 0x8000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => strlen($fileOrStream), + 'mtime' => time(), + ); + } + } + + $link = null; + if ($stat['mode'] & 0x4000) { + $type = 5; // Directory + } else if ($stat['mode'] & 0x8000) { + $type = 0; // Regular + } else if ($stat['mode'] & 0xA000) { + $type = 1; // Link + $link = @readlink($current); + } else { + $type = 9; // Unknown + } + + $filePrefix = ''; + if (strlen($path) > 255) { + throw new Exception( + "$path is too long, must be 255 characters or less" + ); + } else if (strlen($path) > 100) { + $filePrefix = substr($path, 0, strlen($path)-100); + $path = substr($path, -100); + } + + $block = pack('a100a8a8a8a12A12', + $path, + decoct($stat['mode']), + sprintf('%6s ',decoct($stat['uid'])), + sprintf('%6s ',decoct($stat['gid'])), + sprintf('%11s ',decoct($stat['size'])), + sprintf('%11s ',decoct($stat['mtime'])) + ); + + $blockend = pack('a1a100a6a2a32a32a8a8a155a12', + $type, + $link, + 'ustar', + '00', + 'Pyrus', + 'Pyrus', + '', + '', + $filePrefix, + ''); + + $checkheader = array_merge(str_split($block), str_split($blockend)); + if (!function_exists('_pear2tarchecksum')) { + function _pear2tarchecksum($a, $b) {return $a + ord($b);} + } + $checksum = 256; // 8 * ord(' '); + $checksum += array_reduce($checkheader, '_pear2tarchecksum'); + + $checksum = pack('a8', sprintf('%6s ', decoct($checksum))); + + fwrite($this->tmp, $block . $checksum . $blockend, 512); + if (is_resource($fileOrStream)) { + stream_copy_to_stream($fileOrStream, $this->tmp); + if ($stat['size'] % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - $stat['size'] % 512)); + } + } else { + fwrite($this->tmp, $fileOrStream); + if (strlen($fileOrStream) % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512)); + } + } + } + + /** + * Initialize the package creator + */ + function init() + { + switch ($this->compress) { + case 'zlib' : + $this->tmp = gzopen($this->path, 'wb'); + break; + case 'bz2' : + $this->tmp = bzopen($this->path, 'w'); + break; + case 'none' : + $this->tmp = fopen($this->path, 'wb'); + break; + default : + throw new Exception( + 'unknown compression type ' . $this->compress); + } + } + + /** + * Create an internal directory, creating parent directories as needed + * + * @param string $dir + */ + function mkdir($dir) + { + $this->addFile($dir, "", array( + 'mode' => 0x4000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => 0, + 'mtime' => time(), + )); + } + + /** + * Finish saving the package + */ + function close() + { + fwrite($this->tmp, pack('a1024', '')); + fclose($this->tmp); + } +} \ No newline at end of file diff --git a/ext/phar/tests/tar/files/tinylink.tar b/ext/phar/tests/tar/files/tinylink.tar new file mode 100644 index 0000000000..741b56c2f5 Binary files /dev/null and b/ext/phar/tests/tar/files/tinylink.tar differ diff --git a/ext/phar/tests/tar/files/trunc.tar b/ext/phar/tests/tar/files/trunc.tar new file mode 100644 index 0000000000..2156b5c623 Binary files /dev/null and b/ext/phar/tests/tar/files/trunc.tar differ diff --git a/ext/phar/tests/tar/frontcontroller1.phar.phpt b/ext/phar/tests/tar/frontcontroller1.phar.phpt new file mode 100644 index 0000000000..77158169bb --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller1.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller other tar-based +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--ENV-- +SCRIPT_NAME=/frontcontroller1.phar.php +REQUEST_URI=/frontcontroller1.phar.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Content-type: image/jpeg +Content-length: 3 +--EXPECT-- +hio diff --git a/ext/phar/tests/tar/frontcontroller10.phar.phpt b/ext/phar/tests/tar/frontcontroller10.phar.phpt new file mode 100644 index 0000000000..0ca67b3d3e --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller10.phar.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller rewrite array invalid tar-based +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--ENV-- +SCRIPT_NAME=/frontcontroller10.phar.php +REQUEST_URI=/frontcontroller10.phar.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller4.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +Status: 403 Access Denied +--EXPECT-- +<html> + <head> + <title>Access Denied + + +

    403 - File /hi Access Denied

    + + \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller11.phar.phpt b/ext/phar/tests/tar/frontcontroller11.phar.phpt new file mode 100644 index 0000000000..3a420f6c85 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller11.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type extension is not a string tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller11.phar.php +REQUEST_URI=/frontcontroller11.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller5.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.phar.php:2 +Stack trace: +#0 %sfrontcontroller11.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller11.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller12.phar.phpt b/ext/phar/tests/tar/frontcontroller12.phar.phpt new file mode 100644 index 0000000000..e659434e07 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller12.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type unknown int tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller12.phar.php +REQUEST_URI=/frontcontroller12.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller6.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.phar.php:2 +Stack trace: +#0 %sfrontcontroller12.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller12.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller13.phar.phpt b/ext/phar/tests/tar/frontcontroller13.phar.phpt new file mode 100644 index 0000000000..0b9d3e3895 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller13.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type not string/int tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller13.phar.php +REQUEST_URI=/frontcontroller13.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller7.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.phar.php:2 +Stack trace: +#0 %sfrontcontroller13.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller13.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller14.phar.phpt b/ext/phar/tests/tar/frontcontroller14.phar.phpt new file mode 100644 index 0000000000..c40f9b6c34 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller14.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, other tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller14.phar.php +REQUEST_URI=/frontcontroller14.phar.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller8.phar.tar +--EXPECTHEADERS-- +Content-type: foo/bar +Content-length: 4 +--EXPECT-- +hio2 diff --git a/ext/phar/tests/tar/frontcontroller15.phar.phpt b/ext/phar/tests/tar/frontcontroller15.phar.phpt new file mode 100644 index 0000000000..154117fda4 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller15.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type override, Phar::PHPS tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller15.phar.php +REQUEST_URI=/frontcontroller15.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller8.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + + diff --git a/ext/phar/tests/tar/frontcontroller16.phar.phpt b/ext/phar/tests/tar/frontcontroller16.phar.phpt new file mode 100644 index 0000000000..042a695eb3 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller16.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, Phar::PHP tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller16.phar.php +REQUEST_URI=/frontcontroller16.phar.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller8.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio1 + diff --git a/ext/phar/tests/tar/frontcontroller17.phar.phpt b/ext/phar/tests/tar/frontcontroller17.phar.phpt new file mode 100644 index 0000000000..17d04baf30 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller17.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller mime type unknown tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller17.phar.php +REQUEST_URI=/frontcontroller17.phar.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller8.phar.tar +--EXPECTHEADERS-- +Content-type: application/octet-stream +Content-length: 4 +--EXPECT-- +hio3 + diff --git a/ext/phar/tests/tar/frontcontroller18.phar.phpt b/ext/phar/tests/tar/frontcontroller18.phar.phpt new file mode 100644 index 0000000000..c52ce291c7 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller18.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller18.phar.php +REQUEST_URI=/frontcontroller18.phar.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller9.phar.tar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.phar.php:2 +Stack trace: +#0 %sfrontcontroller18.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller18.phar.php on line 2 diff --git a/ext/phar/tests/tar/frontcontroller19.phar.phpt b/ext/phar/tests/tar/frontcontroller19.phar.phpt new file mode 100644 index 0000000000..6b07438787 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller19.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 2 tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller19.phar.php +REQUEST_URI=/frontcontroller19.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller10.phar.tar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.phar.php:2 +Stack trace: +#0 %sfrontcontroller19.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller19.phar.php on line 2 diff --git a/ext/phar/tests/tar/frontcontroller2.phar.phpt b/ext/phar/tests/tar/frontcontroller2.phar.phpt new file mode 100644 index 0000000000..a6b1c780fd --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller2.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller PHP test tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller2.phar.php +REQUEST_URI=/frontcontroller2.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio diff --git a/ext/phar/tests/tar/frontcontroller20.phar.phpt b/ext/phar/tests/tar/frontcontroller20.phar.phpt new file mode 100644 index 0000000000..3cc470d41b --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller20.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 3 tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller20.phar.php +REQUEST_URI=/frontcontroller20.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller11.phar.tar +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.phar.php:2 +Stack trace: +#0 %sfrontcontroller20.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller20.phar.php on line 2 diff --git a/ext/phar/tests/tar/frontcontroller21.phar.phpt b/ext/phar/tests/tar/frontcontroller21.phar.phpt new file mode 100644 index 0000000000..eb21897226 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller21.phar.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller $_SERVER munging success tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller21.phar.php +REQUEST_URI=/frontcontroller21.phar.php/index.php?test=hi +PATH_INFO=/index.php +QUERY_STRING=test=hi +--FILE_EXTERNAL-- +files/frontcontroller12.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(10) "/index.php" +string(10) "/index.php" +string(%d) "phar://%sfrontcontroller21.phar.php/index.php" +string(18) "/index.php?test=hi" +string(37) "/frontcontroller21.phar.php/index.php" +string(27) "/frontcontroller21.phar.php" +string(%d) "%sfrontcontroller21.phar.php" +string(45) "/frontcontroller21.phar.php/index.php?test=hi" \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller3.phar.phpt b/ext/phar/tests/tar/frontcontroller3.phar.phpt new file mode 100644 index 0000000000..dee16ee2b2 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller3.phar.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller phps tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller3.phar.php +REQUEST_URI=/frontcontroller3.phar.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + diff --git a/ext/phar/tests/tar/frontcontroller4.phar.phpt b/ext/phar/tests/tar/frontcontroller4.phar.phpt new file mode 100644 index 0000000000..db4846c69b --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller4.phar.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller index.php relocate (no /) tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller4.phar.php +REQUEST_URI=/frontcontroller4.phar.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller4.phar.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/tar/frontcontroller5.phar.phpt b/ext/phar/tests/tar/frontcontroller5.phar.phpt new file mode 100644 index 0000000000..534e66a1e3 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller5.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller index.php relocate tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller5.phar.php +REQUEST_URI=/frontcontroller5.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller5.phar.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/tar/frontcontroller6.phar.phpt b/ext/phar/tests/tar/frontcontroller6.phar.phpt new file mode 100644 index 0000000000..5375beef8c --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller6.phar.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller 404 tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller6.phar.php +REQUEST_URI=/frontcontroller6.phar.php/notfound.php +PATH_INFO=/notfound.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.tar +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /notfound.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller7.phar.phpt b/ext/phar/tests/tar/frontcontroller7.phar.phpt new file mode 100644 index 0000000000..3b73f2075c --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller7.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller alternate index file tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller7.phar.php +REQUEST_URI=/frontcontroller7.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller2.phar.tar +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller7.phar.php/a.php +--EXPECT-- diff --git a/ext/phar/tests/tar/frontcontroller8.phar.phpt b/ext/phar/tests/tar/frontcontroller8.phar.phpt new file mode 100644 index 0000000000..19844cb199 --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller8.phar.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller no index file 404 tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller8.phar.php +REQUEST_URI=/frontcontroller8.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller3.phar.tar +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /index.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/tar/frontcontroller9.phar.phpt b/ext/phar/tests/tar/frontcontroller9.phar.phpt new file mode 100644 index 0000000000..080db58f8f --- /dev/null +++ b/ext/phar/tests/tar/frontcontroller9.phar.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller rewrite array tar-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller9.phar.php +REQUEST_URI=/frontcontroller9.phar.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller3.phar.tar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + \ No newline at end of file diff --git a/ext/phar/tests/tar/links.phpt b/ext/phar/tests/tar/links.phpt new file mode 100644 index 0000000000..73e257b8be --- /dev/null +++ b/ext/phar/tests/tar/links.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: tar with hard link and symbolic link +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump($p['testit/link']->getContent()); +var_dump($p['testit/hard']->getContent()); +var_dump($p['testit/file']->getContent()); +$p['testit/link'] = 'overwriting'; +var_dump($p['testit/link']->getContent()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(3) "hi +" +string(3) "hi +" +string(3) "hi +" +string(11) "overwriting" +===DONE=== diff --git a/ext/phar/tests/tar/links2.phpt b/ext/phar/tests/tar/links2.phpt new file mode 100644 index 0000000000..1939e002bd --- /dev/null +++ b/ext/phar/tests/tar/links2.phpt @@ -0,0 +1,35 @@ +--TEST-- +Phar: tar with hard link to nowhere +--SKIPIF-- + +--FILE-- +init(); +$a->addFile('hardlink', 'internal/file.txt', array( + 'mode' => 0xA000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => 0, + 'mtime' => time(), + )); +$a->close(); + +try { + $p = new PharData($fname); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +phar error: "%slinks2.tar" is a corrupted tar file - hard link to non-existent file "internal/file.txt" +===DONE=== diff --git a/ext/phar/tests/tar/links3.phpt b/ext/phar/tests/tar/links3.phpt new file mode 100644 index 0000000000..2241081660 --- /dev/null +++ b/ext/phar/tests/tar/links3.phpt @@ -0,0 +1,19 @@ +--TEST-- +Phar: tar with link to absolute path +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +echo $p['file.txt']->getContent(); +echo $p['my/file']->getContent(); +?> +===DONE=== +--EXPECT-- +my file +my file +===DONE=== diff --git a/ext/phar/tests/tar/links4.phpt b/ext/phar/tests/tar/links4.phpt new file mode 100644 index 0000000000..d0783e84ac --- /dev/null +++ b/ext/phar/tests/tar/links4.phpt @@ -0,0 +1,19 @@ +--TEST-- +Phar: tar with link to root directory file from root directory file +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +echo $p['file.txt']->getContent(); +echo $p['link.txt']->getContent(); +?> +===DONE=== +--EXPECT-- +hi +hi +===DONE=== diff --git a/ext/phar/tests/tar/links5.phpt b/ext/phar/tests/tar/links5.phpt new file mode 100644 index 0000000000..262d41d841 --- /dev/null +++ b/ext/phar/tests/tar/links5.phpt @@ -0,0 +1,19 @@ +--TEST-- +Phar: tar with relative link to subdirectory file from subdirectory file +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +echo $p['hi/test.txt']->getContent(); +echo $p['hi/link.txt']->getContent(); +?> +===DONE=== +--EXPECT-- +hi +hi +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_existing.phpt b/ext/phar/tests/tar/open_for_write_existing.phpt new file mode 100644 index 0000000000..641e5ce21d --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_existing.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECT-- +extra +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_existing_b.phpt b/ext/phar/tests/tar/open_for_write_existing_b.phpt new file mode 100755 index 0000000000..54ec5855fb --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_existing_b.phpt @@ -0,0 +1,56 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_b.phar.tar/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d +This is b/c + +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_existing_c.phpt b/ext/phar/tests/tar/open_for_write_existing_c.phpt new file mode 100755 index 0000000000..0e5a181e65 --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_existing_c.phpt @@ -0,0 +1,50 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_c.phar.tar/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d +This is b/c + +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_newfile.phpt b/ext/phar/tests/tar/open_for_write_newfile.phpt new file mode 100644 index 0000000000..31e9d4a7e9 --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_newfile.phpt @@ -0,0 +1,44 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECT-- +This is b/c +extra +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_newfile_b.phpt b/ext/phar/tests/tar/open_for_write_newfile_b.phpt new file mode 100755 index 0000000000..d3a21b4caf --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_newfile_b.phpt @@ -0,0 +1,61 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_b.phar.tar/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_b.phar.tar/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.tar" in %sopen_for_write_newfile_b.php on line %d + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.tar/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/tar/open_for_write_newfile_c.phpt b/ext/phar/tests/tar/open_for_write_newfile_c.phpt new file mode 100755 index 0000000000..231241c8ad --- /dev/null +++ b/ext/phar/tests/tar/open_for_write_newfile_c.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_c.phar.tar/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_c.phar.tar/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.tar" in %sopen_for_write_newfile_c.php on line %d + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.tar/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d + +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/phar_begin_setstub_commit.phpt b/ext/phar/tests/tar/phar_begin_setstub_commit.phpt new file mode 100755 index 0000000000..c990ff9b98 --- /dev/null +++ b/ext/phar/tests/tar/phar_begin_setstub_commit.phpt @@ -0,0 +1,51 @@ +--TEST-- +Phar::startBuffering()/setStub()/stopBuffering() tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +isFileFormat(Phar::TAR)); +//var_dump($p->getStub()); +var_dump($p->isBuffering()); +$p->startBuffering(); +var_dump($p->isBuffering()); +$p['a.php'] = 'setStub(''); +include 'phar://brandnewphar.phar/a.php'; +var_dump($p->getStub()); +$p['b.php'] = 'setStub('getStub()); +$p->stopBuffering(); +echo "===COMMIT===\n"; +var_dump($p->isBuffering()); +include 'phar://brandnewphar.phar/a.php'; +include 'phar://brandnewphar.phar/b.php'; +var_dump($p->getStub()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(false) +string(5) "Hello" +string(84) " +" +string(5) "World" +string(85) " +" +===COMMIT=== +bool(true) +string(5) "Hello" +string(5) "World" +string(85) " +" +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator4.phpt b/ext/phar/tests/tar/phar_buildfromiterator4.phpt new file mode 100644 index 0000000000..b7d6d56f64 --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator4.phpt @@ -0,0 +1,66 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file passed in tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt')))); + var_dump($phar->isFileFormat(Phar::TAR)); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "%sphar_buildfromiterator4.phpt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator5.phpt b/ext/phar/tests/tar/phar_buildfromiterator5.phpt new file mode 100644 index 0000000000..600bd2ee5c --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator5.phpt @@ -0,0 +1,59 @@ +--TEST-- +Phar::buildFromIterator() iterator, iterator returns non-string tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass)))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid value (must return a string) +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator6.phpt b/ext/phar/tests/tar/phar_buildfromiterator6.phpt new file mode 100644 index 0000000000..e891a5d065 --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator6.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, key is int tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar'); + var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid key (must return a string) +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator7.phpt b/ext/phar/tests/tar/phar_buildfromiterator7.phpt new file mode 100644 index 0000000000..d64c032d71 --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator7.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, file can't be opened tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt" +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator8.phpt b/ext/phar/tests/tar/phar_buildfromiterator8.phpt new file mode 100644 index 0000000000..f42640f692 --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator8.phpt @@ -0,0 +1,73 @@ +--TEST-- +Phar::buildFromIterator() iterator, SplFileInfo as current tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^frontcontroller\d{0,2}\.phar\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR); + asort($a); + var_dump($a); + var_dump($phar->isFileFormat(Phar::TAR)); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(21) { + ["frontcontroller1.phar.phpt"]=> + string(%d) "%sfrontcontroller1.phar.phpt" + ["frontcontroller10.phar.phpt"]=> + string(%d) "%sfrontcontroller10.phar.phpt" + ["frontcontroller11.phar.phpt"]=> + string(%d) "%sfrontcontroller11.phar.phpt" + ["frontcontroller12.phar.phpt"]=> + string(%d) "%sfrontcontroller12.phar.phpt" + ["frontcontroller13.phar.phpt"]=> + string(%d) "%sfrontcontroller13.phar.phpt" + ["frontcontroller14.phar.phpt"]=> + string(%d) "%sfrontcontroller14.phar.phpt" + ["frontcontroller15.phar.phpt"]=> + string(%d) "%sfrontcontroller15.phar.phpt" + ["frontcontroller16.phar.phpt"]=> + string(%d) "%sfrontcontroller16.phar.phpt" + ["frontcontroller17.phar.phpt"]=> + string(%d) "%sfrontcontroller17.phar.phpt" + ["frontcontroller18.phar.phpt"]=> + string(%d) "%sfrontcontroller18.phar.phpt" + ["frontcontroller19.phar.phpt"]=> + string(%d) "%sfrontcontroller19.phar.phpt" + ["frontcontroller2.phar.phpt"]=> + string(%d) "%sfrontcontroller2.phar.phpt" + ["frontcontroller20.phar.phpt"]=> + string(%d) "%sfrontcontroller20.phar.phpt" + ["frontcontroller21.phar.phpt"]=> + string(%d) "%sfrontcontroller21.phar.phpt" + ["frontcontroller3.phar.phpt"]=> + string(%d) "%sfrontcontroller3.phar.phpt" + ["frontcontroller4.phar.phpt"]=> + string(%d) "%sfrontcontroller4.phar.phpt" + ["frontcontroller5.phar.phpt"]=> + string(%d) "%sfrontcontroller5.phar.phpt" + ["frontcontroller6.phar.phpt"]=> + string(%d) "%sfrontcontroller6.phar.phpt" + ["frontcontroller7.phar.phpt"]=> + string(%d) "%sfrontcontroller7.phar.phpt" + ["frontcontroller8.phar.phpt"]=> + string(%d) "%sfrontcontroller8.phar.phpt" + ["frontcontroller9.phar.phpt"]=> + string(%d) "%sfrontcontroller9.phar.phpt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/phar_buildfromiterator9.phpt b/ext/phar/tests/tar/phar_buildfromiterator9.phpt new file mode 100644 index 0000000000..f9deef4d9f --- /dev/null +++ b/ext/phar/tests/tar/phar_buildfromiterator9.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file resource passed in tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r'))))); + fclose($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "[stream]" +} +===DONE=== diff --git a/ext/phar/tests/tar/phar_commitwrite.phpt b/ext/phar/tests/tar/phar_commitwrite.phpt new file mode 100644 index 0000000000..b926b9a081 --- /dev/null +++ b/ext/phar/tests/tar/phar_commitwrite.phpt @@ -0,0 +1,44 @@ +--TEST-- +Phar::setStub()/stopBuffering() tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($p->getStub()); +$p->setStub(""); +var_dump($p->getStub()); +var_dump($p->isFileFormat(Phar::TAR)); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(60) " +" +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/phar_convert_phar.phpt b/ext/phar/tests/tar/phar_convert_phar.phpt new file mode 100644 index 0000000000..6a7d78ea8b --- /dev/null +++ b/ext/phar/tests/tar/phar_convert_phar.phpt @@ -0,0 +1,58 @@ +--TEST-- +Phar::convertToPhar() from tar +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump(strlen($phar->getStub())); + +$phar = $phar->convertToExecutable(Phar::TAR); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +$phar['a'] = 'hi there'; + +$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.3.phar'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump(strlen($phar->getStub())); + +copy($fname3, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump(strlen($phar->getStub())); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +int(6651) +bool(true) +string(60) " + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump(strlen($phar->getStub())); + +$phar = $phar->convertToExecutable(Phar::TAR); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +$phar['a'] = 'hi there'; + +$phar = $phar->convertToExecutable(Phar::PHAR, Phar::GZ); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isCompressed()); +var_dump(strlen($phar->getStub())); + +copy($fname . '.gz', $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isCompressed() == Phar::GZ); +var_dump(strlen($phar->getStub())); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +int(6651) +bool(true) +string(60) " + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump(strlen($phar->getStub())); + +$phar = $phar->convertToExecutable(Phar::TAR); +var_dump($phar->isFileFormat(Phar::TAR)); +var_dump($phar->getStub()); + +$phar['a'] = 'hi there'; + +$phar = $phar->convertToExecutable(Phar::PHAR, Phar::BZ2); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isCompressed()); +var_dump(strlen($phar->getStub())); + +copy($fname . '.bz2', $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump($phar->isCompressed() == Phar::BZ2); +var_dump(strlen($phar->getStub())); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +int(6651) +bool(true) +string(60) " + + +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +startBuffering(); + $p->copy('a', 'b'); + echo file_get_contents($p['b']->getPathName()); + $p->copy('b', 'c'); + $p->stopBuffering(); + echo file_get_contents($p['c']->getPathName()); + copy($fname, $fname2); + var_dump($p->isFileFormat(Phar::TAR)); + $p->copy('a', $ename); +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly',1); +$p2 = new Phar($fname2); +var_dump($p2->isFileFormat(Phar::TAR)); +echo "\n"; +echo 'a: ' , file_get_contents($p2['a']->getPathName()); +echo 'b: ' ,file_get_contents($p2['b']->getPathName()); +echo 'c: ' ,file_get_contents($p2['c']->getPathName()); +?> +===DONE=== +--CLEAN-- + + +--EXPECTF-- +hihibool(true) +file "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s +bool(true) + +a: hib: hic: hi===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/phar_magic.phpt b/ext/phar/tests/tar/phar_magic.phpt new file mode 100644 index 0000000000..1bb336f96c --- /dev/null +++ b/ext/phar/tests/tar/phar_magic.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: include/fopen magic tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +isFileFormat(Phar::TAR)); +$p['a'] = 'setStub(' +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(true) +in b + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$phar->setAlias('hio'); + +$files = array(); + +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); + +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; + +copy($fname, $fname2); +$phar->setAlias('unused'); +$a = new Phar($fname2); +echo $a->getAlias() . "\n"; + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +hio +test +test +===DONE=== diff --git a/ext/phar/tests/tar/phar_setalias2.phpt b/ext/phar/tests/tar/phar_setalias2.phpt new file mode 100644 index 0000000000..a44cc397c2 --- /dev/null +++ b/ext/phar/tests/tar/phar_setalias2.phpt @@ -0,0 +1,53 @@ +--TEST-- +Phar::setAlias() error tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$phar->setAlias('hio'); + +$files = array(); + +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} + +$phar->stopBuffering(); + +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; +$b = $phar; +$phar = new Phar(dirname(__FILE__) . '/notphar.phar'); + +try { + $phar->setAlias('test'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +hio +test +alias "test" is already used for archive "%sphar_setalias2.phar.tar" and cannot be used for other archives +===DONE=== diff --git a/ext/phar/tests/tar/phar_setdefaultstub.phpt b/ext/phar/tests/tar/phar_setdefaultstub.phpt new file mode 100644 index 0000000000..c1e6642a17 --- /dev/null +++ b/ext/phar/tests/tar/phar_setdefaultstub.phpt @@ -0,0 +1,80 @@ +--TEST-- +Phar: Phar::setDefaultStub() with and without arg, tar-based phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +'; +$phar['b.php'] = ''; +$phar->setStub(''); + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub(); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub('my/custom/thingy.php'); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub('my/custom/thingy.php', 'the/web.php'); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(51) " +" +============================================================================ +============================================================================ +string(60) " +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$p['a'] = 'a'; +$p['b'] = 'b'; +$p['c'] = 'c'; +copy($fname2, $fname); + +$phar = new Phar($fname); +echo $phar->getStub(); + +$file = ''; + +//// 2 +$phar->setStub($file); +echo $phar->getStub(); + +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php'; +$file = ''; +$fp = fopen($fname3, 'wb'); +fwrite($fp, $file); +fclose($fp); +$fp = fopen($fname3, 'rb'); + +//// 3 +$phar->setStub($fp); +fclose($fp); + +echo $phar->getStub(); + +$fp = fopen($fname3, 'ab'); +fwrite($fp, 'booya'); +fclose($fp); +echo file_get_contents($fname3) . "\n"; + +$fp = fopen($fname3, 'rb'); + +//// 4 +$phar->setStub($fp, strlen($file)); +fclose($fp); +echo $phar->getStub(); + +$phar['testing'] = 'hi'; + +echo $phar->getStub(); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- + + + +booya + + +===DONE=== diff --git a/ext/phar/tests/tar/phar_stub_error.phpt b/ext/phar/tests/tar/phar_stub_error.phpt new file mode 100755 index 0000000000..5d35b932fe --- /dev/null +++ b/ext/phar/tests/tar/phar_stub_error.phpt @@ -0,0 +1,57 @@ +--TEST-- +Phar::setStub()/getStub() tar-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub($stub = '' ."\r\n"); +$phar->setAlias('hio'); +$phar['a'] = 'a'; +$phar->stopBuffering(); + +var_dump($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +$newstub = ''; + +try { + $phar->setStub($newstub); +} catch(exception $e) { + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +$phar->stopBuffering(); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(50) " +" +string(50) " +" +bool(true) +Exception: illegal stub for tar-based phar "%sphar_stub_error.phar.tar" +string(50) " +" +bool(true) +string(50) " +" +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/refcount1.phpt b/ext/phar/tests/tar/refcount1.phpt new file mode 100644 index 0000000000..c6808afb63 --- /dev/null +++ b/ext/phar/tests/tar/refcount1.phpt @@ -0,0 +1,74 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file tar-based +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +init(); +$tar->addFile('.phar/stub.php', ""); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; +$files['.phar/alias.txt'] = 'hio'; + +foreach ($files as $n => $file) { + $tar->addFile($n, $file); +} + +$tar->close(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); +echo "===CLOSE===\n"; +$phar = new Phar($fname); +$b = fopen($alias . '/b/c.php', 'rb'); +$a = $phar['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($alias . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $alias . '/b/c.php'; + +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.tar/b" + ["fileName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.tar/b/c.php" +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.tar", has open file pointers, cannot unlink in %srefcount1.php on line %d +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.tar/b" + ["fileName":"SplFileInfo":private]=> + string(%s) "phar://%srefcount1.phar.tar/b/c.php" +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/tar/refcount1_5_2.phpt b/ext/phar/tests/tar/refcount1_5_2.phpt new file mode 100755 index 0000000000..18587d91ad --- /dev/null +++ b/ext/phar/tests/tar/refcount1_5_2.phpt @@ -0,0 +1,64 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file tar-based +--SKIPIF-- + + +")) die("skip requires 5.2 or earlier"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); +$phar->setAlias('hio'); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); + +echo "===CLOSE===\n"; + +$b = fopen($alias . '/b/c.php', 'rb'); +$a = $phar['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($alias . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar.tar", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/tar/rename.phpt b/ext/phar/tests/tar/rename.phpt new file mode 100644 index 0000000000..96588a6596 --- /dev/null +++ b/ext/phar/tests/tar/rename.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: rename test tar-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +init(); +$tar->addFile('.phar/stub.php', ""); + +$files = array(); +$files['a'] = 'a'; + +foreach ($files as $n => $file) { + $tar->addFile($n, $file); +} + +$tar->close(); + +include $fname; + +echo file_get_contents($alias . '/a') . "\n"; +rename($alias . '/a', $alias . '/b'); +echo file_get_contents($alias . '/b') . "\n"; +echo file_get_contents($alias . '/a') . "\n"; +?> +--CLEAN-- + +--EXPECTF-- +a +a + +Warning: file_get_contents(phar://%srename.phar.tar/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.tar" in %srename.php on line %d diff --git a/ext/phar/tests/tar/tar_001.phpt b/ext/phar/tests/tar/tar_001.phpt new file mode 100644 index 0000000000..500058b70d --- /dev/null +++ b/ext/phar/tests/tar/tar_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: tar-based phar corrupted +--SKIPIF-- + + +--FILE-- +init(); +$tar->addFile('tar_001.phpt', __FILE__); +$tar->close(); + +$tar = fopen('phar://' . dirname(__FILE__) . '/tar_001.phar.tar/tar_001.phpt', 'rb'); +try { + $phar = new Phar(dirname(__FILE__) . '/tar_001.phar.tar'); + echo "should not execute\n"; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: fopen(phar://%star_001.phar.tar/tar_001.phpt): failed to open stream: phar error: "%star_001.phar.tar" is a corrupted tar file (truncated) in %star_001.php on line 9 +phar error: "%star_001.phar.tar" is a corrupted tar file (truncated) +===DONE=== diff --git a/ext/phar/tests/tar/tar_002.phpt b/ext/phar/tests/tar/tar_002.phpt new file mode 100644 index 0000000000..75fc220b40 --- /dev/null +++ b/ext/phar/tests/tar/tar_002.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: tar-based phar corrupted 2 +--SKIPIF-- + + +--INI-- +phar.readonly=0 +--FILE-- +init(); +$tar->addFile('tar_002.phpt', __FILE__); +$tar->close(); + +$tar = fopen('phar://' . dirname(__FILE__) . '/tar_002.phar.tar/tar_002.phpt', 'rb'); + +try { + $phar = new Phar(dirname(__FILE__) . '/tar_002.phar.tar'); + echo "should not execute\n"; +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: fopen(phar://%star_002.phar.tar/tar_002.phpt): failed to open stream: phar error: "%star_002.phar.tar" is a corrupted tar file (truncated) in %star_002.php on line 9 +phar error: "%star_002.phar.tar" is a corrupted tar file (truncated) +===DONE=== diff --git a/ext/phar/tests/tar/tar_003.phpt b/ext/phar/tests/tar/tar_003.phpt new file mode 100644 index 0000000000..47f1d6ca9b --- /dev/null +++ b/ext/phar/tests/tar/tar_003.phpt @@ -0,0 +1,74 @@ +--TEST-- +Phar: tar-based phar, valid 1 +--SKIPIF-- + + +--INI-- +phar.readonly=0 +--FILE-- +init(); +$tar->addFile('.phar/stub.php', "addFile('tar_003.phpt', $g = fopen(__FILE__, 'r')); +$tar->addFile('internal/file/here', "hi there!\n"); +$tar->mkDir('internal/dir'); +$tar->mkDir('dir'); +$tar->close(); + +fclose($g); + +echo file_get_contents($alias . '/internal/file/here'); + +try { +$tar = opendir($alias . '/'); +} catch (Exception $e) { +echo $e->getMessage()."\n"; +} + +while (false !== ($v = readdir($tar))) { + echo (is_file($alias . '/' . $v) ? "file\n" : "dir\n"); + echo $v . "\n"; +} +closedir($tar); + +/* ensure none of the dir tar files were freed */ +echo "second round\n"; +$tar = opendir($alias . '/'); +while (false !== ($v = readdir($tar))) { + echo (is_file($alias . '/' . $v) ? "file\n" : "dir\n"); + echo $v . "\n"; +} +closedir($tar); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +hi there! +dir +.phar +dir +dir +dir +internal +file +tar_003.phpt +second round +dir +.phar +dir +dir +dir +internal +file +tar_003.phpt +===DONE=== diff --git a/ext/phar/tests/tar/tar_004.phpt b/ext/phar/tests/tar/tar_004.phpt new file mode 100644 index 0000000000..2dd7ba169f --- /dev/null +++ b/ext/phar/tests/tar/tar_004.phpt @@ -0,0 +1,38 @@ +--TEST-- +Phar: tar-based phar, tar phar with stub, mapPhar() +--SKIPIF-- + + +--INI-- +phar.readonly=0 +--FILE-- +init(); +$tar->addFile('tar_004.php', 'addFile('internal/file/here', "hi there!\n"); +$tar->mkDir('internal/dir'); +$tar->mkDir('dir'); +$tar->addFile('.phar/stub.php', 'close(); + +include $fname; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(9) "it worked" +string(%d) "phar://%star_004.phar.tar/tar_004.php" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/tar_bz2.phpt b/ext/phar/tests/tar/tar_bz2.phpt new file mode 100644 index 0000000000..ad14541431 --- /dev/null +++ b/ext/phar/tests/tar/tar_bz2.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar: tar-based phar, bzipped tar +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +--FILE-- +init(); +$tar->addFile('tar_004.php', 'addFile('internal/file/here', "hi there!\n"); +$tar->mkDir('internal/dir'); +$tar->mkDir('dir'); +$tar->addFile('.phar/stub.php', 'close(); + +include $fname; + +$phar = new Phar($fname); +$phar['test'] = 'hi'; + +copy($fname, $fname2); + +$phar2 = new Phar($fname2); +var_dump($phar2->isFileFormat(Phar::TAR)); +var_dump($phar2->isCompressed() == Phar::BZ2); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(9) "it worked" +string(%d) "phar://%star_bz2.phar/tar_004.php" +bool(true) +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/tar_gzip.phpt b/ext/phar/tests/tar/tar_gzip.phpt new file mode 100644 index 0000000000..8287ee7f06 --- /dev/null +++ b/ext/phar/tests/tar/tar_gzip.phpt @@ -0,0 +1,51 @@ +--TEST-- +Phar: tar-based phar, gzipped tar +--SKIPIF-- + + + + +--INI-- +phar.readonly=0 +--FILE-- +init(); +$a->addFile('tar_004.php', 'addFile('internal/file/here', "hi there!\n"); +$a->mkDir('internal/dir'); +$a->mkDir('dir'); +$a->addFile('.phar/stub.php', 'close(); + +include $fname; + +$a = new Phar($fname); +$a['test'] = 'hi'; +copy($fname, $fname2); +$b = new Phar($fname2); +var_dump($b->isFileFormat(Phar::TAR)); +var_dump($b->isCompressed() == Phar::GZ); +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(9) "it worked" +string(%d) "phar://%star_gzip.phar/tar_004.php" +bool(true) +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/tar_makebz2.phpt b/ext/phar/tests/tar/tar_makebz2.phpt new file mode 100644 index 0000000000..f703b46924 --- /dev/null +++ b/ext/phar/tests/tar/tar_makebz2.phpt @@ -0,0 +1,40 @@ +--TEST-- +Phar: tar-based phar, make new bzipped tar +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +--FILE-- +isFileFormat(Phar::TAR)); +$phar = $phar->compress(Phar::BZ2); + +copy($fname2, $fname3); + +$phar2 = new Phar($fname3); +var_dump($phar2->isFileFormat(Phar::TAR)); +var_dump($phar2->isCompressed() == Phar::BZ2); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/tar_makegz.phpt b/ext/phar/tests/tar/tar_makegz.phpt new file mode 100644 index 0000000000..46fe177611 --- /dev/null +++ b/ext/phar/tests/tar/tar_makegz.phpt @@ -0,0 +1,41 @@ +--TEST-- +Phar: tar-based phar, make new gzipped tar +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +--FILE-- +isFileFormat(Phar::TAR)); +$phar = $phar->compress(Phar::GZ); + + +copy($fname2, $fname3); + +$phar2 = new Phar($fname3); +var_dump($phar2->isFileFormat(Phar::TAR)); +var_dump($phar2->isCompressed() == Phar::GZ); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(true) +bool(true) +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/tar_nostub.phpt b/ext/phar/tests/tar/tar_nostub.phpt new file mode 100644 index 0000000000..a107a37deb --- /dev/null +++ b/ext/phar/tests/tar/tar_nostub.phpt @@ -0,0 +1,48 @@ +--TEST-- +Phar: tar-based phar, third-party tar with no stub, Phar->getStub() +--SKIPIF-- + + +--INI-- +phar.readonly=1 +--FILE-- +init(); +$tar->addFile('tar_004.php', 'addFile('internal/file/here', "hi there!\n"); +$tar->close(); + +try { + $phar = new Phar($fname); + var_dump($phar->getStub()); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +copy($fname, $fname2); + +try { + $phar = new PharData($fname2); + var_dump($phar->getStub()); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +RecursiveDirectoryIterator::__construct(phar://%star_004.phar.tar/): failed to open dir: '%star_004.phar.tar' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive +phar url "phar://%star_004.phar.tar/" is unknown +string(0) "" +===DONE=== diff --git a/ext/phar/tests/tar/truncated.phpt b/ext/phar/tests/tar/truncated.phpt new file mode 100644 index 0000000000..fbcabb7986 --- /dev/null +++ b/ext/phar/tests/tar/truncated.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar: truncated tar +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +phar error: "%strunc.tar" is a corrupted tar file (truncated) +===DONE=== diff --git a/ext/phar/tests/test_alias_unset.phpt b/ext/phar/tests/test_alias_unset.phpt new file mode 100644 index 0000000000..0127d8bba2 --- /dev/null +++ b/ext/phar/tests/test_alias_unset.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: test for the odd case where we intend to remove an archive from memory +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +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-- + + +--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 diff --git a/ext/phar/tests/test_signaturealgos.phpt b/ext/phar/tests/test_signaturealgos.phpt new file mode 100644 index 0000000000..74f9e639ae --- /dev/null +++ b/ext/phar/tests/test_signaturealgos.phpt @@ -0,0 +1,30 @@ +--TEST-- +Phar: verify signature parsing works +--SKIPIF-- + + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +getSignature(); +var_dump($r['hash_type']); +$a = new Phar(dirname(__FILE__) . '/files/sha512.phar'); +$r = $a->getSignature(); +var_dump($r['hash_type']); +$a = new Phar(dirname(__FILE__) . '/files/sha256.phar'); +$r = $a->getSignature(); +var_dump($r['hash_type']); +$a = new Phar(dirname(__FILE__) . '/files/md5.phar'); +$r = $a->getSignature(); +var_dump($r['hash_type']); +?> +===DONE=== +--EXPECT-- +string(5) "SHA-1" +string(7) "SHA-512" +string(7) "SHA-256" +string(3) "MD5" +===DONE=== diff --git a/ext/phar/tests/test_unset.phpt b/ext/phar/tests/test_unset.phpt new file mode 100644 index 0000000000..3da537c13c --- /dev/null +++ b/ext/phar/tests/test_unset.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: ensure unset() works properly on a non-flushed phar archive +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +setAlias('first'); +$phar->setMetadata('hi'); +unset($phar); + +$phar = new Phar($fname2); +$phar['b'] = 'whatever'; // flushed +try { + $phar->setAlias('first'); +} catch(Exception $e) { + echo $e->getMessage()."\n"; +} + +$phar = new Phar($fname); +var_dump($phar->getMetadata()); +var_dump($phar->getAlias()); +var_dump(file_exists($fname)); + +?> +===DONE=== +--CLEAN-- + + +--EXPECTF-- +NULL +string(%d) "%stest_unset.phar.php" +bool(false) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/webphar_compilefail.phpt b/ext/phar/tests/webphar_compilefail.phpt new file mode 100644 index 0000000000..ab5532d6be --- /dev/null +++ b/ext/phar/tests/webphar_compilefail.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: Phar::webPhar, open compiled file fails +--SKIPIF-- + +--INI-- +phar.readonly=1 +--FILE-- +getMessage() . "\n"; +} +__HALT_COMPILER(); +?> +--EXPECTF-- +internal corruption of phar "%swebphar_compilefail.php" (truncated manifest at manifest length) \ No newline at end of file diff --git a/ext/phar/tests/withphar.phpt b/ext/phar/tests/withphar.phpt new file mode 100644 index 0000000000..c422fa9843 --- /dev/null +++ b/ext/phar/tests/withphar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar: phar run with pecl/phar with default stub +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECT-- +in b + +--ENV-- +SCRIPT_NAME=/withphar_web.php +REQUEST_URI=/withphar_web.php/web.php +PATH_INFO=/web.php +--FILE_EXTERNAL-- +files/nophar.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +web diff --git a/ext/phar/tests/zf_test.phpt b/ext/phar/tests/zf_test.phpt new file mode 100644 index 0000000000..99e5c4f6e7 --- /dev/null +++ b/ext/phar/tests/zf_test.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: test broken app +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +convertToExecutable(); + +$phar = new Phar($phar_file); +$phar->startBuffering(); +$phar->setStub("stopBuffering(); + +foreach(new RecursiveIteratorIterator($phar) as $path) { + echo str_replace('\\', '/', $path->getPathName()) . "\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +phar://%szfapp.phar.tar.gz/.phar/stub.php +phar://%szfapp.phar.tar.gz/application/default/controllers/ErrorController.php +phar://%szfapp.phar.tar.gz/application/default/controllers/IndexController.php +phar://%szfapp.phar.tar.gz/application/default/views/scripts/error/error.phtml +phar://%szfapp.phar.tar.gz/application/default/views/scripts/index/index.phtml +phar://%szfapp.phar.tar.gz/html/.htaccess +phar://%szfapp.phar.tar.gz/html/index.php +===DONE=== diff --git a/ext/phar/tests/zip/033.phpt b/ext/phar/tests/zip/033.phpt new file mode 100644 index 0000000000..c980758a83 --- /dev/null +++ b/ext/phar/tests/zip/033.phpt @@ -0,0 +1,56 @@ +--TEST-- +Phar::chmod zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); + +try { + 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); + var_dump($phar['a.php']->isExecutable()); + echo "test dir\n"; + var_dump($phar['test']->isDir()); + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0000); + var_dump($phar['test']->isReadable()); + $phar['test']->chmod(0666); + var_dump($phar['test']->isReadable()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +bool(true) +bool(false) +test dir +bool(true) +bool(true) +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/033a.phpt b/ext/phar/tests/zip/033a.phpt new file mode 100644 index 0000000000..429d3bdd98 --- /dev/null +++ b/ext/phar/tests/zip/033a.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar::chmod zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +try { + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0777); + var_dump($phar['a.php']->isExecutable()); + $phar['a.php']->chmod(0666); + var_dump($phar['a.php']->isExecutable()); + echo "test dir\n"; + var_dump($phar['test']->isExecutable()); + $phar['test']->chmod(0777); + var_dump($phar['test']->isExecutable()); + $phar['test']->chmod(0666); + var_dump($phar['test']->isExecutable()); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(false) +Cannot modify permissions for file "a.php" in phar "%sa.phar.zip", write operations are prohibited +===DONE=== diff --git a/ext/phar/tests/zip/alias_acrobatics.phpt b/ext/phar/tests/zip/alias_acrobatics.phpt new file mode 100644 index 0000000000..2a58e39efc --- /dev/null +++ b/ext/phar/tests/zip/alias_acrobatics.phpt @@ -0,0 +1,46 @@ +--TEST-- +Phar: alias edge cases +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +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-- + +--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=== diff --git a/ext/phar/tests/zip/all.phpt b/ext/phar/tests/zip/all.phpt new file mode 100644 index 0000000000..84bbfc36be --- /dev/null +++ b/ext/phar/tests/zip/all.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar: test that creation of zip-based phar generates valid zip with all bells/whistles +--SKIPIF-- + + + + +--INI-- +phar.readonly=0 +--FILE-- +setMetadata('hi there'); +$phar['a'] = 'hi'; +$phar['a']->setMetadata('a meta'); +$phar['b'] = 'hi2'; +$phar['b']->compress(Phar::GZ); +$phar['c'] = 'hi3'; +$phar['c']->compress(Phar::BZ2); +$phar['b']->chmod(0444); +$phar->setStub("setAlias("hime"); +unset($phar); +copy($fname, $fname2); +Phar::unlinkArchive($fname); +var_dump(file_exists($fname), file_exists($pname . '/a')); + +$phar = new Phar($fname2); +var_dump($phar['a']->getContent(), $phar['b']->getContent(), $phar['c']->getContent()); +var_dump($phar['a']->isCompressed(), $phar['b']->isCompressed() == Phar::GZ, $phar['c']->isCompressed() == Phar::BZ2); +var_dump((string) decoct(fileperms($pname2 . '/b'))); +var_dump($phar->getStub()); +var_dump($phar->getAlias()); +var_dump($phar->getMetadata()); +var_dump($phar['a']->getMetadata()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +bool(false) +string(2) "hi" +string(3) "hi2" +string(3) "hi3" +bool(false) +bool(true) +bool(true) +string(6) "100444" +string(32) " +" +string(4) "hime" +string(8) "hi there" +string(6) "a meta" +===DONE=== diff --git a/ext/phar/tests/zip/badalias.phpt b/ext/phar/tests/zip/badalias.phpt new file mode 100644 index 0000000000..0291c4b089 --- /dev/null +++ b/ext/phar/tests/zip/badalias.phpt @@ -0,0 +1,25 @@ +--TEST-- +Phar: invalid aliases +--SKIPIF-- + + + +--FILE-- +getMessage(), "\n"; +} +} +?> +===DONE=== +--EXPECTF-- +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=== diff --git a/ext/phar/tests/zip/corrupt_001.phpt b/ext/phar/tests/zip/corrupt_001.phpt new file mode 100644 index 0000000000..0b019c6d83 --- /dev/null +++ b/ext/phar/tests/zip/corrupt_001.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar: corrupted zip (count mismatch) +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/count2.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar "%scount1.zip" +phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar "%scount2.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_002.phpt b/ext/phar/tests/zip/corrupt_002.phpt new file mode 100644 index 0000000000..86a271231d --- /dev/null +++ b/ext/phar/tests/zip/corrupt_002.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: corrupted zip (no end of zip record) +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: end of central directory not found in zip-based phar "%snozipend.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_003.phpt b/ext/phar/tests/zip/corrupt_003.phpt new file mode 100644 index 0000000000..c41e0153d8 --- /dev/null +++ b/ext/phar/tests/zip/corrupt_003.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: corrupted zip (truncated file comment) +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: corrupt zip archive, zip file comment truncated in zip-based phar "%sfilecomment.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_004.phpt b/ext/phar/tests/zip/corrupt_004.phpt new file mode 100644 index 0000000000..3760e8f9ae --- /dev/null +++ b/ext/phar/tests/zip/corrupt_004.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: corrupted zip (central directory offset incorrect) +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: corrupted central directory entry, no magic signature in zip-based phar "%scdir_offset.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_005.phpt b/ext/phar/tests/zip/corrupt_005.phpt new file mode 100644 index 0000000000..6b5d31d967 --- /dev/null +++ b/ext/phar/tests/zip/corrupt_005.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: encrypted zip +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: Cannot process encrypted zip files in zip-based phar "%sencrypted.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_006.phpt b/ext/phar/tests/zip/corrupt_006.phpt new file mode 100644 index 0000000000..9c83617a9a --- /dev/null +++ b/ext/phar/tests/zip/corrupt_006.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: zip with file created from stdin +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: Cannot process zips created from stdin (zero-length filename) in zip-based phar "%sstdin.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_007.phpt b/ext/phar/tests/zip/corrupt_007.phpt new file mode 100644 index 0000000000..80c9139025 --- /dev/null +++ b/ext/phar/tests/zip/corrupt_007.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar: corrupted zip (truncated filename record) +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: corrupted central directory entry, no magic signature in zip-based phar "%struncfilename.zip" +===DONE=== diff --git a/ext/phar/tests/zip/corrupt_008.phpt b/ext/phar/tests/zip/corrupt_008.phpt new file mode 100644 index 0000000000..5a20f4d2ec --- /dev/null +++ b/ext/phar/tests/zip/corrupt_008.phpt @@ -0,0 +1,101 @@ +--TEST-- +Phar: unsupported compression methods +--SKIPIF-- + + +--FILE-- +getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup2.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup3.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup4.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup5.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup6.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup7.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup9.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup10.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup14.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup18.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup19.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup97.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsup98.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +try { + new PharData(dirname(__FILE__) . '/files/compress_unsupunknown.zip'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar error: unsupported compression method (Shrunk) used in this zip in zip-based phar "%scompress_unsup1.zip" +phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup2.zip" +phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup3.zip" +phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup4.zip" +phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup5.zip" +phar error: unsupported compression method (Implode) used in this zip in zip-based phar "%scompress_unsup6.zip" +phar error: unsupported compression method (Tokenize) used in this zip in zip-based phar "%scompress_unsup7.zip" +phar error: unsupported compression method (Deflate64) used in this zip in zip-based phar "%scompress_unsup9.zip" +phar error: unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip in zip-based phar "%scompress_unsup10.zip" +phar error: unsupported compression method (LZMA) used in this zip in zip-based phar "%scompress_unsup14.zip" +phar error: unsupported compression method (IBM TERSE) used in this zip in zip-based phar "%scompress_unsup18.zip" +phar error: unsupported compression method (IBM LZ77) used in this zip in zip-based phar "%scompress_unsup19.zip" +phar error: unsupported compression method (WavPack) used in this zip in zip-based phar "%scompress_unsup97.zip" +phar error: unsupported compression method (PPMd) used in this zip in zip-based phar "%scompress_unsup98.zip" +phar error: unsupported compression method (unknown) used in this zip in zip-based phar "%scompress_unsupunknown.zip" +===DONE=== diff --git a/ext/phar/tests/zip/create_new_and_modify.phpt b/ext/phar/tests/zip/create_new_and_modify.phpt new file mode 100644 index 0000000000..5a3ec3317b --- /dev/null +++ b/ext/phar/tests/zip/create_new_and_modify.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: create and modify zip-based phar +--SKIPIF-- + + +--INI-- +phar.readonly=0 +--FILE-- +isFileFormat(Phar::ZIP)); +$sig1 = md5_file($fname); + +include $pname . '/a.php'; + +file_put_contents($pname .'/a.php', "modified!\n"); +file_put_contents($pname .'/b.php', "another!\n"); + +$phar = new Phar($fname); +$sig2 = md5_file($fname); + +var_dump($sig1 != $sig2); + +include $pname . '/a.php'; +include $pname . '/b.php'; + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(true) +brand new! +bool(true) +modified! +another! +===DONE=== diff --git a/ext/phar/tests/zip/create_new_phar_b.phpt b/ext/phar/tests/zip/create_new_phar_b.phpt new file mode 100644 index 0000000000..e6a5398f64 --- /dev/null +++ b/ext/phar/tests/zip/create_new_phar_b.phpt @@ -0,0 +1,27 @@ +--TEST-- +Phar: create a completely new zip-based phar +--SKIPIF-- + +--INI-- +phar.readonly=1 +phar.require_hash=1 +--FILE-- + + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: file_put_contents(phar://%screate_new_phar_b.phar.zip/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d + +Warning: include(phar://%screate_new_phar_b.phar.zip/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d + +Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.zip/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/zip/delete.phpt b/ext/phar/tests/zip/delete.phpt new file mode 100644 index 0000000000..06078b3a39 --- /dev/null +++ b/ext/phar/tests/zip/delete.phpt @@ -0,0 +1,31 @@ +--TEST-- +Phar: delete test, zip-based phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +"; + +$phar = new Phar($fname); +$phar['a'] = 'a'; +$phar->setStub($file); +$phar->stopBuffering(); + +echo file_get_contents($alias . '/a') . "\n"; +$phar->delete('a'); +echo file_get_contents($alias . '/a') . "\n"; +?> +--CLEAN-- + +--EXPECTF-- +a + +Warning: file_get_contents(phar://%sdelete.phar.zip/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.zip" in %sdelete.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/zip/delete_in_phar.phpt b/ext/phar/tests/zip/delete_in_phar.phpt new file mode 100644 index 0000000000..b7bda7ca4b --- /dev/null +++ b/ext/phar/tests/zip/delete_in_phar.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar: delete a file within a zip-based .phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar['b.php'] = ''; +$phar['b/c.php'] = ''; +$phar->setStub(''); +$phar->stopBuffering(); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +unlink($alias . '/b/c.php'); +?> +===AFTER=== + + +===DONE=== +--CLEAN-- + +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar.phar.zip/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.zip" in %sdelete_in_phar.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.zip/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d + +===DONE=== + \ No newline at end of file diff --git a/ext/phar/tests/zip/delete_in_phar_b.phpt b/ext/phar/tests/zip/delete_in_phar_b.phpt new file mode 100644 index 0000000000..7bc3a2bf1a --- /dev/null +++ b/ext/phar/tests/zip/delete_in_phar_b.phpt @@ -0,0 +1,48 @@ +--TEST-- +Phar: delete a file within a zip-based .phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar['b.php'] = ''; +$phar['b/c.php'] = ''; +$phar->setStub(''); +$phar->stopBuffering(); +ini_set('phar.readonly', 1); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; +unlink($alias . '/b/c.php'); +?> +===AFTER=== + + +===DONE=== +--CLEAN-- + +--EXPECTF-- +This is a +This is b +This is b/c + +Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d +===AFTER=== +This is a +This is b +This is b/c + +===DONE=== diff --git a/ext/phar/tests/zip/delete_in_phar_confirm.phpt b/ext/phar/tests/zip/delete_in_phar_confirm.phpt new file mode 100644 index 0000000000..fdd0b42b5c --- /dev/null +++ b/ext/phar/tests/zip/delete_in_phar_confirm.phpt @@ -0,0 +1,53 @@ +--TEST-- +Phar: delete a file within a zip-based .phar (confirm disk file is changed) +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar['b.php'] = ''; +$phar['b/c.php'] = ''; +$phar->setStub(''); +$phar->stopBuffering(); + +include $alias . '/a.php'; +include $alias . '/b.php'; +include $alias . '/b/c.php'; + +$md5 = md5_file($fname); +unlink($alias . '/b/c.php'); +clearstatcache(); +$md52 = md5_file($fname); +if ($md5 == $md52) echo 'file was not modified'; +?> +===AFTER=== + + +===DONE=== +--CLEAN-- + +--EXPECTF-- +This is a +This is b +This is b/c +===AFTER=== +This is a +This is b + +Warning: include(%sdelete_in_phar_confirm.phar.zip/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.zip" in %sdelete_in_phar_confirm.php on line %d + +Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.zip/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d + +===DONE=== diff --git a/ext/phar/tests/zip/dir.phpt b/ext/phar/tests/zip/dir.phpt new file mode 100644 index 0000000000..3cbeacd1c1 --- /dev/null +++ b/ext/phar/tests/zip/dir.phpt @@ -0,0 +1,43 @@ +--TEST-- +Phar: mkdir/rmdir test zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +isFileFormat(Phar::ZIP)); + +$phar->addEmptyDir('test'); +var_dump($phar['test']->isDir()); +var_dump($phar['test/']->isDir()); +copy($fname, $fname2); +mkdir($pname . '/another/dir/'); +var_dump($phar['another/dir']->isDir()); +rmdir($pname . '/another/dir/'); +copy($fname, $fname3); +clearstatcache(); +var_dump(file_exists($pname . '/another/dir/')); +var_dump(file_exists($pname2 . '/test/')); +var_dump(file_exists($pname3 . '/another/dir/')); +?> +--CLEAN-- + + + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) diff --git a/ext/phar/tests/zip/exists_as_phar.phpt b/ext/phar/tests/zip/exists_as_phar.phpt new file mode 100644 index 0000000000..ccb37e8187 --- /dev/null +++ b/ext/phar/tests/zip/exists_as_phar.phpt @@ -0,0 +1,38 @@ +--TEST-- +Phar: phar-based phar named with ".zip" fails +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +'; +$phar->setAlias('hio'); +$phar->addEmptyDir('test'); +$phar->stopBuffering(); +copy($fname, $tname); +$phar->setAlias('hio2'); + +try { + $p = new Phar($tname); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +phar zip error: phar "%sexists_as_phar.phar.zip" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar +===DONE=== diff --git a/ext/phar/tests/zip/files/badalias1.phar.zip b/ext/phar/tests/zip/files/badalias1.phar.zip new file mode 100644 index 0000000000..0e3adfc7cf Binary files /dev/null and b/ext/phar/tests/zip/files/badalias1.phar.zip differ diff --git a/ext/phar/tests/zip/files/badalias2.phar.zip b/ext/phar/tests/zip/files/badalias2.phar.zip new file mode 100644 index 0000000000..7b5baaa089 Binary files /dev/null and b/ext/phar/tests/zip/files/badalias2.phar.zip differ diff --git a/ext/phar/tests/zip/files/badalias3.phar.zip b/ext/phar/tests/zip/files/badalias3.phar.zip new file mode 100644 index 0000000000..7b5baaa089 Binary files /dev/null and b/ext/phar/tests/zip/files/badalias3.phar.zip differ diff --git a/ext/phar/tests/zip/files/badalias4.phar.zip b/ext/phar/tests/zip/files/badalias4.phar.zip new file mode 100644 index 0000000000..49b7be0dae Binary files /dev/null and b/ext/phar/tests/zip/files/badalias4.phar.zip differ diff --git a/ext/phar/tests/zip/files/badalias5.phar.zip b/ext/phar/tests/zip/files/badalias5.phar.zip new file mode 100644 index 0000000000..9f2b0e8282 Binary files /dev/null and b/ext/phar/tests/zip/files/badalias5.phar.zip differ diff --git a/ext/phar/tests/zip/files/cdir_offset.zip b/ext/phar/tests/zip/files/cdir_offset.zip new file mode 100644 index 0000000000..9172554f2d Binary files /dev/null and b/ext/phar/tests/zip/files/cdir_offset.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup1.zip b/ext/phar/tests/zip/files/compress_unsup1.zip new file mode 100644 index 0000000000..bd1f72baf8 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup1.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup10.zip b/ext/phar/tests/zip/files/compress_unsup10.zip new file mode 100644 index 0000000000..2a7f22128c Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup10.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup14.zip b/ext/phar/tests/zip/files/compress_unsup14.zip new file mode 100644 index 0000000000..d4941437d9 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup14.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup18.zip b/ext/phar/tests/zip/files/compress_unsup18.zip new file mode 100644 index 0000000000..7ef221763c Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup18.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup19.zip b/ext/phar/tests/zip/files/compress_unsup19.zip new file mode 100644 index 0000000000..8086d4546f Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup19.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup2.zip b/ext/phar/tests/zip/files/compress_unsup2.zip new file mode 100644 index 0000000000..d827d2d3a2 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup2.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup3.zip b/ext/phar/tests/zip/files/compress_unsup3.zip new file mode 100644 index 0000000000..d4acc60c1f Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup3.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup4.zip b/ext/phar/tests/zip/files/compress_unsup4.zip new file mode 100644 index 0000000000..76a4dc1aef Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup4.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup5.zip b/ext/phar/tests/zip/files/compress_unsup5.zip new file mode 100644 index 0000000000..d42155de53 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup5.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup6.zip b/ext/phar/tests/zip/files/compress_unsup6.zip new file mode 100644 index 0000000000..50846409cd Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup6.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup7.zip b/ext/phar/tests/zip/files/compress_unsup7.zip new file mode 100644 index 0000000000..65c2e23664 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup7.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup9.zip b/ext/phar/tests/zip/files/compress_unsup9.zip new file mode 100644 index 0000000000..df0c767a58 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup9.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup97.zip b/ext/phar/tests/zip/files/compress_unsup97.zip new file mode 100644 index 0000000000..907f365bf7 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup97.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsup98.zip b/ext/phar/tests/zip/files/compress_unsup98.zip new file mode 100644 index 0000000000..54f19fb3a0 Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsup98.zip differ diff --git a/ext/phar/tests/zip/files/compress_unsupunknown.zip b/ext/phar/tests/zip/files/compress_unsupunknown.zip new file mode 100644 index 0000000000..170695462a Binary files /dev/null and b/ext/phar/tests/zip/files/compress_unsupunknown.zip differ diff --git a/ext/phar/tests/zip/files/corrupt2.php.inc b/ext/phar/tests/zip/files/corrupt2.php.inc new file mode 100644 index 0000000000..3edf620310 --- /dev/null +++ b/ext/phar/tests/zip/files/corrupt2.php.inc @@ -0,0 +1,60 @@ +addFile('hi', null, 'hii'); +$a->addFile('hi2', null, 'hii2', null, null, 'encrypt', 'encrypt'); +$a->writeZip(dirname(__FILE__) . '/encrypted.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii'); +$a->addFile('', null, 'stdin'); +$a->writeZip(dirname(__FILE__) . '/stdin.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hii', null, 'hii', null, null, 'filename_len', 'filename_len'); +$a->addFile('hi', null, 'hii'); +$a->writeZip(dirname(__FILE__) . '/truncfilename.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress'); +$a->writeZip(dirname(__FILE__) . '/compress_unsup1.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 2); +$a->writeZip(dirname(__FILE__) . '/compress_unsup2.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 3); +$a->writeZip(dirname(__FILE__) . '/compress_unsup3.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 4); +$a->writeZip(dirname(__FILE__) . '/compress_unsup4.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 5); +$a->writeZip(dirname(__FILE__) . '/compress_unsup5.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 6); +$a->writeZip(dirname(__FILE__) . '/compress_unsup6.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 7); +$a->writeZip(dirname(__FILE__) . '/compress_unsup7.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 9); +$a->writeZip(dirname(__FILE__) . '/compress_unsup9.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 10); +$a->writeZip(dirname(__FILE__) . '/compress_unsup10.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 14); +$a->writeZip(dirname(__FILE__) . '/compress_unsup14.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 18); +$a->writeZip(dirname(__FILE__) . '/compress_unsup18.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 19); +$a->writeZip(dirname(__FILE__) . '/compress_unsup19.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 97); +$a->writeZip(dirname(__FILE__) . '/compress_unsup97.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 98); +$a->writeZip(dirname(__FILE__) . '/compress_unsup98.zip'); +$a = new corrupt_zipmaker; +$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 11); +$a->writeZip(dirname(__FILE__) . '/compress_unsupunknown.zip'); +?> diff --git a/ext/phar/tests/zip/files/corrupt_count1.php.inc b/ext/phar/tests/zip/files/corrupt_count1.php.inc new file mode 100644 index 0000000000..314fdef6db --- /dev/null +++ b/ext/phar/tests/zip/files/corrupt_count1.php.inc @@ -0,0 +1,11 @@ +addFile('hi', null, 'hii'); +$a->addFile('hi2', null, 'hii2'); +$a->writeZip(dirname(__FILE__) . '/count1.zip', 'count1'); +$a->writeZip(dirname(__FILE__) . '/count2.zip', 'count2'); +$a->writeZip(dirname(__FILE__) . '/nozipend.zip', 'none'); +$a->writeZip(dirname(__FILE__) . '/filecomment.zip', 'comment'); +$a->writeZip(dirname(__FILE__) . '/cdir_offset.zip', 'cdir_offset'); +?> diff --git a/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc b/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc new file mode 100644 index 0000000000..2c1719920d --- /dev/null +++ b/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc @@ -0,0 +1,317 @@ + + * @copyright 1997-2005 The PHP Group + * @license http://www.gnu.org/copyleft/lesser.html LGPL + * @version CVS: $Id$ + * @link http://pear.php.net/package/File_Archive + */ + +/** + * ZIP archive writer + */ +class corrupt_zipmaker +{ + /** + * @var int Current position in the writer + * @access private + */ + var $offset = 0; + + /** + * @var string Optionnal comment to add to the zip + * @access private + */ + var $comment = ""; + + /** + * @var string Data written at the end of the ZIP file + * @access private + */ + var $central = ""; + + /** + * @var string Data written at the start of the ZIP file + * @access private + */ + var $start = ""; + + /** + * Set a comment on the ZIP file + */ + function setComment($comment) { $this->comment = $comment; } + + /** + * @param int $time Unix timestamp of the date to convert + * @return the date formated as a ZIP date + */ + function getMTime($time) + { + $mtime = ($time !== null ? getdate($time) : getdate()); + $mtime = preg_replace( + "/(..){1}(..){1}(..){1}(..){1}/", + "\\x\\4\\x\\3\\x\\2\\x\\1", + dechex(($mtime['year']-1980<<25)| + ($mtime['mon' ]<<21)| + ($mtime['mday' ]<<16)| + ($mtime['hours' ]<<11)| + ($mtime['minutes']<<5)| + ($mtime['seconds']>>1))); + eval('$mtime = "'.$mtime.'";'); + return $mtime; + } + + private function getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $corrupt, $fakecomp) + { + switch ($corrupt) { + case null : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'compress' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $fakecomp) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'encrypt' : + $file = "PK\x03\x04\x14\x00\x01\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'crc32' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'complength' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength + 1, $uncomplength, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'uncomplength' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00) . + $filename . + $data; + break; + case 'filename_len' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00) . + $filename . + $data; + break; + case 'extra_len' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 1) . + $filename . + $data; + break; + case 'filename' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) . + substr($filename, 1) . + $data; + break; + case 'data' : + $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) . + $filename . + substr($data, 1); + break; + } + return $file; + } + + private function getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $corrupt, &$offset, $fakecomp) + { + settype($comment, 'string'); + switch ($corrupt) { + case null : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'encrypt' : + $central = "PK\x01\x02\x00\x00\x14\x00\x01\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'compress' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $fakecomp) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'crc32' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'complength' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength - 1, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'uncomplength' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'filename_len' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + case 'offset' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00, + 0x0000, $this->offset - 1). + $filename . $comment; + $offset = strlen($central) - 1; + break; + case 'comment' : + $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) . + $mtime . + pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment) + 1,0x00,0x00, + 0x0000, $this->offset). + $filename . $comment; + $offset = strlen($central); + break; + } + return $central; + } + + function addFile($filename, $mtime, $data, $comment = null, $compress = null, $filecorrupt = null, $centralcorrupt = null, $fakecomp = 1) + { + $mtime = $this->getMTime($mtime ? $mtime : null); + + $uncomplength = strlen($data); + $crc32 = crc32($data) & 0xFFFFFFFF; + $compmethod = 0; + switch ($compress) { + case 'gz' : + $data = gzcompress($data); + $compmethod = 8; + break; + case 'bz2' : + $data = bzcompress($data); + $compmethod = 12; + break; + } + $complength = strlen($data); + + $this->start .= ($file = $this->getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $filecorrupt, $fakecomp)); + + $offset = 0; + $this->central .= $this->getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $centralcorrupt, $offset, $fakecomp); + + $this->offset += $offset; + $this->count++; + } + + function writeZip($zipfile, $corrupt = null) + { + $write = $this->start . $this->central; + switch ($corrupt) { + case null : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count, $this->count, + $this->offset, strlen($this->start), + strlen($this->comment)) . $this->comment; + break; + case 'count1' : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count + 1, $this->count, + $this->offset, strlen($this->start), + strlen($this->comment)) . $this->comment; + break; + case 'count2' : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count, $this->count + 1, + $this->offset, strlen($this->start), + strlen($this->comment)) . $this->comment; + break; + case 'cdir_offset' : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count, $this->count, + $this->offset, strlen($this->start) - 3, + strlen($this->comment)) . $this->comment; + break; + case 'cdir_len' : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count, $this->count, + $this->offset - 5, strlen($this->start), + strlen($this->comment)) . $this->comment; + break; + case 'comment' : + $write .= "PK\x05\x06\x00\x00\x00\x00" . + pack("vvVVv", $this->count, $this->count, + strlen($this->start), $this->offset + 1, + strlen($this->comment) + 1) . $this->comment; + break; + case 'none' : + } + file_put_contents($zipfile, $write); + } +} +?> \ No newline at end of file diff --git a/ext/phar/tests/zip/files/count1.zip b/ext/phar/tests/zip/files/count1.zip new file mode 100644 index 0000000000..73b556103a Binary files /dev/null and b/ext/phar/tests/zip/files/count1.zip differ diff --git a/ext/phar/tests/zip/files/count2.zip b/ext/phar/tests/zip/files/count2.zip new file mode 100644 index 0000000000..6aa2619539 Binary files /dev/null and b/ext/phar/tests/zip/files/count2.zip differ diff --git a/ext/phar/tests/zip/files/encrypted.zip b/ext/phar/tests/zip/files/encrypted.zip new file mode 100644 index 0000000000..dee73cad37 Binary files /dev/null and b/ext/phar/tests/zip/files/encrypted.zip differ diff --git a/ext/phar/tests/zip/files/filecomment.zip b/ext/phar/tests/zip/files/filecomment.zip new file mode 100644 index 0000000000..414b121fdc Binary files /dev/null and b/ext/phar/tests/zip/files/filecomment.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller.phar.inc b/ext/phar/tests/zip/files/frontcontroller.phar.inc new file mode 100644 index 0000000000..241dceb57b --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller.phar.inc @@ -0,0 +1,13 @@ +setStub(' diff --git a/ext/phar/tests/zip/files/frontcontroller.phar.zip b/ext/phar/tests/zip/files/frontcontroller.phar.zip new file mode 100644 index 0000000000..4ee905dd3a Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller10.phar.inc b/ext/phar/tests/zip/files/frontcontroller10.phar.inc new file mode 100644 index 0000000000..c973cc15d9 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller10.phar.inc @@ -0,0 +1,20 @@ +setStub(' diff --git a/ext/phar/tests/zip/files/frontcontroller10.phar.zip b/ext/phar/tests/zip/files/frontcontroller10.phar.zip new file mode 100644 index 0000000000..c37cb381fb Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller10.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller11.phar.inc b/ext/phar/tests/zip/files/frontcontroller11.phar.inc new file mode 100644 index 0000000000..c24a6f14e4 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller11.phar.inc @@ -0,0 +1,20 @@ +setStub(' diff --git a/ext/phar/tests/zip/files/frontcontroller11.phar.zip b/ext/phar/tests/zip/files/frontcontroller11.phar.zip new file mode 100644 index 0000000000..48e5fc678a Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller11.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller12.phar.inc b/ext/phar/tests/zip/files/frontcontroller12.phar.inc new file mode 100644 index 0000000000..77c4a1dd0e --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller12.phar.inc @@ -0,0 +1,20 @@ +setStub(' diff --git a/ext/phar/tests/zip/files/frontcontroller12.phar.zip b/ext/phar/tests/zip/files/frontcontroller12.phar.zip new file mode 100644 index 0000000000..c086c4d4a4 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller12.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller2.phar.inc b/ext/phar/tests/zip/files/frontcontroller2.phar.inc new file mode 100644 index 0000000000..6cfa052a83 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller2.phar.inc @@ -0,0 +1,12 @@ +setStub(' diff --git a/ext/phar/tests/zip/files/frontcontroller2.phar.zip b/ext/phar/tests/zip/files/frontcontroller2.phar.zip new file mode 100644 index 0000000000..7ef43dc000 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller2.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller3.phar.inc b/ext/phar/tests/zip/files/frontcontroller3.phar.inc new file mode 100644 index 0000000000..ab28f7b3d0 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller3.phar.inc @@ -0,0 +1,18 @@ +setStub(' "a.phps"); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "/index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller3.phar.zip b/ext/phar/tests/zip/files/frontcontroller3.phar.zip new file mode 100644 index 0000000000..40c1d4994b Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller3.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller4.phar.inc b/ext/phar/tests/zip/files/frontcontroller4.phar.inc new file mode 100644 index 0000000000..d78399142e --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller4.phar.inc @@ -0,0 +1,18 @@ +setStub(' false); + if (isset($b[$a])) return $b[$a]; + return $a; +} +Phar::webPhar("whatever", "index.php", null, array(), "s"); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller4.phar.zip b/ext/phar/tests/zip/files/frontcontroller4.phar.zip new file mode 100644 index 0000000000..4dc83408b0 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller4.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller5.phar.inc b/ext/phar/tests/zip/files/frontcontroller5.phar.inc new file mode 100644 index 0000000000..931fa975e1 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller5.phar.inc @@ -0,0 +1,12 @@ +setStub(' "oops")); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller5.phar.zip b/ext/phar/tests/zip/files/frontcontroller5.phar.zip new file mode 100644 index 0000000000..0ab0472101 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller5.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller6.phar.inc b/ext/phar/tests/zip/files/frontcontroller6.phar.inc new file mode 100644 index 0000000000..3b551f268d --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller6.phar.inc @@ -0,0 +1,12 @@ +setStub(' 100)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller6.phar.zip b/ext/phar/tests/zip/files/frontcontroller6.phar.zip new file mode 100644 index 0000000000..bf98255fe9 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller6.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller7.phar.inc b/ext/phar/tests/zip/files/frontcontroller7.phar.inc new file mode 100644 index 0000000000..42c10bc739 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller7.phar.inc @@ -0,0 +1,12 @@ +setStub(' null)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller7.phar.zip b/ext/phar/tests/zip/files/frontcontroller7.phar.zip new file mode 100644 index 0000000000..02fc3e27b6 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller7.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller8.phar.inc b/ext/phar/tests/zip/files/frontcontroller8.phar.inc new file mode 100644 index 0000000000..e04ac414e9 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller8.phar.inc @@ -0,0 +1,13 @@ +setStub(' "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller8.phar.zip b/ext/phar/tests/zip/files/frontcontroller8.phar.zip new file mode 100644 index 0000000000..41952ce745 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller8.phar.zip differ diff --git a/ext/phar/tests/zip/files/frontcontroller9.phar.inc b/ext/phar/tests/zip/files/frontcontroller9.phar.inc new file mode 100644 index 0000000000..50440451f7 --- /dev/null +++ b/ext/phar/tests/zip/files/frontcontroller9.phar.inc @@ -0,0 +1,14 @@ +setStub(' "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS)); +echo "oops did not run\n"; +var_dump($_ENV, $_SERVER); +__HALT_COMPILER();'); +?> diff --git a/ext/phar/tests/zip/files/frontcontroller9.phar.zip b/ext/phar/tests/zip/files/frontcontroller9.phar.zip new file mode 100644 index 0000000000..d3f4ff8404 Binary files /dev/null and b/ext/phar/tests/zip/files/frontcontroller9.phar.zip differ diff --git a/ext/phar/tests/zip/files/make_invalid_tar.php.inc b/ext/phar/tests/zip/files/make_invalid_tar.php.inc new file mode 100644 index 0000000000..cec8ef7793 --- /dev/null +++ b/ext/phar/tests/zip/files/make_invalid_tar.php.inc @@ -0,0 +1,12 @@ +path, 'r+b'); + fseek($fp, 20); + fwrite($fp, 'oopsie'); + fclose($fp); +} +} \ No newline at end of file diff --git a/ext/phar/tests/zip/files/metadata.phar.inc b/ext/phar/tests/zip/files/metadata.phar.inc new file mode 100644 index 0000000000..932fc961e3 --- /dev/null +++ b/ext/phar/tests/zip/files/metadata.phar.inc @@ -0,0 +1,11 @@ +setMetadata('hi there'); +$a['c'] = 'c'; +$a['c']->setMetadata(array('hi', 'there')); +$a['d'] = 'd'; +$a['d']->setMetadata(array('hi'=>'there','foo'=>'bar')); +?> diff --git a/ext/phar/tests/zip/files/metadata.phar.zip b/ext/phar/tests/zip/files/metadata.phar.zip new file mode 100644 index 0000000000..3c5cf0065f Binary files /dev/null and b/ext/phar/tests/zip/files/metadata.phar.zip differ diff --git a/ext/phar/tests/zip/files/nozipend.zip b/ext/phar/tests/zip/files/nozipend.zip new file mode 100644 index 0000000000..f97607221c Binary files /dev/null and b/ext/phar/tests/zip/files/nozipend.zip differ diff --git a/ext/phar/tests/zip/files/odt.odt b/ext/phar/tests/zip/files/odt.odt new file mode 100644 index 0000000000..527e09fefc Binary files /dev/null and b/ext/phar/tests/zip/files/odt.odt differ diff --git a/ext/phar/tests/zip/files/stdin.zip b/ext/phar/tests/zip/files/stdin.zip new file mode 100644 index 0000000000..4376eb67fa Binary files /dev/null and b/ext/phar/tests/zip/files/stdin.zip differ diff --git a/ext/phar/tests/zip/files/truncfilename.zip b/ext/phar/tests/zip/files/truncfilename.zip new file mode 100644 index 0000000000..d8a526a4bb Binary files /dev/null and b/ext/phar/tests/zip/files/truncfilename.zip differ diff --git a/ext/phar/tests/zip/files/zip.zip b/ext/phar/tests/zip/files/zip.zip new file mode 100644 index 0000000000..5ee9cae6ac Binary files /dev/null and b/ext/phar/tests/zip/files/zip.zip differ diff --git a/ext/phar/tests/zip/files/zipmaker.php.inc b/ext/phar/tests/zip/files/zipmaker.php.inc new file mode 100644 index 0000000000..aceab0d26b --- /dev/null +++ b/ext/phar/tests/zip/files/zipmaker.php.inc @@ -0,0 +1,70 @@ +path = $path; + } + + /** + * save a file inside this package + * @param string relative path within the package + * @param string|resource file contents or open file handle + */ + function addFile($path, $fileOrStream) + { + if (is_resource($fileOrStream)) { + $this->zip->addFromString($path, stream_get_contents($fileOrStream)); + } else { + $this->zip->addFromString($path, $fileOrStream); + } + } + + /** + * Initialize the package creator + */ + function init() + { + $this->zip = new ZipArchive; + if (true !== $this->zip->open($this->path, ZIPARCHIVE::CREATE)) { + throw new Exception( + 'Cannot open ZIP archive ' . $this->path + ); + } + } + + /** + * Create an internal directory, creating parent directories as needed + * + * This is a no-op for the tar creator + * @param string $dir + */ + function mkdir($dir) + { + $this->zip->addEmptyDir($dir); + } + + /** + * Finish saving the package + */ + function close() + { + $this->zip->close(); + } +} \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller1.phar.phpt b/ext/phar/tests/zip/frontcontroller1.phar.phpt new file mode 100644 index 0000000000..0a6847885d --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller1.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller other zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller1.phar.php +REQUEST_URI=/frontcontroller1.phar.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Content-type: image/jpeg +Content-length: 3 +--EXPECT-- +hio diff --git a/ext/phar/tests/zip/frontcontroller10.phar.phpt b/ext/phar/tests/zip/frontcontroller10.phar.phpt new file mode 100644 index 0000000000..ffe23bc08e --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller10.phar.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller rewrite array invalid zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller10.phar.php +REQUEST_URI=/frontcontroller10.phar.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller4.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +Status: 403 Access Denied +--EXPECT-- + + + Access Denied + + +

    403 - File /hi Access Denied

    + + \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller11.phar.phpt b/ext/phar/tests/zip/frontcontroller11.phar.phpt new file mode 100644 index 0000000000..f1fd26bb75 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller11.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type extension is not a string zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller11.phar.php +REQUEST_URI=/frontcontroller11.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller5.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.phar.php:2 +Stack trace: +#0 %sfrontcontroller11.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller11.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller12.phar.phpt b/ext/phar/tests/zip/frontcontroller12.phar.phpt new file mode 100644 index 0000000000..dc5bcdce78 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller12.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type unknown int zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller12.phar.php +REQUEST_URI=/frontcontroller12.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller6.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.phar.php:2 +Stack trace: +#0 %sfrontcontroller12.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller12.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller13.phar.phpt b/ext/phar/tests/zip/frontcontroller13.phar.phpt new file mode 100644 index 0000000000..592d662536 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller13.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type not string/int zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller13.phar.php +REQUEST_URI=/frontcontroller13.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller7.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.phar.php:2 +Stack trace: +#0 %sfrontcontroller13.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array) +#1 {main} + thrown in %sfrontcontroller13.phar.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller14.phar.phpt b/ext/phar/tests/zip/frontcontroller14.phar.phpt new file mode 100644 index 0000000000..1caa85bc07 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller14.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, other zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller14.phar.php +REQUEST_URI=/frontcontroller14.phar.php/a.jpg +PATH_INFO=/a.jpg +--FILE_EXTERNAL-- +files/frontcontroller8.phar.zip +--EXPECTHEADERS-- +Content-type: foo/bar +Content-length: 4 +--EXPECT-- +hio2 diff --git a/ext/phar/tests/zip/frontcontroller15.phar.phpt b/ext/phar/tests/zip/frontcontroller15.phar.phpt new file mode 100644 index 0000000000..89adc0a106 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller15.phar.phpt @@ -0,0 +1,18 @@ +--TEST-- +Phar front controller mime type override, Phar::PHPS zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller15.phar.php +REQUEST_URI=/frontcontroller15.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller8.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + + diff --git a/ext/phar/tests/zip/frontcontroller16.phar.phpt b/ext/phar/tests/zip/frontcontroller16.phar.phpt new file mode 100644 index 0000000000..e27faf3931 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller16.phar.phpt @@ -0,0 +1,15 @@ +--TEST-- +Phar front controller mime type override, Phar::PHP zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller16.phar.php +REQUEST_URI=/frontcontroller16.phar.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller8.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio1 + diff --git a/ext/phar/tests/zip/frontcontroller17.phar.phpt b/ext/phar/tests/zip/frontcontroller17.phar.phpt new file mode 100644 index 0000000000..f85bec2911 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller17.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller mime type unknown zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller17.phar.php +REQUEST_URI=/frontcontroller17.phar.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller8.phar.zip +--EXPECTHEADERS-- +Content-type: application/octet-stream +Content-length: 4 +--EXPECT-- +hio3 + diff --git a/ext/phar/tests/zip/frontcontroller18.phar.phpt b/ext/phar/tests/zip/frontcontroller18.phar.phpt new file mode 100644 index 0000000000..c687dd0664 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller18.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller18.phar.php +REQUEST_URI=/frontcontroller18.phar.php/fronk.gronk +PATH_INFO=/fronk.gronk +--FILE_EXTERNAL-- +files/frontcontroller9.phar.zip +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.phar.php:2 +Stack trace: +#0 %sfrontcontroller18.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller18.phar.php on line 2 diff --git a/ext/phar/tests/zip/frontcontroller19.phar.phpt b/ext/phar/tests/zip/frontcontroller19.phar.phpt new file mode 100644 index 0000000000..5b828e9e60 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller19.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 2 zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller19.phar.php +REQUEST_URI=/frontcontroller19.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller10.phar.zip +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.phar.php:2 +Stack trace: +#0 %sfrontcontroller19.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller19.phar.php on line 2 diff --git a/ext/phar/tests/zip/frontcontroller2.phar.phpt b/ext/phar/tests/zip/frontcontroller2.phar.phpt new file mode 100644 index 0000000000..0e101f6d41 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller2.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller PHP test zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller2.phar.php +REQUEST_URI=/frontcontroller2.phar.php/a.php +PATH_INFO=/a.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +hio diff --git a/ext/phar/tests/zip/frontcontroller20.phar.phpt b/ext/phar/tests/zip/frontcontroller20.phar.phpt new file mode 100644 index 0000000000..1cf54860ac --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller20.phar.phpt @@ -0,0 +1,16 @@ +--TEST-- +Phar front controller $_SERVER munging failure 3 zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller20.phar.php +REQUEST_URI=/frontcontroller20.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller11.phar.zip +--EXPECTF-- +Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.phar.php:2 +Stack trace: +#0 %sfrontcontroller20.phar.php(2): Phar::mungServer(Array) +#1 {main} + thrown in %sfrontcontroller20.phar.php on line 2 diff --git a/ext/phar/tests/zip/frontcontroller21.phar.phpt b/ext/phar/tests/zip/frontcontroller21.phar.phpt new file mode 100644 index 0000000000..d31b730ab8 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller21.phar.phpt @@ -0,0 +1,22 @@ +--TEST-- +Phar front controller $_SERVER munging success zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller21.phar.php +REQUEST_URI=/frontcontroller21.phar.php/index.php?test=hi +PATH_INFO=/index.php +QUERY_STRING=test=hi +--FILE_EXTERNAL-- +files/frontcontroller12.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECTF-- +string(10) "/index.php" +string(10) "/index.php" +string(%d) "phar://%sfrontcontroller21.phar.php/index.php" +string(18) "/index.php?test=hi" +string(37) "/frontcontroller21.phar.php/index.php" +string(27) "/frontcontroller21.phar.php" +string(%d) "%sfrontcontroller21.phar.php" +string(45) "/frontcontroller21.phar.php/index.php?test=hi" \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller3.phar.phpt b/ext/phar/tests/zip/frontcontroller3.phar.phpt new file mode 100644 index 0000000000..abe33bb502 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller3.phar.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller phps zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller3.phar.php +REQUEST_URI=/frontcontroller3.phar.php/a.phps +PATH_INFO=/a.phps +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + diff --git a/ext/phar/tests/zip/frontcontroller4.phar.phpt b/ext/phar/tests/zip/frontcontroller4.phar.phpt new file mode 100644 index 0000000000..6c03620c1c --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller4.phar.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar front controller index.php relocate (no /) zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller4.phar.php +REQUEST_URI=/frontcontroller4.phar.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller4.phar.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/zip/frontcontroller5.phar.phpt b/ext/phar/tests/zip/frontcontroller5.phar.phpt new file mode 100644 index 0000000000..9597a1c14c --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller5.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller index.php relocate zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller5.phar.php +REQUEST_URI=/frontcontroller5.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller5.phar.php/index.php +--EXPECT-- diff --git a/ext/phar/tests/zip/frontcontroller6.phar.phpt b/ext/phar/tests/zip/frontcontroller6.phar.phpt new file mode 100644 index 0000000000..1da20e96d7 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller6.phar.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller 404 zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller6.phar.php +REQUEST_URI=/frontcontroller6.phar.php/notfound.php +PATH_INFO=/notfound.php +--FILE_EXTERNAL-- +files/frontcontroller.phar.zip +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /notfound.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller7.phar.phpt b/ext/phar/tests/zip/frontcontroller7.phar.phpt new file mode 100644 index 0000000000..d13cf33c16 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller7.phar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar front controller alternate index file zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller7.phar.php +REQUEST_URI=/frontcontroller7.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller2.phar.zip +--EXPECTHEADERS-- +Status: 301 Moved Permanently +Location: /frontcontroller7.phar.php/a.php +--EXPECT-- diff --git a/ext/phar/tests/zip/frontcontroller8.phar.phpt b/ext/phar/tests/zip/frontcontroller8.phar.phpt new file mode 100644 index 0000000000..1b0d133bc7 --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller8.phar.phpt @@ -0,0 +1,21 @@ +--TEST-- +Phar front controller no index file 404 zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller8.phar.php +REQUEST_URI=/frontcontroller8.phar.php/ +PATH_INFO=/ +--FILE_EXTERNAL-- +files/frontcontroller3.phar.zip +--EXPECTHEADERS-- +Status: 404 Not Found +--EXPECT-- + + + File Not Found + + +

    404 - File /index.php Not Found

    + + \ No newline at end of file diff --git a/ext/phar/tests/zip/frontcontroller9.phar.phpt b/ext/phar/tests/zip/frontcontroller9.phar.phpt new file mode 100644 index 0000000000..8c550539fc --- /dev/null +++ b/ext/phar/tests/zip/frontcontroller9.phar.phpt @@ -0,0 +1,17 @@ +--TEST-- +Phar front controller rewrite array zip-based +--SKIPIF-- + +--ENV-- +SCRIPT_NAME=/frontcontroller9.phar.php +REQUEST_URI=/frontcontroller9.phar.php/hi +PATH_INFO=/hi +--FILE_EXTERNAL-- +files/frontcontroller3.phar.zip +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- + +<?php function hio(){} + + \ No newline at end of file diff --git a/ext/phar/tests/zip/getalias.phpt b/ext/phar/tests/zip/getalias.phpt new file mode 100644 index 0000000000..9c917633c9 --- /dev/null +++ b/ext/phar/tests/zip/getalias.phpt @@ -0,0 +1,59 @@ +--TEST-- +Phar: getAlias() with an existing phar.zip +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +getAlias()); +unset($phar); + +copy(dirname(__FILE__) . '/files/metadata.phar.zip', $fname); + +// existing phar.zip, no alias set +$phar = new Phar($fname); +var_dump($phar->getAlias()); + +// check that default alias can be overwritten +$phar->setAlias('jiminycricket'); +var_dump($phar->getAlias()); +unset($phar); + +// existing phar.zip, alias set +$phar = new Phar($fname); +var_dump($phar->getAlias()); + +// check that alias can't be set manually +try { + $phar['.phar/alias.txt'] = 'pinocchio'; +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} +var_dump($phar->getAlias()); + +// check that user-defined alias can be overwritten +$phar->setAlias('pinocchio'); +var_dump($phar->getAlias()); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(%d) "%sgetalias.phar.zip" +string(%d) "%sgetalias.phar.zip" +string(13) "jiminycricket" +string(13) "jiminycricket" +Cannot set alias ".phar/alias.txt" directly in phar "%sgetalias.phar.zip", use setAlias +string(13) "jiminycricket" +string(9) "pinocchio" +===DONE=== diff --git a/ext/phar/tests/zip/largezip.phpt b/ext/phar/tests/zip/largezip.phpt new file mode 100644 index 0000000000..a8438eb7b7 --- /dev/null +++ b/ext/phar/tests/zip/largezip.phpt @@ -0,0 +1,29 @@ +--TEST-- +Phar: large zip file (zip edge cases) +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +getContent())); +?> +===DONE=== +--CLEAN-- + + +--EXPECT-- +int(200000) +===DONE=== diff --git a/ext/phar/tests/zip/metadata_write_commit.phpt b/ext/phar/tests/zip/metadata_write_commit.phpt new file mode 100644 index 0000000000..cf0945d153 --- /dev/null +++ b/ext/phar/tests/zip/metadata_write_commit.phpt @@ -0,0 +1,85 @@ +--TEST-- +Phar with meta-data (write) zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +"; + +$files = array(); +$files['a'] = array('cont' => 'a'); +$files['b'] = array('cont' => 'b', 'meta' => 'hi there'); +$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there')); +$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar')); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($p2name.'/'.$name)); +} + +copy($f2name, $fname); +$phar = new Phar($fname); +$phar->startBuffering(); +$phar['a']->setMetadata(42); +$phar['b']->setMetadata(NULL); +$phar['c']->setMetadata(array(25, 'foo'=>'bar')); +$phar['d']->setMetadata(true); +$phar->setMetadata('hi'); + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} +$phar->stopBuffering(); + +unset($phar); + +$phar = new Phar($fname); + +foreach($files as $name => $cont) { + var_dump(file_get_contents($pname.'/'.$name)); +} + +foreach($files as $name => $cont) { + var_dump($phar[$name]->getMetadata()); +} +var_dump($phar->getMetadata()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +string(1) "a" +string(1) "b" +string(1) "c" +string(1) "d" +int(42) +NULL +array(2) { + [0]=> + int(25) + ["foo"]=> + string(3) "bar" +} +bool(true) +string(2) "hi" +===DONE=== diff --git a/ext/phar/tests/zip/notphar.phpt b/ext/phar/tests/zip/notphar.phpt new file mode 100644 index 0000000000..26dcd71ed9 --- /dev/null +++ b/ext/phar/tests/zip/notphar.phpt @@ -0,0 +1,23 @@ +--TEST-- +Phar: a non-executable zip with no stub named .phar.zip +--SKIPIF-- + +--INI-- +phar.readonly=1 +--FILE-- + +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: include(phar://%snotphar.phar.zip/.phar/stub.php): failed to open stream: '%snotphar.phar.zip' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive in %snotphar.php on line %d +PK%a \ No newline at end of file diff --git a/ext/phar/tests/zip/odt.phpt b/ext/phar/tests/zip/odt.phpt new file mode 100644 index 0000000000..28187f68b7 --- /dev/null +++ b/ext/phar/tests/zip/odt.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: test a zip archive created by openoffice +--SKIPIF-- + + +--FILE-- +isDir()) { + echo "dir " . $b->getPathName() . "\n"; + } else { + echo $b->getPathName() . "\n"; + } +} +// this next line is for increased code coverage +try { + $b = new Phar(dirname(__FILE__) . '/files/odt.odt'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +phar://%sodt.odt%cConfigurations2%caccelerator%ccurrent.xml +phar://%sodt.odt%cMETA-INF%cmanifest.xml +phar://%sodt.odt%cThumbnails%cthumbnail.png +phar://%sodt.odt%ccontent.xml +phar://%sodt.odt%cmeta.xml +phar://%sodt.odt%cmimetype +phar://%sodt.odt%csettings.xml +phar://%sodt.odt%cstyles.xml +Cannot create phar '%sodt.odt', file extension (or combination) not recognised +===DONE=== diff --git a/ext/phar/tests/zip/open_for_write_existing.phpt b/ext/phar/tests/zip/open_for_write_existing.phpt new file mode 100644 index 0000000000..94f85b4e3f --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_existing.phpt @@ -0,0 +1,39 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECT-- +extra +===DONE=== diff --git a/ext/phar/tests/zip/open_for_write_existing_b.phpt b/ext/phar/tests/zip/open_for_write_existing_b.phpt new file mode 100755 index 0000000000..347a1ce719 --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_existing_b.phpt @@ -0,0 +1,52 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +ini_set('phar.readonly', 1); + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $alias . '/b/c.php'; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_b.phar.zip/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d +This is b/c +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/open_for_write_existing_c.phpt b/ext/phar/tests/zip/open_for_write_existing_c.phpt new file mode 100755 index 0000000000..b66a77b212 --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_existing_c.phpt @@ -0,0 +1,46 @@ +--TEST-- +Phar: fopen a .phar for writing (existing file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +ini_set('phar.readonly', 1); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); +include $alias . '/b/c.php'; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_existing_c.phar.zip/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d +This is b/c +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/open_for_write_newfile.phpt b/ext/phar/tests/zip/open_for_write_newfile.phpt new file mode 100644 index 0000000000..c3782d4fd3 --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_newfile.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECT-- +This is b/c +extra +===DONE=== diff --git a/ext/phar/tests/zip/open_for_write_newfile_b.phpt b/ext/phar/tests/zip/open_for_write_newfile_b.phpt new file mode 100755 index 0000000000..44ad7487fa --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_newfile_b.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +ini_set('phar.readonly', 1); + +function err_handler($errno, $errstr, $errfile, $errline) { + echo "Catchable fatal error: $errstr in $errfile on line $errline\n"; +} + +set_error_handler("err_handler", E_RECOVERABLE_ERROR); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_b.phar.zip/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_b.phar.zip/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.zip" in %sopen_for_write_newfile_b.php on line %d + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.zip/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d + +===DONE=== diff --git a/ext/phar/tests/zip/open_for_write_newfile_c.phpt b/ext/phar/tests/zip/open_for_write_newfile_c.phpt new file mode 100755 index 0000000000..b664397a99 --- /dev/null +++ b/ext/phar/tests/zip/open_for_write_newfile_c.phpt @@ -0,0 +1,54 @@ +--TEST-- +Phar: fopen a .phar for writing (new file) zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(''); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +ini_set('phar.readonly', 1); + +$fp = fopen($alias . '/b/new.php', 'wb'); +fwrite($fp, 'extra'); +fclose($fp); + +include $alias . '/b/c.php'; +include $alias . '/b/new.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Warning: fopen(phar://%sopen_for_write_newfile_c.phar.zip/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d + +Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d + +Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d +This is b/c + +Warning: include(phar://%sopen_for_write_newfile_c.phar.zip/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.zip" in %sopen_for_write_newfile_c.php on line %d + +Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.zip/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d + +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/phar_begin_setstub_commit.phpt b/ext/phar/tests/zip/phar_begin_setstub_commit.phpt new file mode 100755 index 0000000000..81cf4001c3 --- /dev/null +++ b/ext/phar/tests/zip/phar_begin_setstub_commit.phpt @@ -0,0 +1,68 @@ +--TEST-- +Phar::startBuffering()/setStub()/stopBuffering() zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +isFileFormat(Phar::ZIP)); +//var_dump($p->getStub()); +var_dump($p->isBuffering()); +$p->startBuffering(); +var_dump($p->isBuffering()); +$p['a.php'] = 'setStub(''); +include 'phar://brandnewphar.phar/a.php'; +var_dump($p->getStub()); +$p['b.php'] = 'setStub('getStub()); +$p->stopBuffering(); +echo "===COMMIT===\n"; +var_dump($p->isBuffering()); +include 'phar://brandnewphar.phar/a.php'; +include 'phar://brandnewphar.phar/b.php'; +var_dump($p->getStub()); + +// add portion to test setting stub from resource +file_put_contents(dirname(__FILE__) . '/myfakestub.php', ''); +$a = fopen(dirname(__FILE__) . '/myfakestub.php', 'rb'); +$p->setStub($a); +var_dump($p->getStub()); +$c = strlen(''); +file_put_contents(dirname(__FILE__) . '/myfakestub.php', '' . 'extra stuff'); +fseek($a, 0); +$p->setStub($a, $c); +var_dump($p->getStub()); +fclose($a); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(false) +string(5) "Hello" +string(84) " +" +string(5) "World" +string(85) " +" +===COMMIT=== +bool(true) +string(5) "Hello" +string(5) "World" +string(85) " +" +string(93) " +" +string(93) " +" +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/phar_buildfromiterator4.phpt b/ext/phar/tests/zip/phar_buildfromiterator4.phpt new file mode 100644 index 0000000000..cc11fe5537 --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator4.phpt @@ -0,0 +1,66 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file passed in zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt')))); + var_dump($phar->isFileFormat(Phar::ZIP)); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "%sphar_buildfromiterator4.phpt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/phar_buildfromiterator5.phpt b/ext/phar/tests/zip/phar_buildfromiterator5.phpt new file mode 100644 index 0000000000..450ada100d --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator5.phpt @@ -0,0 +1,59 @@ +--TEST-- +Phar::buildFromIterator() iterator, iterator returns non-string zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass)))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid value (must return a string) +===DONE=== diff --git a/ext/phar/tests/zip/phar_buildfromiterator6.phpt b/ext/phar/tests/zip/phar_buildfromiterator6.phpt new file mode 100644 index 0000000000..2dfb04dbf0 --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator6.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, key is int zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip'); + var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned an invalid key (must return a string) +===DONE=== diff --git a/ext/phar/tests/zip/phar_buildfromiterator7.phpt b/ext/phar/tests/zip/phar_buildfromiterator7.phpt new file mode 100644 index 0000000000..16ba6d61b9 --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator7.phpt @@ -0,0 +1,60 @@ +--TEST-- +Phar::buildFromIterator() iterator, file can't be opened zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt')))); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +rewind +valid +current +key +string(24) "UnexpectedValueException" +Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt" +===DONE=== diff --git a/ext/phar/tests/zip/phar_buildfromiterator8.phpt b/ext/phar/tests/zip/phar_buildfromiterator8.phpt new file mode 100644 index 0000000000..d2b1be2087 --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator8.phpt @@ -0,0 +1,73 @@ +--TEST-- +Phar::buildFromIterator() iterator, SplFileInfo as current zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^frontcontroller\d{0,2}\.phar\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR); + asort($a); + var_dump($a); + var_dump($phar->isFileFormat(Phar::ZIP)); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(21) { + ["frontcontroller1.phar.phpt"]=> + string(%d) "%sfrontcontroller1.phar.phpt" + ["frontcontroller10.phar.phpt"]=> + string(%d) "%sfrontcontroller10.phar.phpt" + ["frontcontroller11.phar.phpt"]=> + string(%d) "%sfrontcontroller11.phar.phpt" + ["frontcontroller12.phar.phpt"]=> + string(%d) "%sfrontcontroller12.phar.phpt" + ["frontcontroller13.phar.phpt"]=> + string(%d) "%sfrontcontroller13.phar.phpt" + ["frontcontroller14.phar.phpt"]=> + string(%d) "%sfrontcontroller14.phar.phpt" + ["frontcontroller15.phar.phpt"]=> + string(%d) "%sfrontcontroller15.phar.phpt" + ["frontcontroller16.phar.phpt"]=> + string(%d) "%sfrontcontroller16.phar.phpt" + ["frontcontroller17.phar.phpt"]=> + string(%d) "%sfrontcontroller17.phar.phpt" + ["frontcontroller18.phar.phpt"]=> + string(%d) "%sfrontcontroller18.phar.phpt" + ["frontcontroller19.phar.phpt"]=> + string(%d) "%sfrontcontroller19.phar.phpt" + ["frontcontroller2.phar.phpt"]=> + string(%d) "%sfrontcontroller2.phar.phpt" + ["frontcontroller20.phar.phpt"]=> + string(%d) "%sfrontcontroller20.phar.phpt" + ["frontcontroller21.phar.phpt"]=> + string(%d) "%sfrontcontroller21.phar.phpt" + ["frontcontroller3.phar.phpt"]=> + string(%d) "%sfrontcontroller3.phar.phpt" + ["frontcontroller4.phar.phpt"]=> + string(%d) "%sfrontcontroller4.phar.phpt" + ["frontcontroller5.phar.phpt"]=> + string(%d) "%sfrontcontroller5.phar.phpt" + ["frontcontroller6.phar.phpt"]=> + string(%d) "%sfrontcontroller6.phar.phpt" + ["frontcontroller7.phar.phpt"]=> + string(%d) "%sfrontcontroller7.phar.phpt" + ["frontcontroller8.phar.phpt"]=> + string(%d) "%sfrontcontroller8.phar.phpt" + ["frontcontroller9.phar.phpt"]=> + string(%d) "%sfrontcontroller9.phar.phpt" +} +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/phar_buildfromiterator9.phpt b/ext/phar/tests/zip/phar_buildfromiterator9.phpt new file mode 100644 index 0000000000..0b56307545 --- /dev/null +++ b/ext/phar/tests/zip/phar_buildfromiterator9.phpt @@ -0,0 +1,65 @@ +--TEST-- +Phar::buildFromIterator() iterator, 1 file resource passed in +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +a = $a; + } + function next() { + echo "next\n"; + return next($this->a); + } + function current() { + echo "current\n"; + return current($this->a); + } + function key() { + echo "key\n"; + return key($this->a); + } + function valid() { + echo "valid\n"; + return current($this->a); + } + function rewind() { + echo "rewind\n"; + return reset($this->a); + } +} +try { + chdir(dirname(__FILE__)); + $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); + var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r'))))); + fclose($a); +} catch (Exception $e) { + var_dump(get_class($e)); + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +rewind +valid +current +key +next +valid +array(1) { + ["a"]=> + string(%d) "[stream]" +} +===DONE=== diff --git a/ext/phar/tests/zip/phar_commitwrite.phpt b/ext/phar/tests/zip/phar_commitwrite.phpt new file mode 100644 index 0000000000..84bccb9fae --- /dev/null +++ b/ext/phar/tests/zip/phar_commitwrite.phpt @@ -0,0 +1,44 @@ +--TEST-- +Phar::setStub()/stopBuffering() zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($p->getStub()); +$p->setStub(""); +var_dump($p->getStub()); +var_dump($p->isFileFormat(Phar::ZIP)); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +string(60) " +" +bool(true) +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/phar_convert_phar.phpt b/ext/phar/tests/zip/phar_convert_phar.phpt new file mode 100644 index 0000000000..815656dbf6 --- /dev/null +++ b/ext/phar/tests/zip/phar_convert_phar.phpt @@ -0,0 +1,57 @@ +--TEST-- +Phar::convertToPhar() from zip +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +stopBuffering(); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump(strlen($phar->getStub())); + +$phar = $phar->convertToExecutable(Phar::ZIP); +var_dump($phar->isFileFormat(Phar::ZIP)); +var_dump($phar->getStub()); + +$phar['a'] = 'hi there'; + +$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.3.phar'); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump(strlen($phar->getStub())); + +copy($fname3, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isFileFormat(Phar::PHAR)); +var_dump(strlen($phar->getStub())); + +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(false) +int(6651) +bool(true) +string(60) " + +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- +startBuffering(); + $p->copy('a', 'b'); + echo file_get_contents($p['b']->getPathName()); + $p->copy('b', 'c'); + $p->stopBuffering(); + echo file_get_contents($p['c']->getPathName()); + copy($fname, $fname2); + var_dump($p->isFileFormat(Phar::ZIP)); + $p->copy('a', $ename); +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} +ini_set('phar.readonly',1); +$p2 = new Phar($fname2); +var_dump($p2->isFileFormat(Phar::ZIP)); +echo "\n"; +echo 'a: ' , file_get_contents($p2['a']->getPathName()); +echo 'b: ' ,file_get_contents($p2['b']->getPathName()); +echo 'c: ' ,file_get_contents($p2['c']->getPathName()); +?> +===DONE=== +--CLEAN-- + + +--EXPECTF-- +hihibool(true) +file "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s +bool(true) + +a: hib: hic: hi===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/zip/phar_magic.phpt b/ext/phar/tests/zip/phar_magic.phpt new file mode 100644 index 0000000000..4a17207376 --- /dev/null +++ b/ext/phar/tests/zip/phar_magic.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: include/fopen magic zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +isFileFormat(Phar::ZIP)); +$p['a'] = 'setStub(' +===DONE=== +--CLEAN-- + +--EXPECTF-- +bool(true) +in b + + +--INI-- +phar.readonly=0 +--FILE-- +isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar->compressFiles(Phar::BZ2); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed(Phar::GZ)); +var_dump($phar['a']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed(Phar::GZ)); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +$phar['d'] = 'hi'; // increases code coverage by having ufp open +copy($fname, $fname2); +$c = new Phar($fname2); +var_dump(file_get_contents($pname2 . '/a')); +var_dump($c['a']->isCompressed(Phar::GZ)); +var_dump($c['a']->isCompressed(Phar::BZ2)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(false) +bool(true) +string(1) "b" +bool(false) +bool(true) +string(1) "c" +bool(false) +bool(true) +string(1) "a" +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/phar_oo_compressallgz.phpt b/ext/phar/tests/zip/phar_oo_compressallgz.phpt new file mode 100644 index 0000000000..47dddac487 --- /dev/null +++ b/ext/phar/tests/zip/phar_oo_compressallgz.phpt @@ -0,0 +1,58 @@ +--TEST-- +Phar::compressFiles(Phar::GZ) zip format +--SKIPIF-- + + +--INI-- +phar.readonly=0 +--FILE-- +isCompressed()); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed()); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['c']->isCompressed()); + +$phar->compressFiles(Phar::GZ); +var_dump(file_get_contents($pname . '/a')); +var_dump($phar['a']->isCompressed(Phar::BZ2)); +var_dump($phar['a']->isCompressed(Phar::GZ)); +var_dump(file_get_contents($pname . '/b')); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump($phar['b']->isCompressed(Phar::GZ)); +var_dump(file_get_contents($pname . '/c')); +var_dump($phar['b']->isCompressed(Phar::BZ2)); +var_dump($phar['c']->isCompressed(Phar::GZ)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(1) "a" +bool(false) +string(1) "b" +bool(false) +string(1) "c" +bool(false) +string(1) "a" +bool(false) +bool(true) +string(1) "b" +bool(false) +bool(true) +string(1) "c" +bool(false) +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/phar_setalias.phpt b/ext/phar/tests/zip/phar_setalias.phpt new file mode 100644 index 0000000000..1a39633863 --- /dev/null +++ b/ext/phar/tests/zip/phar_setalias.phpt @@ -0,0 +1,62 @@ +--TEST-- +Phar::setAlias() zip-based +--SKIPIF-- + + + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$phar->setAlias('hio'); + +$files = array(); + +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; + +// test compression + +$phar->compressFiles(Phar::GZ); +copy($fname, $fname2); +$phar->setAlias('unused'); +$p2 = new Phar($fname2); +echo $p2->getAlias(), "\n"; +$p2->compressFiles(Phar::BZ2); +copy($fname2, $fname3); +$p2->setAlias('unused2'); +$p3 = new Phar($fname3); +echo $p3->getAlias(), "\n"; +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +hio +test +test +test +===DONE=== diff --git a/ext/phar/tests/zip/phar_setalias2.phpt b/ext/phar/tests/zip/phar_setalias2.phpt new file mode 100644 index 0000000000..c89f4c777a --- /dev/null +++ b/ext/phar/tests/zip/phar_setalias2.phpt @@ -0,0 +1,49 @@ +--TEST-- +Phar::setAlias() error zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$phar->setAlias('hio'); + +$files = array(); + +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +echo $phar->getAlias() . "\n"; +$phar->setAlias('test'); +echo $phar->getAlias() . "\n"; +$b = $phar; +$phar = new Phar(dirname(__FILE__) . '/notphar.phar'); +try { + $phar->setAlias('test'); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +hio +test +alias "test" is already used for archive "%sphar_setalias2.phar.zip" and cannot be used for other archives +===DONE=== diff --git a/ext/phar/tests/zip/phar_setdefaultstub.phpt b/ext/phar/tests/zip/phar_setdefaultstub.phpt new file mode 100644 index 0000000000..e21d764487 --- /dev/null +++ b/ext/phar/tests/zip/phar_setdefaultstub.phpt @@ -0,0 +1,80 @@ +--TEST-- +Phar: Phar::setDefaultStub() with and without arg, zip-based phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +'; +$phar['b.php'] = ''; +$phar->setStub(''); + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub(); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub('my/custom/thingy.php'); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +echo "============================================================================\n"; +echo "============================================================================\n"; + +try { + $phar->setDefaultStub('my/custom/thingy.php', 'the/web.php'); + $phar->stopBuffering(); +} catch(Exception $e) { + echo $e->getMessage(). "\n"; +} + +var_dump($phar->getStub()); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(51) " +" +============================================================================ +============================================================================ +string(60) " +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub(''); +$p['a'] = 'a'; +$p['b'] = 'b'; +$p['c'] = 'c'; +copy($fname2, $fname); + +$phar = new Phar($fname); +echo $phar->getStub(); + +$file = ''; + +//// 2 +$phar->setStub($file); +echo $phar->getStub(); + +$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php'; +$file = ''; +$fp = fopen($fname3, 'wb'); +fwrite($fp, $file); +fclose($fp); +$fp = fopen($fname3, 'rb'); + +//// 3 +$phar->setStub($fp); +fclose($fp); + +echo $phar->getStub(); + +$fp = fopen($fname3, 'ab'); +fwrite($fp, 'booya'); +fclose($fp); +echo file_get_contents($fname3) . "\n"; + +$fp = fopen($fname3, 'rb'); + +//// 4 +$phar->setStub($fp, strlen($file)); +fclose($fp); +echo $phar->getStub(); + +$phar['testing'] = 'hi'; + +echo $phar->getStub(); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- + + + +booya + + +===DONE=== diff --git a/ext/phar/tests/zip/phar_stub_error.phpt b/ext/phar/tests/zip/phar_stub_error.phpt new file mode 100755 index 0000000000..268130df40 --- /dev/null +++ b/ext/phar/tests/zip/phar_stub_error.phpt @@ -0,0 +1,58 @@ +--TEST-- +Phar::setStub()/getStub() zip-based +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setStub($stub = '' . "\r\n"); +$phar->setAlias('hio'); +$phar['a'] = 'a'; +$phar->stopBuffering(); + +var_dump($stub); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +$newstub = ''; +try +{ + $phar->setStub($newstub); +} +catch(exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); +$phar->stopBuffering(); +var_dump($phar->getStub()); +var_dump($phar->getStub() == $stub); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(50) " +" +string(50) " +" +bool(true) +Exception: illegal stub for zip-based phar "%sphar_stub_error.phar.zip" +string(50) " +" +bool(true) +string(50) " +" +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/refcount1.phpt b/ext/phar/tests/zip/refcount1.phpt new file mode 100644 index 0000000000..6d7b7420c6 --- /dev/null +++ b/ext/phar/tests/zip/refcount1.phpt @@ -0,0 +1,70 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file zip-based +--SKIPIF-- + + + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); +$phar->setAlias('hio'); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); +echo "===CLOSE===\n"; +$b = fopen($alias . '/b/c.php', 'rb'); +$a = $phar['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($alias . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.zip/b" + ["fileName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.zip/b/c.php" +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.zip", has open file pointers, cannot unlink in %srefcount1.php on line %d +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%srefcount1.phar.zip/b" + ["fileName":"SplFileInfo":private]=> + string(%s) "phar://%srefcount1.phar.zip/b/c.php" +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/zip/refcount1_5_2.phpt b/ext/phar/tests/zip/refcount1_5_2.phpt new file mode 100755 index 0000000000..f3b2771f44 --- /dev/null +++ b/ext/phar/tests/zip/refcount1_5_2.phpt @@ -0,0 +1,64 @@ +--TEST-- +Phar: test that refcounting avoids problems with deleting a file zip-based +--SKIPIF-- + + +")) die("skip requires 5.2 or earlier"); ?> +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); +$phar->setAlias('hio'); + +$files = array(); + +$files['a.php'] = ''; +$files['b.php'] = ''; +$files['b/c.php'] = ''; + +foreach ($files as $n => $file) { + $phar[$n] = $file; +} +$phar->stopBuffering(); + +$fp = fopen($alias . '/b/c.php', 'wb'); +fwrite($fp, "extra"); +fclose($fp); + +echo "===CLOSE===\n"; + +$b = fopen($alias . '/b/c.php', 'rb'); +$a = $phar['b/c.php']; +var_dump($a); +var_dump(fread($b, 20)); +rewind($b); +echo "===UNLINK===\n"; +unlink($alias . '/b/c.php'); +var_dump($a); +var_dump(fread($b, 20)); +include $alias . '/b/c.php'; +?> + +===DONE=== +--CLEAN-- + +--EXPECTF-- +===CLOSE=== +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +===UNLINK=== + +Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar.zip", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d +object(PharFileInfo)#%d (0) { +} +string(5) "extra" +extra +===DONE=== diff --git a/ext/phar/tests/zip/rename.phpt b/ext/phar/tests/zip/rename.phpt new file mode 100644 index 0000000000..9b1f5c98cd --- /dev/null +++ b/ext/phar/tests/zip/rename.phpt @@ -0,0 +1,34 @@ +--TEST-- +Phar: rename test zip-based +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +setStub(""); +$phar['a'] = 'a'; +$phar->stopBuffering(); + +include $fname; + +echo file_get_contents($alias . '/a') . "\n"; +rename($alias . '/a', $alias . '/b'); +echo file_get_contents($alias . '/b') . "\n"; +echo file_get_contents($alias . '/a') . "\n"; +?> +--CLEAN-- + +--EXPECTF-- +a +a + +Warning: file_get_contents(phar://%srename.phar.zip/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.zip" in %srename.php on line %d \ No newline at end of file diff --git a/ext/phar/tests/zip/unixzip.phpt b/ext/phar/tests/zip/unixzip.phpt new file mode 100644 index 0000000000..374489d013 --- /dev/null +++ b/ext/phar/tests/zip/unixzip.phpt @@ -0,0 +1,26 @@ +--TEST-- +Phar: test a zip archive created by unix "zip" command +--SKIPIF-- + + +--FILE-- +isDir()) { + echo "dir " . $b->getPathName() . "\n"; + } else { + echo $b->getPathName() . "\n"; + } +} +if (isset($a['notempty/hi.txt'])) { + echo $a['notempty/hi.txt']->getPathName() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +dir phar://%szip.zip%cempty +phar://%szip.zip%chi.txt +dir phar://%szip.zip%cnotempty +phar://%szip.zip/notempty/hi.txt +===DONE=== diff --git a/ext/phar/util.c b/ext/phar/util.c new file mode 100644 index 0000000000..77e83098a4 --- /dev/null +++ b/ext/phar/util.c @@ -0,0 +1,1296 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension | + | utility functions | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + | Marcus Boerger | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "phar_internal.h" +#if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300 +extern php_stream_wrapper php_stream_phar_wrapper; +#endif + +/* for links to relative location, prepend cwd of the entry */ +static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) +{ + char *p, *ret = NULL; + if (!entry->link) { + return NULL; + } + if (entry->link[0] == '/') { + return estrdup(entry->link + 1); + } + p = strrchr(entry->filename, '/'); + if (p) { + *p = '\0'; + spprintf(&ret, 0, "%s/%s", entry->filename, entry->link); + return ret; + } + return entry->link; +} + +phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) +{ + phar_entry_info *link_entry; + char *link = phar_get_link_location(entry TSRMLS_CC); + + if (!entry->link) { + return entry; + } + + if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) || + SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) { + if (link != entry->link) { + efree(link); + } + return phar_get_link_source(link_entry TSRMLS_CC); + } else { + if (link != entry->link) { + efree(link); + } + return NULL; + } +} + +/* retrieve a phar_entry_info's current file pointer for reading contents */ +php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) +{ + if (follow_links && entry->link) { + phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC); + + if (link_entry && link_entry != entry) { + return phar_get_efp(link_entry, 1 TSRMLS_CC); + } + } + if (entry->fp_type == PHAR_FP) { + if (!entry->phar->fp) { + /* re-open just in time for cases where our refcount reached 0 on the phar archive */ + phar_open_archive_fp(entry->phar TSRMLS_CC); + } + return entry->phar->fp; + } else if (entry->fp_type == PHAR_UFP) { + return entry->phar->ufp; + } else if (entry->fp_type == PHAR_MOD) { + return entry->fp; + } else { + /* temporary manifest entry */ + if (!entry->fp) { + entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL); + } + return entry->fp; + } +} + +int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) +{ + php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC); + off_t temp; + + if (!fp) { + return -1; + } + if (follow_links) { + phar_entry_info *t; + t = phar_get_link_source(entry TSRMLS_CC); + if (t) { + entry = t; + } + } + if (entry->is_dir) { + return 0; + } + switch (whence) { + case SEEK_END : + temp = entry->offset + entry->uncompressed_filesize + offset; + break; + case SEEK_CUR : + temp = entry->offset + position + offset; + break; + case SEEK_SET : + temp = entry->offset + offset; + break; + } + if (temp > entry->offset + (off_t) entry->uncompressed_filesize) { + return -1; + } + if (temp < entry->offset) { + return -1; + } + return php_stream_seek(fp, temp, SEEK_SET); +} + +/* mount an absolute path or uri to a path internal to the phar archive */ +int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) +{ + phar_entry_info entry = {0}; + php_stream_statbuf ssb; + int is_phar; + const char *err; + + if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) { + return FAILURE; + } + + is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7)); + + entry.phar = phar; + entry.filename = estrndup(path, path_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(entry.filename, path_len); +#endif + entry.filename_len = path_len; + if (is_phar) { + entry.tmp = estrndup(filename, filename_len); + } else { + entry.tmp = expand_filepath(filename, NULL TSRMLS_CC); + if (!entry.tmp) { + entry.tmp = estrndup(filename, filename_len); + } + } +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { + efree(entry.tmp); + efree(entry.filename); + return FAILURE; + } +#endif + + filename_len = strlen(entry.tmp); + filename = entry.tmp; + /* only check openbasedir for files, not for phar streams */ + if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) { + efree(entry.tmp); + efree(entry.filename); + return FAILURE; + } + entry.is_mounted = 1; + entry.is_crc_checked = 1; + entry.fp_type = PHAR_TMP; + + if (SUCCESS != php_stream_stat_path(filename, &ssb)) { + efree(entry.tmp); + efree(entry.filename); + return FAILURE; + } + if (ssb.sb.st_mode & S_IFDIR) { + entry.is_dir = 1; + if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) { + /* directory already mounted */ + efree(entry.tmp); + efree(entry.filename); + return FAILURE; + } + } else { + entry.is_dir = 0; + entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size; + } + entry.flags = ssb.sb.st_mode; + if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + return SUCCESS; + } + efree(entry.tmp); + efree(entry.filename); + return FAILURE; +} + +char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */ +{ +#if PHP_VERSION_ID >= 50300 + char *path, *fname, *arch, *entry, *ret, *test; + int arch_len, entry_len, fname_len; + + if (pphar) { + *pphar = NULL; + } + + if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) { + return phar_save_resolve_path(filename, filename_len TSRMLS_CC); + } + fname = zend_get_executed_filename(TSRMLS_C); + fname_len = strlen(fname); + + if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { + return phar_save_resolve_path(filename, filename_len TSRMLS_CC); + } + efree(entry); + if (*filename == '.') { + int try_len; + + if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + return phar_save_resolve_path(filename, filename_len TSRMLS_CC); + } + try_len = filename_len; + test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC); + if (*test == '/') { + if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) { + spprintf(&ret, 0, "phar://%s%s", arch, test); + efree(arch); + efree(test); + return ret; + } + } else { + if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) { + spprintf(&ret, 0, "phar://%s/%s", arch, test); + efree(arch); + efree(test); + return ret; + } + } + } + spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); + efree(arch); + ret = php_resolve_path(filename, filename_len, path TSRMLS_CC); + efree(path); + if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) { + char *arch; + int arch_len, ret_len; + + ret_len = strlen(ret); + /* found phar:// */ + + if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { + return ret; + } + zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar); + efree(arch); + efree(entry); + } + return ret; +#else /* PHP 5.2 */ + char resolved_path[MAXPATHLEN]; + char trypath[MAXPATHLEN]; + char *ptr, *end, *path = PG(include_path); + php_stream_wrapper *wrapper; + const char *p; + int n = 0; + char *fname, *arch, *entry, *ret, *test; + int arch_len, entry_len; + + if (!filename) { + return NULL; + } + + if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) { + goto doit; + } + fname = zend_get_executed_filename(TSRMLS_C); + if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { + goto doit; + } + + efree(entry); + if (*filename == '.') { + phar_archive_data **pphar; + int try_len; + + if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) { + efree(arch); + goto doit; + } + try_len = filename_len; + test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC); + if (*test == '/') { + if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) { + spprintf(&ret, 0, "phar://%s%s", arch, test); + efree(arch); + efree(test); + return ret; + } + } else { + if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) { + spprintf(&ret, 0, "phar://%s/%s", arch, test); + efree(arch); + efree(test); + return ret; + } + } + efree(test); + } + efree(arch); + +doit: + if (*filename == '.' || + IS_ABSOLUTE_PATH(filename, filename_len) || + !path || + !*path) { + if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) { + return estrdup(resolved_path); + } else { + return NULL; + } + } + /* test for stream wrappers and return */ + for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n); + if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) { + /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */ + return estrndup(filename, filename_len); + } + + ptr = (char *) path; + while (ptr && *ptr) { + int len, is_stream_wrapper = 0, maybe_stream = 1; + + end = strchr(ptr, DEFAULT_DIR_SEPARATOR); +#ifndef PHP_WIN32 + /* search for stream wrapper */ + if (end - ptr <= 1) { + maybe_stream = 0; + goto not_stream; + } + for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n); + + if (n == end - ptr && *p && !strncmp("//", p+1, 2)) { + is_stream_wrapper = 1; + /* seek to real end of include_path portion */ + end = strchr(end + 1, DEFAULT_DIR_SEPARATOR); + } else { + maybe_stream = 0; + } +not_stream: +#endif + if (end) { + if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) { + ptr = end + 1; + continue; + } + memcpy(trypath, ptr, end-ptr); + len = end-ptr; + trypath[end-ptr] = '/'; + memcpy(trypath+(end-ptr)+1, filename, filename_len+1); + ptr = end+1; + } else { + len = strlen(ptr); + + if (len + 1 + filename_len + 1 >= MAXPATHLEN) { + break; + } + memcpy(trypath, ptr, len); + trypath[len] = '/'; + memcpy(trypath+len+1, filename, filename_len+1); + ptr = NULL; + } + + if (!is_stream_wrapper && maybe_stream) { + /* search for stream wrapper */ + for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n); + } + + if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) { + char *actual; + + wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); + if (wrapper == &php_plain_files_wrapper) { + strncpy(trypath, actual, MAXPATHLEN); + } else if (!wrapper) { + /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */ + continue; + } else { + if (wrapper->wops->url_stat) { + php_stream_statbuf ssb; + + if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) { + if (wrapper == &php_stream_phar_wrapper) { + char *arch, *entry; + int arch_len, entry_len, ret_len; + + ret_len = strlen(trypath); + /* found phar:// */ + + if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) { + return estrndup(trypath, ret_len); + } + zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar); + efree(arch); + efree(entry); + return estrndup(trypath, ret_len); + } + return estrdup(trypath); + } + } + continue; + } + } + + if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) { + return estrdup(resolved_path); + } + } /* end provided path */ + + /* check in calling scripts' current working directory as a fall back case + */ + if (zend_is_executing(TSRMLS_C)) { + char *exec_fname = zend_get_executed_filename(TSRMLS_C); + int exec_fname_length = strlen(exec_fname); + const char *p; + int n = 0; + + while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); + if (exec_fname && exec_fname[0] != '[' && + exec_fname_length > 0 && + exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) { + memcpy(trypath, exec_fname, exec_fname_length + 1); + memcpy(trypath+exec_fname_length + 1, filename, filename_len+1); + + /* search for stream wrapper */ + for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n); + if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) { + char *actual; + + wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); + if (wrapper == &php_plain_files_wrapper) { + /* this should never technically happen, but we'll leave it here for completeness */ + strncpy(trypath, actual, MAXPATHLEN); + } else if (!wrapper) { + /* if wrapper is NULL, there was a mal-formed include_path stream wrapper + this also should be impossible */ + return NULL; + } else { + return estrdup(trypath); + } + } + if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) { + return estrdup(resolved_path); + } + } + } + + return NULL; +#endif /* PHP 5.2 */ +} +/* }}} */ + +/** + * Retrieve a copy of the file information on a single file within a phar, or null. + * This also transfers the open file pointer, if any, to the entry. + * + * If the file does not already exist, this will fail. Pre-existing files can be + * appended, truncated, or read. For read, if the entry is marked unmodified, it is + * assumed that the file pointer, if present, is opened for reading + */ +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) /* {{{ */ +{ + phar_archive_data *phar; + phar_entry_info *entry; + int for_write = mode[0] != 'r' || mode[1] == '+'; + int for_append = mode[0] == 'a'; + int for_create = mode[0] != 'r'; + int for_trunc = mode[0] == 'w'; + + if (!ret) { + return FAILURE; + } + *ret = NULL; + if (error) { + *error = NULL; + } + if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { + return FAILURE; + } + if (for_write && PHAR_G(readonly) && !phar->is_data) { + if (error) { + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname); + } + return FAILURE; + } + if (!path_len) { + if (error) { + spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname); + } + return FAILURE; + } + if (allow_dir) { + if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) { + if (for_create && (!PHAR_G(readonly) || phar->is_data)) { + return SUCCESS; + } + return FAILURE; + } + } else { + if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) { + if (for_create && (!PHAR_G(readonly) || phar->is_data)) { + return SUCCESS; + } + return FAILURE; + } + } + if (entry->is_modified && !for_write) { + if (error) { + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname); + } + return FAILURE; + } + if (entry->fp_refcount && for_write) { + if (error) { + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname); + } + return FAILURE; + } + if (entry->is_deleted) { + if (!for_create) { + return FAILURE; + } + entry->is_deleted = 0; + } + if (entry->is_dir) { + *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); + (*ret)->position = 0; + (*ret)->fp = NULL; + (*ret)->phar = phar; + (*ret)->for_write = for_write; + (*ret)->internal_file = entry; + (*ret)->is_zip = entry->is_zip; + (*ret)->is_tar = entry->is_tar; + ++(entry->phar->refcount); + ++(entry->fp_refcount); + return SUCCESS; + } + if (entry->fp_type == PHAR_MOD) { + if (for_trunc) { + if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) { + return FAILURE; + } + } else if (for_append) { + phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC); + } + } else { + if (entry->link) { + efree(entry->link); + entry->link = NULL; + entry->tar_type = (entry->tar_type ? TAR_FILE : 0); + } + if (for_write) { + if (for_trunc) { + if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) { + return FAILURE; + } + } else { + if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) { + return FAILURE; + } + } + } else { + if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { + return FAILURE; + } + } + } + *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); + (*ret)->position = 0; + (*ret)->phar = phar; + (*ret)->for_write = for_write; + (*ret)->internal_file = entry; + (*ret)->is_zip = entry->is_zip; + (*ret)->is_tar = entry->is_tar; + (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC); + (*ret)->zero = entry->offset; + ++(entry->fp_refcount); + ++(entry->phar->refcount); + return SUCCESS; +} +/* }}} */ + +/** + * Create a new dummy file slot within a writeable phar for a newly created file + */ +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) /* {{{ */ +{ + phar_archive_data *phar; + phar_entry_info *entry, etemp; + phar_entry_data *ret; + const char *pcr_error; + char is_dir; + +#ifdef PHP_WIN32 + phar_unixify_path_separators(path, path_len); +#endif + + is_dir = (path_len > 0 && path != NULL) ? path[path_len - 1] == '/' : 0; + + if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { + return NULL; + } + + if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error TSRMLS_CC)) { + return NULL; + } else if (ret) { + return ret; + } + + 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); + } + return NULL; + } + + /* create a new phar data holder */ + ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); + + /* create an entry, this is a new file */ + memset(&etemp, 0, sizeof(phar_entry_info)); + etemp.filename_len = path_len; + etemp.fp_type = PHAR_MOD; + etemp.fp = php_stream_fopen_tmpfile(); + if (!etemp.fp) { + if (error) { + spprintf(error, 0, "phar error: unable to create temporary file"); + } + return NULL; + } + etemp.fp_refcount = 1; + + if (allow_dir == 2) { + etemp.is_dir = 1; + etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR; + if (is_dir) { + etemp.filename_len--; /* strip trailing / */ + path_len--; + } + } else { + etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE; + } + etemp.is_modified = 1; + etemp.timestamp = time(0); + etemp.is_crc_checked = 1; + etemp.phar = phar; + etemp.filename = estrndup(path, path_len); + etemp.is_zip = phar->is_zip; + if (phar->is_tar) { + etemp.is_tar = phar->is_tar; + etemp.tar_type = TAR_FILE; + } + if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) { + if (error) { + spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname); + } + return NULL; + } + + if (!entry) { + php_stream_close(etemp.fp); + efree(etemp.filename); + return NULL; + } + + ++(phar->refcount); + ret->phar = phar; + ret->fp = entry->fp; + ret->position = ret->zero = 0; + ret->for_write = 1; + ret->is_zip = entry->is_zip; + ret->is_tar = entry->is_tar; + ret->internal_file = entry; + return ret; +} +/* }}} */ + +/* initialize a phar_archive_data's read-only fp for existing phar data */ +int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) +{ + if (phar->fp) { + return SUCCESS; + } + +#if PHP_MAJOR_VERSION < 6 + if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + return FAILURE; + } +#endif + + if (php_check_open_basedir(phar->fname TSRMLS_CC)) { + return FAILURE; + } + + phar->fp = php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); + if (!phar->fp) { + return FAILURE; + } + return SUCCESS; +} + +/* copy file data from an existing to a new phar_entry_info that is not in the manifest */ +int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) +{ + phar_entry_info *link; + + if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) { + return FAILURE; + } + if (dest->link) { + efree(dest->link); + dest->link = NULL; + dest->tar_type = (dest->tar_type ? TAR_FILE : 0); + } + dest->fp_type = PHAR_MOD; + dest->offset = 0; + dest->is_modified = 1; + dest->fp = php_stream_fopen_tmpfile(); + + phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC); + link = phar_get_link_source(source TSRMLS_CC); + if (!link) { + link = source; + } + if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize)) { + php_stream_close(dest->fp); + dest->fp_type = PHAR_FP; + if (error) { + spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname); + } + return FAILURE; + } + return SUCCESS; +} + +/* open and decompress a compressed phar entry + */ +int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) +{ + php_stream_filter *filter; + phar_archive_data *phar = entry->phar; + char *filtername; + off_t loc; + + if (follow_links && entry->link) { + phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC); + + if (link_entry && link_entry != entry) { + return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC); + } + } + if (entry->fp_type == PHAR_TMP) { + if (!entry->fp) { + entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL); + } + return SUCCESS; + } + if (entry->fp_type != PHAR_FP) { + /* either newly created or already modified */ + return SUCCESS; + } + if (!phar->fp) { + if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) { + spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname); + return FAILURE; + } + } + if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { + return SUCCESS; + } + if (!phar->ufp) { + phar->ufp = php_stream_fopen_tmpfile(); + if (!phar->ufp) { + spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename); + return FAILURE; + } + } + + if ((filtername = phar_decompress_filter(entry, 0)) != NULL) { + filter = php_stream_filter_create(filtername, NULL, php_stream_is_persistent(phar->ufp) TSRMLS_CC); + } else { + filter = NULL; + } + if (!filter) { + spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename); + return FAILURE; + } + /* now we can safely use proper decompression */ + /* save the new offset location within ufp */ + php_stream_seek(phar->ufp, 0, SEEK_END); + loc = php_stream_tell(phar->ufp); + php_stream_filter_append(&phar->ufp->writefilters, filter); + php_stream_seek(phar->fp, entry->offset, SEEK_SET); + if (php_stream_copy_to_stream(phar->fp, phar->ufp, entry->compressed_filesize) != entry->compressed_filesize) { + spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + return FAILURE; + } + php_stream_filter_flush(filter, 1); + php_stream_flush(phar->ufp); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + if (php_stream_tell(phar->ufp) - loc != (off_t) entry->uncompressed_filesize) { + spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename); + return FAILURE; + } + + entry->old_flags = entry->flags; + entry->fp_type = PHAR_UFP; + /* this is now the new location of the file contents within this fp */ + entry->offset = loc; + + return SUCCESS; +} + +#if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202 +typedef struct { + char *data; + size_t fpos; + size_t fsize; + size_t smax; + int mode; + php_stream **owner_ptr; +} php_stream_memory_data; +#endif + +int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */ +{ + if (entry->fp_type == PHAR_MOD) { + /* already newly created, truncate */ +#if PHP_VERSION_ID >= 50202 + php_stream_truncate_set_size(entry->fp, 0); +#else + if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) { + if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) { + php_stream *inner = *(php_stream**)entry->fp->abstract; + php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract; + memfp->fpos = 0; + memfp->fsize = 0; + } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) { + php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0); + } else { + if (error) { + spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname); + } + return FAILURE; + } + } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) { + php_stream_truncate_set_size(entry->fp, 0); + } else { + if (error) { + spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname); + } + return FAILURE; + } +#endif + entry->old_flags = entry->flags; + entry->is_modified = 1; + phar->is_modified = 1; + /* reset file size */ + entry->uncompressed_filesize = 0; + entry->compressed_filesize = 0; + entry->crc32 = 0; + entry->flags = PHAR_ENT_PERM_DEF_FILE; + entry->fp_type = PHAR_MOD; + entry->offset = 0; + return SUCCESS; + } + if (error) { + *error = NULL; + } + /* open a new temp file for writing */ + if (entry->link) { + efree(entry->link); + entry->link = NULL; + entry->tar_type = (entry->tar_type ? TAR_FILE : 0); + } + entry->fp = php_stream_fopen_tmpfile(); + if (!entry->fp) { + if (error) { + spprintf(error, 0, "phar error: unable to create temporary file"); + } + return FAILURE; + } + entry->old_flags = entry->flags; + entry->is_modified = 1; + phar->is_modified = 1; + /* reset file size */ + entry->uncompressed_filesize = 0; + entry->compressed_filesize = 0; + entry->crc32 = 0; + entry->flags = PHAR_ENT_PERM_DEF_FILE; + entry->fp_type = PHAR_MOD; + entry->offset = 0; + return SUCCESS; +} +/* }}} */ + +int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) +{ + php_stream *fp; + phar_entry_info *link; + + if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { + return FAILURE; + } + + if (entry->fp_type == PHAR_MOD) { + return SUCCESS; + } + + fp = php_stream_fopen_tmpfile(); + phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC); + link = phar_get_link_source(entry TSRMLS_CC); + if (!link) { + link = entry; + } + if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) { + if (error) { + spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname); + } + return FAILURE; + } + + if (entry->link) { + efree(entry->link); + entry->link = NULL; + entry->tar_type = (entry->tar_type ? TAR_FILE : 0); + } + + entry->offset = 0; + entry->fp = fp; + entry->fp_type = PHAR_MOD; + entry->is_modified = 1; + return SUCCESS; +} + +/** + * helper function to open an internal file's fp just-in-time + */ +phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp, + char **error, int for_write TSRMLS_DC) +{ + if (error) { + *error = NULL; + } + /* seek to start of internal file and read it */ + if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) { + return NULL; + } + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) { + spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname); + return NULL; + } + 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 + */ +int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */ +{ + phar_archive_data *fd, **fd_ptr; + char *my_realpath, *save; + int save_len; + + phar_request_initialize(TSRMLS_C); + + if (error) { + *error = NULL; + } + *archive = NULL; + if (alias && alias_len) { + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) { + if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) { + 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; + return SUCCESS; + } + } + my_realpath = NULL; + save = fname; + save_len = fname_len; + if (fname && fname_len) { + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) { + *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); + } + zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL); + } + return SUCCESS; + } + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, (void**)&fd_ptr)) { + *archive = *fd_ptr; + return SUCCESS; + } + + /* not found, try converting \ to / */ + my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC); + if (my_realpath) { + fname_len = strlen(my_realpath); + fname = my_realpath; + } else { + return FAILURE; + } +#ifdef PHP_WIN32 + phar_unixify_path_separators(fname, fname_len); +#endif + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) { + *archive = *fd_ptr; + fd = *fd_ptr; + if (alias && alias_len) { + zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL); + } + efree(my_realpath); + return SUCCESS; + } + efree(my_realpath); + } + return FAILURE; +} +/* }}} */ + +/** + * Determine which stream compression filter (if any) we need to read this file + */ +char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */ +{ + switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) { + case PHAR_ENT_COMPRESSED_GZ: + return "zlib.deflate"; + case PHAR_ENT_COMPRESSED_BZ2: + return "bzip2.compress"; + default: + return return_unknown ? "unknown" : NULL; + } +} +/* }}} */ + +/** + * Determine which stream decompression filter (if any) we need to read this file + */ +char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */ +{ + php_uint32 flags; + + if (entry->is_modified) { + flags = entry->old_flags; + } else { + flags = entry->flags; + } + switch (flags & PHAR_ENT_COMPRESSION_MASK) { + case PHAR_ENT_COMPRESSED_GZ: + return "zlib.inflate"; + case PHAR_ENT_COMPRESSED_BZ2: + return "bzip2.decompress"; + default: + return return_unknown ? "unknown" : NULL; + } +} +/* }}} */ + +/** + * retrieve information on a file contained within a phar, or null if it ain't there + */ +phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC) /* {{{ */ +{ + return phar_get_entry_info_dir(phar, path, path_len, 0, error TSRMLS_CC); +} +/* }}} */ +/** + * retrieve information on a file or directory contained within a phar, or null if none found + * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only + * valid pre-existing empty directory entries + */ +phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC) /* {{{ */ +{ + const char *pcr_error; + phar_entry_info *entry; + char is_dir; + +#ifdef PHP_WIN32 + phar_unixify_path_separators(path, path_len); +#endif + + is_dir = path_len && (path[path_len - 1] == '/'); + + if (error) { + *error = NULL; + } + + if (!path_len && !dir) { + if (error) { + spprintf(error, 4096, "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, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error); + } + return NULL; + } + + if (!phar->manifest.arBuckets) { + return NULL; + } + if (is_dir) { + path_len--; + } + if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ + return NULL; + } + if (entry->is_dir && !dir) { + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" is a directory", path); + } + return NULL; + } + if (!entry->is_dir && dir == 2) { + /* user requested a directory, we must return one */ + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path); + } + return NULL; + } + return entry; + } else if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) { + char *key; + ulong unused; + uint keylen; + + zend_hash_internal_pointer_reset(&phar->mounted_dirs); + while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) { + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) { + break; + } + if ((int)keylen >= path_len || strncmp(key, path, keylen)) { + continue; + } else { + char *test; + int test_len; + phar_entry_info *entry; + php_stream_statbuf ssb; + + if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) { + if (error) { + spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", key); + } + return NULL; + } + if (!entry->tmp || !entry->is_mounted) { + if (error) { + spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", key); + } + return NULL; + } + test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen); + if (SUCCESS != php_stream_stat_path(test, &ssb)) { + efree(test); + return NULL; + } + if (ssb.sb.st_mode & S_IFDIR && !dir) { + efree(test); + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" is a directory", path); + } + return NULL; + } + if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) { + efree(test); + /* user requested a directory, we must return one */ + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path); + } + return NULL; + } + /* mount the file just in time */ + if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) { + efree(test); + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test); + } + return NULL; + } + efree(test); + if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) { + if (error) { + spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test); + } + return NULL; + } + return entry; + } + } + } + if (dir) { + /* try to find a directory */ + HashTable *manifest; + char *key; + 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 (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) { + break; + } + if (0 != memcmp(key, path, path_len)) { + /* entry in directory not found */ + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } else { + if (key[path_len] != '/') { + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } + /* found a file in this path */ + entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info)); + /* this next line tells PharFileInfo->__destruct() to efree the filename */ + entry->is_temp_dir = entry->is_dir = 1; + entry->filename = (char *) estrndup(path, path_len + 1); + entry->filename_len = path_len; + entry->phar = phar; + return entry; + } + } + } + return NULL; +} +/* }}} */ diff --git a/ext/phar/zip.c b/ext/phar/zip.c new file mode 100644 index 0000000000..0261033ff9 --- /dev/null +++ b/ext/phar/zip.c @@ -0,0 +1,1100 @@ +/* + +----------------------------------------------------------------------+ + | ZIP archive support for Phar | + +----------------------------------------------------------------------+ + | Copyright (c) 2007-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + +----------------------------------------------------------------------+ +*/ + +#include "phar_internal.h" + +#ifdef WORDS_BIGENDIAN +# define PHAR_GET_32(buffer) (((((unsigned char*)(buffer))[3]) << 24) \ + | ((((unsigned char*)(buffer))[2]) << 16) \ + | ((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0]))) +# define PHAR_GET_16(buffer) (((((unsigned char*)(buffer))[1]) << 8) \ + | (((unsigned char*)(buffer))[0])) +# define PHAR_SET_32(buffer) PHAR_GET_32(buffer) +# define PHAR_SET_16(buffer) PHAR_GET_16(buffer) +#else +# define PHAR_GET_32(buffer) (buffer) +# define PHAR_GET_16(buffer) (buffer) +# define PHAR_SET_32(buffer) (buffer) +# define PHAR_SET_16(buffer) (buffer) +#endif + +static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC) +{ + union { + phar_zip_extra_field_header header; + phar_zip_unix3 unix3; + } h; + int read; + + do { + if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) { + return FAILURE; + } + if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') { + /* skip to next header */ + php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR); + len -= PHAR_GET_16(h.header.size) + 4; + continue; + } + /* unix3 header found */ + read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header)); + len -= read + 4; + if (sizeof(h.unix3) - sizeof(h.header) != read) { + return FAILURE; + } + if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) { + /* skip symlink filename - we may add this support in later */ + php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR); + } + /* set permissions */ + entry->flags &= PHAR_ENT_COMPRESSION_MASK; + if (entry->is_dir) { + entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK; + } else { + entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK; + } + } while (len); + return SUCCESS; +} + +/* + extracted from libzip + zip_dirent.c -- read directory entry (local or central), clean dirent + Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner + + This function is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +static time_t phar_zip_d2u_time(int dtime, int ddate) +{ + struct tm *tm, tmbuf; + time_t now; + + now = time(NULL); + tm = php_localtime_r(&now, &tmbuf); + + tm->tm_year = ((ddate>>9)&127) + 1980 - 1900; + tm->tm_mon = ((ddate>>5)&15) - 1; + tm->tm_mday = ddate&31; + + tm->tm_hour = (dtime>>11)&31; + tm->tm_min = (dtime>>5)&63; + tm->tm_sec = (dtime<<1)&62; + + return mktime(tm); +} + +static void phar_zip_u2d_time(time_t time, php_uint16 *dtime, php_uint16 *ddate) +{ + struct tm *tm, tmbuf; + + tm = php_localtime_r(&time, &tmbuf); + *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday; + *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1); +} + +/** + * Does not check for a previously opened phar in the cache. + * + * Parse a new one and add it to the cache, returning either SUCCESS or + * FAILURE, and setting pphar to the pointer to the manifest entry + * + * This is used by phar_open_fp to process a zip-based phar, but can be called + * directly. + */ +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) /* {{{ */ +{ + phar_zip_dir_end locator; + char buf[sizeof(locator) + 65536]; + long size; + size_t read; + php_uint16 i; + phar_archive_data *mydata = NULL; + phar_entry_info entry = {0}; + char *p = buf, *ext, *actual_alias = NULL; + + size = php_stream_tell(fp); + if (size > sizeof(locator) + 65536) { + /* seek to max comment length + end of central directory record */ + size = sizeof(locator) + 65536; + if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) { + php_stream_close(fp); + if (error) { + spprintf(error, 4096, "phar error: unable to search for end of central directory in zip-based phar \"%s\"", fname); + } + return FAILURE; + } + } else { + php_stream_seek(fp, 0, SEEK_SET); + } + if (!(read = php_stream_read(fp, buf, size))) { + php_stream_close(fp); + if (error) { + spprintf(error, 4096, "phar error: unable to read in data to search for end of central directory in zip-based phar \"%s\"", fname); + } + return FAILURE; + } + while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) { + if (!memcmp(p + 1, "K\5\6", 3)) { + memcpy((void *)&locator, (void *) p, sizeof(locator)); + if (locator.centraldisk != 0 || locator.disknumber != 0) { + /* split archives not handled */ + php_stream_close(fp); + if (error) { + spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname); + } + return FAILURE; + } + if (locator.counthere != locator.count) { + if (error) { + spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname); + } + php_stream_close(fp); + return FAILURE; + } + mydata = ecalloc(sizeof(phar_archive_data), 1); + + /* read in archive comment, if any */ + if (locator.comment_len) { + char *metadata; + + metadata = p + sizeof(locator); + if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) { + if (error) { + spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname); + } + php_stream_close(fp); + efree(mydata); + return FAILURE; + } + if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) { + /* if not valid serialized data, it is a regular string */ + ALLOC_INIT_ZVAL(mydata->metadata); + ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 1); + } + } else { + mydata->metadata = NULL; + } + goto foundit; + } + } + php_stream_close(fp); + if (error) { + spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname); + } + return FAILURE; +foundit: + mydata->fname = estrndup(fname, fname_len); +#ifdef PHP_WIN32 + phar_unixify_path_separators(mydata->fname, fname_len); +#endif + mydata->is_zip = 1; + mydata->fname_len = fname_len; + ext = strrchr(mydata->fname, '/'); + if (ext) { + mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext); + if (mydata->ext == ext) { + mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + fname_len) - mydata->ext; + } + } + /* clean up on big-endian systems */ + /* seek to central directory */ + php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET); + /* read in central directory */ + zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_hash_init(&mydata->mounted_dirs, sizeof(char *), + zend_get_hash_value, NULL, 0); + entry.phar = mydata; + entry.is_zip = 1; + entry.fp_type = PHAR_FP; +#define PHAR_ZIP_FAIL(errmsg) \ + zend_hash_destroy(&mydata->manifest); \ + mydata->manifest.arBuckets = 0; \ + zend_hash_destroy(&mydata->mounted_dirs); \ + mydata->mounted_dirs.arBuckets = 0; \ + php_stream_close(fp); \ + if (mydata->metadata) { \ + zval_dtor(mydata->metadata); \ + } \ + if (error) { \ + spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \ + } \ + efree(mydata->fname); \ + if (mydata->alias) { \ + efree(mydata->alias); \ + } \ + efree(mydata); \ + return FAILURE; + + /* add each central directory item to the manifest */ + for (i = 0; i < locator.count; ++i) { + phar_zip_central_dir_file zipentry; + + if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) { + PHAR_ZIP_FAIL("unable to read central directory entry, truncated"); + } + /* clean up for bigendian systems */ + if (memcmp("PK\1\2", zipentry.signature, 4)) { + /* corrupted entry */ + PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature"); + } + entry.compressed_filesize = PHAR_GET_32(zipentry.compsize); + entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize); + entry.crc32 = PHAR_GET_32(zipentry.crc32); + /* do not PHAR_GET_16 either on the next line */ + entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp); + entry.flags = PHAR_ENT_PERM_DEF_FILE; + entry.header_offset = PHAR_GET_32(zipentry.offset); + entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) + + PHAR_GET_16(zipentry.extra_len); + if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) { + PHAR_ZIP_FAIL("Cannot process encrypted zip files"); + } + if (!PHAR_GET_16(zipentry.filename_len)) { + PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)"); + } + entry.filename_len = PHAR_GET_16(zipentry.filename_len); + entry.filename = (char *) emalloc(entry.filename_len + 1); + if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) { + efree(entry.filename); + PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated"); + } + entry.filename[entry.filename_len] = '\0'; + if (entry.filename[entry.filename_len - 1] == '/') { + entry.is_dir = 1; + entry.filename_len--; + entry.flags |= PHAR_ENT_PERM_DEF_DIR; + } else { + entry.is_dir = 0; + } + if (PHAR_GET_16(zipentry.extra_len)) { + off_t loc = php_stream_tell(fp); + if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) { + efree(entry.filename); + PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory"); + } + php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET); + } + switch (zipentry.compressed) { + case PHAR_ZIP_COMP_NONE : + /* compression flag already set */ + break; + case PHAR_ZIP_COMP_DEFLATE : + entry.flags |= PHAR_ENT_COMPRESSED_GZ; + if (!phar_has_zlib) { + efree(entry.filename); + PHAR_ZIP_FAIL("zlib extension is required"); + } + break; + case PHAR_ZIP_COMP_BZIP2 : + entry.flags |= PHAR_ENT_COMPRESSED_BZ2; + if (!phar_has_bz2) { + efree(entry.filename); + PHAR_ZIP_FAIL("bzip2 extension is required"); + } + break; + case 1 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip"); + case 2 : + case 3 : + case 4 : + case 5 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip"); + case 6 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip"); + case 7 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip"); + case 9 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip"); + case 10 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip"); + case 14 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip"); + case 18 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip"); + case 19 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip"); + case 97 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip"); + case 98 : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip"); + default : + efree(entry.filename); + PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip"); + } + /* get file metadata */ + if (zipentry.comment_len) { + if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) { + efree(entry.filename); + PHAR_ZIP_FAIL("unable to read in file comment, truncated"); + } + p = buf; + if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) { + /* if not valid serialized data, it is a regular string */ + ALLOC_INIT_ZVAL(entry.metadata); + ZVAL_STRINGL(entry.metadata, buf, PHAR_GET_16(zipentry.comment_len), 1); + } + } else { + entry.metadata = NULL; + } + 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; + + /* 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) { + efree(entry.filename); + PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed"); + } + php_stream_filter_append(&fp->readfilters, filter); + 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 if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) { + php_stream_filter *filter; + filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); + if (!filter) { + efree(entry.filename); + PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed"); + } + php_stream_filter_append(&fp->readfilters, filter); + php_stream_filter_append(&fp->readfilters, filter); + 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 { + 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"); + } + } + + /* return to central directory parsing */ + php_stream_seek(fp, saveloc, SEEK_SET); + } + zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL); + } + 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; + } + return SUCCESS; +} +/* }}} */ + +/** + * 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 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, is_data, options, &phar, error TSRMLS_CC); + + if (FAILURE == ret) { + return FAILURE; + } + + if (pphar) { + *pphar = phar; + } + + phar->is_data = is_data; + + if (phar->is_zip) { + return ret; + } + + if (phar->is_brandnew) { + phar->internal_file_start = 0; + phar->is_zip = 1; + return SUCCESS; + } + + /* we've reached here - the phar exists and is a regular phar */ + if (error) { + spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname); + } + return FAILURE; +} +/* }}} */ + +struct _phar_zip_pass { + php_stream *filefp; + php_stream *centralfp; + php_stream *old; + int free_fp; + int free_ufp; + char **error; +}; +/* perform final modification of zip contents for each file in the manifest before saving */ +static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */ +{ + phar_entry_info *entry; + phar_zip_file_header local; + phar_zip_unix3 perms; + phar_zip_central_dir_file central; + struct _phar_zip_pass *p; + php_uint32 newcrc32; + off_t offset; + + entry = (phar_entry_info *)data; + p = (struct _phar_zip_pass*) arg; + if (entry->is_mounted) { + return ZEND_HASH_APPLY_KEEP; + } + if (entry->is_deleted) { + if (entry->fp_refcount <= 0) { + return ZEND_HASH_APPLY_REMOVE; + } else { + /* we can't delete this in-memory until it is closed */ + return ZEND_HASH_APPLY_KEEP; + } + } + memset(&local, 0, sizeof(local)); + memset(¢ral, 0, sizeof(central)); + memset(&perms, 0, sizeof(perms)); + strncpy(local.signature, "PK\3\4", 4); + strncpy(central.signature, "PK\1\2", 4); + central.extra_len = local.extra_len = PHAR_SET_16(sizeof(perms)); + perms.tag[0] = 'n'; + perms.tag[1] = 'u'; + perms.size = PHAR_SET_16(sizeof(perms) - 4); + perms.perms = PHAR_SET_16(entry->flags & PHAR_ENT_PERM_MASK); + perms.crc32 = ~0; + CRC32(perms.crc32, (char)perms.perms & 0xFF); + CRC32(perms.crc32, (char)perms.perms & 0xFF00 >> 8); + perms.crc32 = PHAR_SET_32(~(perms.crc32)); + if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { + local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE); + } + if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) { + local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2); + } + /* do not use PHAR_SET_16 on either field of the next line */ + phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp); + central.timestamp = local.timestamp; + central.datestamp = local.datestamp; + central.filename_len = local.filename_len = PHAR_SET_16(entry->filename_len + (entry->is_dir ? 1 : 0)); + central.offset = PHAR_SET_32(php_stream_tell(p->filefp)); + /* do extra field for perms later */ + if (entry->is_modified) { + php_uint32 loc; + php_stream_filter *filter; + php_stream *efp; + + if (entry->is_dir) { + entry->is_modified = 0; + if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) { + php_stream_close(entry->fp); + entry->fp = NULL; + entry->fp_type = PHAR_FP; + } + goto continue_dir; + } + if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) { + spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + efp = phar_get_efp(entry, 0 TSRMLS_CC); + + newcrc32 = ~0; + for (loc = 0;loc < entry->uncompressed_filesize; ++loc) { + CRC32(newcrc32, php_stream_getc(efp)); + } + entry->crc32 = ~newcrc32; + central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); + if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { + /* not compressed */ + entry->compressed_filesize = entry->uncompressed_filesize; + central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + goto not_compressed; + } + filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC); + if (!filter) { + if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { + spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + } else { + spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + } + return ZEND_HASH_APPLY_STOP; + } + + /* create new file that holds the compressed version */ + /* work around inability to specify freedom in write and strictness + in read count */ + entry->cfp = php_stream_fopen_tmpfile(); + if (!entry->cfp) { + spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + php_stream_flush(efp); + if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) { + spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + php_stream_filter_append((&entry->cfp->writefilters), filter); + if (entry->uncompressed_filesize != php_stream_copy_to_stream(efp, entry->cfp, entry->uncompressed_filesize)) { + spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + php_stream_filter_flush(filter, 1); + php_stream_flush(entry->cfp); + php_stream_filter_remove(filter, 1 TSRMLS_CC); + php_stream_seek(entry->cfp, 0, SEEK_END); + entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp); + central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + /* generate crc on compressed file */ + php_stream_rewind(entry->cfp); + entry->old_flags = entry->flags; + entry->is_modified = 1; + } else { + central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); + central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) { + spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + } +not_compressed: + central.crc32 = local.crc32 = PHAR_SET_32(entry->crc32); +continue_dir: + /* set file metadata */ + if (entry->metadata) { + php_serialize_data_t metadata_hash; + + if (entry->metadata_str.c) { + smart_str_free(&entry->metadata_str); + } + entry->metadata_str.c = 0; + entry->metadata_str.len = 0; + PHP_VAR_SERIALIZE_INIT(metadata_hash); + php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(metadata_hash); + central.comment_len = PHAR_SET_16(entry->metadata_str.len); + } + entry->header_offset = php_stream_tell(p->filefp); + offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms); + if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) { + spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (sizeof(central) != php_stream_write(p->centralfp, (char *)¢ral, sizeof(central))) { + spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (entry->is_dir) { + if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) { + spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (1 != php_stream_write(p->filefp, "/", 1)) { + spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) { + spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (1 != php_stream_write(p->centralfp, "/", 1)) { + spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + } else { + if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) { + spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) { + spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + } + if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) { + spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) { + spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + if (entry->is_modified) { + if (entry->cfp) { + if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) { + spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + php_stream_close(entry->cfp); + entry->cfp = NULL; + } else { + if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) { + return ZEND_HASH_APPLY_STOP; + } + phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC); + if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) { + spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + } + if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) { + php_stream_close(entry->fp); + } + entry->is_modified = 0; + } else { + if (entry->fp_refcount) { + /* open file pointers refer to this fp, do not free the stream */ + switch (entry->fp_type) { + case PHAR_FP: + p->free_fp = 0; + break; + case PHAR_UFP: + p->free_ufp = 0; + default: + break; + } + } + if (!entry->is_dir && entry->compressed_filesize && entry->compressed_filesize != php_stream_copy_to_stream(p->old, p->filefp, entry->compressed_filesize)) { + spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + return ZEND_HASH_APPLY_STOP; + } + } + entry->fp = NULL; + entry->offset = entry->offset_abs = offset; + entry->fp_type = PHAR_FP; + if (entry->metadata_str.c) { + if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) { + spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); + smart_str_free(&entry->metadata_str); + return ZEND_HASH_APPLY_STOP; + } + smart_str_free(&entry->metadata_str); + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */ +{ + char *pos; + smart_str main_metadata_str = {0}; + static const char newstub[] = "is_data) { + goto nostub; + } + + /* set alias */ + if (!phar->is_temporary_alias && phar->alias_len) { + entry.fp = php_stream_fopen_tmpfile(); + if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) { + if (error) { + spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len; + entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1); + entry.filename_len = sizeof(".phar/alias.txt")-1; + if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + if (error) { + spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + } else { + zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1); + } + /* register alias */ + if (phar->alias_len) { + if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) { + return EOF; + } + } + + /* set stub */ + if (user_stub && !defaultstub) { + if (len < 0) { + /* resource passed in */ + if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) { + if (error) { + spprintf(error, 0, "unable to access resource to copy stub to new zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + if (len == -1) { + len = PHP_STREAM_COPY_ALL; + } else { + len = -len; + } + user_stub = 0; + if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) { + if (error) { + spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + free_user_stub = 1; + } else { + free_user_stub = 0; + } + if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL) + { + if (error) { + spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + return EOF; + } + len = pos - user_stub + 18; + entry.fp = php_stream_fopen_tmpfile(); + entry.uncompressed_filesize = len + 5; + + if ((size_t)len != php_stream_write(entry.fp, user_stub, len) + || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) { + if (error) { + spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname); + } + if (free_user_stub) { + efree(user_stub); + } + php_stream_close(entry.fp); + return EOF; + } + entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); + entry.filename_len = sizeof(".phar/stub.php")-1; + if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + if (free_user_stub) { + efree(user_stub); + } + if (error) { + spprintf(error, 0, "unable to set stub in zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + if (free_user_stub) { + efree(user_stub); + } + } else { + /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */ + entry.fp = php_stream_fopen_tmpfile(); + + if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { + php_stream_close(entry.fp); + if (error) { + spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); + } + return EOF; + } + + entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1; + entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); + entry.filename_len = sizeof(".phar/stub.php")-1; + + if (!defaultstub) { + if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_close(entry.fp); + efree(entry.filename); + if (error) { + spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + } else { + php_stream_close(entry.fp); + efree(entry.filename); + } + } else { + if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { + php_stream_close(entry.fp); + efree(entry.filename); + if (error) { + spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname); + } + return EOF; + } + } + } + +nostub: + + if (phar->fp && !phar->is_brandnew) { + oldfile = phar->fp; + closeoldfile = 0; + php_stream_rewind(oldfile); + } else { + oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL); + closeoldfile = oldfile != NULL; + } + + /* save modified files to the zip */ + pass.old = oldfile; + pass.filefp = php_stream_fopen_tmpfile(); + if (!pass.filefp) { + if (closeoldfile) { + php_stream_close(oldfile); + } + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); + } + return EOF; + } + pass.centralfp = php_stream_fopen_tmpfile(); + if (!pass.centralfp) { + if (closeoldfile) { + php_stream_close(oldfile); + } + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); + } + return EOF; + } + pass.free_fp = pass.free_ufp = 1; + memset(&eocd, 0, sizeof(eocd)); + + strncpy(eocd.signature, "PK\5\6", 4); + eocd.counthere = eocd.count = zend_hash_num_elements(&phar->manifest); + zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC); + if (temperr) { + php_stream_close(pass.filefp); + php_stream_close(pass.centralfp); + if (closeoldfile) { + php_stream_close(oldfile); + } + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr); + } + efree(temperr); + return EOF; + } + + /* save zip */ + eocd.cdir_size = php_stream_tell(pass.centralfp); + eocd.cdir_offset = php_stream_tell(pass.filefp); + php_stream_seek(pass.centralfp, 0, SEEK_SET); + if (eocd.cdir_size != php_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL)) { + php_stream_close(pass.filefp); + php_stream_close(pass.centralfp); + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + return EOF; + } + php_stream_close(pass.centralfp); + if (phar->metadata) { + /* set phar metadata */ + PHP_VAR_SERIALIZE_INIT(metadata_hash); + php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC); + PHP_VAR_SERIALIZE_DESTROY(metadata_hash); + eocd.comment_len = PHAR_SET_16(main_metadata_str.len); + if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { + php_stream_close(pass.filefp); + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + smart_str_free(&main_metadata_str); + return EOF; + } + if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) { + php_stream_close(pass.filefp); + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + smart_str_free(&main_metadata_str); + return EOF; + } + smart_str_free(&main_metadata_str); + } else { + if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { + php_stream_close(pass.filefp); + if (error) { + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); + } + if (closeoldfile) { + php_stream_close(oldfile); + } + return EOF; + } + } + if (phar->fp && pass.free_fp) { + php_stream_close(phar->fp); + } + if (phar->ufp) { + if (pass.free_ufp) { + php_stream_close(phar->ufp); + } + phar->ufp = NULL; + } + /* re-open */ + phar->is_brandnew = 0; + if (phar->donotflush) { + /* deferred flush */ + phar->fp = pass.filefp; + } else { + phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); + if (!phar->fp) { + if (closeoldfile) { + php_stream_close(oldfile); + } + phar->fp = pass.filefp; + if (error) { + spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); + } + return EOF; + } + php_stream_rewind(pass.filefp); + php_stream_copy_to_stream(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL); + /* we could also reopen the file in "rb" mode but there is no need for that */ + php_stream_close(pass.filefp); + } + + if (closeoldfile) { + php_stream_close(oldfile); + } + return EOF; +} +/* }}} */