Zip::extract() trusted the sizes and the compression method from an
entry's headers before checking that the data was there.
The copy loops padded short reads with pack('a'.$read_size, $buffer), so
a small archive could make extraction write a much larger file:
- a stored entry declaring more bytes than the archive holds copied
central directory bytes and NUL padding past the end of the file,
- a deflated entry declaring a large uncompressed size padded the
output up to that size, and
- an archive written by "zip -fz" produced 4 GiB from 280 bytes,
because ZIP64 stores 0xFFFFFFFF in the 32 bit size fields.
Entries using neither store nor deflate ended up in the output as their
raw compressed data. zlib answers the faked gzip header of an unknown
method with the bytes unchanged instead of an error.
Incomplete headers reached unpack(), which warned about the missing
input before the exception was thrown.
Extraction now checks that an entry's data lies in front of the central
directory, fails on a short read instead of padding it, and rejects
unsupported compression methods. Entries that the include and exclude
filters skip stay unchecked, because their data is never read. All
headers are read through readRecord(), which refuses a short read.
Regression tests cover each of these archives.