ext/zip: ZipArchive::openString and other improvements

php.internals

Tim Starling

179 days ago
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