X Phar->setStub() for specifying a new stub to the phar [Greg]

This commit is contained in:
Greg Beaver 2007-01-21 23:22:57 +00:00
parent 17eedd00b9
commit 9c2651d210
5 changed files with 209 additions and 28 deletions

View File

@ -12,9 +12,9 @@ Version 1.0.0
have a handle opened for writing
* docs on file format/manifest description
* docs on uses
* stream context for specifying compression of a file
X stream context for specifying compression of a file [Marcus]
* stream context for specifying meta-data
* stream context for specifying a new prologue to the phar
X Phar->setStub() for specifying a new stub to the phar [Greg]
* add setUncompressed(), setCompressedGZ() and setCompressedBZ2() to
PharFileInfo class
* add uncompressAllFiles(), compressAllFilesGZ() and compressAllFilesBZ2()

View File

@ -1170,6 +1170,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
php_stream *fp, *fpf;
php_stream_filter *filter, *consumed;
php_uint32 offset;
zval **pzoption;
resource = php_url_parse(path);
@ -1203,6 +1204,17 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
idata->phar->refcount++;
php_url_free(resource);
efree(internal_file);
if (idata->internal_file->uncompressed_filesize == 0
&& idata->internal_file->compressed_filesize == 0
&& context && context->options
&& zend_hash_find(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption) == SUCCESS
&& zend_hash_find(HASH_OF(*pzoption), "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);
}
return fpf;
} else {
if (NULL == (idata = phar_get_entry_data(resource->host, strlen(resource->host), internal_file, strlen(internal_file) TSRMLS_CC))) {
@ -1287,7 +1299,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
idata->fp = php_stream_temp_new();
if (php_stream_copy_to_stream(fp, idata->fp, idata->internal_file->uncompressed_filesize) != idata->internal_file->uncompressed_filesize) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", idata->phar->fname, internal_file);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch 1 on file \"%s\")", idata->phar->fname, internal_file);
php_stream_close(idata->fp);
efree(idata);
efree(internal_file);
@ -1298,7 +1310,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
php_stream_filter_flush(consumed, 1);
php_stream_filter_remove(consumed, 1 TSRMLS_CC);
if (offset + idata->internal_file->compressed_filesize != php_stream_tell(fp)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", idata->phar->fname, internal_file);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch 2 on file \"%s\")", idata->phar->fname, internal_file);
php_stream_close(idata->fp);
efree(idata);
efree(internal_file);
@ -1310,7 +1322,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
/* bypass to temp stream */
idata->fp = php_stream_temp_new();
if (php_stream_copy_to_stream(fp, idata->fp, idata->internal_file->uncompressed_filesize) != idata->internal_file->uncompressed_filesize) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", idata->phar->fname, internal_file);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch 3 on file \"%s\")", idata->phar->fname, internal_file);
php_stream_close(idata->fp);
efree(idata);
efree(internal_file);
@ -1537,9 +1549,15 @@ static inline void phar_set_16(char *buffer, int var) /* {{{ */
#endif
} /* }}} */
int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */
/**
* 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_entry_data *data, char *user_stub, long len TSRMLS_DC) /* {{{ */
{
static const char newprologue[] = "<?php __HALT_COMPILER();";
static const char newstub[] = "<?php __HALT_COMPILER();";
phar_entry_info *entry;
int alias_len, fname_len, halt_offset, restore_alias_len, global_flags = 0;
char *fname, *alias;
@ -1548,7 +1566,7 @@ int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */
long offset;
php_uint32 copy, loc, new_manifest_count;
php_uint32 newcrc32;
php_stream *file, *oldfile, *newfile, *compfile;
php_stream *file, *oldfile, *newfile, *compfile, *stubfile;
php_stream_filter *filter;
php_serialize_data_t metadata_hash;
smart_str metadata_str = {0};
@ -1561,28 +1579,65 @@ int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */
newfile = php_stream_fopen_tmpfile();
filter = 0;
if (data->phar->halt_offset && oldfile) {
if (data->phar->halt_offset != php_stream_copy_to_stream(oldfile, newfile, data->phar->halt_offset)) {
if (oldfile) {
php_stream_close(oldfile);
if (len != 0) {
if (len < 0) {
/* resource passed in */
if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
if (oldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to read resource to copy stub to new phar \"%s\"", data->phar->fname);
return EOF;
}
if (len == -1) {
len = PHP_STREAM_COPY_ALL;
} else {
len = -len;
}
if (len != php_stream_copy_to_stream(stubfile, newfile, len) && len != PHP_STREAM_COPY_ALL) {
if (oldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to copy stub from resource to new phar \"%s\"", data->phar->fname);
return EOF;
}
} else {
if (len != php_stream_write(newfile, user_stub, len)) {
if (oldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to create stub from string in new phar \"%s\"", data->phar->fname);
return EOF;
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to copy prologue of old phar to new phar \"%s\"", data->phar->fname);
return EOF;
}
} else {
/* this is a brand new phar */
data->phar->halt_offset = sizeof(newprologue)-1;
if (sizeof(newprologue)-1 != php_stream_write(newfile, newprologue, sizeof(newprologue)-1)) {
if (oldfile) {
php_stream_close(oldfile);
if (data->phar->halt_offset && oldfile) {
if (data->phar->halt_offset != php_stream_copy_to_stream(oldfile, newfile, data->phar->halt_offset)) {
if (oldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to copy stub of old phar to new phar \"%s\"", data->phar->fname);
return EOF;
}
} else {
/* this is a brand new phar */
data->phar->halt_offset = sizeof(newstub)-1;
if (sizeof(newstub)-1 != php_stream_write(newfile, newstub, sizeof(newstub)-1)) {
if (oldfile) {
php_stream_close(oldfile);
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to create stub in new phar \"%s\"", data->phar->fname);
return EOF;
}
php_stream_close(newfile);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to create prologue in new phar \"%s\"", data->phar->fname);
return EOF;
}
}
manifest_ftell = php_stream_tell(newfile);
halt_offset = manifest_ftell;
/* compress as necessary, calculate crcs, manifest size, and file sizes */
new_manifest_count = 0;
@ -1912,7 +1967,6 @@ int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */
alias = 0;
}
alias_len = data->phar->alias_len;
halt_offset = data->phar->halt_offset;
zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, data->phar TSRMLS_CC);
zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len);
phar_open_file(file, fname, fname_len, alias, alias_len, halt_offset, NULL TSRMLS_CC);
@ -1930,7 +1984,7 @@ int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */
static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
{
if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) {
return phar_flush((phar_entry_data *)stream->abstract TSRMLS_CC);
return phar_flush((phar_entry_data *)stream->abstract, 0, 0 TSRMLS_CC);
} else {
return EOF;
}
@ -2315,7 +2369,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
idata = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
idata->fp = 0;
idata->phar = phar_get_archive(resource->host, strlen(resource->host), 0, 0 TSRMLS_CC);
phar_flush(idata TSRMLS_CC);
phar_flush(idata, 0, 0 TSRMLS_CC);
php_url_free(resource);
efree(idata);
return SUCCESS;

View File

@ -247,7 +247,7 @@ static int phar_dir_stat( php_stream *stream, php_stream_statbuf *ssb TSRMLS_
void phar_destroy_phar_data(phar_archive_data *data TSRMLS_DC);
phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len TSRMLS_DC);
phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len TSRMLS_DC);
int phar_flush(phar_entry_data *data TSRMLS_DC);
int phar_flush(phar_entry_data *data, char *user_stub, long len TSRMLS_DC);
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC);
END_EXTERN_C()

View File

@ -362,7 +362,7 @@ PHP_METHOD(Phar, offsetUnset)
data->phar = phar_obj->arc.archive;
data->fp = 0;
/* internal_file is unused in phar_flush, so we won't set it */
phar_flush(data TSRMLS_CC);
phar_flush(data, 0, 0 TSRMLS_CC);
efree(data);
RETURN_TRUE;
}
@ -372,6 +372,47 @@ PHP_METHOD(Phar, offsetUnset)
}
/* }}} */
/* {{{ proto int Phar::setStub(string|stream stub [, int len])
* set the pre-phar stub for the current writeable phar
*/
PHP_METHOD(Phar, setStub)
{
zval *stub;
phar_entry_data *idata;
long len = -1;
php_stream *stream;
PHAR_ARCHIVE_OBJECT();
if (PHAR_G(readonly)) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot set stub, phar is read-only");
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &stub, &len) == FAILURE) {
return;
}
idata = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
idata->phar = phar_obj->arc.archive;
idata->fp = 0;
idata->internal_file = 0;
if (Z_TYPE_P(stub) == IS_STRING) {
phar_flush(idata, Z_STRVAL_P(stub), Z_STRLEN_P(stub) TSRMLS_CC);
efree(idata);
} else if (Z_TYPE_P(stub) == IS_RESOURCE && (php_stream_from_zval_no_verify(stream, &stub))) {
if (len > 0) {
len = -len;
}
phar_flush(idata, (char *) &stub, len TSRMLS_CC);
efree(idata);
} else {
efree(idata);
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot only set stub to a string or read from a stream resource");
}
}
/* }}} */
/* {{{ proto void PharFileInfo::__construct(string entry)
* Construct a Phar entry object
*/
@ -573,6 +614,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mapPhar, 0, 0, 0)
ZEND_ARG_INFO(0, alias)
ZEND_END_ARG_INFO();
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setStub, 0, 0, 0)
ZEND_ARG_INFO(0, newstub)
ZEND_END_ARG_INFO();
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_loadPhar, 0, 0, 1)
ZEND_ARG_INFO(0, fname)
@ -601,6 +647,7 @@ zend_function_entry php_archive_methods[] = {
PHP_ME(Phar, getVersion, NULL, 0)
PHP_ME(Phar, getSignature, NULL, 0)
PHP_ME(Phar, getModified, NULL, 0)
PHP_ME(Phar, setStub, arginfo_phar_setStub, 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)

View File

@ -0,0 +1,80 @@
--TEST--
Phar stub
--SKIPIF--
<?php if (!extension_loaded("phar")) print "skip"; ?>
--INI--
phar.require_hash=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 '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);
?>
===DONE===
--CLEAN--
<?php
unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
__HALT_COMPILER();
?>
--EXPECT--
===DONE===
<?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(); ?>