ID: 48763 Updated by: paj...@php.net Reported By: dani dot church at gmail dot com Status: Assigned Bug Type: Zip Related Operating System: CentOS 5 PHP Version: 5.2CVS-2009-07-01 (snap) Assigned To: pajoye New Comment:
Thanks for your patch! I have applied it to all branches and pecl. A pecl release will be done next week. Please note that the patch has been applied upstream as well (libzip repo). I will close the bug once the test is there too. Previous Comments: ------------------------------------------------------------------------ [2009-07-04 14:37:24] dani dot church at gmail dot com RalfBecker: In fact, one probable workaround, until this bug gets fixed, is to iterate through EVERY file in the ZipArchive, get the contents, and addFromString to put them back into the archive. By overwriting every single file in the archive (with its own contents), you won't trigger the bug. ------------------------------------------------------------------------ [2009-07-04 08:29:41] RalfBecker at outdoor-training dot de I can reproduce that bug with php5.2.9 under openSUSE11.0, thought I tried so far only oo3 *.odt files. It seems not to depend on the file, in fact I can not create a file, where I can replace content.xml with itself, without corrupting it. Ralf ------------------------------------------------------------------------ [2009-07-04 00:53:02] dani dot church at gmail dot com The patch, a PHP testbed, and a test ZIP file (empty.zip) can all be found at http://dchurch.ath.cx/phpzip/. The test ZIP is minimal and contains one empty file that uses a data descriptor. The PHP testbed takes this ZIP file, sets the modified flag by adding and removing a dummy file, and writes the results back to the browser. The ZIP file that PHP writes back to the browser is identical to the input file with the following exceptions: 1) The data descriptor, addresses 0x23-0x32 in the original file, is missing. The central directory starts at 0x33 in the original file, and at 0x23 in the modified file. 2) The central directory address, stored at 0x76 in the original file and 0x66 in the modified file, is updated from 0x33 to 0x23. 3) The local file header contains the flag 0x08 at address 0x06 to indicate that a data descriptor is present. This flag is cleared. 4) The central directory file header contains the flag 0x08 at address 0x3b (corresponding to 0x2b in the modified file), which is a copy of the same flag at 0x06. This flag SHOULD be cleared, but in the current CVS, it does not get cleared. The patch clears this flag. I don't have a test case for the other bug I found, since the if block at lines 173-185 seems to be something that isn't supposed to happen in the normal flow of execution. At the very least, I can't figure out a way to get to that point with ch_filename == NULL. However, if that block ever did get executed, it would result in a central directory entry with a listed filename length of 0 but the character "-" in the filename field-- again, an invalid ZIP file. ------------------------------------------------------------------------ [2009-07-03 17:35:24] paj...@php.net Ah thanks guys :) Do you have test cases for these two bugs (this one and the other you found while writing the patch)? It will help to valid the patch before I apply it. If you can post a link to the patch and the tests. Thanks for your work! ------------------------------------------------------------------------ [2009-07-03 02:33:42] dani dot church at gmail dot com You're absolutely right, that's the file with the bug. Both PHP 5.2.6 and 5.2.8+ produce malformed ZIP files, in slightly different ways, though only when UPDATING (not creating from scratch) ZIP files. The zip library does not write optional data descriptors, even if the input file has them. In 5.2.6, the "data descriptor exists" flag is set, even though there is no data descriptor. In 5.2.8+, the flag is (properly) cleared in the local file header, but not in the central directory. OpenOffice.org tolerates the bug in 5.2.6 but not the one in 5.2.8+. A patch to fix this bug (and another minor bug I found in the same area) follows: --- ext/zip/lib/zip_close.c.orig 2009-07-02 21:40:03.000000000 -0400 +++ ext/zip/lib/zip_close.c 2009-07-02 22:24:54.000000000 -0400 @@ -175,6 +175,7 @@ de.filename = strdup("-"); de.filename_len = 1; cd->entry[j].filename = "-"; + cd->entry[j].filename_len = 1; } else { de.filename = strdup(za->cdir->entry[i].filename); @@ -195,13 +196,14 @@ error = 1; break; } + memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { de.crc = za->cdir->entry[i].crc; de.comp_size = za->cdir->entry[i].comp_size; de.uncomp_size = za->cdir->entry[i].uncomp_size; de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; + cd->entry[j].bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; } - memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); } if (za->entry[i].ch_filename) { ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/48763 -- Edit this bug report at http://bugs.php.net/?id=48763&edit=1