]> granicus.if.org Git - php/commitdiff
implement Phar::buildFromIterator()
authorGreg Beaver <cellog@php.net>
Wed, 12 Dec 2007 18:01:40 +0000 (18:01 +0000)
committerGreg Beaver <cellog@php.net>
Wed, 12 Dec 2007 18:01:40 +0000 (18:01 +0000)
first argument is an iterator that returns as values paths to files to add to the phar archive
the key should be the path that the file should be saved as within the phar archive
if the optional second parameter is passed, then the key is ignored and substr(value, strlen(base_directory)) is
used as the save path within the phar archive
[DOC]

ext/phar/TODO
ext/phar/package.php
ext/phar/package.xml
ext/phar/phar.phar
ext/phar/phar_object.c

index 3352eb9b6f99b4fdb9db3c32b1b3893c310c71c8..18d9e4d0f05d900ca52f998ad5e3f5829ea19227 100644 (file)
@@ -70,8 +70,7 @@ Version 1.3.0
    or foreach ($p->match('mime-type', 'image/jpeg') as $file)
  * Phar::copy($from, $to);
  X Phar::delete($what) [Greg]
- * Phar::buildFromIterator($filename, Iterator $it, array $addinfo = null);
-   $addinfo = array('alias','flags','metadata','stub'...)
+ X Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
  * Layout: Option to compress all content rather than single files.
    That excludes stub and manifest haeder.
  * stream context option for cleaning crap paths like phar://blah.phar/file//to\\here.php
index f1331eb0dfdedc0d2812b87ac3aa10f70a89bb04..2482c145e6bff4c5c8773a38bdfe511970eb42bf 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 $notes = '
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
  * add mapping of include/require from within a phar to location within phar [Greg]
    solves the include_path issue without code munging
  * add Phar::delete() [Greg]
index 512a6461fce64e55298b6df18e419c89a6ebecbb..b2f8aa869e466aa97e0153de53e827a83799649d 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.6.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+<package packagerversion="1.7.0RC1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  <name>phar</name>
  <channel>pecl.php.net</channel>
  <summary>allows running of complete applications out of .phar files (like Java .jar files)</summary>
@@ -29,10 +29,10 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
   <email>helly@php.net</email>
   <active>yes</active>
  </lead>
- <date>2007-08-24</date>
- <time>20:06:43</time>
+ <date>2007-12-12</date>
+ <time>11:56:58</time>
  <version>
-  <release>1.2.1</release>
+  <release>1.3.0</release>
   <api>1.1.0</api>
  </version>
  <stability>
@@ -42,18 +42,10 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
  <license uri="http://www.php.net/license">PHP License</license>
  <notes>
 
- * 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]
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * add mapping of include/require from within a phar to location within phar [Greg]
+   solves the include_path issue without code munging
+ * add Phar::delete() [Greg]
 
  </notes>
  <contents>
@@ -66,7 +58,6 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="phar.inc" role="src" />
     <file name="phar.php" role="src" />
     <file name="pharcommand.inc" role="src" />
-    <file name="phar.phar" role="php" />
    </dir> <!-- /phar -->
    <dir name="tests">
     <file name="001.phpt" role="test" />
@@ -113,6 +104,7 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="create_new_phar_b.phpt" role="test" />
     <file name="create_new_phar_c.phpt" role="test" />
     <file name="create_path_error.phpt" role="test" />
+    <file name="delete.phpt" role="test" />
     <file name="delete_in_phar.phpt" role="test" />
     <file name="delete_in_phar_b.phpt" role="test" />
     <file name="delete_in_phar_confirm.phpt" role="test" />
@@ -120,6 +112,7 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="extracted_001.phpt" role="test" />
     <file name="ini_set.phpt" role="test" />
     <file name="ini_set_off.phpt" role="test" />
+    <file name="md5.phar" role="test" />
     <file name="metadata_read.phpt" role="test" />
     <file name="metadata_write.phpt" role="test" />
     <file name="metadata_write_commit.phpt" role="test" />
@@ -133,6 +126,11 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="phar_commitwrite.phpt" role="test" />
     <file name="phar_create_in_cwd.phpt" role="test" />
     <file name="phar_ctx_001.phpt" role="test" />
+    <file name="phar_dir_iterate.phpt" role="test" />
+    <file name="phar_get_supportedcomp1.phpt" role="test" />
+    <file name="phar_get_supportedcomp2.phpt" role="test" />
+    <file name="phar_get_supportedcomp3.phpt" role="test" />
+    <file name="phar_get_supportedcomp4.phpt" role="test" />
     <file name="phar_get_suppoted_signatures_001.phpt" role="test" />
     <file name="phar_get_suppoted_signatures_002.phpt" role="test" />
     <file name="phar_metadata_read.phpt" role="test" />
@@ -159,6 +157,8 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="phar_oo_compressed_001b.phpt" role="test" />
     <file name="phar_oo_compressed_002.phpt" role="test" />
     <file name="phar_oo_compressed_002b.phpt" role="test" />
+    <file name="phar_oo_getmodified.phpt" role="test" />
+    <file name="phar_oo_nosig.phpt" role="test" />
     <file name="phar_oo_test.inc" role="test" />
     <file name="phar_oo_uncompressall.phpt" role="test" />
     <file name="phar_setalias.phpt" role="test" />
@@ -171,7 +171,12 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
     <file name="phar_stub_write_file.phpt" role="test" />
     <file name="phar_test.inc" role="test" />
     <file name="refcount1.phpt" role="test" />
+    <file name="refcount1_5_2.phpt" role="test" />
     <file name="rename.phpt" role="test" />
+    <file name="sha1.phar" role="test" />
+    <file name="sha256.phar" role="test" />
+    <file name="sha512.phar" role="test" />
+    <file name="test_signaturealgos.phpt" role="test" />
    </dir> <!-- /tests -->
    <file name="build_precommand.php" role="php" />
    <file name="config.m4" role="src" />
@@ -181,7 +186,7 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
    <file name="LICENSE" role="doc" />
    <file name="Makefile.frag" role="src" />
    <file name="phar.c" role="src" />
-   <file name="phar.phar" role="data" />
+   <file name="phar.phar" role="script" />
    <file name="phar_internal.h" role="src" />
    <file name="phar_object.c" role="src" />
    <file name="phar_path_check.c" role="src" />
@@ -223,32 +228,48 @@ avaiable then SHA-256 and SHA-512 signatures are supported as well.</description
  <changelog>
   <release>
    <version>
-    <release>1.2.1</release>
+    <release>1.3.0</release>
     <api>1.1.0</api>
    </version>
    <stability>
     <release>stable</release>
     <api>stable</api>
    </stability>
-   <date>2007-08-24</date>
+   <date>2007-12-12</date>
    <license uri="http://www.php.net/license">PHP License</license>
    <notes>
 
- * 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]
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * add mapping of include/require from within a phar to location within phar [Greg]
+   solves the include_path issue without code munging
+ * add Phar::delete() [Greg]
 
    </notes>
   </release>
+  <release>
+   <version>
+    <release>1.2.1</release>
+    <api>1.1.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2007-08-24</date>
+   <license uri="http://www.php.net/license">PHP License</license>
+   <notes>* 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]</notes>
+  </release>
   <release>
    <version>
     <release>1.2.0</release>
index b69bce64d3bfd21161a985a264b59be55ca91dd6..1ca18e93597e9f3326f115c57cbe418816de8044 100755 (executable)
Binary files a/ext/phar/phar.phar and b/ext/phar/phar.phar differ
index 7816dc3e4dcf7b8b0679f5c13790cfa08fc1de9e..3dc62a731921dbdab559d293c121c37113ddc7f1 100755 (executable)
@@ -306,6 +306,156 @@ PHP_METHOD(Phar, __construct)
                return; \
        }
 
+/* {{{ proto 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
+ */
+PHP_METHOD(Phar, buildFromIterator)
+{
+       zend_object_iterator *iter = NULL;
+       zval *obj, **value;
+       char *str_key, *base, *error;
+       uint str_key_len, base_len = 0;
+       zend_uchar key_type;
+       ulong int_key;
+       zend_class_entry *ce;
+       PHAR_ARCHIVE_OBJECT();
+
+
+       if (PHAR_G(readonly)) {
+               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;
+       }
+
+       ce = Z_OBJCE_P(obj);
+
+       iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
+       if (iter && !EG(exception)) {
+               obj = zend_iterator_wrap(iter TSRMLS_CC);
+       } else {
+               if (!EG(exception)) {
+                       zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name);
+               }
+               return;
+       }
+
+       if (iter) {
+               iter->index = 0;
+               if (iter->funcs->rewind) {
+                       iter->funcs->rewind(iter TSRMLS_CC);
+               }
+               if (FAILURE == iter->funcs->valid(iter TSRMLS_CC)) {
+                       zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned no values", ce->name);
+                       return;
+               }
+               do {
+                       phar_entry_data *data;
+                       php_stream *fp;
+                       long contents_len;
+                       char *fname;
+                       iter->funcs->get_current_data(iter, &value TSRMLS_CC);
+                       if (EG(exception)) {
+                               break;
+                       }
+                       if (!value) {
+                               /* failure in get_current_data */
+                               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned no value", ce->name);
+                       }
+                       if (Z_TYPE_PP(value) != IS_STRING) {
+                               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid value (must return a string)", ce->name);
+                               break;
+                       }
+                       if (!base_len && 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)) {
+                                       break;
+                               }
+                               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);
+                                       break;
+                               }
+                               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);
+                               break;
+                       }
+
+                       fname = Z_STRVAL_PP(value);
+                       if (base_len) {
+                               if (strstr(fname, base)) {
+                                       str_key_len = Z_STRLEN_PP(value) - base_len;
+                                       if (str_key_len <= 0) {
+                                               continue;
+                                       }
+                                       str_key = fname + base_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);
+                                       break;
+                               }
+                       }
+#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);
+                               break;
+                       }
+#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);
+                               break;
+                       }
+
+                       /* try to open source file, then create internal phar file and copy contents */
+                       fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, NULL);
+                       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);
+                               break;
+                       }
+
+                       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", &error TSRMLS_CC))) {
+                               zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error);
+                               efree(error);
+                               break;
+                       } else {
+                               if (error) {
+                                       efree(error);
+                               }
+                               contents_len = php_stream_copy_to_stream(fp, data->fp, PHP_STREAM_COPY_ALL);
+                       }
+                       data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
+                       phar_entry_delref(data TSRMLS_CC);
+                       /* This could cause an endless loop if index becomes zero again.
+                        * In case that ever happens we need an additional flag. */
+                       iter->funcs->move_forward(iter TSRMLS_CC);
+                       if (EG(exception)) {
+                               break;
+                       }
+                       if (iter->funcs->valid(iter TSRMLS_CC) == FAILURE) {
+                               /* reached end of iteration */
+                               break;
+                       }
+               } while (1);
+               if (!EG(exception)) {
+                       phar_flush(phar_obj->arc.archive, 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
  */
@@ -1603,6 +1753,12 @@ 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_build, 0, 0, 1)
+       ZEND_ARG_INFO(0, iterator)
+       ZEND_ARG_INFO(0, base_directory)
+ZEND_END_ARG_INFO();
 #endif
 
 static
@@ -1639,6 +1795,7 @@ zend_function_entry php_archive_methods[] = {
        PHP_ME(Phar, offsetSet,             arginfo_phar_offsetSet,    ZEND_ACC_PUBLIC)
        PHP_ME(Phar, offsetUnset,           arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
        PHP_ME(Phar, uncompressAllFiles,    NULL,                      ZEND_ACC_PUBLIC)
+       PHP_ME(Phar, buildFromIterator,     arginfo_phar_build,        ZEND_ACC_PUBLIC)
 #endif
        /* static member functions */
        PHP_ME(Phar, apiVersion,            NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)