Do webového rozhraní jsem potřeboval umístit odkaz pro stažení velkého množství fotek. Když by to bylo určeno pro technicky orientované uživatele, tak bych jim to šoupnul do TAR archivu, který má triviální strukturu a snadno se vytváří za běhu (není potřeba průběžně shromažďovat žádné informace). Tento archiv nepodporuje kompresi, to ale u fotek nevadí, protože ty už jsou komprimované samy o sobě. Běžní uživatelé si s tímto formátem ale neporadí a potřebují ZIP.
V PHP je extenze ZIP, která je šikovná na vytváření malých archivů, pro velké se ale vůbec nehodí. Archiv lze vytvářet v zásadě třemi způsoby:
Extenze ZIP patří do první kategorie, my bychom ideálně potřebovali něco z třetí kategorie. Druhá kategorie je nepříjemná v tom, že dokud není práce hotova, tak uživatel nemá žádnou odezvu. Navíc pokud má archiv několik giga, tak může být i problém místo na disku, obzvlášť pokud archivy stahuje víc lidí najednou.
Odolal jsem pokušení nastudovat si formát ZIP a vytvářet si ho sám a sáhl jsem po hotové knihovně. Chvíli jsem toho litoval, ale nakonec to dobře dopadlo. Nejprve jsem vyzkoušel knihovnu ZipStream-PHP, se kterou se docela dobře pracuje, ale vytvořený archiv nedokáže rozbalit Finder na Macu. Když zjistí, že archiv nedokáže rozbalit, tak neohlásí žádnou chybu a místo toho ho podruhé zabalí – uživatelsky přívětivé! Kód jsem proto přepsal pro knihovnu PHPZip, se kterou se taky dobře pracuje a archiv šlo rozbalit všude.
<?php include 'ZipStream.php'; $zip = new ZipStream("$archive.zip"); $compress = false; // output buffering by naše úsilí o postupné posílání zhatil while (ob_get_level()) { ob_end_clean(); } foreach (glob("files/*") as $filename) { $file = file_get_contents($filename); $zip->addFile($file, $filename, filemtime($filename), null, $compress); } $zip->finalize(); ?>
Za hlavní možnost vylepšení tohoto kódu považuji možnost navázat přerušené stahování hlavičkou Range
. Je velmi frustrující, když stáhnete giga fotek a kvůli nějakému zakuckání je musíte stahovat znovu. Vyžadovalo by to mít někde dostupnou velikost souborů bez nutnosti je stahovat (což obvykle není problém), vypnout kompresi (což u fotek nevadí) a vědět, jaká je velikost hlaviček vytvářených knihovnou.
Dalším vylepšením by bylo posílat hlavičku Content-Length
, aby uživatel věděl, kolik procent už stáhl. To by navíc ještě vyžadovalo vědět, jak velký bude adresář umísťovaný na konec archivu.
Fotky jsou v mém případě umístěny v úložišti S3, což obnáší ještě jednu nepříjemnost – musíme je tam odtud přenášet na webový server (což je rychlé a ničemu to nevadí) a z webového serveru ke klientovi (což může být pomalejší než z S3 a může to být dražší). Ideální by bylo, když by možnost stažení více souborů najednou podporovalo přímo S3. Pokud bychom dopředu věděli, které fotky budeme stahovat pohromadě, tak bychom si archiv mohli do S3 uložit, to ale nebyl můj případ.
Diskuse je zrušena z důvodu spamu.