I have a PR open to add ZipArchive::openString():
https://github.com/php/php-src/pull/21205
This is a fork of a 2024 pull request by Soner Sayakci. I found the
old pull request and figured it could benefit from a bit of
enthusiasm, to get it over the line and into PHP.
ext/zip doesn't currently have a maintainer. It's been challenging to
find someone willing to hit the merge button. Nora Dossche provided a
much-needed review, and might eventually merge it, but they also
suggested that I post here, to see if anyone else is willing to take
it on.
The usual syndrome with PHP pull requests is that there are plenty of
people available for drive-by nitpicks, but nobody who really wants to
take responsibility. The nitpicks contradict each other so I have to
figure out who is serious about doing the merge. If you're just
passing by, I feel like I can respectfully disagree, but if you have
your finger on the merge button, I'll write it whatever way you want.
In comments on the PR I've outlined a plan for future improvements to
ext/zip which I'll relate here.
The current PR adds ZipArchive::openString(), which takes a single
parameter, being a ZIP archive stored in a string. It opens the
archive in read-only mode. I think it can be merged alone, it's
sufficiently forwards-compatible.
I've suggested that in future we could add a $flags parameter to
ZipArchive::openString(), by analogy with ZipArchive::open(), allowing
the user to choose whether the archive is read-only or read/write. For
consistency with ZipArchive::open(), it would be read/write by
default. Then we would add ZipArchive::closeToString(), which would
provide access to the updated string.
The read-only restriction in the current patch is the result of using
zip_source_buffer_create(), which takes a pointer to the string data.
But zip_source_buffer_create() is implemented as a wrapper around
zip_source_function_create(), a callback interface. If we call
zip_source_function_create() directly, we can separate and reallocate
the underlying zend string when libzip makes a write request.
Using the callback interface, we could also implement
ZipArchive::openStream(), that is, opening a ZIP file stored in a
seekable stream resource. You could open a ZIP stored inside a ZIP
this way:
$zip2->openStream( $zip1->getStream( 'file.zip' ) );
It also answers my own use case which is opening zip files in the
php://temp streams used by Guzzle for HTTP response bodies.
We could even reimplement ZipArchive::open() using the same mechanism,
using PHP to open the file and then wrapping the stream for libzip to
directly read. This would solve a long-standing request to allow
ZipArchive::open() to use stream protocols. The difficulty with this
is maintaining backwards compatibility with ext/zip's highly
idiosyncratic error reporting scheme.
--
Tim Starling
Wikimedia Foundation