ext/zip: ZipArchive::openString and other improvements
| From: | Tim Starling | Date: | Thu, 05 Mar 2026 23:57:15 +0000 |
| Subject: | ext/zip: ZipArchive::openString and other improvements | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-130261@lists.php.net to get a copy of this message | ||
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