php_stream *fp, *fpf;
php_stream_filter *filter, *consumed;
php_uint32 offset;
+ zval **pzoption;
resource = php_url_parse(path);
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))) {
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);
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);
/* 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);
#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;
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};
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;
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);
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;
}
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;
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;
}
}
/* }}} */
+/* {{{ 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
*/
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)
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)
--- /dev/null
+--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(); ?>
\ No newline at end of file