nur-sery/nur_src/b/io/ZipBuilder.php

82 lines
2.3 KiB
PHP

<?php
namespace nur\b\io;
use nur\file;
use ZipArchive;
/**
* Class ZipStreamer: classe outil pour faciliter la construction dynamique d'un
* fichier zip qui est streamé vers l'utilisateur
*/
class ZipBuilder {
const TMPDIR = null;
function __construct(string $filename) {
$tmpzip = file::temp("zipf", static::TMPDIR);
$zip = new ZipArchive();
if ($zip->open($tmpzip, ZipArchive::CREATE) !== true) {
throw new IOException("unable to create $tmpzip");
}
$this->filename = $filename;
$this->tmpzip = $tmpzip;
$this->zip = $zip;
$this->deletes = [$tmpzip];
}
private $filename;
private $tmpzip;
private $zip;
private $deletes;
/**
* ajouter une entrée dans le fichier zip avec le nom spécifié
*
* un fichier temporaire est préparé, et une instance permettant d'y écrire
* est retournée. c'est ce fichier qui sera inséré dans le fichier zip.
*/
function newFile(string $entryname): IWriter {
$tmpfile = file::temp("zipe", static::TMPDIR);
$this->deletes[] = $tmpfile;
$outw = new FileWriter($tmpfile, "wb");
if ($this->zip->addFile($tmpfile, $entryname) !== true) {
$outw->close();
throw new IOException("unable to add $entryname");
}
return $outw;
}
/**
* ajouter une entrée dans le fichier zip construite à partir du fichier
* spécifié. ce fichier doit exister jusqu'à ce que la méthode {@link send()}
* soit appelée
*/
function addFile(string $file, ?string $entryname=null): void {
if ($entryname === null) $entryname = basename($file);
if ($this->zip->addFile($file, $entryname) !== true) {
throw new IOException("unable to add $file");
}
}
/**
* ajouter une entrée dans le fichier zip construite à partir de la chaine
* spécifiée
*/
function addString(string $entryname, string $content): void {
if ($this->zip->addFromString($entryname, $content) !== true) {
throw new IOException("unable to add $entryname");
}
}
/** finaliser le fichier zip et le streamer vers le client */
function send(): void {
$this->zip->close();
$zipf = file::open($this->tmpzip, "rb");
foreach ($this->deletes as $delete) {
unlink($delete);
}
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=\"$this->filename\"");
fpassthru($zipf);
}
}