-
-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Calculates the resulting file size with the minimal amount of work that is required. Fixes #89
- Loading branch information
Showing
8 changed files
with
863 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,47 @@ | ||
Adding Content-Length header | ||
============= | ||
|
||
Adding a ``Content-Length`` header for ``ZipStream`` is not trivial since the | ||
size is not known beforehand. | ||
Adding a ``Content-Length`` header for ``ZipStream`` can be achieved by | ||
using the options ``SIMULATION_STRICT`` or ``SIMULATION_LAX`` in the | ||
``operationMode`` parameter. | ||
|
||
The following workaround adds an approximated header: | ||
In the ``SIMULATION_STRICT`` mode, ``ZipStream`` will not allow to calculate the | ||
size based on reading the whole file. ``SIMULATION_LAX`` will read the whole | ||
file if neccessary. | ||
|
||
.. code-block:: php | ||
``SIMULATION_STRICT`` is therefore useful to make sure that the size can be | ||
calculated efficiently. | ||
|
||
use ZipStream\CompressionMethod; | ||
.. code-block:: php | ||
use ZipStream\OperationMode; | ||
use ZipStream\ZipStream; | ||
class Zip | ||
{ | ||
private $files = []; | ||
public function __construct( | ||
private readonly string $name | ||
) { } | ||
public function addFile( | ||
string $name, | ||
string $data, | ||
): void { | ||
$this->files[] = ['type' => 'addFile', 'name' => $name, 'data' => $data]; | ||
} | ||
public function addFileFromPath( | ||
string $name, | ||
string $path, | ||
): void { | ||
$this->files[] = ['type' => 'addFileFromPath', 'name' => $name, 'path' => $path]; | ||
$zip = new ZipStream( | ||
operationMode: OperationMode::SIMULATE_STRICT, // or SIMULATE_LAX | ||
defaultEnableZeroHeader: false, | ||
sendHttpHeaders: true, | ||
outputStream: $stream, | ||
); | ||
// Normally add files | ||
$zip->addFile('sample.txt', 'Sample String Data'); | ||
// Use addFileFromCallback and exactSize if you want to defer opening of | ||
// the file resource | ||
$zip->addFileFromCallback( | ||
'sample.txt', | ||
exactSize: 18, | ||
callback: function () { | ||
return fopen('...'); | ||
} | ||
); | ||
public function getEstimate(): int { | ||
$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()); | ||
$zip = new ZipStream( | ||
outputName: $this->name, | ||
SendHttpHeaders: true, | ||
enableZip64: false, | ||
defaultCompressionMethod: CompressionMethod::STORE, | ||
); | ||
foreach ($this->files as $file) { | ||
if ($file['type'] === 'addFile') { | ||
$zip->addFile( | ||
fileName: $file['name'], | ||
data: $file['data'], | ||
); | ||
} | ||
if ($file['type'] === 'addFileFromPath') { | ||
$zip->addFileFromPath( | ||
fileName: $file['name'], | ||
path: $file['path'], | ||
); | ||
} | ||
} | ||
$zip->finish(); | ||
} | ||
} | ||
It only works with the following constraints: | ||
|
||
- All file content is known beforehand. | ||
- Content Deflation is disabled | ||
// Read resulting file size | ||
$size = $zip->finish(); | ||
// Tell it to the browser | ||
header('Content-Length: '. $size); | ||
// Execute the Simulation and stream the actual zip to the client | ||
$zip->executeSimulation(); | ||
Thanks to | ||
`partiellkorrekt <https://github.com/maennchen/ZipStream-PHP/issues/89#issuecomment-1047949274>`_ | ||
for this workaround. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace ZipStream\Exception; | ||
|
||
use ZipStream\Exception; | ||
|
||
/** | ||
* This Exception gets invoked if a file is not as large as it was specified. | ||
*/ | ||
class FileSizeIncorrectException extends Exception | ||
{ | ||
/** | ||
* @internal | ||
*/ | ||
public function __construct( | ||
public readonly int $expectedSize, | ||
public readonly int $actualSize | ||
) { | ||
parent::__construct("File is {$actualSize} instead of {$expectedSize} bytes large. Adjust `exactSize` parameter."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace ZipStream\Exception; | ||
|
||
use ZipStream\Exception; | ||
|
||
/** | ||
* This Exception gets invoked if a strict simulation is executed and the file | ||
* information can't be determined without reading the entire file. | ||
*/ | ||
class SimulationFileUnknownException extends Exception | ||
{ | ||
public function __construct() | ||
{ | ||
parent::__construct('The details of the strict simulation file could not be determined without reading the entire file.'); | ||
} | ||
} |
Oops, something went wrong.