@ -40,14 +40,34 @@ class Streamer {
*
* @param IRequest $request
* @param int $size The size of the files in bytes
* @param int $numberOfFiles The number of files (and directories) that will
* be included in the streamed file
*/
public function __construct(IRequest $request, int $size){
public function __construct(IRequest $request, int $size, int $numberOfFiles ){
/**
* If the size if below 4GB always use zip32
* Use 4*1000*1000*1000 so we have a buffer for all the extra zip data
* zip32 constraints for a basic (without compression, volumes nor
* encryption) zip file according to the Zip specification:
* - No file size is larger than 4 bytes (file size < 4294967296 ) ; see
* 4.4.9 uncompressed size
* - The size of all files plus their local headers is not larger than
* 4 bytes; see 4.4.16 relative offset of local header and 4.4.24
* offset of start of central directory with respect to the starting
* disk number
* - The total number of entries (files and directories) in the zip file
* is not larger than 2 bytes (number of entries < 65536 ) ; see 4 . 4 . 22
* total number of entries in the central dir
* - The size of the central directory is not larger than 4 bytes; see
* 4.4.23 size of the central directory
*
* Due to all that, zip32 is used if the size is below 4GB and there are
* less than 65536 files; the margin between 4*1000^3 and 4*1024^3
* should give enough room for the extra zip metadata. Technically, it
* would still be possible to create an invalid zip32 file (for example,
* a zip file from files smaller than 4GB with a central directory
* larger than 4GiB), but it should not happen in the real world.
*/
if ($size < 4 * 1000 * 1000 * 1000 ) {
if ($size < 4 * 1000 * 1000 * 1000 & & $ numberOfFiles < 65536 ) {
$this->streamerInstance = new ZipStreamer(['zip64' => false]);
} else if ($request->isUserAgent($this->preferTarFor)) {
$this->streamerInstance = new TarStreamer();