]> granicus.if.org Git - php/commitdiff
implement Phar->getMetadata() Phar->setMetadata(), add tests, implement meta-data...
authorGreg Beaver <cellog@php.net>
Mon, 29 Jan 2007 03:59:55 +0000 (03:59 +0000)
committerGreg Beaver <cellog@php.net>
Mon, 29 Jan 2007 03:59:55 +0000 (03:59 +0000)
ext/phar/TODO
ext/phar/package.xml
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/phar_object.c
ext/phar/tests/009.phpt
ext/phar/tests/010.phpt
ext/phar/tests/phar_metadata_read.phpt [new file with mode: 0644]
ext/phar/tests/phar_metadata_write.phpt [new file with mode: 0644]
ext/phar/tests/phar_oo_001.phpt
ext/phar/tests/phar_test.inc

index 92116421de7326c9bcfda413d789277c026efcfe..3939b9b49ec8ebb432f850f48eef5112a77cb42c 100644 (file)
@@ -25,7 +25,7 @@ Version 1.0.0
  X add PharFileInfo::getMetaData() [Marcus]
  * always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from 
    streams interface
- * Phar archive metadata Phar::setMetaData($metadata) Phar::getMetaData()
+ X Phar archive metadata Phar::setMetaData($metadata) Phar::getMetaData() [Greg]
  X support rename() in stream wrapper [Greg]
  
 Version 1.1.0
index 37789e673e615c4461d60c9797cc1ca24343d91b..5e1fd4c214f2e269ad2f34709e210fa317cd4bf2 100644 (file)
@@ -107,6 +107,8 @@ if the ini variable phar.require_hash is set to true.
     <file name="open_for_write_newfile_c.phpt" role="test"/>
     <file name="phar_ctx_001.phpt" role="test"/>
     <file name="phar_commitwrite.phpt" role="test"/>
+    <file name="phar_metadata_read.phpt" role="test"/>
+    <file name="phar_metadata_write.phpt" role="test"/>
     <file name="phar_oo_001.phpt" role="test"/>
     <file name="phar_oo_002.phpt" role="test"/>
     <file name="phar_oo_003.phpt" role="test"/>
index a1de40f86fc20f33a217921297468e579790af39..9733534dd7f924fb31624171dfacc2648bc09090 100644 (file)
@@ -97,6 +97,10 @@ static void phar_destroy_phar_data(phar_archive_data *data TSRMLS_DC) /* {{{ */
        if (data->manifest.arBuckets) {
                zend_hash_destroy(&data->manifest);
        }
+       if (data->metadata) {
+               zval_ptr_dtor(&data->metadata);
+               data->metadata = 0;
+       }
        if (data->fp) {
                php_stream_close(data->fp);
                data->fp = 0;
@@ -802,8 +806,17 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int
                MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
        }
 
-       /* set up our manifest */
        mydata = ecalloc(sizeof(phar_archive_data), 1);
+       if (*(php_uint32 *) buffer) {
+               if (phar_parse_metadata(fp, &buffer, endbuffer, &mydata->metadata TSRMLS_CC) == FAILURE) {
+                       MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+               }
+       } else {
+               mydata->metadata = 0;
+               buffer += 4;
+       }
+       
+       /* set up our manifest */
        zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
                zend_get_hash_value, destroy_phar_manifest, 0);
        offset = 0;
@@ -838,7 +851,7 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int
                PHAR_GET_32(buffer, entry.flags);
                if (*(php_uint32 *) buffer) {
                        if (phar_parse_metadata(fp, &buffer, endbuffer, &entry.metadata TSRMLS_CC) == FAILURE) {
-                               MAPPHAR_FAIL("unable to read metadata in .phar file \"%s\"");
+                               MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
                        }
                } else {
                        buffer += 4;
@@ -1855,7 +1868,15 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC)
         * we need to skip entries marked is_deleted. */
        zend_hash_apply(&archive->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
 
-       /* compress as necessary, calculate crcs, manifest size, and file sizes */
+       /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
+       metadata_str.c = 0;
+       if (archive->metadata) {
+               PHP_VAR_SERIALIZE_INIT(metadata_hash);
+               php_var_serialize(&metadata_str, &archive->metadata, &metadata_hash TSRMLS_CC);
+               PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+       } else {
+               metadata_str.len = 0;
+       }
        new_manifest_count = 0;
        offset = 0;
        buf = (char *) emalloc(8192);
@@ -1953,14 +1974,17 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC)
         *  4: manifest entry count
         *  2: phar version
         *  4: phar global flags
-        *  4: alias length, the rest is the alias itself
+        *  4: alias length
+        *  ?: the alias itself
+        *  4: phar metadata length
+        *  ?: phar metadata
         */
        restore_alias_len = archive->alias_len;
        if (!archive->is_explicit_alias) {
                archive->alias_len = 0;
        }
 
-       manifest_len = offset + archive->alias_len + sizeof(manifest) - 4;
+       manifest_len = offset + archive->alias_len + sizeof(manifest) + metadata_str.len;
        phar_set_32(manifest, manifest_len);
        phar_set_32(manifest+4, new_manifest_count);
        *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
@@ -1976,11 +2000,40 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC)
                }
                php_stream_close(newfile);
                archive->alias_len = restore_alias_len;
-               php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest meta-data of new phar \"%s\"", archive->fname);
+               php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest header of new phar \"%s\"", archive->fname);
                return EOF;
        }
+       
        archive->alias_len = restore_alias_len;
        
+       metadata_str.c = 0;
+       phar_set_32(manifest, metadata_str.len);
+       if (metadata_str.len) {
+               if (4 != php_stream_write(newfile, manifest, 4) ||
+               metadata_str.len != php_stream_write(newfile, metadata_str.c, metadata_str.len)) {
+                       smart_str_free(&metadata_str);
+                       if (closeoldfile) {
+                               php_stream_close(oldfile);
+                       }
+                       php_stream_close(newfile);
+                       archive->alias_len = restore_alias_len;
+                       php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest meta-data of new phar \"%s\"", archive->fname);
+                       return EOF;
+               } 
+       } else {
+               if (4 != php_stream_write(newfile, manifest, 4)) {
+                       smart_str_free(&metadata_str);
+                       if (closeoldfile) {
+                               php_stream_close(oldfile);
+                       }
+                       php_stream_close(newfile);
+                       archive->alias_len = restore_alias_len;
+                       php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest header of new phar \"%s\"", archive->fname);
+                       return EOF;
+               }
+       }
+       smart_str_free(&metadata_str);
+       
        /* re-calculate the manifest location to simplify later code */
        manifest_ftell = php_stream_tell(newfile);
        
index 43fb5a4111744b37975c5cc0381d3fa5f2c4d63d..5130edb103aa452528c2f201cb1fc5b5ad1f544a 100755 (executable)
@@ -59,7 +59,7 @@
 #define PHAR_VERSION_STR          "1.0.0"
 /* x.y.z maps to 0xyz0 */
 #define PHAR_API_VERSION          0x1000
-#define PHAR_API_MIN_READ         0x0900
+#define PHAR_API_MIN_READ         0x1000
 #define PHAR_API_MAJORVERSION     0x1000
 #define PHAR_API_MAJORVER_MASK    0xF000
 #define PHAR_API_VER_MASK         0xFFF0
@@ -167,6 +167,7 @@ struct _phar_archive_data {
        php_uint32               sig_flags;
        int                      sig_len;
        char                     *signature;
+       zval                     *metadata;
        int                      is_explicit_alias:1;
        int                      is_modified:1;
        int                      is_writeable:1;
index 761f476c85a94b814741d7d1f72838472399bfc2..45f8f7dba6a8356772f4b7b32537a482256e1e8a 100755 (executable)
@@ -623,6 +623,41 @@ PHP_METHOD(Phar, getStub)
 }
 /* }}}*/
 
+/* {{{ proto int Phar::getMetaData()
+ * Returns the 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)
+ * Returns the metadata of the phar
+ */
+PHP_METHOD(Phar, setMetadata)
+{
+       zval *metadata;
+       PHAR_ARCHIVE_OBJECT();
+
+       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);
+}
+/* }}} */
+
 /* {{{ proto void PharFileInfo::__construct(string entry)
  * Construct a Phar entry object
  */
@@ -964,6 +999,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetSet, 0, 0, 2)
 ZEND_END_ARG_INFO();
 #endif
 
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_setMetadata, 0, 0, 1)
+       ZEND_ARG_INFO(0, metadata)
+ZEND_END_ARG_INFO();
+
 zend_function_entry php_archive_methods[] = {
 #if !HAVE_SPL
        PHP_ME(Phar, __construct,           arginfo_phar___construct,  ZEND_ACC_PRIVATE)
@@ -984,6 +1024,8 @@ zend_function_entry php_archive_methods[] = {
        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, getMetadata,           NULL,                       0)
+       PHP_ME(Phar, setMetadata,           arginfo_entry_setMetadata,  0)
 #endif
        /* static member functions */
        PHP_ME(Phar, apiVersion,            NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
@@ -1001,11 +1043,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_entry___construct, 0, 0, 1)
        ZEND_ARG_INFO(0, flags)
 ZEND_END_ARG_INFO();
 
-static
-ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_setMetadata, 0, 0, 1)
-       ZEND_ARG_INFO(0, metadata)
-ZEND_END_ARG_INFO();
-
 zend_function_entry php_entry_methods[] = {
        PHP_ME(PharFileInfo, __construct,        arginfo_entry___construct,  0)
        PHP_ME(PharFileInfo, getCompressedSize,  NULL,                       0)
index d594e88f4f11bd804d4b29c146187cbcc212b4f5..6a5bb7318795ed77f9d15ee2e1b9a74175333556 100644 (file)
@@ -9,7 +9,7 @@ phar.require_hash=0
 $file = "<?php
 Phar::mapPhar('hio');
 __HALT_COMPILER(); ?>";
-$file .= pack('VVnVV', 500, 500, 0x0900, 0x00000000, 0) . str_repeat('A', 500);
+$file .= pack('VVnVVV', 500, 500, 0x1000, 0x00000000, 0, 0) . str_repeat('A', 500);
 file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file);
 include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
 ?>
index dd905edada9a13734b8c744a8c24e822bdc84818..e07c85743b636acce7ad37321b2c84ce2bfed323 100644 (file)
@@ -13,7 +13,7 @@ __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, 0x0900, 0x00000000, 3) . 'hio' . $manifest;
+$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);
 include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
diff --git a/ext/phar/tests/phar_metadata_read.phpt b/ext/phar/tests/phar_metadata_read.phpt
new file mode 100644 (file)
index 0000000..eca2514
--- /dev/null
@@ -0,0 +1,64 @@
+--TEST--
+Phar with phar-level meta-data (read)
+--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 __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 'phar_test.inc';
+
+foreach($files as $name => $cont) {
+       var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+var_dump($phar->getMetaData());
+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"
+string(8) "hi there"
+NULL
+NULL
+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/phar_metadata_write.phpt b/ext/phar/tests/phar_metadata_write.phpt
new file mode 100644 (file)
index 0000000..a49799a
--- /dev/null
@@ -0,0 +1,69 @@
+--TEST--
+Phar with phar meta-data (write)
+--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 __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 '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'));
+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===
index 8b18873a1f387ad95e25b3268e664ad2f7aaf1d9..b2bb8cc0a7dfd701c5bb30e8139a0701478ccbb0 100755 (executable)
@@ -39,7 +39,7 @@ unlink(dirname(__FILE__) . '/phar_oo_test.phar.php');
 __halt_compiler();
 ?>
 --EXPECT--
-string(5) "0.9.0"
+string(5) "1.0.0"
 int(5)
 string(50) "Cannot call method on an uninitialized Phar object"
 ===DONE===
index 36ab85a29bb5cc9e6b3d645c29be7fc8307a8de6..213e95558c2fc04e5e301b7c34c533e1182e5639 100755 (executable)
@@ -49,7 +49,9 @@ foreach($files as $name => $cont)
 }
 
 $alias = 'hio';
-$manifest = pack('VnVV', count($files), 0x0900, $glags, strlen($alias)) . $alias . $manifest;
+
+if (isset($pmeta)) $pmeta = serialize($pmeta); else $pmeta = '';
+$manifest = pack('VnVV', count($files), 0x1000, $glags, strlen($alias)) . $alias . pack('V', strlen($pmeta)) . $pmeta . $manifest;
 $file .= pack('V', strlen($manifest)) . $manifest;
 
 foreach($files as $cont)