@@ -573,8 +573,12 @@ static char * php_zipobj_get_zip_comment(ze_zip_object *obj, int *len) /* {{{ */
573573}
574574/* }}} */
575575
576- /* Close and free the zip_t */
577- static bool php_zipobj_close (ze_zip_object * obj ) /* {{{ */
576+ /* Close and free the zip_t. If the archive was opened as a string, the
577+ * final contents of the archive will be assigned to *out_str and that
578+ * string will afterwards be owned by the caller.
579+ *
580+ * If out_str is NULL, the final string contents, if any, will be discarded. */
581+ static bool php_zipobj_close (ze_zip_object * obj , zend_string * * out_str ) /* {{{ */
578582{
579583 struct zip * intern = obj -> za ;
580584 bool success = false;
@@ -606,7 +610,19 @@ static bool php_zipobj_close(ze_zip_object *obj) /* {{{ */
606610 obj -> filename_len = 0 ;
607611 }
608612
613+ if (obj -> out_str ) {
614+ if (out_str ) {
615+ * out_str = obj -> out_str ;
616+ } else {
617+ zend_string_release (obj -> out_str );
618+ }
619+ obj -> out_str = NULL ;
620+ } else {
621+ ZEND_ASSERT (!out_str );
622+ }
623+
609624 obj -> za = NULL ;
625+ obj -> from_string = false;
610626 return success ;
611627}
612628/* }}} */
@@ -1060,7 +1076,7 @@ static void php_zip_object_free_storage(zend_object *object) /* {{{ */
10601076{
10611077 ze_zip_object * intern = php_zip_fetch_object (object );
10621078
1063- php_zipobj_close (intern );
1079+ php_zipobj_close (intern , NULL );
10641080
10651081#ifdef HAVE_PROGRESS_CALLBACK
10661082 /* if not properly called by libzip */
@@ -1467,7 +1483,7 @@ PHP_METHOD(ZipArchive, open)
14671483 }
14681484
14691485 /* If we already have an opened zip, free it */
1470- php_zipobj_close (ze_obj );
1486+ php_zipobj_close (ze_obj , NULL );
14711487
14721488 /* open for write without option to empty the archive */
14731489 if ((flags & (ZIP_TRUNCATE | ZIP_RDONLY )) == 0 ) {
@@ -1491,28 +1507,34 @@ PHP_METHOD(ZipArchive, open)
14911507 ze_obj -> filename = resolved_path ;
14921508 ze_obj -> filename_len = strlen (resolved_path );
14931509 ze_obj -> za = intern ;
1510+ ze_obj -> from_string = false;
14941511 RETURN_TRUE ;
14951512}
14961513/* }}} */
14971514
1498- /* {{{ Create new read-only zip using given string */
1515+ /* {{{ Create new zip from a string, or a create an empty zip to be saved to a string */
14991516PHP_METHOD (ZipArchive , openString )
15001517{
1501- zend_string * buffer ;
1518+ zend_string * buffer = NULL ;
1519+ zend_long flags = 0 ;
15021520 zval * self = ZEND_THIS ;
15031521
1504- if (zend_parse_parameters (ZEND_NUM_ARGS (), "S " , & buffer ) == FAILURE ) {
1522+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "|Sl " , & buffer , & flags ) == FAILURE ) {
15051523 RETURN_THROWS ();
15061524 }
15071525
1526+ if (!buffer ) {
1527+ buffer = ZSTR_EMPTY_ALLOC ();
1528+ }
1529+
15081530 ze_zip_object * ze_obj = Z_ZIP_P (self );
15091531
1510- php_zipobj_close (ze_obj );
1532+ php_zipobj_close (ze_obj , NULL );
15111533
15121534 zip_error_t err ;
15131535 zip_error_init (& err );
15141536
1515- zip_source_t * zip_source = php_zip_create_string_source (buffer , NULL , & err );
1537+ zip_source_t * zip_source = php_zip_create_string_source (buffer , & ze_obj -> out_str , & err );
15161538
15171539 if (!zip_source ) {
15181540 ze_obj -> err_zip = zip_error_code_zip (& err );
@@ -1521,7 +1543,7 @@ PHP_METHOD(ZipArchive, openString)
15211543 RETURN_LONG (ze_obj -> err_zip );
15221544 }
15231545
1524- struct zip * intern = zip_open_from_source (zip_source , ZIP_RDONLY , & err );
1546+ struct zip * intern = zip_open_from_source (zip_source , flags , & err );
15251547 if (!intern ) {
15261548 ze_obj -> err_zip = zip_error_code_zip (& err );
15271549 ze_obj -> err_sys = zip_error_code_system (& err );
@@ -1530,6 +1552,7 @@ PHP_METHOD(ZipArchive, openString)
15301552 RETURN_LONG (ze_obj -> err_zip );
15311553 }
15321554
1555+ ze_obj -> from_string = true;
15331556 ze_obj -> za = intern ;
15341557 zip_error_fini (& err );
15351558 RETURN_TRUE ;
@@ -1568,7 +1591,34 @@ PHP_METHOD(ZipArchive, close)
15681591
15691592 ZIP_FROM_OBJECT (intern , self );
15701593
1571- RETURN_BOOL (php_zipobj_close (Z_ZIP_P (self )));
1594+ RETURN_BOOL (php_zipobj_close (Z_ZIP_P (self ), NULL ));
1595+ }
1596+ /* }}} */
1597+
1598+ /* {{{ close the zip archive and get the result as a string */
1599+ PHP_METHOD (ZipArchive , closeString )
1600+ {
1601+ struct zip * intern ;
1602+ zval * self = ZEND_THIS ;
1603+
1604+ ZEND_PARSE_PARAMETERS_NONE ();
1605+
1606+ ZIP_FROM_OBJECT (intern , self );
1607+
1608+ if (!Z_ZIP_P (self )-> from_string ) {
1609+ zend_throw_error (NULL , "ZipArchive::closeString can only be called on "
1610+ "an archive opened with ZipArchive::openString" );
1611+ RETURN_THROWS ();
1612+ }
1613+
1614+ zend_string * ret = NULL ;
1615+ bool success = php_zipobj_close (Z_ZIP_P (self ), & ret );
1616+ ZEND_ASSERT (ret );
1617+ if (success ) {
1618+ RETURN_STR (ret );
1619+ }
1620+ zend_string_release (ret );
1621+ RETURN_FALSE ;
15721622}
15731623/* }}} */
15741624
0 commit comments