ContentLength.rst 2.3 KB

Adding Content-Length header

Adding a Content-Length header for ZipStream is not trivial since the size is not known beforehand.

The following workaround adds an approximated header:

class Zip
{
    /** @var string */
    private $name;

    private $files = [];

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function addFile($name, $data)
    {
        $this->files[] = ['type' => 'addFile', 'name' => $name, 'data' => $data];
    }

    public function addFileFromPath($name, $path)
    {
        $this->files[] = ['type' => 'addFileFromPath', 'name' => $name, 'path' => $path];
    }

    public function getEstimate()
    {
        $estimate = 22;
        foreach ($this->files as $file) {
        $estimate += 76 + 2 * strlen($file['name']);
        if ($file['type'] === 'addFile') {
            $estimate += strlen($file['data']);
        }
        if ($file['type'] === 'addFileFromPath') {
            $estimate += filesize($file['path']);
        }
        }
        return $estimate;
    }

    public function finish()
    {
        header('Content-Length: ' . $this->getEstimate());
        $options = new \ZipStream\Option\Archive();
        $options->setSendHttpHeaders(true);
        $options->setEnableZip64(false);
        $options->setDeflateLevel(-1);
        $zip = new \ZipStream\ZipStream($this->name, $options);

        $fileOptions = new \ZipStream\Option\File();
        $fileOptions->setMethod(\ZipStream\Option\Method::STORE());
        foreach ($this->files as $file) {
        if ($file['type'] === 'addFile') {
            $zip->addFile($file['name'], $file['data'], $fileOptions);
        }
        if ($file['type'] === 'addFileFromPath') {
            $zip->addFileFromPath($file['name'], $file['path'], $fileOptions);
        }
        }
        $zip->finish();
        exit;
    }
}

It only works with the following constraints:

  • All file content is known beforehand.
  • Content Deflation is disabled

Thanks to partiellkorrekt for this workaround.