]> granicus.if.org Git - php/commitdiff
X Phar->setStub() for specifying a new stub to the phar [Greg]
authorGreg Beaver <cellog@php.net>
Sun, 21 Jan 2007 23:22:57 +0000 (23:22 +0000)
committerGreg Beaver <cellog@php.net>
Sun, 21 Jan 2007 23:22:57 +0000 (23:22 +0000)
ext/phar/TODO
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/phar_object.c
ext/phar/tests/phar_stub.phpt [new file with mode: 0644]

index a77289454442e15f5e32e8105948afbadf84ac5b..432e754e8421db15421af811f03ffa1885c1ff78 100644 (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() 
index 9a337fd0999ca26d17ea7346d9e905d27f5dc2dc..4e7d9e292af7b24a5fd12d95b77d6c80eb26c512 100644 (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 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 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 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;
index 028a723e71f5ab71534ef3c44970f42c564ece5f..53f1343e35dbaa267ef37dccb64118cc2939b817 100755 (executable)
@@ -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()
index b816b70beaa3c9f9493c70f2177f02dfe25f6166..eae4a83fb4efe433c66a85687d5332b3b812448a 100755 (executable)
@@ -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)
diff --git a/ext/phar/tests/phar_stub.phpt b/ext/phar/tests/phar_stub.phpt
new file mode 100644 (file)
index 0000000..97f7f15
--- /dev/null
@@ -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(); ?>
\ No newline at end of file