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

Reply via email to